diff --git a/AutoBangumi/app/auto_set_rule.py b/AutoBangumi/app/auto_set_rule.py index fa655e11..3b7598e5 100644 --- a/AutoBangumi/app/auto_set_rule.py +++ b/AutoBangumi/app/auto_set_rule.py @@ -1,3 +1,4 @@ +import re import sys from env import EnvInfo import qbittorrentapi @@ -8,7 +9,8 @@ import os class SetRule: def __init__(self): with open(EnvInfo.info_path) as f: - self.bangumi_info = json.load(f)["bangumi_info"] + self.info = json.load(f) + self.bangumi_info = self.info["bangumi_info"] self.rss_link = EnvInfo.rss_link self.host_ip = EnvInfo.host_ip self.user_name = EnvInfo.user_name @@ -34,11 +36,15 @@ class SetRule: 'lastMatch': '', 'addPaused': False, 'assignedCategory': 'Bangumi', - 'savePath': str(os.path.join(self.download_path, bangumi_name, season)) + 'savePath': str(os.path.join(self.download_path, re.sub(EnvInfo.rule_name_re," ", bangumi_name), season)) } self.qb.rss_set_rule(rule_name=bangumi_name, rule_def=rule) def rss_feed(self): + try: + self.qb.rss_remove_item(item_path="Mikan_RSS") + except qbittorrentapi.exceptions.Conflict409Error: + sys.stdout.write(f"[{EnvInfo.time_show_obj}] No feed exists, starting adding feed." + "\n") try: self.qb.rss_add_feed(url=self.rss_link, item_path="Mikan_RSS") sys.stdout.write(f"[{EnvInfo.time_show_obj}] Successes adding RSS Feed." + "\n") @@ -51,7 +57,11 @@ class SetRule: sys.stdout.write(f"[{EnvInfo.time_show_obj}] Start adding rules." + "\n") sys.stdout.flush() for info in self.bangumi_info: - self.set_rule(info["title"], info["season"]) + if not info["added"]: + self.set_rule(info["title"], info["season"]) + info["added"] = True + with open(EnvInfo.info_path, 'w', encoding='utf8') as f: + json.dump(self.info, f, indent=4, separators=(',', ': '), ensure_ascii=False) sys.stdout.write(f"[{EnvInfo.time_show_obj}] Finished." + "\n") sys.stdout.flush() diff --git a/AutoBangumi/app/collect_bangumi_info.py b/AutoBangumi/app/collect_bangumi_info.py index 24f25cfd..02171420 100644 --- a/AutoBangumi/app/collect_bangumi_info.py +++ b/AutoBangumi/app/collect_bangumi_info.py @@ -10,7 +10,7 @@ from env import EnvInfo class MatchRule: split_rule = r"\[|\]|\【|\】|\★|\(|\)|\(|\)" last_rule = r"(.*)( \-)" - sub_title = r"[^\x00-\xff]{1,}| \d{1,2}|\·" + sub_title = r"[^\x00-\xff]{1,}| \d{1,2}^.*|\·" match_rule = r"(S\d{1,2}(.*))" season_match = r"(.*)(Season \d{1,2}|S\d{1,2}|第.*季|第.*期)" @@ -55,7 +55,7 @@ class CollectRSS: while '' in b: b.remove('') pre_name = max(b, key=len, default='').strip() - if pre_name != '' and len(pre_name.encode()) > 3: + if len(pre_name.encode()) > 3: bangumi_title = pre_name for i in range(2): match_obj = re.match(MatchRule.last_rule, bangumi_title, re.I) @@ -90,12 +90,14 @@ class CollectRSS: json_title = match_title_season.group(1).strip() json_season = match_title_season.group(2) else: - json_season = '' + json_season = 'S01' json_title = title if json_title not in had_data: self.info["bangumi_info"].append({ "title": json_title, - "season": json_season + "season": json_season, + "group": '', + "added": False }) sys.stdout.write(f"[{EnvInfo.time_show_obj}] add {json_title} {json_season}" + "\n") sys.stdout.flush() diff --git a/AutoBangumi/app/docker_main.py b/AutoBangumi/app/docker_main.py index e4be98d1..86f66329 100644 --- a/AutoBangumi/app/docker_main.py +++ b/AutoBangumi/app/docker_main.py @@ -9,7 +9,7 @@ from env import EnvInfo def create_data_file(): if not os.path.exists(EnvInfo.info_path): - bangumi_info = {"rss_link": EnvInfo.rss_link, + bangumi_info = {"rss_link": "", "bangumi_info": [] } with open(EnvInfo.info_path, "w") as i: diff --git a/AutoBangumi/app/env.py b/AutoBangumi/app/env.py index af1e01aa..fde5003b 100644 --- a/AutoBangumi/app/env.py +++ b/AutoBangumi/app/env.py @@ -3,15 +3,30 @@ import time class EnvInfo: - info_path = "/config/bangumi.json" - host_ip = os.environ["HOST"] - sleep_time = float(os.environ["TIME"]) - user_name = os.environ["USER"] - password = os.environ["PASSWORD"] - rss_link = os.environ["RSS"] - download_path = os.environ["DOWNLOAD_PATH"] - method = os.environ["METHOD"] - # rss_link = "https://mikanani.me/RSS/Classic" + debug_mode = False + # Docker Env + if not debug_mode: + host_ip = os.environ["HOST"] + sleep_time = float(os.environ["TIME"]) + user_name = os.environ["USER"] + password = os.environ["PASSWORD"] + rss_link = os.environ["RSS"] + download_path = os.environ["DOWNLOAD_PATH"] + method = os.environ["METHOD"] + info_path = "/config/bangumi.json" + rule_path = "/config/rule.json" + else: + # Debug ENV + host_ip = "localhost:8080" + sleep_time = 10 + user_name = "admin" + password = "adminadmin" + rss_link = "" + download_path = "/downloads/Bangumi" + method = "pn" + info_path = "../config/bangumi.json" + rule_path = "../config/rule.json" + # Static ENV rule_url = "https://raw.githubusercontent.com/EstrellaXD/Bangumi_Auto_Collector/main/AutoBangumi/config/rule.json" - rule_path = "/config/rule.json" - time_show_obj = time.strftime('%Y-%m-%d %X') \ No newline at end of file + time_show_obj = time.strftime('%Y-%m-%d %X') + rule_name_re = r"\:|\/|\." diff --git a/AutoBangumi/app/rename_qb.py b/AutoBangumi/app/rename_qb.py index df406f84..42974351 100644 --- a/AutoBangumi/app/rename_qb.py +++ b/AutoBangumi/app/rename_qb.py @@ -14,7 +14,7 @@ class qBittorrentRename: self.qbt_client.auth_log_in() except qbittorrentapi.LoginFailed as e: print(e) - self.recent_info = self.qbt_client.torrents_info(status_filter='completed') + self.recent_info = self.qbt_client.torrents_info(status_filter='completed',category="Bangumi") self.hash = None self.name = None self.new_name = None diff --git a/AutoBangumi/config/rule.json b/AutoBangumi/config/rule.json index 31d412e2..e519c591 100644 --- a/AutoBangumi/config/rule.json +++ b/AutoBangumi/config/rule.json @@ -1,58 +1,58 @@ [ - { - "group_name": [ - "Lilith-Raws", - "NC-Raws", - "Skymoon-Raws", - "天月搬运组", - "LoliHouse", - "猎户不鸽发布组", - "NaN-Raws", - "猎户随缘发布组", - "桜都字幕组", - "澄空学园&雪飘工作室", - "千夏字幕组", - "IET字幕组", - "离谱Sub", - "酷漫404", - "星空字幕组", - "轻之国度字幕组", - "枫叶字幕组", - "雪飘工作室", - "豌豆字幕组", - "云光字幕组", - "悠哈璃羽字幕社", - "桜都字幕组", - "ANi", - "❀拨雪寻春❀", - "极彩字幕组", - "悠哈璃羽字幕社", - "爱恋&漫猫字幕组", - "MingY", - "VCB-Studio" - ], - "name_position": 1 - }, - { - "group_name": [ - "喵萌奶茶屋", - "爱恋字母社", - "诸神字幕组", - "驯兽师联盟", - "夏沐字幕组", - "幻樱", - "动漫国字幕组", - "SweetSub&圆环记录攻略组", - "动漫萌", - "极影字幕社", - "喵萌Production" - ], - "name_position": 2 - }, - { - "group_name": [ - "爱恋字母社" - ], - "name_position": 3 - } + { + "group_name": [ + "Lilith-Raws", + "NC-Raws", + "Skymoon-Raws", + "天月搬运组", + "LoliHouse", + "猎户不鸽发布组", + "NaN-Raws", + "猎户随缘发布组", + "桜都字幕组", + "澄空学园&雪飘工作室", + "千夏字幕组", + "IET字幕组", + "离谱Sub", + "酷漫404", + "星空字幕组", + "轻之国度字幕组", + "枫叶字幕组", + "雪飘工作室", + "豌豆字幕组", + "云光字幕组", + "悠哈璃羽字幕社", + "桜都字幕组", + "ANi", + "❀拨雪寻春❀", + "极彩字幕组", + "悠哈璃羽字幕社", + "爱恋&漫猫字幕组", + "MingY", + "VCB-Studio" + ], + "name_position": 1 + }, + { + "group_name": [ + "喵萌奶茶屋", + "爱恋字母社", + "诸神字幕组", + "驯兽师联盟", + "夏沐字幕组", + "幻樱", + "动漫国字幕组", + "SweetSub&圆环记录攻略组", + "动漫萌", + "极影字幕社", + "喵萌Production" + ], + "name_position": 2 + }, + { + "group_name": [ + "爱恋字母社" + ], + "name_position": 3 + } ] \ No newline at end of file diff --git a/README.md b/README.md index b26f5a2d..78d83a00 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # AutoBangumi - 全自动追番程序 -# V 2.0 -V2.0 Beta 已经完成,相比于 1.0 改进: +# 2.0 +2.0 Stable 已经完成,相比于 1.0 改进: - 无需手动设定下载规则 - 更符合刮削器的命名规则 - 自动归类 Season diff --git a/Windows/app/auto_set_rule.py b/Windows/app/auto_set_rule.py deleted file mode 100644 index 6bc63f8e..00000000 --- a/Windows/app/auto_set_rule.py +++ /dev/null @@ -1,56 +0,0 @@ -import sys -import time - -import qbittorrentapi -import json -import os - - -class SetRule: - def __init__(self, config): - with open("../config/bangumi.json") as f: - self.bangumi_info = json.load(f) - self.rss_link = config["rss_link"] - self.host_ip = config["host_ip"] - self.user_name = config["user_name"] - self.password = config["password"] - self.download_path = config["download_path"] - self.qb = qbittorrentapi.Client(host=self.host_ip, username=self.user_name, password=self.password) - try: - self.qb.auth_log_in() - except qbittorrentapi.LoginFailed as e: - print(e) - - def set_rule(self, bangumi_name, season): - rule = { - 'enable': True, - 'mustContain': bangumi_name, - 'mustNotContain': '720', - 'useRegx': True, - 'episodeFilter': '', - 'smartFilter': False, - 'previouslyMatchedEpisodes': [], - 'affectedFeeds': [self.rss_link], - 'ignoreDays': 0, - 'lastMatch': '', - 'addPaused': False, - 'assignedCategory': 'Bangumi', - 'savePath': str(os.path.join(self.download_path, bangumi_name, season)) - } - self.qb.rss_set_rule(rule_name=bangumi_name, rule_def=rule) - - def add_rss_feed(self): - try: - self.qb.rss_add_feed(self.rss_link) - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] Successes adding RSS Feed." + "\n") - except ConnectionError: - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] Error with adding RSS Feed." + "\n") - - def run(self): - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] Start adding rules." + "\n") - sys.stdout.flush() - for info in self.bangumi_info: - self.set_rule(info["title"], info["season"]) - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] Finished." + "\n") - sys.stdout.flush() - diff --git a/Windows/app/collect_bangumi_info.py b/Windows/app/collect_bangumi_info.py deleted file mode 100644 index dbcba356..00000000 --- a/Windows/app/collect_bangumi_info.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: UTF-8 -*- -import sys -import time -import requests -from bs4 import BeautifulSoup -import json -import re - - -class CollectRSS: - def __init__(self, config, info, rules): - self.bangumi_list = [] - self.rules = rules - rss = requests.get(config["rss_link"], 'utf-8') - soup = BeautifulSoup(rss.text, 'xml') - self.items = soup.find_all('item') - self.info = info - - def get_info_list(self): - split_rule = r"\[|\]|\【|\】|\★|\(|\)|\(|\)" - last_rule = r"(.*)( \-)" - for item in self.items: - name = item.title.string - exit_flag = False - for rule in self.rules: - for group in rule["group_name"]: - if re.search(group, name): - exit_flag = True - n = re.split(split_rule, name) - while '' in n: - n.remove('') - while ' ' in n: - n.remove(' ') - try: - bangumi_title = n[rule['name_position']].strip() - except IndexError: - continue - sub_title = re.sub(r"[^\x00-\xff]{1,}| \d{1,2}|\·","",bangumi_title) - b = re.split(r"\/|\_", sub_title) - while '' in b: - b.remove('') - pre_name = max(b, key=len, default='').strip() - if pre_name != '': - bangumi_title = pre_name - for i in range(2): - match_obj = re.match(last_rule, bangumi_title, re.I) - if match_obj is not None: - bangumi_title = match_obj.group(1).strip() - match_obj = re.match(r"(S\d{1,2}(.*))", bangumi_title, re.I) - if match_obj is not None: - bangumi_title = match_obj.group(2).strip() - if bangumi_title not in self.bangumi_list: - self.bangumi_list.append(bangumi_title) - break - if exit_flag: - break - if not exit_flag: - print(f"[{time.strftime('%Y-%m-%d %X')}] ERROR Not match with {name}") - - def put_info_json(self): - season_match = r"(.*)(Season \d{1,2}|S\d{1,2}|第.*季)" - - had_data = [] - for data in self.info: - had_data.append(data["title"]) - - for title in self.bangumi_list: - match_title_season = re.match(season_match, title, re.I) - if match_title_season is not None: - json_title = match_title_season.group(1).strip() - json_season = match_title_season.group(2) - else: - json_season = '' - json_title = title - if json_title not in had_data: - self.info.append({ - "title": json_title, - "season": json_season - }) - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] add {json_title} {json_season}" + "\n") - sys.stdout.flush() - with open("../config/bangumi.json", 'w', encoding='utf8') as f: - json.dump(self.info, f, indent=4, separators=(',', ': '), ensure_ascii=False) - - def run(self): - self.get_info_list() - self.put_info_json() \ No newline at end of file diff --git a/Windows/app/rename_qb.py b/Windows/app/rename_qb.py deleted file mode 100644 index 700c9469..00000000 --- a/Windows/app/rename_qb.py +++ /dev/null @@ -1,93 +0,0 @@ -import re -import sys -import qbittorrentapi -import time - - -class QbittorrentRename: - def __init__(self, config): - self.qbt_client = qbittorrentapi.Client(host=config['host_ip'], username=config['user_name'], password=config['password']) - try: - self.qbt_client.auth_log_in() - except qbittorrentapi.LoginFailed as e: - print(e) - self.recent_info = self.qbt_client.torrents_info(status_filter='completed') - self.hash = None - self.name = None - self.new_name = None - self.path_name = None - self.count = 0 - self.rename_count = 0 - self.torrent_count = len(self.recent_info) - self.method = config['method'] - self.rules = [r'(.*)\[(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)', - r'(.*)\[E(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)', - r'(.*)\[第(\d*\.*\d*)话(?:END)?\](.*)', - r'(.*)\[第(\d*\.*\d*)話(?:END)?\](.*)', - r'(.*)第(\d*\.*\d*)话(?:END)?(.*)', - r'(.*)第(\d*\.*\d*)話(?:END)?(.*)', - r'(.*)- (\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)? (.*)'] - - def rename_normal(self, idx): - self.name = self.recent_info[idx].name - self.hash = self.recent_info[idx].hash - self.path_name = self.recent_info[idx].content_path.split("/")[-1] - file_name = self.name - for rule in self.rules: - matchObj = re.match(rule, file_name, re.I) - if matchObj is not None: - self.new_name = f'{matchObj.group(1).strip()} E{matchObj.group(2)}{matchObj.group(3)}' - - def rename_pn(self, idx): - self.name = self.recent_info[idx].name - self.hash = self.recent_info[idx].hash - self.path_name = self.recent_info[idx].content_path.split("/")[-1] - n = re.split(r'\[|\]', self.name) - file_name = self.name.replace(f'[{n[1]}]', '') - for rule in self.rules: - matchObj = re.match(rule, file_name, re.I) - if matchObj is not None: - self.new_name = re.sub(r'\[|\]', '', f'{matchObj.group(1).strip()} E{matchObj.group(2)}{n[-1]}') - - def rename(self): - if self.path_name != self.new_name: - self.qbt_client.torrents_rename_file(torrent_hash=self.hash, old_path=self.path_name, new_path=self.new_name) - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] {self.path_name} >> {self.new_name}") - self.count += 1 - else: - return - - def clear_info(self): - self.name = None - self.hash = None - self.new_name = None - self.path_name = None - - def print_result(self): - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] 已完成对{self.torrent_count}个文件的检查" + '\n') - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] 已对其中{self.count}个文件进行重命名" + '\n') - sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] 完成" + '\n') - sys.stdout.flush() - - def run(self): - if self.method not in ['pn', 'normal']: - print('error method') - elif self.method == 'normal': - for i in range(0, self.torrent_count + 1): - try: - self.rename_normal(i) - self.rename() - self.clear_info() - except: - self.print_result() - elif self.method == 'pn': - for i in range(0, self.torrent_count + 1): - try: - self.rename_pn(i) - self.rename() - self.clear_info() - except: - self.print_result() - - - diff --git a/Windows/config.json b/Windows/config.json new file mode 100644 index 00000000..03f2237c --- /dev/null +++ b/Windows/config.json @@ -0,0 +1,47 @@ +{ + "host_ip": "localhost:8080", + "user_name": "admin", + "password": "adminadmin", + "method": "pn", + "rss_link": "https://mikanani.me/RSS/MyBangumi?token=qTxKo48gH1SrFNy8X%2fCfQUoeElNsgKNWFNzNieKwBH8%3d", + "download_path": "/downloads/Bangumi", + "time": 10, + "bangumi_info": [ + { + "title": "Gaikotsu Kishi-sama", + "season": "" + }, + { + "title": "Paripi Koumei", + "season": "" + }, + { + "title": "Tate no Yuusha no Nariagari", + "season": "S02" + }, + { + "title": "Yuusha Yamemasu", + "season": "" + }, + { + "title": "Honzuki no Gekokujou", + "season": "" + }, + { + "title": "SPYxFAMILY", + "season": "" + }, + { + "title": "Machikado Mazoku", + "season": "S2" + }, + { + "title": "Kaguya-sama wa Kokurasetai", + "season": "S03" + }, + { + "title": "Date A Live", + "season": "S4" + } + ] +} \ No newline at end of file diff --git a/Windows/config/bangumi.json b/Windows/config/bangumi.json deleted file mode 100644 index 4c9b023c..00000000 --- a/Windows/config/bangumi.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "title": "simple", - "season": "" - }, - { - "title": "Kawaii dake ja Nai Shikimori-san", - "season": "" - }, - { - "title": "Kakkou no Iinazuke", - "season": "" - }, - { - "title": "SPYxFAMILY", - "season": "" - }, - { - "title": "Love Live!虹咲学园 学园偶像同好会", - "season": "S02" - }, - { - "title": "CUE!", - "season": "" - }, - { - "title": "Kaguya-sama wa Kokurasetai", - "season": "S03" - }, - { - "title": "Shokei Shoujo no Virgin Road", - "season": "" - }, - { - "title": "Kakkou no Iikagen", - "season": "" - }, - { - "title": "Summer Time Rendering", - "season": "" - }, - { - "title": "Paripi Koumei", - "season": "" - }, - { - "title": "Tate no Yuusha no Nariagari", - "season": "S02" - }, - { - "title": "Shijou Saikyou no Daimaou", - "season": "" - }, - { - "title": "Yuusha, Yamemasu", - "season": "" - } -] \ No newline at end of file diff --git a/Windows/config/config.json b/Windows/config/config.json deleted file mode 100644 index 73fb7cfb..00000000 --- a/Windows/config/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "host_ip": "192.168.31.10:8181", - "user_name": "admin", - "password": "adminadmin", - "method": "pn", - "rss_link": "https://mikanani.me/RSS/MyBangumi?token=qTxKo48gH1SrFNy8X%2fCfQUoeElNsgKNWFNzNieKwBH8%3d", - "download_path": "/downloads/Bangumi" -} \ No newline at end of file diff --git a/Windows/config/rule.json b/Windows/config/rule.json deleted file mode 100644 index e5ead51b..00000000 --- a/Windows/config/rule.json +++ /dev/null @@ -1,48 +0,0 @@ -[ - { - "group_name": [ - "Lilith-Raws", - "NC-Raws", - "Skymoon-Raws", - "天月搬运组", - "LoliHouse", - "猎户不鸽发布组", - "NaN-Raws", - "猎户随缘发布组", - "桜都字幕组", - "澄空学园&雪飘工作室", - "千夏字幕组", - "IET字幕组", - "离谱Sub", - "酷漫404", - "星空字幕组", - "轻之国度字幕组", - "枫叶字幕组", - "雪飘工作室", - "豌豆字幕组", - "云光字幕组", - "悠哈璃羽字幕社", - "桜都字幕组", - "ANi", - "❀拨雪寻春❀", - "极彩字幕组", - "悠哈璃羽字幕社", - "漫猫字幕组", - "MingY" - ], - "name_position": 1 - }, - { - "group_name": [ - "喵萌奶茶屋", - "爱恋字母社", - "诸神字幕组", - "驯兽师联盟", - "夏沐字幕组", - "幻樱", - "动漫国字幕组", - "SweetSub&圆环记录攻略组" - ], - "name_position": 2 - } -] \ No newline at end of file diff --git a/Windows/win_main.py b/Windows/win_main.py index 6fd5ca4a..127c9026 100644 --- a/Windows/win_main.py +++ b/Windows/win_main.py @@ -1,20 +1,270 @@ import os +import re +import sys import time -from app.collect_bangumi_info import CollectRSS -from app.auto_set_rule import SetRule -from app.rename_qb import QbittorrentRename import json +import qbittorrentapi +import requests +from bs4 import BeautifulSoup + + +class EnvInfo: + if getattr(sys, 'frozen', False): + application_path = os.path.dirname(sys.executable) + elif __file__: + application_path = os.path.dirname(__file__) + path = os.path.join(application_path, 'config.json') + with open(path) as f: + data = f.read() + info = json.loads(data) + host_ip = info["host_ip"] + sleep_time = float(info["time"]) + user_name = info["user_name"] + password = info["password"] + rss_link = info["rss_link"] + download_path = info["download_path"] + method = info["method"] + # rss_link = "https://mikanani.me/RSS/MyBangumi?token=Td8ceWZZv3s2OZm5ji9RoMer8vk5VS3xzC1Hmg8A26E%3d" + rule_url = "https://raw.githubusercontent.com/EstrellaXD/Bangumi_Auto_Collector/main/AutoBangumi/config/rule.json" + time_show_obj = time.strftime('%Y-%m-%d %X') + bangumi_info = info["bangumi_info"] + + +class SetRule: + def __init__(self): + self.bangumi_info = EnvInfo.bangumi_info + self.rss_link = EnvInfo.rss_link + self.host_ip = EnvInfo.host_ip + self.user_name = EnvInfo.user_name + self.password = EnvInfo.password + self.download_path = EnvInfo.download_path + self.qb = qbittorrentapi.Client(host=self.host_ip, username=self.user_name, password=self.password) + try: + self.qb.auth_log_in() + except qbittorrentapi.LoginFailed as e: + print(e) + + def set_rule(self, bangumi_name, season): + rule = { + 'enable': True, + 'mustContain': bangumi_name, + 'mustNotContain': '720', + 'useRegx': True, + 'episodeFilter': '', + 'smartFilter': False, + 'previouslyMatchedEpisodes': [], + 'affectedFeeds': [self.rss_link], + 'ignoreDays': 0, + 'lastMatch': '', + 'addPaused': False, + 'assignedCategory': 'Bangumi', + 'savePath': str(os.path.join(self.download_path, bangumi_name, season)) + } + self.qb.rss_set_rule(rule_name=bangumi_name, rule_def=rule) + + def rss_feed(self): + try: + self.qb.rss_remove_item(item_path="Mikan_RSS") + self.qb.rss_add_feed(url=self.rss_link, item_path="Mikan_RSS") + sys.stdout.write(f"[{EnvInfo.time_show_obj}] Successes adding RSS Feed." + "\n") + except ConnectionError: + sys.stdout.write(f"[{EnvInfo.time_show_obj}] Error with adding RSS Feed." + "\n") + except qbittorrentapi.exceptions.Conflict409Error: + sys.stdout.write(f"[{EnvInfo.time_show_obj}] RSS Already exists." + "\n") + + def run(self): + sys.stdout.write(f"[{EnvInfo.time_show_obj}] Start adding rules." + "\n") + sys.stdout.flush() + for info in self.bangumi_info: + self.set_rule(info["title"], info["season"]) + sys.stdout.write(f"[{EnvInfo.time_show_obj}] Finished." + "\n") + sys.stdout.flush() + + +class MatchRule: + split_rule = r"\[|\]|\【|\】|\★|\(|\)|\(|\)" + last_rule = r"(.*)( \-)" + sub_title = r"[^\x00-\xff]{1,}| \d{1,2}^.*|\·" + match_rule = r"(S\d{1,2}(.*))" + season_match = r"(.*)(Season \d{1,2}|S\d{1,2}|第.*季|第.*期)" + + +class CollectRSS: + def __init__(self): + self.bangumi_list = [] + try: + self.rules = requests.get(EnvInfo.rule_url).json() + except ConnectionError: + sys.stdout.write(f"[{EnvInfo.time_show_obj}] Get rules Erroe=r") + rss = requests.get(EnvInfo.rss_link, 'utf-8') + soup = BeautifulSoup(rss.text, 'xml') + self.items = soup.find_all('item') + self.info = EnvInfo.bangumi_info + + def get_info_list(self): + for item in self.items: + name = item.title.string + # debug 用 + # print(name) + exit_flag = False + for rule in self.rules: + for group in rule["group_name"]: + if re.search(group, name): + exit_flag = True + n = re.split(MatchRule.split_rule, name) + while '' in n: + n.remove('') + while ' ' in n: + n.remove(' ') + try: + bangumi_title = n[rule['name_position']].strip() + except IndexError: + continue + sub_title = re.sub(MatchRule.sub_title, "", bangumi_title) + b = re.split(r"\/|\_", sub_title) + while '' in b: + b.remove('') + pre_name = max(b, key=len, default='').strip() + if len(pre_name.encode()) > 3: + bangumi_title = pre_name + for i in range(2): + match_obj = re.match(MatchRule.last_rule, bangumi_title, re.I) + if match_obj is not None: + bangumi_title = match_obj.group(1).strip() + match_obj = re.match(MatchRule.match_rule, bangumi_title, re.I) + if match_obj is not None: + bangumi_title = match_obj.group(2).strip() + if bangumi_title not in self.bangumi_list: + self.bangumi_list.append(bangumi_title) + # debug + # print(bangumi_title) + break + if exit_flag: + break + if not exit_flag: + print(f"[{EnvInfo.time_show_obj}] ERROR Not match with {name}") + + def put_info_json(self): + had_data = [] + for data in self.info: + had_data.append(data["title"]) + for title in self.bangumi_list: + match_title_season = re.match(MatchRule.season_match, title, re.I) + if match_title_season is not None: + json_title = match_title_season.group(1).strip() + json_season = match_title_season.group(2) + else: + json_season = '' + json_title = title + if json_title not in had_data: + self.info.append({ + "title": json_title, + "season": json_season + }) + sys.stdout.write(f"[{EnvInfo.time_show_obj}] add {json_title} {json_season}" + "\n") + sys.stdout.flush() + EnvInfo.info["bangumi_info"] = self.info + with open(EnvInfo.path, 'w', encoding='utf8') as f: + data = json.dumps(EnvInfo.info, indent=4, separators=(',', ': '), ensure_ascii=False) + f.write(data) + + def run(self): + self.get_info_list() + self.put_info_json() + + +class qBittorrentRename: + + def __init__(self): + self.qbt_client = qbittorrentapi.Client(host=EnvInfo.host_ip, + username=EnvInfo.user_name, + password=EnvInfo.password) + try: + self.qbt_client.auth_log_in() + except qbittorrentapi.LoginFailed as e: + print(e) + self.recent_info = self.qbt_client.torrents_info(status_filter='completed',category="Bangumi") + self.hash = None + self.name = None + self.new_name = None + self.path_name = None + self.count = 0 + self.rename_count = 0 + self.torrent_count = len(self.recent_info) + self.rules = [r'(.*)\[(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)', + r'(.*)\[E(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)', + r'(.*)\[第(\d*\.*\d*)话(?:END)?\](.*)', + r'(.*)\[第(\d*\.*\d*)話(?:END)?\](.*)', + r'(.*)第(\d*\.*\d*)话(?:END)?(.*)', + r'(.*)第(\d*\.*\d*)話(?:END)?(.*)', + r'(.*)- (\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)? (.*)'] + + def rename_normal(self, idx): + self.name = self.recent_info[idx].name + self.hash = self.recent_info[idx].hash + self.path_name = self.recent_info[idx].content_path.split("/")[-1] + file_name = self.name + for rule in self.rules: + matchObj = re.match(rule, file_name, re.I) + if matchObj is not None: + self.new_name = f'{matchObj.group(1).strip()} E{matchObj.group(2)}{matchObj.group(3)}' + + def rename_pn(self, idx): + self.name = self.recent_info[idx].name + self.hash = self.recent_info[idx].hash + self.path_name = self.recent_info[idx].content_path.split("/")[-1] + n = re.split(r'\[|\]', self.name) + file_name = self.name.replace(f'[{n[1]}]', '') + for rule in self.rules: + matchObj = re.match(rule, file_name, re.I) + if matchObj is not None: + self.new_name = re.sub(r'\[|\]', '', f'{matchObj.group(1).strip()} E{matchObj.group(2)}{n[-1]}') + + def rename(self): + if self.path_name != self.new_name: + self.qbt_client.torrents_rename_file(torrent_hash=self.hash, old_path=self.path_name, new_path=self.new_name) + sys.stdout.write(f"[{time.strftime('%Y-%m-%d %X')}] {self.path_name} >> {self.new_name}") + self.count += 1 + else: + return + + def clear_info(self): + self.name = None + self.hash = None + self.new_name = None + self.path_name = None + + def print_result(self): + sys.stdout.write(f"[{EnvInfo.time_show_obj}] 已完成对{self.torrent_count}个文件的检查" + '\n') + sys.stdout.write(f"[{EnvInfo.time_show_obj}] 已对其中{self.count}个文件进行重命名" + '\n') + sys.stdout.write(f"[{EnvInfo.time_show_obj}] 完成" + '\n') + sys.stdout.flush() + + def run(self): + if EnvInfo.method not in ['pn', 'normal']: + print('error method') + elif EnvInfo.method == 'normal': + for i in range(0, self.torrent_count + 1): + try: + self.rename_normal(i) + self.rename() + self.clear_info() + except: + self.print_result() + elif EnvInfo.method == 'pn': + for i in range(0, self.torrent_count + 1): + try: + self.rename_pn(i) + self.rename() + self.clear_info() + except: + self.print_result() + if __name__ == "__main__": - with open("config/config.json") as f: - config = json.load(f) while True: - with open("config/bangumi.json") as f: - info = json.load(f) - with open("../config/rule.json") as f: - rule = json.load(f) - CollectRSS(config, info, rule).run() - SetRule(config).run() - QbittorrentRename(config).run() - time.sleep(float(1800)) + CollectRSS().run() + SetRule().run() + qBittorrentRename().run() + time.sleep(EnvInfo.sleep_time) diff --git a/test/test.py b/test/test.py index d7f9b9ab..eb914c31 100644 --- a/test/test.py +++ b/test/test.py @@ -1,6 +1,6 @@ +import os + import qbittorrentapi -qb = qbittorrentapi.Client(host="localhost:8080",username="admin",password="adminadmin") - -qb.auth_log_in() -qb.rss_add_feed(url="https://mikanani.me",item_path="自动下载") \ No newline at end of file +abs_path = os.path.dirname(os.path.abspath(__file__)) +print(abs_path) \ No newline at end of file