mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-04-14 02:20:53 +08:00
refactor
- 区分 Consts 和 Settings,取代 Env - 独立 downloader module,为便于后续提供多下载器支持 - 加入命令行选项,提供 debug 模式 - 其他细节
This commit is contained in:
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@@ -4,11 +4,23 @@
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: 当前文件",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"cwd": "${workspaceFolder}/AutoBangumi/app",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": "Python: docker_main",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/AutoBangumi/app/docker_main.py",
|
||||
"program": "${workspaceFolder}/AutoBangumi/app/app.py",
|
||||
"args": [
|
||||
"-d"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/AutoBangumi/app",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": true
|
||||
|
||||
@@ -18,4 +18,4 @@ ENV RULE_DEBUG=False
|
||||
COPY ./app /app
|
||||
COPY ./config /config
|
||||
|
||||
CMD [ "python3", "/app/docker_main.py"]
|
||||
CMD [ "python3", "/app/app.py"]
|
||||
@@ -2,13 +2,11 @@ import re
|
||||
import json
|
||||
import zhconv
|
||||
import logging
|
||||
from RssFilter.fliter_base import *
|
||||
from fliter_base import *
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
handler = logging.FileHandler(
|
||||
filename="RssFilter/rename_log.txt",
|
||||
mode="w",
|
||||
encoding="utf-8"
|
||||
filename="RssFilter/rename_log.txt", mode="w", encoding="utf-8"
|
||||
)
|
||||
handler.setFormatter(
|
||||
logging.Formatter(
|
||||
@@ -18,36 +16,8 @@ handler.setFormatter(
|
||||
logger.level = logging.WARNING
|
||||
logger.addHandler(handler)
|
||||
|
||||
|
||||
class RSSInfoCleaner:
|
||||
class Name:
|
||||
raw = None
|
||||
conv = None
|
||||
zh = None
|
||||
en = None
|
||||
jp = None
|
||||
clean = None
|
||||
|
||||
class Info:
|
||||
group = None
|
||||
season = None
|
||||
episode = None
|
||||
vision = None
|
||||
|
||||
class Tag:
|
||||
dpi = None
|
||||
ass = None
|
||||
lang = None
|
||||
type = None
|
||||
code = None
|
||||
source = None
|
||||
|
||||
def __init__(self, file_name):
|
||||
self.file_name = file_name
|
||||
self.Name.raw = file_name # 接收文件名参数
|
||||
self.clean() # 清理广告等杂质
|
||||
# 匹配特征等
|
||||
self.group_character = [
|
||||
const = {
|
||||
"group_character":[
|
||||
"字幕社",
|
||||
"字幕组",
|
||||
"字幕屋",
|
||||
@@ -78,8 +48,8 @@ class RSSInfoCleaner:
|
||||
"百合组",
|
||||
"慕留人",
|
||||
"行动组",
|
||||
]
|
||||
self.group_char = [
|
||||
],
|
||||
"group_char" : [
|
||||
"dmhy",
|
||||
"澄空学园",
|
||||
"c.c动漫",
|
||||
@@ -109,25 +79,62 @@ class RSSInfoCleaner:
|
||||
"cxraw",
|
||||
"witex.io",
|
||||
]
|
||||
with open("../config/clean_rule.json", encoding="utf-8") as file_obj:
|
||||
}
|
||||
const["all_charactor"] = const["group_character"] + const["group_char"]
|
||||
|
||||
class RSSInfoCleaner:
|
||||
class Name:
|
||||
def __init__(self) -> None:
|
||||
self.raw = None
|
||||
self.conv = None
|
||||
self.zh = None
|
||||
self.en = None
|
||||
self.jp = None
|
||||
self.clean = None
|
||||
|
||||
class Info:
|
||||
def __init__(self) -> None:
|
||||
self.group = None
|
||||
self.season = None
|
||||
self.episode = None
|
||||
self.vision = None
|
||||
|
||||
class Tag:
|
||||
def __init__(self) -> None:
|
||||
self.dpi = None
|
||||
self.ass = None
|
||||
self.lang = None
|
||||
self.type = None
|
||||
self.code = None
|
||||
self.source = None
|
||||
|
||||
def __init__(self, file_name):
|
||||
self.name = RSSInfoCleaner.Name()
|
||||
self.info = RSSInfoCleaner.Info()
|
||||
self.tag = RSSInfoCleaner.Tag()
|
||||
self.file_name = file_name
|
||||
self.name.raw = file_name # 接收文件名参数
|
||||
self.clean() # 清理广告等杂质
|
||||
# 匹配特征等
|
||||
with open("RssFilter/clean_rule.json", encoding="utf-8") as file_obj:
|
||||
rule_json = json.load(file_obj)[0]["group_name"]
|
||||
self.group_rule = [zhconv.convert(x, "zh-cn") for x in rule_json]
|
||||
const["group_rule"] = [zhconv.convert(x, "zh-cn") for x in rule_json]
|
||||
self.file_info = {}
|
||||
|
||||
self.pre_analyse = None
|
||||
# 匹配字幕组特征
|
||||
self.recognize_group()
|
||||
self.Info.group = self.get_group()
|
||||
self.Tag.dpi = self.get_dpi()
|
||||
self.Info.season = self.get_season()
|
||||
self.Info.episode = self.get_episode()
|
||||
self.Info.vision = self.get_vision()
|
||||
self.Tag.lang = self.get_language()
|
||||
self.Tag.ass = self.get_ass()
|
||||
self.Tag.type = self.get_type()
|
||||
self.Tag.code = self.get_code()
|
||||
self.Tag.source = self.get_source()
|
||||
self.Name.clean = self.get_clean_name()
|
||||
self.info.group = self.get_group()
|
||||
self.tag.dpi = self.get_dpi()
|
||||
self.info.season = self.get_season()
|
||||
self.info.episode = self.get_episode()
|
||||
self.info.vision = self.get_vision()
|
||||
self.tag.lang = self.get_language()
|
||||
self.tag.ass = self.get_ass()
|
||||
self.tag.type = self.get_type()
|
||||
self.tag.code = self.get_code()
|
||||
self.tag.source = self.get_source()
|
||||
self.name.clean = self.get_clean_name()
|
||||
self.zh_list = []
|
||||
self.jp_list = []
|
||||
self.en_list = []
|
||||
@@ -136,7 +143,7 @@ class RSSInfoCleaner:
|
||||
# 清理原链接(中文字符替换为英文)
|
||||
|
||||
def clean(self):
|
||||
file_name = zhconv.convert(self.Name.raw, "zh-cn")
|
||||
file_name = zhconv.convert(self.name.raw, "zh-cn")
|
||||
# 去广告
|
||||
file_name = re.sub(
|
||||
"[((\[【]?(字幕)?[\u4e00-\u9fa5、]{0,3}(新人|招募?新?)[\u4e00-\u9fa5、]{0,8}[))\]】]?",
|
||||
@@ -198,7 +205,7 @@ class RSSInfoCleaner:
|
||||
f_res.group(1), "%s/" % f_res.group(1).strip(".")
|
||||
)
|
||||
|
||||
self.Name.raw = (
|
||||
self.name.raw = (
|
||||
str(file_name)
|
||||
.replace(":", ":")
|
||||
.replace("【", "[")
|
||||
@@ -215,11 +222,9 @@ class RSSInfoCleaner:
|
||||
|
||||
# 检索字幕组特征
|
||||
def recognize_group(self):
|
||||
character = self.group_character
|
||||
group = self.group_char
|
||||
rule = self.group_rule
|
||||
rule = const["group_rule"]
|
||||
# 字幕组(特例)特征优先级大于通用特征
|
||||
character = group + character
|
||||
character = const["all_charactor"]
|
||||
# !强规则,人工录入标准名,区分大小写,优先匹配
|
||||
for char in rule:
|
||||
if ("&" + char) in self.file_name or (char + "&") in self.file_name:
|
||||
@@ -237,8 +242,8 @@ class RSSInfoCleaner:
|
||||
self.pre_analyse = char.lower()
|
||||
return "enforce"
|
||||
# 如果文件名以 [字幕组名] 开头
|
||||
if self.Name.raw[0] == "[":
|
||||
str_split = self.Name.raw.lower().split("]")
|
||||
if self.name.raw[0] == "[":
|
||||
str_split = self.name.raw.lower().split("]")
|
||||
# 检索特征值是否位于文件名第1、2、最后一段
|
||||
for char in character:
|
||||
if (
|
||||
@@ -259,16 +264,16 @@ class RSSInfoCleaner:
|
||||
self.pre_analyse = None
|
||||
return False
|
||||
# 文件名以 -字幕组名 结尾
|
||||
elif "-" in self.Name.raw:
|
||||
elif "-" in self.name.raw:
|
||||
for char in character:
|
||||
if char in self.Name.raw.lower().split("-")[-1]:
|
||||
self.pre_analyse = self.Name.raw.lower().split("-")[-1]
|
||||
if char in self.name.raw.lower().split("-")[-1]:
|
||||
self.pre_analyse = self.name.raw.lower().split("-")[-1]
|
||||
return "reserve"
|
||||
self.pre_analyse = None
|
||||
return False
|
||||
# 文件名以空格分隔 字幕组名为第一段
|
||||
else:
|
||||
first_str = self.Name.raw.lower().split(" ")[0]
|
||||
first_str = self.name.raw.lower().split(" ")[0]
|
||||
for char in character:
|
||||
if char in first_str:
|
||||
self.pre_analyse = first_str
|
||||
@@ -289,16 +294,16 @@ class RSSInfoCleaner:
|
||||
# 大部分情况
|
||||
elif status == "success":
|
||||
# 如果是 [字幕组名] ,这么标准的格式直接else送走吧,剩下的匹配一下
|
||||
if "[%s]" % res_char not in self.Name.raw.lower():
|
||||
if self.Name.raw[0] == "[":
|
||||
if "[%s]" % res_char not in self.name.raw.lower():
|
||||
if self.name.raw[0] == "[":
|
||||
try:
|
||||
# 以特征值为中心,匹配最近的中括号,八成就这个了
|
||||
gp = get_gp(res_char, self.Name.raw.lower())
|
||||
gp = get_gp(res_char, self.name.raw.lower())
|
||||
return gp
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"bug -- res_char:%s,%s,%s"
|
||||
% (res_char, self.Name.raw.lower(), e)
|
||||
% (res_char, self.name.raw.lower(), e)
|
||||
)
|
||||
else:
|
||||
return res_char
|
||||
@@ -307,7 +312,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 扒了6W数据,硬找的参数,没啥说的
|
||||
def get_dpi(self):
|
||||
file_name = self.Name.raw
|
||||
file_name = self.name.raw
|
||||
dpi_list = [
|
||||
"4k",
|
||||
"2160p",
|
||||
@@ -356,7 +361,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 获取语种
|
||||
def get_language(self):
|
||||
file_name = self.Name.raw
|
||||
file_name = self.name.raw
|
||||
lang = []
|
||||
# 中文标示
|
||||
try:
|
||||
@@ -394,7 +399,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 文件种类
|
||||
def get_type(self):
|
||||
file_name = self.Name.raw
|
||||
file_name = self.name.raw
|
||||
type_list = []
|
||||
# 英文标示
|
||||
try:
|
||||
@@ -415,7 +420,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 编码格式
|
||||
def get_code(self):
|
||||
file_name = self.Name.raw
|
||||
file_name = self.name.raw
|
||||
code = []
|
||||
# 视频编码
|
||||
try:
|
||||
@@ -447,7 +452,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 来源
|
||||
def get_source(self):
|
||||
file_name = str(self.Name.raw).lower()
|
||||
file_name = str(self.name.raw).lower()
|
||||
type_list = []
|
||||
# 英文标示
|
||||
for _ in range(3):
|
||||
@@ -474,7 +479,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 获取季度
|
||||
def get_season(self):
|
||||
file_name = self.Name.raw.lower()
|
||||
file_name = self.name.raw.lower()
|
||||
season = []
|
||||
# 中文标示
|
||||
try:
|
||||
@@ -504,7 +509,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 获取集数
|
||||
def get_episode(self):
|
||||
file_name = self.Name.raw.lower()
|
||||
file_name = self.name.raw.lower()
|
||||
episode = []
|
||||
# _集,国漫
|
||||
try:
|
||||
@@ -562,7 +567,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 获取版本
|
||||
def get_vision(self):
|
||||
file_name = self.Name.raw.lower()
|
||||
file_name = self.name.raw.lower()
|
||||
vision = []
|
||||
# 中文
|
||||
try:
|
||||
@@ -596,7 +601,7 @@ class RSSInfoCleaner:
|
||||
|
||||
# 获取字幕类型
|
||||
def get_ass(self):
|
||||
file_name = self.Name.raw.lower()
|
||||
file_name = self.name.raw.lower()
|
||||
ass = []
|
||||
# 中文标示
|
||||
try:
|
||||
@@ -639,7 +644,7 @@ class RSSInfoCleaner:
|
||||
elif has_zh(k_i) and has_en(k_i):
|
||||
# 如果还是同时包含中英文的情况,递龟一下
|
||||
if " " not in k_i:
|
||||
res = re.search(k_i, self.Name.raw.lower())
|
||||
res = re.search(k_i, self.name.raw.lower())
|
||||
if res is not None:
|
||||
zh_list.append(res.group())
|
||||
else:
|
||||
@@ -658,7 +663,7 @@ class RSSInfoCleaner:
|
||||
elif has_en(k_i) is False:
|
||||
zh_list.append(k_i.strip(" "))
|
||||
elif has_zh(k_i) and has_en(k_i):
|
||||
res = re.search(k_i, self.Name.raw.lower())
|
||||
res = re.search(k_i, self.name.raw.lower())
|
||||
if res is not None:
|
||||
zh_list.append(res.group())
|
||||
|
||||
@@ -678,19 +683,19 @@ class RSSInfoCleaner:
|
||||
def get_clean_name(self):
|
||||
# 获取到的信息
|
||||
info = {
|
||||
"group": self.Info.group,
|
||||
"dpi": self.Tag.dpi,
|
||||
"season": self.Info.season,
|
||||
"episode": self.Info.episode,
|
||||
"vision": self.Info.vision,
|
||||
"lang": self.Tag.lang,
|
||||
"ass": self.Tag.ass,
|
||||
"type": self.Tag.type,
|
||||
"code": self.Tag.code,
|
||||
"source": self.Tag.source,
|
||||
"group": self.info.group,
|
||||
"dpi": self.tag.dpi,
|
||||
"season": self.info.season,
|
||||
"episode": self.info.episode,
|
||||
"vision": self.info.vision,
|
||||
"lang": self.tag.lang,
|
||||
"ass": self.tag.ass,
|
||||
"type": self.tag.type,
|
||||
"code": self.tag.code,
|
||||
"source": self.tag.source,
|
||||
}
|
||||
# 字母全部小写
|
||||
clean_name = self.Name.raw.lower()
|
||||
clean_name = self.name.raw.lower()
|
||||
|
||||
# 去除拿到的有效信息
|
||||
for k, v in info.items():
|
||||
@@ -743,108 +748,108 @@ class RSSInfoCleaner:
|
||||
|
||||
# 提取标题
|
||||
def get_title(self):
|
||||
self.Name.zh, self.Name.en, self.Name.jp = None, None, None
|
||||
self.name.zh, self.name.en, self.name.jp = None, None, None
|
||||
# 国漫筛选
|
||||
if "国漫" in self.Name.raw:
|
||||
if "国漫" in self.name.raw:
|
||||
zh = re.search(
|
||||
"-?([\u4e00-\u9fa5]{2,10})_?", self.Name.raw.replace("[国漫]", "")
|
||||
"-?([\u4e00-\u9fa5]{2,10})_?", self.name.raw.replace("[国漫]", "")
|
||||
)
|
||||
if zh is not None:
|
||||
self.Name.zh = clean_list([zh.group()])
|
||||
self.name.zh = clean_list([zh.group()])
|
||||
return
|
||||
if "/" not in self.Name.clean:
|
||||
if has_jp(self.Name.clean) is False:
|
||||
if has_zh(self.Name.clean) is False:
|
||||
en = re.search(self.Name.clean, self.Name.raw.lower())
|
||||
if "/" not in self.name.clean:
|
||||
if has_jp(self.name.clean) is False:
|
||||
if has_zh(self.name.clean) is False:
|
||||
en = re.search(self.name.clean, self.name.raw.lower())
|
||||
if en is not None:
|
||||
self.Name.en = clean_list([en.group()])
|
||||
self.name.en = clean_list([en.group()])
|
||||
return
|
||||
elif (
|
||||
re.search(
|
||||
"(^[\u4e00-\u9fa5\u3040-\u31ff\d:\-·??、.。,!]{1,20}[a-z\d]{,3} ?!?)([a-z\d:\-.。,,!! ]* ?)",
|
||||
self.Name.clean,
|
||||
self.name.clean,
|
||||
)
|
||||
is not None
|
||||
):
|
||||
res = re.search(
|
||||
"(^[\u4e00-\u9fa5\u3040-\u31ff\d:\-·??、.。,!]{1,20}[a-z\d]{,3} ?!?)[._&]?([a-z\d:\-.。,,!! ]* ?)",
|
||||
self.Name.clean,
|
||||
self.name.clean,
|
||||
)
|
||||
zh = res.group(1)
|
||||
en = res.group(2)
|
||||
zh = re.search(zh, self.Name.raw.lower())
|
||||
zh = re.search(zh, self.name.raw.lower())
|
||||
if zh is not None:
|
||||
self.Name.zh = clean_list([zh.group()])
|
||||
en = re.search(en, self.Name.raw.lower())
|
||||
self.name.zh = clean_list([zh.group()])
|
||||
en = re.search(en, self.name.raw.lower())
|
||||
if en is not None:
|
||||
self.Name.en = clean_list([en.group()])
|
||||
self.name.en = clean_list([en.group()])
|
||||
return
|
||||
# 英中
|
||||
elif (
|
||||
re.search(
|
||||
"(^([a-z\d:\-_.。,,!! ]* ?) ?)[._&]?([\u4e00-\u9fa5\u3040-\u31ffa-z\d:\-_·??、.。,!! ]{1,20})",
|
||||
self.Name.clean,
|
||||
self.name.clean,
|
||||
)
|
||||
is not None
|
||||
):
|
||||
res = re.search(
|
||||
"(^([a-z\d:\-_.。,,!! ]* ?) ?)[._&]?([\u4e00-\u9fa5\u3040-\u31ffa-z\d:\-_·??、.。,!! ]{1,20})",
|
||||
self.Name.clean,
|
||||
self.name.clean,
|
||||
)
|
||||
|
||||
zh = res.group(3)
|
||||
en = res.group(1)
|
||||
zh = re.search(zh, self.Name.raw.lower())
|
||||
zh = re.search(zh, self.name.raw.lower())
|
||||
if zh is not None:
|
||||
self.Name.zh = clean_list([zh.group()])
|
||||
en = re.search(en, self.Name.raw.lower())
|
||||
self.name.zh = clean_list([zh.group()])
|
||||
en = re.search(en, self.name.raw.lower())
|
||||
if en is not None:
|
||||
self.Name.en = clean_list([en.group()])
|
||||
self.name.en = clean_list([en.group()])
|
||||
return
|
||||
elif len(re.findall("[a-zA-Z]", self.Name.clean.lower())) < 10:
|
||||
zh = re.search(self.Name.clean, self.Name.raw.lower())
|
||||
elif len(re.findall("[a-zA-Z]", self.name.clean.lower())) < 10:
|
||||
zh = re.search(self.name.clean, self.name.raw.lower())
|
||||
if zh is not None:
|
||||
self.Name.zh = clean_list([zh.group()])
|
||||
self.name.zh = clean_list([zh.group()])
|
||||
return
|
||||
if debug > 0:
|
||||
print("初筛:\r\n%s\r\n%s\r\n%s" % (self.zh_list, self.en_list, self.jp_list))
|
||||
if (has_zh(self.Name.clean) or has_jp(self.Name.clean)) and has_en(
|
||||
self.Name.clean
|
||||
if (has_zh(self.name.clean) or has_jp(self.name.clean)) and has_en(
|
||||
self.name.clean
|
||||
):
|
||||
self.Name.clean = add_separator(self.Name.clean)
|
||||
self.easy_split(self.Name.clean, self.zh_list, self.en_list, self.jp_list)
|
||||
self.name.clean = add_separator(self.name.clean)
|
||||
self.easy_split(self.name.clean, self.zh_list, self.en_list, self.jp_list)
|
||||
|
||||
if debug > 0:
|
||||
print("二筛:\r\n%s\r\n%s\r\n%s" % (self.zh_list, self.en_list, self.jp_list))
|
||||
# 结果反代入原名验证
|
||||
self.all_verity([self.Name.raw, self.Name.clean])
|
||||
self.all_verity([self.name.raw, self.name.clean])
|
||||
|
||||
# 去除正确结果后,重新识别其他部分
|
||||
if self.jp_list:
|
||||
temp_name = del_rules(self.Name.clean, self.jp_list)
|
||||
temp_name = del_rules(self.name.clean, self.jp_list)
|
||||
self.easy_split(temp_name, self.zh_list, self.en_list, self.jp_list)
|
||||
if self.zh_list and self.en_list == []:
|
||||
temp_name = del_rules(self.Name.clean, self.zh_list)
|
||||
temp_name = del_rules(self.name.clean, self.zh_list)
|
||||
self.easy_split(temp_name, self.zh_list, self.en_list, self.jp_list)
|
||||
elif self.zh_list == [] and self.en_list:
|
||||
temp_name = del_rules(self.Name.clean, self.en_list)
|
||||
temp_name = del_rules(self.name.clean, self.en_list)
|
||||
self.easy_split(temp_name, self.zh_list, self.en_list, self.jp_list)
|
||||
while "" in self.en_list:
|
||||
self.en_list.remove("")
|
||||
if debug > 0:
|
||||
print("三筛:\r\n%s\r\n%s\r\n%s" % (self.zh_list, self.en_list, self.jp_list))
|
||||
# 一步一验
|
||||
self.all_verity([self.Name.raw, self.Name.clean])
|
||||
self.all_verity([self.name.raw, self.name.clean])
|
||||
for _ in range(5):
|
||||
# 拼合碎片
|
||||
splicing(self.zh_list, self.zh_list, self.Name.clean)
|
||||
splicing(self.en_list, self.en_list, self.Name.clean)
|
||||
splicing(self.jp_list, self.jp_list, self.Name.clean)
|
||||
splicing(self.zh_list, self.zh_list, self.name.clean)
|
||||
splicing(self.en_list, self.en_list, self.name.clean)
|
||||
splicing(self.jp_list, self.jp_list, self.name.clean)
|
||||
try:
|
||||
# 拼合中英文碎片
|
||||
for i in self.en_list:
|
||||
for j in self.zh_list:
|
||||
res = re.search("%s +%s" % (i, j), self.Name.raw.lower())
|
||||
res = re.search("%s +%s" % (i, j), self.name.raw.lower())
|
||||
if res is not None:
|
||||
self.en_list.remove(i)
|
||||
self.zh_list.append(res.group())
|
||||
@@ -853,16 +858,16 @@ class RSSInfoCleaner:
|
||||
if debug > 0:
|
||||
print("拼合:\r\n%s\r\n%s\r\n%s" % (self.zh_list, self.en_list, self.jp_list))
|
||||
# 再次验证,这里只能验raw名
|
||||
self.all_verity(self.Name.raw)
|
||||
self.all_verity(self.name.raw)
|
||||
# 灌装
|
||||
self.Name.zh = clean_list(self.zh_list)
|
||||
self.name.zh = clean_list(self.zh_list)
|
||||
bug_list = ["不白吃话山海经"]
|
||||
for i in bug_list:
|
||||
if i in self.Name.raw.lower():
|
||||
if i in self.name.raw.lower():
|
||||
if has_zh(i):
|
||||
self.Name.zh = [i]
|
||||
self.Name.en = clean_list(self.en_list)
|
||||
self.Name.jp = clean_list(self.jp_list)
|
||||
self.name.zh = [i]
|
||||
self.name.en = clean_list(self.en_list)
|
||||
self.name.jp = clean_list(self.jp_list)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -873,7 +878,8 @@ if __name__ == "__main__":
|
||||
row = 1 if debug else 200
|
||||
name_list = read_data("mikan", num, row)
|
||||
for i in range(0, len(name_list)):
|
||||
title = RSSInfoCleaner(name_list[i]).Name
|
||||
info = RSSInfoCleaner(name_list[i])
|
||||
title = info.Name
|
||||
print("%s:%s" % (num + i, name_list[i]))
|
||||
print("raw_name:%s" % title.raw)
|
||||
print("clean_name:%s" % title.clean)
|
||||
0
AutoBangumi/app/RssFilter/__init__.py
Normal file
0
AutoBangumi/app/RssFilter/__init__.py
Normal file
0
AutoBangumi/app/__init__.py
Normal file
0
AutoBangumi/app/__init__.py
Normal file
@@ -1,35 +1,30 @@
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
import logging
|
||||
|
||||
from collect_info import CollectRSS
|
||||
from set_rule import SetRule
|
||||
from rename_qb import qBittorrentRename
|
||||
from env import EnvInfo
|
||||
|
||||
|
||||
def setup_logger():
|
||||
DATE_FORMAT = "%Y-%m-%d %X"
|
||||
LOGGING_FORMAT = "%(asctime)s %(levelname)s: %(message)s"
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
datefmt=DATE_FORMAT,
|
||||
format=LOGGING_FORMAT,
|
||||
encoding="utf-8",
|
||||
)
|
||||
from conf import settings
|
||||
from argument_parser import parse
|
||||
from log import setup_logger
|
||||
from utils import json_config
|
||||
|
||||
|
||||
def create_data_file():
|
||||
if not os.path.exists(EnvInfo.info_path):
|
||||
if not os.path.exists(settings.info_path):
|
||||
bangumi_info = {"rss_link": "", "bangumi_info": []}
|
||||
with open(EnvInfo.info_path, "w") as i:
|
||||
json.dump(
|
||||
bangumi_info, i, indent=4, separators=(",", ": "), ensure_ascii=False
|
||||
)
|
||||
json_config.save(settings.info_path, bangumi_info)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse()
|
||||
if args.debug:
|
||||
from const_dev import DEV_SETTINGS
|
||||
|
||||
settings.init(DEV_SETTINGS)
|
||||
else:
|
||||
settings.init()
|
||||
setup_logger()
|
||||
create_data_file()
|
||||
SetRule().rss_feed()
|
||||
@@ -37,4 +32,4 @@ if __name__ == "__main__":
|
||||
CollectRSS().run()
|
||||
SetRule().run()
|
||||
qBittorrentRename().run()
|
||||
time.sleep(EnvInfo.sleep_time)
|
||||
time.sleep(settings.sleep_time)
|
||||
|
||||
15
AutoBangumi/app/argument_parser.py
Normal file
15
AutoBangumi/app/argument_parser.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import argparse
|
||||
|
||||
|
||||
def parse():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="Auto Bangumi",
|
||||
description="""
|
||||
本项目是基于 Mikan Project、qBittorrent 的全自动追番整理下载工具。
|
||||
只需要在 Mikan Project 上订阅番剧,就可以全自动追番。
|
||||
并且整理完成的名称和目录可以直接被 Plex、Jellyfin 等媒体库软件识别,
|
||||
无需二次刮削。""",
|
||||
)
|
||||
|
||||
parser.add_argument("-d", "--debug",action="store_true", help="debug mode")
|
||||
return parser.parse_args()
|
||||
@@ -5,8 +5,10 @@ import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import json
|
||||
import re
|
||||
from env import EnvInfo, BColors
|
||||
from RSSFilter import RSSInfoCleaner as Filter
|
||||
from conf import settings
|
||||
from utils import json_config
|
||||
|
||||
# from RssFilter.RSSFilter import RSSInfoCleaner as Filter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -23,32 +25,27 @@ class MatchRule:
|
||||
class CollectRSS:
|
||||
def __init__(self):
|
||||
self.bangumi_list = []
|
||||
with open(EnvInfo.rule_path, encoding="utf-8") as r:
|
||||
self.rules = json.load(r)
|
||||
self.rules = json_config.load(settings.rule_path)
|
||||
try:
|
||||
self.rules = requests.get(EnvInfo.rule_url).json()
|
||||
with open(EnvInfo.rule_path, "w", encoding="utf-8") as f:
|
||||
json.dump(
|
||||
self.rules, f, indent=4, separators=(",", ": "), ensure_ascii=False
|
||||
)
|
||||
except:
|
||||
with open(EnvInfo.rule_path, encoding="utf-8") as r:
|
||||
self.rules = json.load(r)
|
||||
self.rules = requests.get(settings.rule_url).json()
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
json_config.save(settings.rule_path, self.rules)
|
||||
try:
|
||||
rss = requests.get(EnvInfo.rss_link, "utf-8")
|
||||
except:
|
||||
logger.debug("ERROR with DNS/Connection.")
|
||||
rss = requests.get(settings.rss_link, "utf-8")
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.error("ERROR with DNS/Connection.")
|
||||
quit()
|
||||
soup = BeautifulSoup(rss.text, "xml")
|
||||
self.items = soup.find_all("item")
|
||||
with open(EnvInfo.info_path, encoding="utf-8") as i:
|
||||
self.info = json.load(i)
|
||||
self.info = json_config.load(settings.info_path)
|
||||
|
||||
def get_info_list(self):
|
||||
for item in self.items:
|
||||
name = item.title.string
|
||||
# debug 用
|
||||
if EnvInfo.get_rule_debug:
|
||||
if settings.get_rule_debug:
|
||||
logger.debug(f"Raw {name}")
|
||||
exit_flag = False
|
||||
for rule in self.rules:
|
||||
@@ -64,8 +61,7 @@ class CollectRSS:
|
||||
bangumi_title = n[rule["name_position"]].strip()
|
||||
except IndexError:
|
||||
continue
|
||||
sub_title = re.sub(
|
||||
MatchRule.sub_title, "", bangumi_title)
|
||||
sub_title = re.sub(MatchRule.sub_title, "", bangumi_title)
|
||||
b = re.split(r"\/|\_", sub_title)
|
||||
while "" in b:
|
||||
b.remove("")
|
||||
@@ -78,8 +74,7 @@ class CollectRSS:
|
||||
)
|
||||
if match_obj is not None:
|
||||
bangumi_title = match_obj.group(1).strip()
|
||||
match_obj = re.match(
|
||||
MatchRule.match_rule, bangumi_title, re.I)
|
||||
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:
|
||||
@@ -97,11 +92,11 @@ class CollectRSS:
|
||||
|
||||
def put_info_json(self):
|
||||
had_data = []
|
||||
if self.info["rss_link"] == EnvInfo.rss_link:
|
||||
if self.info["rss_link"] == settings.rss_link:
|
||||
for data in self.info["bangumi_info"]:
|
||||
had_data.append(data["title"])
|
||||
else:
|
||||
self.info = {"rss_link": EnvInfo.rss_link, "bangumi_info": []}
|
||||
self.info = {"rss_link": settings.rss_link, "bangumi_info": []}
|
||||
for item in self.bangumi_list:
|
||||
title = item["title"]
|
||||
match_title_season = re.match(MatchRule.season_match, title, re.I)
|
||||
@@ -134,10 +129,7 @@ class CollectRSS:
|
||||
)
|
||||
had_data.append(json_title)
|
||||
logger.debug("add {json_title} {json_season}")
|
||||
with open(EnvInfo.info_path, "w", encoding="utf8") as f:
|
||||
json.dump(
|
||||
self.info, f, indent=4, separators=(",", ": "), ensure_ascii=False
|
||||
)
|
||||
json_config.save(settings.info_path, self.info)
|
||||
|
||||
def run(self):
|
||||
self.get_info_list()
|
||||
@@ -145,14 +137,15 @@ class CollectRSS:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# rss = requests.get(EnvInfo.rss_link, 'utf-8')
|
||||
# from const import BCOLORS
|
||||
# rss = requests.get(settings.rss_link, 'utf-8')
|
||||
# soup = BeautifulSoup(rss.text, 'xml')
|
||||
# items = soup.find_all('item')
|
||||
# for item in items:
|
||||
# name = item.title.string
|
||||
# pn = Filter(name).Name
|
||||
# print(BColors.HEADER + name)
|
||||
# print(BColors.OKGREEN + str(pn.zh))
|
||||
# print(BCOLORS.HEADER + name)
|
||||
# print(BCOLORS.OKGREEN + str(pn.zh))
|
||||
# print(str(pn.en))
|
||||
print(__file__)
|
||||
print(os.path.dirname(__file__))
|
||||
|
||||
35
AutoBangumi/app/conf.py
Normal file
35
AutoBangumi/app/conf.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
|
||||
import const
|
||||
|
||||
class Settings(dict):
|
||||
def __getattr__(self, item):
|
||||
return self.get(item)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
self[key] = value
|
||||
|
||||
def init(self, args=None):
|
||||
self.update(self._settings_from_env())
|
||||
if args:
|
||||
self.update(args)
|
||||
|
||||
def _val_from_env(self, env, attr):
|
||||
"""Transforms env-strings to python."""
|
||||
val = os.environ[env]
|
||||
if isinstance(attr, tuple):
|
||||
conv_func = attr[1]
|
||||
val = conv_func(val)
|
||||
return val
|
||||
|
||||
|
||||
def _settings_from_env(self):
|
||||
"""Loads settings from env."""
|
||||
return {
|
||||
attr: self._val_from_env(env, attr)
|
||||
for env, attr in const.ENV_TO_ATTR.items()
|
||||
if env in os.environ
|
||||
}
|
||||
|
||||
|
||||
settings = Settings(const.DEFAULT_SETTINGS)
|
||||
51
AutoBangumi/app/const.py
Normal file
51
AutoBangumi/app/const.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
from math import fabs
|
||||
|
||||
|
||||
DEFAULT_SETTINGS = {
|
||||
"host_ip": "localhost:8080",
|
||||
"sleep_time": 1800,
|
||||
"user_name": "admin",
|
||||
"password": "adminadmin",
|
||||
"rss_link": "https://mikanani.me/RSS/classic",
|
||||
"download_path": "/downloads/Bangumi",
|
||||
"method": "pn",
|
||||
"enable_group_tag": True,
|
||||
"info_path": "config/bangumi.json",
|
||||
"rule_path": "config/rule.json",
|
||||
"not_contain": "720",
|
||||
"get_rule_debug": False,
|
||||
"rule_url": "https://raw.githubusercontent.com/EstrellaXD/Bangumi_Auto_Collector/main/AutoBangumi/config/rule.json",
|
||||
"rule_name_re": r"\:|\/|\.",
|
||||
"connect_retry_interval": 5,
|
||||
"enable_eps_complete": False,
|
||||
}
|
||||
|
||||
ENV_TO_ATTR = {
|
||||
"HOST": "host_ip",
|
||||
"TIME": ("sleep_time", lambda e: float(e)),
|
||||
"USER": "user_name",
|
||||
"PASSWORD": "password",
|
||||
"RSS": "rss_link",
|
||||
"DOWNLOAD_PATH": "download_path",
|
||||
"METHOD": "method",
|
||||
"GROUP_TAG": ("enable_group_tag", lambda e: e.lower() in ("true", "1", "t")),
|
||||
"NOT_CONTAIN": "not_contain",
|
||||
"RULE_DEBUG": ("get_rule_debug", lambda e: e.lower() in ("true", "1", "t")),
|
||||
"EP_COMPLETE": ("enable_eps_complete", lambda e: e.lower() in ("true", "1", "t")),
|
||||
}
|
||||
|
||||
FULL_SEASON_SUPPORT_GROUP = ["Lilith-Raws"]
|
||||
|
||||
BCOLORS = {
|
||||
"HEADER": "\033[95m",
|
||||
"OKBLUE": "\033[94m",
|
||||
"OKCYAN": "\033[96m",
|
||||
"OKGREEN": "\033[92m",
|
||||
"WARNING": "\033[93m",
|
||||
"FAIL": "\033[91m",
|
||||
"ENDC": "\033[0m",
|
||||
"BOLD": "\033[1m",
|
||||
"UNDERLINE": "\033[4m",
|
||||
}
|
||||
7
AutoBangumi/app/const_dev.py
Normal file
7
AutoBangumi/app/const_dev.py
Normal file
@@ -0,0 +1,7 @@
|
||||
DEV_SETTINGS = {
|
||||
"host_ip": "localhost:8181",
|
||||
"sleep_time": 10,
|
||||
"info_path": "../config/bangumi.json",
|
||||
"rule_path": "../config/rule.json",
|
||||
"enable_eps_complete": True,
|
||||
}
|
||||
10
AutoBangumi/app/downloader/__init__.py
Normal file
10
AutoBangumi/app/downloader/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from conf import settings
|
||||
|
||||
def getClient():
|
||||
host=settings.host_ip
|
||||
username=settings.user_name
|
||||
password=settings.password
|
||||
# TODO 多下载器支持
|
||||
# 从 settings 里读取下载器名称,然后返回对应 Client
|
||||
from downloader.qb_downloader import QbDownloader
|
||||
return QbDownloader(host, username, password)
|
||||
2
AutoBangumi/app/downloader/exceptions.py
Normal file
2
AutoBangumi/app/downloader/exceptions.py
Normal file
@@ -0,0 +1,2 @@
|
||||
class ConflictError(Exception):
|
||||
pass
|
||||
60
AutoBangumi/app/downloader/qb_downloader.py
Normal file
60
AutoBangumi/app/downloader/qb_downloader.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
from qbittorrentapi import Client, LoginFailed
|
||||
from qbittorrentapi.exceptions import Conflict409Error
|
||||
from tomlkit import item
|
||||
|
||||
from conf import settings
|
||||
|
||||
from downloader.exceptions import ConflictError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class QbDownloader:
|
||||
def __init__(self, host, username, password):
|
||||
self._client = Client(
|
||||
host=host,
|
||||
username=username,
|
||||
password=password,
|
||||
)
|
||||
while True:
|
||||
try:
|
||||
self._client.auth_log_in()
|
||||
break
|
||||
except LoginFailed:
|
||||
logger.warning(
|
||||
f"Can't log in qBittorrent Server {host} by {username}, retry in {settings.connect_retry_interval}"
|
||||
)
|
||||
time.sleep(settings.connect_retry_interval)
|
||||
|
||||
def torrents_info(self, status_filter, category):
|
||||
return self._client.torrents_info(status_filter, category)
|
||||
|
||||
def torrents_add(self, urls, save_path, category):
|
||||
return self._client.torrents_add(
|
||||
urls=urls,
|
||||
save_path=save_path,
|
||||
category=category,
|
||||
)
|
||||
|
||||
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 rss_add_feed(self, url, item_path):
|
||||
try:
|
||||
self._client.rss_add_feed(url, item_path)
|
||||
except Conflict409Error as e:
|
||||
logger.exception(e)
|
||||
raise ConflictError()
|
||||
|
||||
def rss_remove_item(self, item_path):
|
||||
try:
|
||||
self._client.rss_remove_item(item_path)
|
||||
except Conflict409Error as e:
|
||||
logger.exception(e)
|
||||
raise ConflictError()
|
||||
|
||||
def rss_set_rule(self, rule_name, rule_def):
|
||||
self._client.rss_set_rule(rule_name, rule_def)
|
||||
@@ -1,59 +0,0 @@
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class EnvInfo:
|
||||
debug_mode = True
|
||||
# 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"]
|
||||
enable_group_tag = os.getenv("GROUP_TAG", 'False').lower() in ('true', '1', 't')
|
||||
info_path = "/config/bangumi.json"
|
||||
rule_path = "/config/clean_rule.json"
|
||||
not_contain = os.environ["NOT_CONTAIN"]
|
||||
get_rule_debug = os.getenv("RULE_DEBUG", 'False').lower() in ('true', '1', 't')
|
||||
enable_eps_complete = os.getenv("EP_COMPLETE", 'False').lower() in ('true', '1', 't')
|
||||
else:
|
||||
# Debug ENV
|
||||
host_ip = "localhost:8181"
|
||||
sleep_time = 10
|
||||
user_name = "admin"
|
||||
password = "adminadmin"
|
||||
rss_link = "https://mikanani.me/RSS/classic"
|
||||
download_path = "/downloads/Bangumi"
|
||||
method = "pn"
|
||||
enable_group_tag = True
|
||||
info_path = "../config/bangumi.json"
|
||||
rule_path = "../config/rule_beta.json"
|
||||
not_contain = "720"
|
||||
get_rule_debug = True
|
||||
enable_eps_complete = True
|
||||
# Static ENV
|
||||
rule_url = "https://raw.githubusercontent.com/EstrellaXD/Bangumi_Auto_Collector/main/AutoBangumi/config/rule.json"
|
||||
|
||||
rule_name_re = r"\:|\/|\."
|
||||
|
||||
|
||||
class BColors:
|
||||
HEADER = '\033[95m'
|
||||
OKBLUE = '\033[94m'
|
||||
OKCYAN = '\033[96m'
|
||||
OKGREEN = '\033[92m'
|
||||
WARNING = '\033[93m'
|
||||
FAIL = '\033[91m'
|
||||
ENDC = '\033[0m'
|
||||
BOLD = '\033[1m'
|
||||
UNDERLINE = '\033[4m'
|
||||
|
||||
|
||||
class Other:
|
||||
full_season_support_group = [
|
||||
"Lilith-Raws"
|
||||
]
|
||||
@@ -1,10 +1,13 @@
|
||||
import os.path
|
||||
import requests
|
||||
from qbittorrentapi import Client
|
||||
from env import EnvInfo, Other
|
||||
from bs4 import BeautifulSoup
|
||||
import logging
|
||||
|
||||
from conf import settings
|
||||
from const import FULL_SEASON_SUPPORT_GROUP
|
||||
from downloader import getClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -14,6 +17,7 @@ class FullSeasonGet:
|
||||
self.bangumi_name = bangumi_name
|
||||
self.group = group
|
||||
self.season = season
|
||||
self.client = getClient()
|
||||
|
||||
def get_season_rss(self):
|
||||
if self.season == "S01":
|
||||
@@ -21,30 +25,23 @@ class FullSeasonGet:
|
||||
else:
|
||||
season = self.season
|
||||
season = requests.get(
|
||||
f"https://mikanani.me/RSS/Search?searchstr={self.group}+{self.bangumi_name}+{season}")
|
||||
f"https://mikanani.me/RSS/Search?searchstr={self.group}+{self.bangumi_name}+{season}"
|
||||
)
|
||||
soup = BeautifulSoup(season.content, "xml")
|
||||
self.torrents = soup.find_all("enclosure")
|
||||
|
||||
def add_torrents(self):
|
||||
qb = Client(
|
||||
host=EnvInfo.host_ip, username=EnvInfo.user_name, password=EnvInfo.password
|
||||
)
|
||||
try:
|
||||
qb.auth_log_in()
|
||||
except:
|
||||
logger.error("Error")
|
||||
for torrent in self.torrents:
|
||||
qb.torrents_add(
|
||||
self.client.torrents_add(
|
||||
urls=torrent["url"],
|
||||
save_path=str(
|
||||
os.path.join(EnvInfo.download_path,
|
||||
self.bangumi_name, self.season)
|
||||
os.path.join(settings.download_path, self.bangumi_name, self.season)
|
||||
),
|
||||
category="Bangumi",
|
||||
)
|
||||
|
||||
def run(self):
|
||||
if self.group in Other.full_season_support_group:
|
||||
if self.group in FULL_SEASON_SUPPORT_GROUP:
|
||||
self.get_season_rss()
|
||||
self.add_torrents()
|
||||
|
||||
|
||||
14
AutoBangumi/app/log.py
Normal file
14
AutoBangumi/app/log.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import logging
|
||||
|
||||
|
||||
def setup_logger():
|
||||
DATE_FORMAT = "%Y-%m-%d %X"
|
||||
LOGGING_FORMAT = "%(asctime)s %(levelname)s: %(message)s"
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
datefmt=DATE_FORMAT,
|
||||
format=LOGGING_FORMAT,
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
setup_logger()
|
||||
4
AutoBangumi/app/parser/parser.py
Normal file
4
AutoBangumi/app/parser/parser.py
Normal file
@@ -0,0 +1,4 @@
|
||||
class Parser:
|
||||
def parse(filename):
|
||||
# TODO 番剧名称识别
|
||||
pass
|
||||
@@ -2,21 +2,17 @@ import re
|
||||
import qbittorrentapi
|
||||
import logging
|
||||
|
||||
from env import EnvInfo
|
||||
from downloader import getClient
|
||||
|
||||
from conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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:
|
||||
logger.exception(e)
|
||||
self.recent_info = self.qbt_client.torrents_info(
|
||||
self.client = getClient()
|
||||
self.recent_info = self.client.torrents_info(
|
||||
status_filter="completed", category="Bangumi"
|
||||
)
|
||||
self.count = 0
|
||||
@@ -55,7 +51,7 @@ class qBittorrentRename:
|
||||
|
||||
def rename_torrent_file(self, hash, path_name, new_name):
|
||||
if path_name != new_name:
|
||||
self.qbt_client.torrents_rename_file(
|
||||
self.client.torrents_rename_file(
|
||||
torrent_hash=hash, old_path=path_name, new_path=new_name
|
||||
)
|
||||
logger.debug(f"{path_name} >> {new_name}")
|
||||
@@ -68,7 +64,7 @@ class qBittorrentRename:
|
||||
|
||||
def run(self):
|
||||
method_dict = {"pn": self.rename_pn, "normal": self.rename_normal}
|
||||
if EnvInfo.method not in method_dict:
|
||||
if settings.method not in method_dict:
|
||||
logger.error(f"error method")
|
||||
else:
|
||||
for i in range(0, self.torrent_count):
|
||||
@@ -77,7 +73,7 @@ class qBittorrentRename:
|
||||
name = info.name
|
||||
hash = info.hash
|
||||
path_name = info.content_path.split("/")[-1]
|
||||
new_name = method_dict[EnvInfo.method](name)
|
||||
new_name = method_dict[settings.method](name)
|
||||
self.rename_torrent_file(hash, path_name, new_name)
|
||||
except:
|
||||
logger.warning(f"{name} rename fail")
|
||||
|
||||
@@ -1,63 +1,64 @@
|
||||
import re
|
||||
import logging
|
||||
from env import EnvInfo
|
||||
import qbittorrentapi
|
||||
import json
|
||||
import os
|
||||
|
||||
from downloader import getClient
|
||||
from downloader.exceptions import ConflictError
|
||||
|
||||
from conf import settings
|
||||
from utils import json_config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SetRule:
|
||||
def __init__(self):
|
||||
with open(EnvInfo.info_path, encoding="utf-8") as f:
|
||||
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
|
||||
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:
|
||||
logger.exception(e)
|
||||
self.info = json_config.load(settings.info_path)
|
||||
self.bangumi_info = self.info["bangumi_info"]
|
||||
self.rss_link = settings.rss_link
|
||||
self.download_path = settings.download_path
|
||||
self.client = getClient()
|
||||
|
||||
def set_rule(self, bangumi_name, group, season):
|
||||
rule = {
|
||||
'enable': True,
|
||||
'mustContain': bangumi_name,
|
||||
'mustNotContain': EnvInfo.not_contain,
|
||||
'useRegx': True,
|
||||
'episodeFilter': '',
|
||||
'smartFilter': False,
|
||||
'previouslyMatchedEpisodes': [],
|
||||
'affectedFeeds': [self.rss_link],
|
||||
'ignoreDays': 0,
|
||||
'lastMatch': '',
|
||||
'addPaused': False,
|
||||
'assignedCategory': 'Bangumi',
|
||||
'savePath': str(os.path.join(EnvInfo.download_path, re.sub(EnvInfo.rule_name_re, " ", bangumi_name).strip(), season))
|
||||
"enable": True,
|
||||
"mustContain": bangumi_name,
|
||||
"mustNotContain": settings.not_contain,
|
||||
"useRegx": True,
|
||||
"episodeFilter": "",
|
||||
"smartFilter": False,
|
||||
"previouslyMatchedEpisodes": [],
|
||||
"affectedFeeds": [self.rss_link],
|
||||
"ignoreDays": 0,
|
||||
"lastMatch": "",
|
||||
"addPaused": False,
|
||||
"assignedCategory": "Bangumi",
|
||||
"savePath": str(
|
||||
os.path.join(
|
||||
settings.download_path,
|
||||
re.sub(settings.rule_name_re, " ", bangumi_name).strip(),
|
||||
season,
|
||||
)
|
||||
),
|
||||
}
|
||||
if EnvInfo.enable_group_tag:
|
||||
if settings.enable_group_tag:
|
||||
rule_name = f"[{group}] {bangumi_name}"
|
||||
else:
|
||||
rule_name = bangumi_name
|
||||
self.qb.rss_set_rule(rule_name=rule_name, rule_def=rule)
|
||||
self.client.rss_set_rule(rule_name=rule_name, rule_def=rule)
|
||||
|
||||
def rss_feed(self):
|
||||
try:
|
||||
self.qb.rss_remove_item(item_path="Mikan_RSS")
|
||||
except qbittorrentapi.exceptions.Conflict409Error:
|
||||
self.client.rss_remove_item(item_path="Mikan_RSS")
|
||||
except ConflictError:
|
||||
logger.debug("No feed exists, starting adding feed.")
|
||||
try:
|
||||
self.qb.rss_add_feed(url=self.rss_link, item_path="Mikan_RSS")
|
||||
self.client.rss_add_feed(url=self.rss_link, item_path="Mikan_RSS")
|
||||
logger.debug("Successes adding RSS Feed.")
|
||||
except ConnectionError:
|
||||
logger.debug("Error with adding RSS Feed.")
|
||||
except qbittorrentapi.exceptions.Conflict409Error:
|
||||
except ConflictError:
|
||||
logger.debug("RSS Already exists.")
|
||||
|
||||
def run(self):
|
||||
@@ -66,9 +67,7 @@ class SetRule:
|
||||
if not info["added"]:
|
||||
self.set_rule(info["title"], info["group"], 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)
|
||||
json_config.save(settings.info_path, self.info)
|
||||
logger.debug("Finished.")
|
||||
|
||||
|
||||
|
||||
0
AutoBangumi/app/utils/__init__.py
Normal file
0
AutoBangumi/app/utils/__init__.py
Normal file
12
AutoBangumi/app/utils/json_config.py
Normal file
12
AutoBangumi/app/utils/json_config.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import json
|
||||
|
||||
|
||||
def load(filename):
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def save(filename, obj):
|
||||
with open(filename, "w", encoding="utf8") as f:
|
||||
json.dump(obj, f, indent=4, separators=(",", ": "), ensure_ascii=False)
|
||||
pass
|
||||
@@ -56,4 +56,4 @@
|
||||
],
|
||||
"name_position": 3
|
||||
}
|
||||
]
|
||||
]
|
||||
Reference in New Issue
Block a user