diff --git a/Dockerfile b/Dockerfile index 303d92d7..ecfecea6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,4 +13,6 @@ ADD ./auto_bangumi /auto_bangumi ADD ./config /config ADD ./templates /templates -CMD ["python3", "app.py"] +RUN chmod a+x run.sh + +CMD ["./run.sh"] diff --git a/auto_bangumi/network/web.py b/auto_bangumi/api.py similarity index 63% rename from auto_bangumi/network/web.py rename to auto_bangumi/api.py index 7c6ad09e..144dc8a2 100644 --- a/auto_bangumi/network/web.py +++ b/auto_bangumi/api.py @@ -7,7 +7,7 @@ import logging from core import RSSAnalyser from core import DownloadClient -from conf import settings +from conf import settings, parse from utils import json_config logger = logging.getLogger(__name__) @@ -15,13 +15,13 @@ logger = logging.getLogger(__name__) app = FastAPI() -templates = Jinja2Templates(directory="templates") +# templates = Jinja2Templates(directory="templates") -@app.get("/", response_class=HTMLResponse) -def index(request: Request): - context = {"request": request} - return templates.TemplateResponse("index.html", context) +# @app.get("/", response_class=HTMLResponse) +# def index(request: Request): +# context = {"request": request} +# return templates.TemplateResponse("index.html", context) class Config(BaseModel): @@ -65,13 +65,16 @@ class RSS(BaseModel): @app.post("/api/v1/subscriptions") async def receive(link: RSS): - data = RSSAnalyser().rss_to_data(link.link) - from conf.const_dev import DEV_SETTINGS - settings.init(DEV_SETTINGS) client = DownloadClient() - client.add_collection_feed(link.link, item_path=data["title"]) - client.set_rule(data, link.link) - return "Successes" + try: + data = RSSAnalyser().rss_to_data(link.link) + client.add_collection_feed(link.link, item_path=data["official_title"]) + client.set_rule(data, link.link) + return data + except Exception as e: + logger.debug(e) + return "Error" + class Search(BaseModel): @@ -85,5 +88,19 @@ async def search(input: Search): return "Nothing Happened" +def run(): + args = parse() + if args.debug: + try: + from conf.const_dev import DEV_SETTINGS + settings.init(DEV_SETTINGS) + except ModuleNotFoundError: + logger.debug("Please copy `const_dev.py` to `const_dev.py` to use custom settings") + else: + settings.init() + uvicorn.run(app, host="0.0.0.0", port=settings.webui_port) + + if __name__ == "__main__": - uvicorn.run(app, host="0.0.0.0", port=settings.webui_port) \ No newline at end of file + run() + diff --git a/auto_bangumi/app.py b/auto_bangumi/app.py index bf41595f..a6db9c37 100644 --- a/auto_bangumi/app.py +++ b/auto_bangumi/app.py @@ -1,13 +1,13 @@ import os import time import logging -from multiprocessing import Process from conf import settings, parse from conf.log import setup_logger from utils import json_config -from core import RSSAnalyser, DownloadClient, Renamer +from core import RSSAnalyser, DownloadClient, Renamer, FullSeasonGet + logger = logging.getLogger(__name__) @@ -20,12 +20,15 @@ def load_data_file(): "data_version": settings.data_version, "bangumi_info": [] } + logger.info("Building data information...") else: bangumi_data = json_config.load(info_path) if bangumi_data["data_version"] != settings.data_version or bangumi_data["rss_link"] != settings.rss_link: - bangumi_data["bangumi_info"] = [] - bangumi_data["data_version"] = settings.data_version - bangumi_data["rss_link"] = settings.rss_link + bangumi_data = { + "rss_link": settings.rss_link, + "data_version": settings.data_version, + "bangumi_info": [] + } logger.info("Rebuilding data information...") return bangumi_data @@ -50,15 +53,22 @@ def show_info(): def main_process(bangumi_data, download_client: DownloadClient): - rss_analyser = RSSAnalyser() rename = Renamer(download_client) + rss_analyser = RSSAnalyser() + first_run = True while True: - rss_analyser.run(bangumi_data["bangumi_info"], download_client) - save_data_file(bangumi_data) times = 0 + if settings.enable_rss_collector: + rss_analyser.run(bangumi_data["bangumi_info"], download_client) + if settings.eps_complete and first_run: + FullSeasonGet().eps_complete(bangumi_data["bangumi_info"], download_client) + first_run = False + logger.info("Running....") + save_data_file(bangumi_data) while times < settings.times: - rename.refresh() - rename.run() + if settings.enable_rename: + rename.refresh() + rename.run() times += 1 time.sleep(settings.sleep_time/settings.times) @@ -77,7 +87,7 @@ def run(): # 初始化 setup_logger() show_info() - time.sleep(3) + time.sleep(1) download_client = DownloadClient() download_client.init_downloader() if settings.rss_link is None: diff --git a/auto_bangumi/conf/__init__.py b/auto_bangumi/conf/__init__.py index 8625087f..90226d02 100644 --- a/auto_bangumi/conf/__init__.py +++ b/auto_bangumi/conf/__init__.py @@ -1,6 +1,6 @@ from .conf import settings, Settings from .const import BCOLORS -from .const_dev import DEV_SETTINGS +# from .const_dev import DEV_SETTINGS from .parse import parse from .log import setup_logger diff --git a/auto_bangumi/conf/const.py b/auto_bangumi/conf/const.py index 7dec0b2e..dc87cebe 100644 --- a/auto_bangumi/conf/const.py +++ b/auto_bangumi/conf/const.py @@ -1,11 +1,11 @@ # -*- encoding: utf-8 -*- DEFAULT_SETTINGS = { - "version": "2.5.0-beta2", + "version": "2.5.0-beta10", "data_version": 4.0, "host_ip": "localhost:8080", - "sleep_time": 1800, - "times": 10, + "sleep_time": 7200, + "times": 20, "user_name": "admin", "password": "adminadmin", "download_path": "/downloads/Bangumi", @@ -21,6 +21,11 @@ DEFAULT_SETTINGS = { "eps_complete": False, "webui_port": 7892, "title_language": "zh", + "tmdb_api": "", + "enable_tmdb": False, + "socks": None, + "enable_rss_collector": True, + "enable_rename": True } ENV_TO_ATTR = { @@ -36,13 +41,17 @@ ENV_TO_ATTR = { "AB_NOT_CONTAIN": "not_contain", "AB_DEBUG_MODE": ("debug_mode", lambda e: e.lower() in ("true", "1", "t")), "AB_EP_COMPLETE": ( - "enable_eps_complete", + "eps_complete", lambda e: e.lower() in ("true", "1", "t") ), "AB_REMOVE_BAD_BT": ("remove_bad_torrent", lambda e: e.lower() in ("true", "1", "t")), "AB_WEBUI_PORT": ("webui_port", lambda e: int(e)), "AB_HTTP_PROXY": "http_proxy", "AB_LANGUAGE": "title_language", + "AB_ENABLE_TMDB": ("enable_tmdb", lambda e: e.lower() in ("true", "1", "t")), + "AB_SOCKS": "socks", + "AB_RENAME": ("enable_rename", lambda e: e.lower() in ("true", "1", "t")), + "AB_RSS_COLLECTOR": ("enable_rss_collector", lambda e: e.lower() in ("true", "1", "t")), } diff --git a/auto_bangumi/core/eps_complete.py b/auto_bangumi/core/eps_complete.py index 75fc7bc2..acf6b741 100644 --- a/auto_bangumi/core/eps_complete.py +++ b/auto_bangumi/core/eps_complete.py @@ -14,13 +14,17 @@ class FullSeasonGet: self._get_rss = RequestContent() def init_eps_complete_search_str(self, data: dict): - search_str = re.sub(r"[\W_]", "+", - f"{data['group']} {data['title_raw']} {data['season_raw']} {data['subtitle']} {data['source']} {data['dpi']}") + search_str_pre = "" + for i in [data['group'], data['title_raw'], data['season_raw'], data['subtitle'], data['source'], data['dpi']]: + if i is not None: + search_str_pre += f" {i}" + search_str = re.sub(r"[\W_ ]", "+", + search_str_pre.strip()) return search_str def get_season_torrents(self, data: dict): keyword = self.init_eps_complete_search_str(data) - torrents = self._get_rss.get_torrents(f"https://mikanani.me/RSS/Search?str={keyword}") + torrents = self._get_rss.get_torrents(f"https://mikanani.me/RSS/Search?searchstr={keyword}") return torrents def collect_season_torrents(self, data: dict): @@ -28,7 +32,7 @@ class FullSeasonGet: downloads = [] for torrent in torrents: download_info = { - "url": torrent["url"], + "url": torrent, "save_path": os.path.join( settings.download_path, data["official_title"], @@ -39,12 +43,28 @@ class FullSeasonGet: def eps_complete(self, bangumi_info, download_client: DownloadClient): for data in bangumi_info: - if data["eps_complete"]: + if data["eps_collect"]: logger.info(f"Start collecting past episodes of {data['official_title']} Season {data['season']}...") downloads = self.collect_season_torrents(data) for download in downloads: download_client.add_torrent(download) logger.info("Completed!") - data["eps_complete"] = False + data["eps_collect"] = False +if __name__ == "__main__": + a = FullSeasonGet() + data = { + "official_title": "指名!", + "title_raw": "CUE!", + "season": 1, + "season_raw": "", + "group": "喵萌Production", + "dpi": "1080p", + "source": None, + "subtitle": "简日双语", + "added": True, + "eps_collect": True + } + torrents = a.collect_season_torrents(data) + print(torrents) \ No newline at end of file diff --git a/auto_bangumi/core/renamer.py b/auto_bangumi/core/renamer.py index 11533d0f..ba906cb0 100644 --- a/auto_bangumi/core/renamer.py +++ b/auto_bangumi/core/renamer.py @@ -34,11 +34,14 @@ class Renamer: if PurePath(info.content_path).name != info.content_path \ else PureWindowsPath(info.content_path).parts path_name = path_parts[-1] - season = int(re.search(r"\d", path_parts[-2]).group()) try: - new_name = self._renamer.download_parser(name, season, settings.method) - logger.debug(f"Origin name: {path_name}") - logger.debug(f"New name: {new_name}") + season = int(re.search(r"\d", path_parts[-2]).group()) + except Exception as e: + logger.debug(e) + season = 1 + folder_name = path_parts[-3] + try: + new_name = self._renamer.download_parser(name, folder_name, season, settings.method) if path_name != new_name: self.client.rename_torrent_file(torrent_hash, path_name, new_name) self.rename_count += 1 @@ -46,6 +49,7 @@ class Renamer: continue except: logger.warning(f"{path_name} rename failed") + logger.debug(f"origin: {name}") if settings.remove_bad_torrent: self.client.delete_torrent(torrent_hash) self.print_result() diff --git a/auto_bangumi/core/rss_analyser.py b/auto_bangumi/core/rss_analyser.py index 0773ab35..0fb1a92c 100644 --- a/auto_bangumi/core/rss_analyser.py +++ b/auto_bangumi/core/rss_analyser.py @@ -24,6 +24,7 @@ class RSSAnalyser: extra_add = True for d in bangumi_info: if re.search(d["title_raw"], raw_title) is not None: + logger.debug(f"Had added {d['title_raw']} before") extra_add = False break if extra_add: @@ -38,8 +39,14 @@ class RSSAnalyser: return data def run(self, bangumi_info: list, download_client: DownloadClient): - self.rss_to_datas(bangumi_info) - download_client.add_rules(bangumi_info, rss_link=settings.rss_link) + logger.info("Start collecting RSS info.") + try: + self.rss_to_datas(bangumi_info) + download_client.add_rules(bangumi_info, rss_link=settings.rss_link) + except Exception as e: + logger.debug(e) + logger.info("Connection error.") + logger.info("Finished") if __name__ == "__main__": diff --git a/auto_bangumi/network/request.py b/auto_bangumi/network/request.py index a62e29dc..63851363 100644 --- a/auto_bangumi/network/request.py +++ b/auto_bangumi/network/request.py @@ -1,6 +1,8 @@ import time import requests +import socket +import socks import logging from bs4 import BeautifulSoup @@ -14,13 +16,15 @@ class RequestURL: def __init__(self): self.session = requests.session() if settings.http_proxy is not None: - self.proxy = { + self.session.proxies = { "https": settings.http_proxy, "http": settings.http_proxy, - "socks": settings.http_proxy } - else: - self.proxy = None + elif settings.socks is not None: + socks_info = settings.socks.split(",") + socks.set_default_proxy(socks.SOCKS5, addr=socks_info[0], port=int(socks_info[1]), rdns=True, + username=socks_info[2], password=socks_info[3]) + socket.socket = socks.socksocket self.header = { "user-agent": "Mozilla/5.0", "Accept": "application/xml" @@ -30,11 +34,11 @@ class RequestURL: times = 0 while times < 5: try: - req = self.session.get(url=url, headers=self.header, proxies=self.proxy) + req = self.session.get(url=url, headers=self.header) return req except Exception as e: logger.debug(f"URL: {url}") - logger.error("ERROR with DNS/Connection.") + logger.warning("ERROR with DNS/Connection.") time.sleep(settings.connect_retry_interval) times += 1 @@ -48,3 +52,11 @@ class RequestURL: self.session.close() +if __name__ == "__main__": + a = RequestURL() + socks.set_default_proxy(socks.SOCKS5, "192.168.30.2", 19990, True, username="abc", password="abc") + socket.socket = socks.socksocket + b = a.get_url('https://www.themoviedb.org').text + print(b) + + diff --git a/auto_bangumi/parser/analyser/rename_parser.py b/auto_bangumi/parser/analyser/rename_parser.py index 56931731..f8ca27eb 100644 --- a/auto_bangumi/parser/analyser/rename_parser.py +++ b/auto_bangumi/parser/analyser/rename_parser.py @@ -15,14 +15,15 @@ class DownloadParser: 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)? (.*)", + r"(.*)- (\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?(.*)", ] def rename_normal(self, name, season): for rule in self.rules: - matchObj = re.match(rule, name, re.I) - if matchObj is not None: - new_name = f"{matchObj.group(1).strip()} S{season}E{matchObj.group(2)}{matchObj.group(3)}" + match_obj = re.match(rule, name, re.I) + if match_obj is not None: + title = re.sub(r"([Ss]|Season )\d{1,3}", "", match_obj.group(1)).strip() + new_name = f"{title} S{season}E{match_obj.group(2)}{match_obj.group(3)}" return new_name def rename_pn(self, name, season): @@ -31,26 +32,44 @@ class DownloadParser: if season < 10: season = f"0{season}" for rule in self.rules: - matchObj = re.match(rule, file_name, re.I) - if matchObj is not None: + match_obj = re.match(rule, file_name, re.I) + if match_obj is not None: + title = re.sub(r"([Ss]|Season )\d{1,3}", "", match_obj.group(1)).strip() new_name = re.sub( r"[\[\]]", "", - f"{matchObj.group(1).strip()} S{season}E{matchObj.group(2)}{path.splitext(name)[-1]}", + f"{title} S{season}E{match_obj.group(2)}{path.splitext(name)[-1]}", ) return new_name - def download_rename(self, name, season, method): + def rename_advance(self, name, folder_name, season): + n = re.split(r"[\[\]()【】()]", name) + file_name = name.replace(f"[{n[1]}]", "") + if season < 10: + season = f"0{season}" + for rule in self.rules: + match_obj = re.match(rule, file_name, re.I) + if match_obj is not None: + new_name = re.sub( + r"[\[\]]", + "", + f"{folder_name} S{season}E{match_obj.group(2)}{path.splitext(name)[-1]}", + ) + return new_name + + def download_rename(self, name, folder_name, season, method): if method.lower() == "pn": return self.rename_pn(name, season) elif method.lower() == "normal": return self.rename_normal(name, season) elif method.lower() == "none": return name + elif method.lower() == "advance": + return self.rename_advance(name, folder_name, season) if __name__ == "__main__": - name = "[NC-Raws]间谍过家家 - 09(B-Global 3840x2160 HEVC AAC MKV).mkv" + name = "[NC-Raws]Summer Time Rendering S02 - 09(B-Global 3840x2160 HEVC AAC MKV).mkv" rename = DownloadParser() - new_name = rename.rename_pn(name, "pn") + new_name = rename.rename_pn(name, 1) print(new_name) \ No newline at end of file diff --git a/auto_bangumi/parser/analyser/tmdb.py b/auto_bangumi/parser/analyser/tmdb.py index 49a06b15..3837f88f 100644 --- a/auto_bangumi/parser/analyser/tmdb.py +++ b/auto_bangumi/parser/analyser/tmdb.py @@ -16,9 +16,9 @@ class TMDBInfo: class TMDBMatcher: def __init__(self): self.search_url = lambda e: \ - f"https://api.themoviedb.org/3/search/tv?api_key={settings.tdmb_api}&page=1&query={e}&include_adult=false" + f"https://api.themoviedb.org/3/search/tv?api_key={settings.tmdb_api}&page=1&query={e}&include_adult=false" self.info_url = lambda e: \ - f"https://api.themoviedb.org/3/tv/{e}?api_key={settings.tdmb_api}&language=zh-CN" + f"https://api.themoviedb.org/3/tv/{e}?api_key={settings.tmdb_api}&language=zh-CN" self._request = RequestContent() def is_animation(self, id): diff --git a/auto_bangumi/parser/parser.py b/auto_bangumi/parser/parser.py index 2873bcb7..3cb47484 100644 --- a/auto_bangumi/parser/parser.py +++ b/auto_bangumi/parser/parser.py @@ -14,20 +14,24 @@ class TitleParser: def raw_parser(self, raw): return self._raw_parser.analyse(raw) - def download_parser(self, download_raw, season, method=settings.method): - return self._download_parser.download_rename(download_raw, season, method) + def download_parser(self, download_raw, folder_name, season, method=settings.method): + return self._download_parser.download_rename(download_raw, folder_name, season, method) def return_dict(self, raw): tmdb = TMDBMatcher() try: episode = self.raw_parser(raw) - try: - tmdb_info = tmdb.tmdb_search(episode.title) - official_title = tmdb_info.title_zh if settings.title_language == "zh" else tmdb_info.title_jp - season = tmdb_info.last_season - except Exception as e: - logger.debug(e) - logger.info("Not Match in TMDB") + if settings.enable_tmdb: + try: + tmdb_info = tmdb.tmdb_search(episode.title) + official_title = tmdb_info.title_zh if settings.title_language == "zh" else tmdb_info.title_jp + season = tmdb_info.last_season + except Exception as e: + logger.debug(e) + logger.info("Not Match in TMDB") + official_title = episode.title + season = episode.season_info.number + else: official_title = episode.title season = episode.season_info.number data = { diff --git a/auto_bangumi/run.sh b/auto_bangumi/run.sh new file mode 100755 index 00000000..5faa441a --- /dev/null +++ b/auto_bangumi/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +exec python3 app.py & +exec python3 api.py \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2dc7725d..78c2edba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ qbittorrent-api bs4 -requests~=2.27.1 +requests==2.28.0 +pysocks lxml setuptools~=62.1.0