2.5.11 若干调整

- 调整 TDMB 识别器
- 调整番剧补全功能
- 调整获取 torrent 添加过滤器
This commit is contained in:
EstrellaXD
2022-07-14 22:53:23 +08:00
parent ddfe2505d7
commit ebf332b181
16 changed files with 170 additions and 132 deletions

View File

@@ -1,4 +1,4 @@
name: build-docker-image
name: Build(Docker)
on:
release:

4
.gitignore vendored
View File

@@ -163,13 +163,13 @@ cython_debug/
# Custom
/auto_bangumi/conf/const_dev.py
/config/bangumi.json
/config
/auto_bangumi/tester.py
/resource/names.txt
/auto_bangumi/parser/analyser/tmdb.py
/auto_bangumi/parser/analyser/tmdb_parser.py
/auto_bangumi/run_debug.sh
/auto_bangumi/debug_run.sh

View File

@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
DEFAULT_SETTINGS = {
"version": "2.5.10",
"version": "2.5.11",
"data_version": 4.0,
"host_ip": "localhost:8080",
"sleep_time": 7200,
@@ -12,7 +12,7 @@ DEFAULT_SETTINGS = {
"method": "pn",
"enable_group_tag": False,
"info_path": "/config/bangumi.json",
"not_contain": "720",
"not_contain": r"720|\d+-\d+",
"rule_name_re": r"\:|\/|\.",
"connect_retry_interval": 5,
"debug_mode": False,

View File

@@ -1,6 +1,7 @@
import re
import logging
import os
from attrdict import AttrDict
from downloader import getClient
from downloader.exceptions import ConflictError
@@ -54,17 +55,25 @@ class DownloadClient:
logger.info(f"Add {official_name} Season {season}")
def rss_feed(self):
try:
self.client.rss_remove_item(item_path="Mikan_RSS")
except ConflictError:
logger.info("No feed exists, start adding feed.")
try:
self.client.rss_add_feed(url=settings.rss_link, item_path="Mikan_RSS")
logger.info("Add RSS Feed successfully.")
except ConnectionError:
logger.warning("Error with adding RSS Feed.")
except ConflictError:
logger.info("RSS Already exists.")
if not settings.refresh_rss:
if self.client.get_rss_info() == settings.rss_link:
logger.info("RSS Already exists.")
else:
logger.info("No feed exists, start adding feed.")
self.client.rss_add_feed(url=settings.rss_link, item_path="Mikan_RSS")
logger.info("Add RSS Feed successfully.")
else:
try:
self.client.rss_remove_item(item_path="Mikan_RSS")
except ConflictError:
logger.info("No feed exists, start adding feed.")
try:
self.client.rss_add_feed(url=settings.rss_link, item_path="Mikan_RSS")
logger.info("Add RSS Feed successfully.")
except ConnectionError:
logger.warning("Error with adding RSS Feed.")
except ConflictError:
logger.info("RSS Already exists.")
def add_collection_feed(self, rss_link, item_path):
self.client.rss_add_feed(url=rss_link, item_path=item_path)
@@ -79,7 +88,7 @@ class DownloadClient:
# logger.info("to rule.")
logger.debug("Finished.")
def get_torrent_info(self):
def get_torrent_info(self) -> [AttrDict]:
return self.client.torrents_info(
status_filter="completed", category="Bangumi"
)
@@ -113,6 +122,7 @@ class DownloadClient:
self.client.rss_add_feed(url=rss_link, item_path=item_path)
logger.info("Add RSS Feed successfully.")
if __name__ == "__main__":
put = DownloadClient()

View File

@@ -31,7 +31,7 @@ class FullSeasonGet:
downloads = []
for torrent in torrents:
download_info = {
"url": torrent,
"url": torrent.torrent_link,
"save_path": os.path.join(
settings.download_path,
data["official_title"],
@@ -77,4 +77,4 @@ if __name__ == "__main__":
"added": True,
"eps_collect": True
}
print(a.init_eps_complete_search_str(data))
print(a.init_eps_complete_search_str(data))

View File

@@ -17,7 +17,8 @@ class Renamer:
self.client = download_client
self._renamer = TitleParser()
def print_result(self, torrent_count, rename_count):
@staticmethod
def print_result(torrent_count, rename_count):
if rename_count != 0:
logger.info(f"Finished checking {torrent_count} files' name, renamed {rename_count} files.")
logger.debug(f"Checked {torrent_count} files")
@@ -27,7 +28,8 @@ class Renamer:
torrent_count = len(recent_info)
return recent_info, torrent_count
def split_path(self, path: str):
@staticmethod
def split_path(path: str):
suffix = os.path.splitext(path)[-1]
path = path.replace(settings.download_path, "")
path_parts = PurePath(path).parts \

View File

@@ -16,10 +16,11 @@ class RSSAnalyser:
self._title_analyser = TitleParser()
self._request = RequestContent()
def rss_to_datas(self, bangumi_info: list):
rss_titles = self._request.get_titles(settings.rss_link)
def rss_to_datas(self, bangumi_info: list) -> list:
rss_torrents = self._request.get_torrents(settings.rss_link)
self._request.close_session()
for raw_title in rss_titles:
for torrent in rss_torrents:
raw_title = torrent.name
extra_add = True
if bangumi_info is not []:
for d in bangumi_info:
@@ -27,18 +28,16 @@ class RSSAnalyser:
logger.debug(f"Had added {d['title_raw']} before")
extra_add = False
break
if re.search(settings.not_contain, raw_title) is not None:
extra_add = False
if extra_add:
data = self._title_analyser.return_dict(raw_title)
if data is not None and data["official_title"] not in bangumi_info:
bangumi_info.append(data)
return bangumi_info
def rss_to_data(self, url):
rss_title = self._request.get_title(url)
def rss_to_data(self, url) -> dict:
rss_torrents = self._request.get_torrents(url)
self._request.close_session()
data = self._title_analyser.return_dict(rss_title)
data = self._title_analyser.return_dict(rss_torrents[0].name)
return data
def run(self, bangumi_info: list, download_client: DownloadClient):

View File

@@ -59,6 +59,13 @@ 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):
item = self._client.rss_items().get("Mikan_RSS")
if item is not None:
return item.url
else:
return None
def rss_add_feed(self, url, item_path):
try:
self._client.rss_add_feed(url, item_path)

View File

@@ -1,4 +1,14 @@
import re
from dataclasses import dataclass
from network.request import RequestURL
from conf import settings
@dataclass
class TorrentInfo:
name: str
torrent_link: str
class RequestContent:
@@ -6,23 +16,24 @@ class RequestContent:
self._req = RequestURL()
# Mikanani RSS
def get_titles(self, url):
def get_torrents(self, url: str) -> [TorrentInfo]:
soup = self._req.get_content(url)
items = soup.find_all("item")
return [item.title.string for item in items]
torrent_titles = [item.title.string for item in soup.find_all("item")]
keep_index = []
for idx, title in enumerate(torrent_titles):
if re.search(settings.not_contain, title) is None:
keep_index.append(idx)
torrent_urls = [item.get("url") for item in soup.find_all("enclosure")]
return [TorrentInfo(torrent_titles[i], torrent_urls[i]) for i in keep_index]
def get_title(self, url):
def get_torrent(self, url) -> TorrentInfo:
soup = self._req.get_content(url)
item = soup.find("item")
return item.title.string
def get_torrents(self, url):
soup = self._req.get_content(url)
enclosure = soup.find_all("enclosure")
return [t["url"] for t in enclosure]
enclosure = item.find("enclosure")
return TorrentInfo(item.title.string, enclosure["url"])
# API JSON
def get_json(self, url):
def get_json(self, url) -> dict:
return self._req.get_content(url, content="json")
def close_session(self):
@@ -31,6 +42,8 @@ class RequestContent:
if __name__ == "__main__":
r = RequestContent()
url = "https://mikanani.me/RSS/Bangumi?bangumiId=2685&subgroupid=552"
title = r.get_title(url)
print(title)
rss_url = "https://mikanani.me/RSS/Bangumi?bangumiId=2739&subgroupid=203"
titles = r.get_torrents(rss_url)
print(settings.not_contain)
for title in titles:
print(title.name, title.torrent_link)

View File

@@ -1,3 +1,4 @@
from .raw_parser import RawParser
from .rename_parser import DownloadParser
from .tmdb import TMDBMatcher
from .tmdb_parser import TMDBMatcher

View File

@@ -5,7 +5,7 @@ from network import RequestContent
from conf import settings
class BangumiAPI:
class BgmAPI:
def __init__(self):
self.search_url = lambda e: \
f"https://api.bgm.tv/search/subject/{e}?type=2"
@@ -21,7 +21,6 @@ class BangumiAPI:
return contents[0]["name"], contents[0]["name_cn"]
if __name__ == '__main__':
BGM = BangumiAPI()
BGM = BgmAPI()
print(BGM.search("辉夜大小姐"))

View File

@@ -128,7 +128,7 @@ class RawParser:
sub, dpi, source = self.find_tags(other) # 剩余信息处理
return name, season, season_raw, episode, sub, dpi, source, name_group, group
def analyse(self, raw):
def analyse(self, raw: str) -> Episode or None:
try:
ret = self.process(raw)
if ret is None:
@@ -150,5 +150,6 @@ class RawParser:
if __name__ == "__main__":
test = RawParser()
ep = test.analyse("[ANi] Classroom of the Elite S2 - 欢迎来到实力至上主义的教室 第二季 - 01 [1080P][Baha][WEB-DL][AAC AVC][CHT][MP4]")
print(ep.title, ep.ep_info.number)
test_txt = "[SWSUB][7月新番][继母的拖油瓶是我的前女友/継母の连れ子が元カノだった][001][GB_JP][AVC][1080P][网盘][无修正] [331.6MB] [复制磁连]"
ep = test.analyse(test_txt)
print(ep.title)

View File

@@ -1,12 +1,23 @@
import dataclasses
import re
import logging
from os import path
from dataclasses import dataclass
# from .raw_parser import RawParser
logger = logging.getLogger(__name__)
@dataclass
class DownloadInfo:
name: str
season: int
suffix: str
file_name: str
folder_name: str
class DownloadParser:
def __init__(self):
self.rules = [
@@ -18,82 +29,65 @@ class DownloadParser:
r"(.*)第(\d*\.*\d*)話(?:END)?(.*)",
]
def rename_normal(self, info_dict):
name = info_dict["name"]
season = info_dict["season"]
@staticmethod
def rename_init(name, folder_name, season, suffix) -> DownloadInfo:
n = re.split(r"[\[\]()【】()]", name)
suffix = suffix if suffix is not None else n[-1]
file_name = name.replace(f"[{n[1]}]", "")
if season < 10:
season = f"0{season}"
return DownloadInfo(name, season, suffix, file_name, folder_name)
def rename_normal(self, info: DownloadInfo):
for rule in self.rules:
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)}"
new_name = f"{title} S{info.season}E{match_obj.group(2)}{match_obj.group(3)}"
return new_name
def rename_pn(self, info_dict):
name = info_dict["name"]
season = info_dict["season"]
suffix = info_dict["suffix"]
n = re.split(r"[\[\]()【】()]", name)
file_name = name.replace(f"[{n[1]}]", "")
if season < 10:
season = f"0{season}"
def rename_pn(self, info: DownloadInfo):
for rule in self.rules:
match_obj = re.match(rule, file_name, re.I)
match_obj = re.match(rule, info.file_name, re.I)
if match_obj is not None:
title = re.sub(r"([Ss]|Season )\d{1,3}", "", match_obj.group(1)).strip()
title = title if title != "" else info_dict.get("folder_name")
title = title if title != "" else info.folder_name
new_name = re.sub(
r"[\[\]]",
"",
f"{title} S{season}E{match_obj.group(2)}{suffix}",
f"{title} S{info.season}E{match_obj.group(2)}{info.suffix}",
)
return new_name
def rename_advance(self, info_dict):
name = info_dict["name"]
folder_name = info_dict["folder_name"]
suffix = info_dict["suffix"]
season = info_dict["season"]
n = re.split(r"[\[\]()【】()]", name)
file_name = name.replace(f"[{n[1]}]", "")
if season < 10:
season = f"0{season}"
def rename_advance(self, info: DownloadInfo):
for rule in self.rules:
match_obj = re.match(rule, file_name, re.I)
match_obj = re.match(rule, info.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)}{suffix}",
f"{info.folder_name} S{info.season}E{match_obj.group(2)}{info.suffix}",
)
return new_name
def rename_no_season_pn(self, info_dict):
name = info_dict["name"]
suffix = info_dict["suffix"]
n = re.split(r"[\[\]()【】()]", name)
file_name = name.replace(f"[{n[1]}]", "")
def rename_no_season_pn(self, info: DownloadInfo):
for rule in self.rules:
match_obj = re.match(rule, file_name, re.I)
match_obj = re.match(rule, info.file_name, re.I)
if match_obj is not None:
title = match_obj.group(1).strip()
new_name = re.sub(
r"[\[\]]",
"",
f"{title} E{match_obj.group(2)}{suffix}",
f"{title} E{match_obj.group(2)}{info.suffix}",
)
return new_name
@staticmethod
def rename_none(info_dict):
return info_dict["name"]
def rename_none(info: DownloadInfo):
return info.name
def download_rename(self, name, folder_name, season,suffix, method):
info_dict = {
"name": name,
"folder_name": folder_name,
"season": season,
"suffix": suffix
}
def download_rename(self, name, folder_name, season, suffix, method):
rename_info = self.rename_init(name, folder_name, season, suffix)
method_dict = {
"normal": self.rename_normal,
"pn": self.rename_pn,
@@ -102,11 +96,11 @@ class DownloadParser:
"none": self.rename_none
}
logger.debug(f"Name: {folder_name}, File type: {path.splitext(name)[-1]}, Season {season}")
return method_dict[method.lower()](info_dict)
return method_dict[method.lower()](rename_info)
if __name__ == "__main__":
name = "[Isekai Meikyuu de Harem wo][01][BIG5][1080P][AT-X].mp4"
name = "[sub][Isekai Meikyuu de Harem wo][01][BIG5][1080P][AT-X].mp4"
rename = DownloadParser()
new_name = rename.download_rename(name, "Made abyess", 1, ".mp4", "Advance")
print(new_name)
new_name = rename.download_rename(name, "Made abyess", 1, ".mp4", "pn")
print(new_name)

