This commit is contained in:
EstrellaXD
2023-05-02 23:50:30 +08:00
parent a9f3cdd281
commit 9e296b57d6
13 changed files with 138 additions and 108 deletions

View File

@@ -12,7 +12,7 @@ from module.models import Config
router = FastAPI()
api_func = APIProcess()
api_func = APIProcess(settings)
@router.on_event("startup")

View File

@@ -2,13 +2,13 @@ import os
import time
import logging
from module.conf import settings, setup_logger, LOG_PATH, DATA_PATH, RSSLink, VERSION
from module.conf import setup_logger, LOG_PATH, DATA_PATH, RSSLink, VERSION
from module.utils import load_program_data, save_program_data
from module.core import DownloadClient
from module.manager import Renamer, FullSeasonGet
from module.rss import RSSAnalyser
from module.models import ProgramData
from module.models import ProgramData, Config
logger = logging.getLogger(__name__)
@@ -19,10 +19,10 @@ def reset_log():
os.remove(LOG_PATH)
def load_data_file(rss_link: str) -> ProgramData:
def load_data_file(rss_link: str, data_version) -> ProgramData:
empty_data = ProgramData(
rss_link=rss_link,
data_version=settings.data_version,
data_version=data_version,
)
if not os.path.exists(DATA_PATH):
program_data = empty_data
@@ -30,28 +30,29 @@ def load_data_file(rss_link: str) -> ProgramData:
logger.info("Building data information...")
else:
program_data = load_program_data(DATA_PATH)
if program_data.rss_link != rss_link or program_data.data_version != settings.data_version:
if program_data.rss_link != rss_link or program_data.data_version != data_version:
program_data = empty_data
logger.info("Rebuilding data information...")
return program_data
def main_process(program_data: ProgramData, download_client: DownloadClient):
rename = Renamer(download_client, settings)
rss_analyser = RSSAnalyser(settings)
def main_process(program_data: ProgramData, download_client: DownloadClient, _settings: Config):
rename = Renamer(download_client, _settings)
rss_analyser = RSSAnalyser(_settings)
while True:
times = 0
if settings.rss_parser.enable:
rss_analyser.run(program_data.bangumi_info, download_client, program_data.rss_link)
if settings.bangumi_manage.eps_complete and program_data.bangumi_info != []:
FullSeasonGet().eps_complete(program_data.bangumi_info, download_client)
if _settings.rss_parser.enable:
rss_analyser.run(program_data.bangumi_info, program_data.rss_link)
download_client.add_rules(program_data.bangumi_info, program_data.rss_link)
if _settings.bangumi_manage.eps_complete and program_data.bangumi_info != []:
FullSeasonGet(settings=_settings).eps_complete(program_data.bangumi_info, download_client)
logger.info("Running....")
save_program_data(DATA_PATH, program_data)
while times < settings.program.rename_times:
if settings.bangumi_manage.enable:
while times < _settings.program.rename_times:
if _settings.bangumi_manage.enable:
rename.rename()
times += 1
time.sleep(settings.program.sleep_time / settings.program.rename_times)
time.sleep(_settings.program.sleep_time / _settings.program.rename_times)
def show_info():
@@ -63,9 +64,8 @@ def show_info():
logger.info("Starting AutoBangumi...")
def run():
def run(settings: Config):
# 初始化
settings.reload()
rss_link = RSSLink()
reset_log()
setup_logger()
@@ -73,10 +73,10 @@ def run():
if settings.rss_parser.token in ["", "token", None]:
logger.error("Please set your RSS token in config file.")
exit(1)
download_client = DownloadClient()
download_client = DownloadClient(settings)
download_client.auth()
download_client.init_downloader()
download_client.rss_feed(rss_link)
bangumi_data = load_data_file(rss_link)
bangumi_data = load_data_file(rss_link, settings.data_version)
# 主程序循环
main_process(bangumi_data, download_client)
main_process(bangumi_data, download_client, settings)

View File

@@ -5,7 +5,7 @@ from module.core import DownloadClient
from module.manager import FullSeasonGet
from module.rss import RSSAnalyser
from module.utils import json_config
from module.conf import DATA_PATH, settings
from module.conf import DATA_PATH
from module.conf.config import save_config_to_file, CONFIG_PATH
from module.models import Config
from module.network import RequestContent
@@ -16,13 +16,14 @@ logger = logging.getLogger(__name__)
class APIProcess:
def __init__(self):
self._rss_analyser = RSSAnalyser()
self._client = DownloadClient()
self._full_season_get = FullSeasonGet()
def __init__(self, settings: Config):
self._rss_analyser = RSSAnalyser(settings)
self._client = DownloadClient(settings)
self._full_season_get = FullSeasonGet(settings)
self._custom_url = settings.rss_parser.custom_url
def link_process(self, link):
return self._rss_analyser.rss_to_data(link, filter=False)
return self._rss_analyser.rss_to_data(link, _filter=False)
@api_failed
def download_collection(self, link):
@@ -85,10 +86,9 @@ class APIProcess:
def get_config() -> dict:
return json_config.load(CONFIG_PATH)
@staticmethod
def get_rss(full_path: str):
def get_rss(self, full_path: str):
url = f"https://mikanani.me/RSS/{full_path}"
custom_url = settings.rss_parser.custom_url
custom_url = self._custom_url
if "://" not in custom_url:
custom_url = f"https://{custom_url}"
with RequestContent() as request:

View File

@@ -3,25 +3,22 @@ import logging
import os
from module.downloader import getClient
from module.conf import settings
from module.models import BangumiData
from module.models import BangumiData, Config
logger = logging.getLogger(__name__)
class DownloadClient:
def __init__(self):
self.client = getClient()
def __init__(self, settings: Config):
self.client = getClient(settings)
self.authed = False
self.download_path = settings.downloader.path
self.group_tag = settings.bangumi_manage.group_tag
def auth(self):
host, username, password = settings.downloader.host, settings.downloader.username, settings.downloader.password
try:
self.client.auth(host, username, password)
self.authed = True
except Exception as e:
logger.error(f"Can't login {host} by {username}, {e}")
self.client.auth()
self.authed = True
def init_downloader(self):
prefs = {
@@ -36,16 +33,16 @@ class DownloadClient:
except Exception as e:
logger.warning("Cannot add new category, maybe already exists.")
logger.debug(e)
if settings.downloader.path == "":
if self.download_path == "":
prefs = self.client.get_app_prefs()
settings.downloader.path = os.path.join(prefs["save_path"], "Bangumi")
self.download_path = os.path.join(prefs["save_path"], "Bangumi")
def set_rule(self, info: BangumiData, rss_link):
official_name, raw_name, season, group = info.official_title, info.title_raw, info.season, info.group
rule = {
"enable": True,
"mustContain": raw_name,
"mustNotContain": "|".join(settings.rss_parser.filter),
"mustNotContain": "|".join(info.filter),
"useRegex": True,
"episodeFilter": "",
"smartFilter": False,
@@ -57,28 +54,23 @@ class DownloadClient:
"assignedCategory": "Bangumi",
"savePath": str(
os.path.join(
settings.downloader.path,
self.download_path,
re.sub(r"[:/.]", " ", official_name).strip(),
f"Season {season}",
)
),
}
rule_name = f"[{group}] {official_name}" if settings.bangumi_manage.group_tag else official_name
rule_name = f"[{group}] {official_name}" if self.group_tag else official_name
self.client.rss_set_rule(rule_name=f"{rule_name} S{season}", rule_def=rule)
logger.info(f"Add {official_name} Season {season}")
def rss_feed(self, rss_link, item_path="Mikan_RSS"):
# TODO: 定时刷新 RSS
if self.client.get_rss_info(rss_link):
logger.info("RSS Already exists.")
else:
logger.info("No feed exists, start adding feed.")
self.client.rss_add_feed(url=rss_link, item_path="Mikan_RSS")
logger.info("Add RSS Feed successfully.")
self.client.rss_add_feed(url=rss_link, item_path=item_path)
def add_collection_feed(self, rss_link, item_path):
self.client.rss_add_feed(url=rss_link, item_path=item_path)
logger.info("Add RSS Feed successfully.")
logger.info("Add Collection RSS Feed successfully.")
def add_rules(self, bangumi_info: list[BangumiData], rss_link: str):
logger.debug("Start adding rules.")

View File

@@ -1,11 +1,15 @@
from module.conf import settings
from module.models import Config
def getClient():
def getClient(settings: Config):
# TODO 多下载器支持
# 从 settings 里读取下载器名称,然后返回对应 Client
if settings.downloader.type == "qbittorrent":
type = settings.downloader.type
host = settings.downloader.host
username = settings.downloader.username
password = settings.downloader.password
ssl = settings.downloader.ssl
if type == "qbittorrent":
from .qb_downloader import QbDownloader
return QbDownloader()
return QbDownloader(host, username, password, ssl)
else:
raise Exception(f"Unsupported downloader type: {settings.downloader.type}")
raise Exception(f"Unsupported downloader type: {type}")

View File

@@ -4,33 +4,32 @@ import time
from qbittorrentapi import Client, LoginFailed
from qbittorrentapi.exceptions import Conflict409Error
from module.conf import settings
from module.ab_decorator import qb_connect_failed_wait
from module.downloader.exceptions import ConflictError
logger = logging.getLogger(__name__)
class QbDownloader:
def __init__(self):
self._client: Client | None = None
@qb_connect_failed_wait
def auth(self, host, username, password):
self._client = Client(
def __init__(self, host: str, username: str, password: str, ssl: bool):
self._client: Client = Client(
host=host,
username=username,
password=password,
VERIFY_WEBUI_CERTIFICATE=settings.downloader.ssl
VERIFY_WEBUI_CERTIFICATE=ssl
)
self.host = host
self.username = username
@qb_connect_failed_wait
def auth(self):
while True:
try:
self._client.auth_log_in()
break
except LoginFailed:
logger.warning(
f"Can't login qBittorrent Server {host} by {username}, retry in {5} seconds."
logger.error(
f"Can't login qBittorrent Server {self.host} by {self.username}, retry in {5} seconds."
)
time.sleep(5)
@@ -66,21 +65,35 @@ class QbDownloader:
def torrents_rename_file(self, torrent_hash, old_path, new_path):
self._client.torrents_rename_file(torrent_hash=torrent_hash, old_path=old_path, new_path=new_path)
def get_rss_info(self, url) -> str | None:
def check_rss(self, url, item_path) -> tuple[str | None, bool]:
items = self._client.rss_items()
for item in items.items():
if item[1].url == url:
return item[0]
return None
for key, value in items.items():
rss_url = value.get("url")
if key == item_path:
if rss_url != url:
return key, False
return None, True
else:
if rss_url == url:
return key, True
return None, False
def rss_add_feed(self, url, item_path):
try:
path = self.get_rss_info(url)
if path:
self.rss_remove_item(path)
self._client.rss_add_feed(url, item_path)
except Conflict409Error:
logger.exception("RSS Exist.")
path, added = self.check_rss(url, item_path)
if path:
if not added:
logger.info("RSS Exist, Update URL.")
self._client.rss_remove_item(path)
self._client.rss_add_feed(url, item_path)
else:
logger.info("RSS Exist.")
else:
if added:
logger.info("RSS Exist.")
else:
logger.info("Add new RSS")
self._client.rss_add_feed(url, item_path)
logger.info("Successfully added RSS")
def rss_remove_item(self, item_path):
try:

View File

@@ -2,29 +2,27 @@ import os.path
import re
import logging
from module.conf import settings
from module.network import RequestContent
from module.core import DownloadClient
from module.models import BangumiData
from module.models import BangumiData, Config
logger = logging.getLogger(__name__)
SEARCH_KEY = ["group", "title_raw", "season_raw", "subtitle", "source", "dpi"]
CUSTOM_URL = "https://mikanani.me" if settings.rss_parser.custom_url == "" else settings.rss_parser.custom_url
if "://" not in CUSTOM_URL:
if re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", CUSTOM_URL):
CUSTOM_URL = f"http://{CUSTOM_URL}"
CUSTOM_URL = f"https://{CUSTOM_URL}"
class FullSeasonGet:
def __init__(self):
pass
def __init__(self, settings: Config):
self.SEARCH_KEY = ["group", "title_raw", "season_raw", "subtitle", "source", "dpi"]
self.CUSTOM_URL = "https://mikanani.me" if settings.rss_parser.custom_url == "" else settings.rss_parser.custom_url
if "://" not in self.CUSTOM_URL:
if re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", self.CUSTOM_URL):
self.CUSTOM_URL = f"http://{self.CUSTOM_URL}"
self.CUSTOM_URL = f"https://{self.CUSTOM_URL}"
self.save_path = settings.downloader.path
@staticmethod
def init_eps_complete_search_str(data: BangumiData):
def init_eps_complete_search_str(self, data: BangumiData):
test = []
for key in SEARCH_KEY:
for key in self.SEARCH_KEY:
data_dict = data.dict()
if data_dict[key] is not None:
test.append(data_dict[key])
@@ -35,17 +33,16 @@ class FullSeasonGet:
def get_season_torrents(self, data: BangumiData):
keyword = self.init_eps_complete_search_str(data)
with RequestContent() as req:
torrents = req.get_torrents(f"{CUSTOM_URL}/RSS/Search?searchstr={keyword}")
torrents = req.get_torrents(f"{self.CUSTOM_URL}/RSS/Search?searchstr={keyword}")
return [torrent for torrent in torrents if data.title_raw in torrent.name]
@staticmethod
def collect_season_torrents(data: BangumiData, torrents):
def collect_season_torrents(self, data: BangumiData, torrents):
downloads = []
for torrent in torrents:
download_info = {
"url": torrent.torrent_link,
"save_path": os.path.join(
settings.downloader.path,
self.save_path,
data.official_title,
f"Season {data.season}")
}

View File

@@ -1 +1 @@
from .rss_analyser import RSSAnalyser
from .rss_analyser import RSSAnalyser

View File

@@ -46,9 +46,9 @@ class RSSAnalyser:
bangumi_info.append(data)
return bangumi_info
def rss_to_data(self, url, filter: bool = True) -> BangumiData:
def rss_to_data(self, url, _filter: bool = True) -> BangumiData:
with RequestContent() as req:
rss_torrents = req.get_torrents(url, filter)
rss_torrents = req.get_torrents(url, _filter)
for torrent in rss_torrents:
try:
data = self._title_analyser.raw_parser(
@@ -59,11 +59,10 @@ class RSSAnalyser:
except Exception as e:
logger.debug(e)
def run(self, bangumi_info: list[BangumiData], download_client: DownloadClient, rss_link: str):
def run(self, bangumi_info: list[BangumiData], rss_link: str):
logger.info("Start collecting RSS info.")
try:
self.rss_to_datas(bangumi_info, rss_link)
download_client.add_rules(bangumi_info, rss_link=rss_link)
except Exception as e:
logger.debug(e)
logger.info("Finished")