浏览代码

Add files via upload

MoeClub 2 年之前
父节点
当前提交
7d0b57d4c3
共有 1 个文件被更改,包括 348 次插入0 次删除
  1. 348 0
      Deluge/deluge/RSS/DelugeRSS.py

+ 348 - 0
Deluge/deluge/RSS/DelugeRSS.py

@@ -0,0 +1,348 @@
+#!/usr/bin/env python3
+# -*- encoding: utf-8 -*-
+# Author:  MoeClub.org
+
+import os, re, gc, sqlite3, base64, time, json
+from lxml import etree
+from urllib import request
+from deluge_client import DelugeRPCClient
+
+
+Refresh_sec = '96'    # Time(s)
+Free_Space = '20'    # GB
+Ratio_Complete_Time = '80/2/5/100'    # 80/2/5; Complete_Ratio=80%; MinSpeed/Hour=2G/h; Hours_After=5h; Ignore_Size:100G; Disable: '0/0/0/0'
+File_Max_Size = '0'    # GB
+Torrent_Min_Size = '0'    # GB
+Torrent_Max_Size = '64'    # GB
+Torrent_Max_Time = '3.5'    # Days
+Torrent_Max_Ratio = '3'
+Download_Path = '/home/www/home'
+
+
+Spider_dict = {
+    'MT': {
+        'Enable': True,
+        'SavePath_ID': False,
+        'URL': ['', ],
+        'Download_URL': '',
+        'Cookie': ''
+    },
+}
+
+
+class Deluge:
+    def __init__(self, host='127.0.0.1', port='58846'):
+        self.path = os.path.dirname(os.path.abspath(__file__))
+        self.host = host
+        self.port = port
+
+    def auth(self):
+        auth_file = os.path.join(self.path, "auth")
+        if not os.path.exists(auth_file):
+            raise Exception
+        fd = open(auth_file, 'r', encoding='utf8')
+        client = None
+        for line in fd:
+            if line.startswith("#"):
+                continue
+            auth = line.split(":")
+            if len(auth) >= 2 and auth[0] == "localclient":
+                client = DelugeRPCClient(str(self.host), int(self.port), auth[0], auth[1], automatic_reconnect=False)
+                break
+        fd.close()
+        return client
+
+    def online(self, client):
+        if not client.connected:
+            try:
+                client.connect()
+                if not client.connected:
+                    print('%s:%s CONNECT FAIL.' % (self.host, self.port))
+                    return False
+            except:
+                print('%s:%s NOT TO CONNECT.' % (self.host, self.port))
+                return False
+        return True
+
+    def add_task(self, client, task, option={}):
+        if self.online(client):
+            if not isinstance(option, dict):
+                option = {}
+            return client.call('core.add_torrent_file', '', task, option)
+        else:
+            return False
+
+    def free_space(self, client, free='0', path=None):
+        if self.online(client):
+            reserve_space_total = 0
+            status = client.call('core.get_torrents_status', {}, ['progress', 'total_size'])
+            for torrent in status:
+                reserve_space = int(status[torrent][b'total_size'] * (100 - float(status[torrent][b'progress'])) / 100)
+                reserve_space_total += reserve_space
+            free_space_client = client.call('core.get_free_space', path)
+            free_space_reserve = int(float(free) * 1024 * 1024 * 1024)
+            really_space = int(free_space_client - reserve_space_total - free_space_reserve)
+            if really_space > 0:
+                return really_space
+            else:
+                return False
+        else:
+            return False
+
+    def torrents_status(self, client, Torrent_Max_Ratio, Torrent_Max_Time, Ratio_Complete_Time):
+        if self.online(client):
+            return_list = []
+            try:
+                RCT = [int(RCT_Item) for RCT_Item in str(Ratio_Complete_Time).split('/')]
+                assert len(RCT) == 4
+            except:
+                RCT = [0, 0, 0, 0]
+            result_dict = client.call('core.get_torrents_status', {}, ['progress', 'time_added', 'ratio', 'total_done', 'total_wanted'])
+            time_now = int(time.time())
+            for item in result_dict:
+                time_cost = int(time_now - int(result_dict[item][b'time_added']))
+                done_progress = int(result_dict[item][b'progress'])
+                if done_progress == int(100):
+                    if time_cost >= int(float(Torrent_Max_Time) * 86400) or float(result_dict[item][b'ratio']) >= float(Torrent_Max_Ratio):
+                        return_list.append(str(item.decode()))
+                else:
+                    if RCT[0] > 0 and RCT[1] > 0 and RCT[2] > 0:
+                        if int(RCT[3]) > 0 and int(result_dict[item][b'total_wanted']) >= int(RCT[3] * 1024 * 1024 * 1024):
+                            continue
+                        if time_cost > int(RCT[2] * 3600) and int(RCT[0]) > done_progress:
+                            if int(int(result_dict[item][b'total_done']) / time_cost) < int(RCT[1] * 1024 * 1024 * 1024 / 3600):
+                                return_list.append(str(item.decode()))
+            del result_dict
+            return return_list
+        else:
+            return False
+
+    def remove_torrents(self, client, id_list=[], remove_data=False):
+        if isinstance(id_list, bool) and id_list is False:
+            return False
+        if self.online(client):
+            if isinstance(id_list, list) and len(id_list) > 0:
+                for id_hash in id_list:
+                    client.call('core.remove_torrent', id_hash, remove_data)
+
+
+class Spider:
+    def __init__(self, URL='', Cookie='', Download_URL='', datatable='', database='DelugeRSS.db', Save_Id=False, charset='utf-8'):
+        self.path = os.path.dirname(os.path.abspath(__file__))
+        self.database = os.path.join(self.path, database)
+        self.URL = URL
+        self.Cookie = Cookie
+        self.datatable = datatable
+        self.download_url = Download_URL
+        self.charset = charset
+        self.save_id = Save_Id
+        self.http_timeout = 8
+
+        conn = sqlite3.connect(self.database, timeout=1)
+        cursor = conn.cursor()
+        # status 0: False, 1: True
+        sql = '''create table if not exists ''' + self.datatable + ''' (item_id int PRIMARY KEY, status int);'''
+        cursor.execute(sql)
+        conn.commit()
+        conn.close()
+
+        self.Header = {'User-Agent': 'Mozilla/5.0', 'Cookie': str(self.Cookie)}
+        self.req = request.Request(self.URL, headers=self.Header)
+
+    def get_item(self):
+        item_list = []
+        try:
+            page = request.urlopen(self.req, timeout=self.http_timeout).read().decode(self.charset, "ignore")
+            if 'logout.php' not in page:
+                print('[%s] Login Fail! ' % self.datatable)
+                raise Exception
+        except:
+            return item_list
+        html = etree.HTML(page)
+        try:
+            ratio = str(html.xpath('//*[@class="color_ratio"]/following::text()[1]')[0])
+            if ratio:
+                print('[%s] Ratio: %s' % (self.datatable, ratio))
+        except:
+            print('[%s] Ratio: Null' % self.datatable)
+        for href in html.xpath('//a[contains(@href, "download.php")]'):
+            try:
+                item_id = re.findall('id=[0-9]+|hash=[0-9a-zA-Z,_\-]+', href.attrib['href'], re.I)[0].split('=')[1]
+                if item_id not in item_list:
+                    item_list.append(item_id)
+            except:
+                try:
+                    item_id = re.findall('id=[0-9]+|hash=[0-9a-zA-Z,_\-]+', href.attrib['action'], re.I)[0].split('=')[1]
+                    if item_id not in item_list:
+                        item_list.append(item_id)
+                except:
+                    continue
+        del html
+        del page
+        return item_list
+
+    def check_item(self, item_id):
+        conn = sqlite3.connect(self.database, timeout=1)
+        cursor = conn.cursor()
+        sql = '''select status FROM ''' + self.datatable + ''' WHERE item_id=''' + str(item_id) + ''';'''
+        cursor.execute(sql)
+        res = cursor.fetchone()
+        conn.close()
+        if res:
+            if res[0] > 0:
+                return True
+            else:
+                return False
+        else:
+            return False
+
+    def add_item(self, item_id, status):
+        conn = sqlite3.connect(self.database, timeout=1)
+        cursor = conn.cursor()
+        sql = '''INSERT INTO ''' + self.datatable + ''' VALUES (''' + str(item_id) + ''', ''' + str(status) + ''');'''
+        cursor.execute(sql)
+        row = cursor.rowcount
+        conn.commit()
+        conn.close()
+        if row >= 1:
+            return True
+        else:
+            return False
+
+    def data_item(self, item_id):
+        torrent_URL = str(self.download_url) + str(item_id)
+        torrent_req = request.Request(torrent_URL, headers=self.Header)
+        torrent_data = request.urlopen(torrent_req, timeout=self.http_timeout).read()
+        return base64.b64encode(torrent_data)
+
+    def exec_item(self):
+        item_continue = True
+        item_list = self.get_item()
+        if not isinstance(item_list, list):
+            raise Exception
+        for item_id in item_list:
+            if not item_continue:
+                break
+            if not self.check_item(item_id):
+                try:
+                    torrent_base64 = self.data_item(item_id)
+                    torrent_info = utils.torrent_info(torrent_base64, Torrent_Max_Size, Torrent_Min_Size, File_Max_Size)
+                except:
+                    continue
+                disk_free_space = deluge.free_space(client, Free_Space)
+                if isinstance(disk_free_space, bool) and disk_free_space is False:
+                    item_continue = False
+                    print('Error! Get disk space. ')
+                    continue
+                if not torrent_info['over_max']:
+                    if disk_free_space > torrent_info['size']:
+                        try:
+                            if '/' not in str(Download_Path) or not str(Download_Path).startswith('/'):
+                                raise Exception
+                            if self.save_id:
+                                option = '{"download_location":"' + str(Download_Path) + '/' + str(item_id) + '"}'
+                            else:
+                                option = '{"download_location":"' + str(Download_Path) + '"}'
+                            option = json.loads(re.sub('/+', '/', option))
+                        except:
+                            option = {}
+                        task = deluge.add_task(client, torrent_base64, option)
+                        # task = 'task_debug'
+                    else:
+                        task = 'task_full'
+                else:
+                    task = 'task_big'
+                if task != None:
+                    if task == 'task_full':
+                        print('%s[skip_full]: %s' % (self.datatable, item_id))
+                    elif task == 'task_big':
+                        self.add_item(item_id, 2)
+                        print('%s[skip_big]: %s' % (self.datatable, item_id))
+                    else:
+                        self.add_item(item_id, 1)
+                        print('%s[success]: %s' % (self.datatable, item_id))
+                else:
+                    self.add_item(item_id, 1)
+                    print('%s[already]: %s' %(self.datatable, item_id))
+                del torrent_base64
+
+
+class Utils:
+    def __init__(self):
+        self.path = os.path.dirname(os.path.abspath(__file__))
+
+    def free_cache(self):
+        gc.collect()
+        cache_path = '/proc/sys/vm/drop_caches'
+        if os.path.exists(cache_path):
+            os.system('echo 3 > ' + cache_path)
+
+    def torrent_read(self, torrent_name):
+        torrent_path = os.path.join(self.path, torrent_name)
+        if not os.path.exists(torrent_path):
+            return None
+        fd = open(torrent_path, 'rb')
+        torrent_data = fd.read()
+        fd.close()
+        return base64.b64encode(torrent_data)
+
+    def torrent_info(self, torrent_base64, Max_Torrent_Size='0', Min_Torrent_Size='0', Max_Single_Size='0'):
+        torrent_size = 0
+        torrent_item = 0
+        status_list = []
+        single_max_size_status = False
+        torrent_max_size_status = False
+        single_max_size = int(float(Max_Single_Size) * 1024 * 1024 * 1024)
+        torrent_max_size = int(float(Max_Torrent_Size) * 1024 * 1024 * 1024)
+        torrent_min_size = int(float(Min_Torrent_Size) * 1024 * 1024 * 1024)
+        torrent_data = base64.b64decode(torrent_base64)
+        for x_size in re.findall(b':lengthi\d+e', torrent_data):
+            item_size = int(re.findall('\d+', str(x_size))[0])
+            if not single_max_size_status and single_max_size != 0 and item_size > single_max_size:
+                single_max_size_status = True
+            torrent_size += item_size
+            torrent_item += 1
+        status_list.append(torrent_max_size != 0 and torrent_size > torrent_max_size)
+        status_list.append(torrent_min_size != 0 and torrent_size < torrent_min_size)
+        if True in status_list:
+            torrent_max_size_status = True
+        return {'size': torrent_size, 'item': torrent_item, 'over_max': torrent_max_size_status, 'over_max_single': single_max_size_status}
+
+
+if __name__ == "__main__":
+    deluge = Deluge()
+    utils = Utils()
+    while True:
+        client = deluge.auth()
+        try:
+            print('Time:', time.strftime('%Y/%m/%d %H:%M:%S', time.localtime()))
+            for item in Spider_dict:
+                if Spider_dict[item]['Enable']:
+                    utils.free_cache()
+                    print('Refreshing [%s] ...' % item)
+                    for ItemURL in Spider_dict[item]['URL']:
+                        try:
+                            if not str(ItemURL).strip():
+                                continue
+                            spider = Spider(URL=str(ItemURL).strip(),  Cookie=str(Spider_dict[item]['Cookie']).strip(), Download_URL=str(Spider_dict[item]['Download_URL']).strip(), Save_Id=Spider_dict[item]['SavePath_ID'], datatable=str(item).strip())
+                            spider.exec_item()
+                            del spider
+                        except:
+                            print("Error! Task URL [%s]! " % item)
+                else:
+                    print('Refreshing [%s] skip! ' % item)
+        except:
+            print('Error! Task Exception. ')
+        finally:
+            print('Checking torrents ...')
+            try:
+                deluge.remove_torrents(client, deluge.torrents_status(client, Torrent_Max_Ratio, Torrent_Max_Time, Ratio_Complete_Time), True)
+                del client
+                utils.free_cache()
+            except Exception as error:
+                print('Error!', error)
+            finally:
+                print(str('Waitting refresh: {}\n').format(Refresh_sec))
+                time.sleep(int(Refresh_sec))
+
+