View File

@@ -1,16 +1,19 @@
import re
import time
from dataclasses import dataclass
from network import RequestContent
from conf import settings
@dataclass
class TMDBInfo:
id: int
title_jp: str
title_zh: str
season: dict
last_season: int
year_number: int
class TMDBMatcher:
@@ -21,11 +24,11 @@ class TMDBMatcher:
f"https://api.themoviedb.org/3/tv/{e}?api_key={settings.tmdb_api}&language=zh-CN"
self._request = RequestContent()
def is_animation(self, id):
url_info = self.info_url(id)
def is_animation(self, tv_id) -> bool:
url_info = self.info_url(tv_id)
type_id = self._request.get_json(url_info)["genres"]
for type in type_id:
if type["id"] == 16:
if type.get("id") == 16:
return True
return False
@@ -37,39 +40,40 @@ class TMDBMatcher:
# return title["title"]
# return None
def get_season(self, seasons: list):
@staticmethod
def get_season(seasons: list) -> int:
for season in seasons:
if re.search(r"\d 季", season["season"]) is not None:
date = season["air_date"].split("-")
if re.search(r"\d 季", season.get("season")) is not None:
date = season.get("air_date").split("-")
[year, _ , _] = date
now_year = time.localtime().tm_year
if int(year) == now_year:
return int(re.findall(r"\d", season["season"])[0])
return int(re.findall(r"\d", season.get("season"))[0])
def tmdb_search(self, title):
tmdb_info = TMDBInfo()
def tmdb_search(self, title) -> TMDBInfo:
url = self.search_url(title)
contents = self._request.get_json(url)["results"]
contents = self._request.get_json(url).get("results")
if contents.__len__() == 0:
url = self.search_url(title.replace(" ", ""))
contents = self._request.get_json(url)["results"]
contents = self._request.get_json(url).get("results")
# 判断动画
for content in contents:
id = content["id"]
if self.is_animation(id):
tmdb_info.id = id
break
url_info = self.info_url(tmdb_info.id)
url_info = self.info_url(id)
info_content = self._request.get_json(url_info)
# 关闭链接
self._request.close_session()
tmdb_info.season = [{"season": s["name"], "air_date": s["air_date"]} for s in info_content["seasons"]]
tmdb_info.last_season = self.get_season(tmdb_info.season)
tmdb_info.title_jp = info_content["original_name"]
tmdb_info.title_zh = info_content["name"]
return tmdb_info
season = [{"season": s.get("name"), "air_date": s.get("air_date")} for s in info_content.get("seasons")]
last_season = self.get_season(season)
title_jp = info_content.get("original_name")
title_zh = info_content.get("name")
year_number = info_content.get("first_air_date").split("-")[0]
return TMDBInfo(id, title_jp, title_zh, season, last_season, year_number)
if __name__ == "__main__":
test = " Love Live虹咲学园 学园偶像同好会"
print(TMDBMatcher().tmdb_search(test).title_zh)
test = "辉夜大小姐"
info = TMDBMatcher().tmdb_search(test)
print(f"{info.title_zh}({info.year_number})")

View File

@@ -10,27 +10,33 @@ class TitleParser:
def __init__(self):
self._raw_parser = RawParser()
self._download_parser = DownloadParser()
self._tmdb_parser = TMDBMatcher()
def raw_parser(self, raw):
def raw_parser(self, raw: str):
return self._raw_parser.analyse(raw)
def download_parser(self, download_raw, folder_name, season, suffix, method=settings.method):
return self._download_parser.download_rename(download_raw, folder_name, season, suffix, method)
def return_dict(self, raw):
tmdb = TMDBMatcher()
def tmdb_parser(self, title: str, season:int):
try:
tmdb_info = self._tmdb_parser.tmdb_search(title)
logger.debug(f"TMDB Matched, title is {tmdb_info.title_zh}")
except Exception as e:
logger.warning("Not Matched with TMDB")
return title, season
if settings.title_language == "zh":
official_title = f"{tmdb_info.title_zh}({tmdb_info.year_number})"
elif settings.title_language == "jp":
official_title = f"{tmdb_info.title_jp}({tmdb_info.year_number})"
season = tmdb_info.last_season
return official_title, season
def return_dict(self, raw: str):
try:
episode = self.raw_parser(raw)
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
official_title, season = self.tmdb_parser(episode.title, episode.season_info.number)
else:
official_title = episode.title
season = episode.season_info.number
@@ -54,9 +60,10 @@ class TitleParser:
if __name__ == '__main__':
import re
from conf.const_dev import DEV_SETTINGS
settings.init(DEV_SETTINGS)
T = TitleParser()
raw = "[Lilith-Raws] 神渣☆偶像 / Kami Kuzu☆Idol - 01 [Baha][WEB-DL][1080p][AVC AAC][CHT][MP4]"
raw = "[SWSUB][7月新番][继母的拖油瓶是我的前女友/継母の连れ子が元カノだった][001][GB_JP][AVC][1080P][网盘][无修正] [331.6MB] [复制磁连]"
season = int(re.search(r"\d{1,2}", "S02").group())
title = T.raw_parser(raw)
print(season, title.title, title.ep_info.number)
print(T.return_dict(raw))
dict = T.return_dict(raw)
print(dict)

View File

@@ -17,3 +17,4 @@ soupsieve
typing_extensions==4.3.0
urllib3==1.26.9
uvicorn
attrdict