mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-04-25 11:00:53 +08:00
2.0beta 开发完成
This commit is contained in:
11
AutoBangumi2.0/Dockerfile
Normal file
11
AutoBangumi2.0/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM python:3.10-slim-buster
|
||||
WORKDIR /auto-bangumi
|
||||
COPY requirements.txt .
|
||||
RUN pip3 install -r requirements.txt
|
||||
|
||||
COPY ./app /app
|
||||
COPY ./config /config
|
||||
|
||||
|
||||
CMD [ "python3", "/app/docker_main.py"]
|
||||
@@ -4,23 +4,19 @@ import os
|
||||
|
||||
|
||||
class SetRule:
|
||||
def __init__(self):
|
||||
with open("config.json") as f:
|
||||
info = json.load(f)
|
||||
|
||||
with open("bangumi.json") as f:
|
||||
self.bangumi_info = json.load(f)
|
||||
self.rss_link = info["rss_link"]
|
||||
self.host_ip = "192.168.31.10:8181"
|
||||
self.user_name = "admin"
|
||||
self.password = "adminadmin"
|
||||
|
||||
def set_rule(self, bangumi_name, season):
|
||||
qb = qbittorrentapi.Client(host=self.host_ip, username=self.user_name, password=self.password)
|
||||
def __init__(self, config, info):
|
||||
self.bangumi_info = info
|
||||
self.rss_link = config["rss_link"]
|
||||
self.host_ip = config["host_ip"]
|
||||
self.user_name = config["user_name"]
|
||||
self.password = config["password"]
|
||||
self.qb = qbittorrentapi.Client(host=self.host_ip, username=self.user_name, password=self.password)
|
||||
try:
|
||||
qb.auth_log_in()
|
||||
self.qb.auth_log_in()
|
||||
except qbittorrentapi.LoginFailed as e:
|
||||
print(e)
|
||||
|
||||
def set_rule(self, bangumi_name, season):
|
||||
rule = {
|
||||
'enable': False,
|
||||
'mustContain': bangumi_name,
|
||||
@@ -29,20 +25,16 @@ class SetRule:
|
||||
'episodeFilter': '',
|
||||
'smartFilter': False,
|
||||
'previouslyMatchedEpisodes': [],
|
||||
'affectedFeeds': [rss_link],
|
||||
'affectedFeeds': [self.rss_link],
|
||||
'ignoreDays': 0,
|
||||
'lastMatch': '',
|
||||
'addPaused': False,
|
||||
'assignedCategory': 'Bangumi',
|
||||
'savePath': os.path.join('/downloads', bangumi_name, season)
|
||||
}
|
||||
qb.rss_set_rule(rule_name=bangumi_name, rule_def=rule)
|
||||
self.qb.rss_set_rule(rule_name=bangumi_name, rule_def=rule)
|
||||
|
||||
def set_rule_main(self):
|
||||
def run(self):
|
||||
for info in self.bangumi_info:
|
||||
self.set_rule(info["title"], info["season"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
rule = SetRule()
|
||||
rule.set_rule_main()
|
||||
66
AutoBangumi2.0/app/collect_bangumi_info.py
Normal file
66
AutoBangumi2.0/app/collect_bangumi_info.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
class CollectRSS:
|
||||
def __init__(self, config, info):
|
||||
self.info = info
|
||||
self.config = config
|
||||
self.bangumi_title = []
|
||||
|
||||
def collect_info(self):
|
||||
episode_rules = [r'(.*)\[(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)',
|
||||
r'(.*)\[E(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)',
|
||||
r'(.*)\[第(\d*\.*\d*)话(?:END)?\](.*)',
|
||||
r'(.*)\[第(\d*\.*\d*)話(?:END)?\](.*)',
|
||||
r'(.*)第(\d*\.*\d*)话(?:END)?(.*)',
|
||||
r'(.*)第(\d*\.*\d*)話(?:END)?(.*)',
|
||||
r'(.*)- (\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)? (.*)']
|
||||
url = self.config["rss_link"]
|
||||
rss = requests.get(url, 'utf-8')
|
||||
soup = BeautifulSoup(rss.text, 'xml')
|
||||
item = soup.find_all('item')
|
||||
bangumi_title = []
|
||||
for a in item:
|
||||
name = str(a.find('title'))
|
||||
name = re.sub('<title>|</title>', '', name)
|
||||
parrten = r'\[|\]|\u3010|\u3011|\★|\*'
|
||||
for i in range(2):
|
||||
n = re.split(parrten, name)
|
||||
name = re.sub(f'\[{n[1]}\]|【{n[1]}】|★{n[1]}★', '', name)
|
||||
for rule in episode_rules:
|
||||
matchObj = re.match(rule, name, re.I)
|
||||
if matchObj is not None:
|
||||
new_name = re.sub(r'\[|\]', '', f'{matchObj.group(1)}')
|
||||
new_name = re.split(r'/', new_name)[-1].strip()
|
||||
if new_name not in self.bangumi_title:
|
||||
self.bangumi_title.append(new_name)
|
||||
|
||||
def write_info(self):
|
||||
bangumi_info = self.info
|
||||
had_data = []
|
||||
for data in bangumi_info:
|
||||
had_data.append(data["title"])
|
||||
for title in self.bangumi_title:
|
||||
a = re.match(r'(.*)(S.\d)', title, re.I)
|
||||
if a is not None:
|
||||
title = a.group(1).strip()
|
||||
season = a.group(2).strip()
|
||||
else:
|
||||
season = ''
|
||||
if title not in had_data:
|
||||
bangumi_info.append({
|
||||
"title": title,
|
||||
"season": season
|
||||
})
|
||||
print(f"add {title} {season}")
|
||||
# 写入数据
|
||||
with open("../config/bangumi.json", 'w', encoding='utf8') as f:
|
||||
json.dump(bangumi_info, f, indent=4, separators=(',', ': '), ensure_ascii=False)
|
||||
|
||||
def run(self):
|
||||
self.collect_info()
|
||||
self.write_info()
|
||||
19
AutoBangumi2.0/app/docker_main.py
Normal file
19
AutoBangumi2.0/app/docker_main.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
import time
|
||||
from collect_bangumi_info import CollectRSS
|
||||
from auto_set_rule import SetRule
|
||||
from rename_qb import QbittorrentRename
|
||||
import json
|
||||
|
||||
#sleep_time = os.environ["TIME"]
|
||||
|
||||
if __name__ == "__main__":
|
||||
while True:
|
||||
with open("../config/config.json") as f:
|
||||
config = json.load(f)
|
||||
with open("../config/bangumi.json") as f:
|
||||
info = json.load(f)
|
||||
CollectRSS(config, info).run()
|
||||
SetRule(config, info).run()
|
||||
QbittorrentRename(config).run()
|
||||
time.sleep(1800)
|
||||
94
AutoBangumi2.0/app/rename_qb.py
Normal file
94
AutoBangumi2.0/app/rename_qb.py
Normal file
@@ -0,0 +1,94 @@
|
||||
import re
|
||||
import io
|
||||
import sys
|
||||
import qbittorrentapi
|
||||
from os import environ
|
||||
import time
|
||||
|
||||
|
||||
class QbittorrentRename:
|
||||
def __init__(self, config):
|
||||
self.qbt_client = qbittorrentapi.Client(host=config['host_ip'], username=config['user_name'], password=config['password'])
|
||||
try:
|
||||
self.qbt_client.auth_log_in()
|
||||
except qbittorrentapi.LoginFailed as e:
|
||||
print(e)
|
||||
self.recent_info = self.qbt_client.torrents_info(status_filter='completed')
|
||||
self.hash = None
|
||||
self.name = None
|
||||
self.new_name = None
|
||||
self.path_name = None
|
||||
self.count = 0
|
||||
self.rename_count = 0
|
||||
self.torrent_count = len(self.recent_info)
|
||||
self.method = config['method']
|
||||
self.rules = [r'(.*)\[(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)',
|
||||
r'(.*)\[E(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)',
|
||||
r'(.*)\[第(\d*\.*\d*)话(?:END)?\](.*)',
|
||||
r'(.*)\[第(\d*\.*\d*)話(?:END)?\](.*)',
|
||||
r'(.*)第(\d*\.*\d*)话(?:END)?(.*)',
|
||||
r'(.*)第(\d*\.*\d*)話(?:END)?(.*)',
|
||||
r'(.*)- (\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)? (.*)']
|
||||
|
||||
def rename_normal(self, idx):
|
||||
self.name = self.recent_info[idx].name
|
||||
self.hash = self.recent_info[idx].hash
|
||||
self.path_name = self.recent_info[idx].content_path.split("/")[-1]
|
||||
file_name = self.name
|
||||
for rule in self.rules:
|
||||
matchObj = re.match(rule, file_name, re.I)
|
||||
if matchObj is not None:
|
||||
self.new_name = f'{matchObj.group(1).strip()} E{matchObj.group(2)}{matchObj.group(3)}'
|
||||
|
||||
def rename_pn(self, idx):
|
||||
self.name = self.recent_info[idx].name
|
||||
self.hash = self.recent_info[idx].hash
|
||||
self.path_name = self.recent_info[idx].content_path.split("/")[-1]
|
||||
n = re.split(r'\[|\]', self.name)
|
||||
file_name = self.name.replace(f'[{n[1]}]', '')
|
||||
for rule in self.rules:
|
||||
matchObj = re.match(rule, file_name, re.I)
|
||||
if matchObj is not None:
|
||||
self.new_name = re.sub(r'\[|\]', '', f'{matchObj.group(1).strip()} E{matchObj.group(2)}{n[-1]}')
|
||||
|
||||
def rename(self):
|
||||
if self.path_name != self.new_name:
|
||||
self.qbt_client.torrents_rename_file(torrent_hash=self.hash, old_path=self.name, new_path=self.new_name)
|
||||
print(f'{self.name} >> {self.new_name}')
|
||||
self.count += 1
|
||||
else:
|
||||
return
|
||||
|
||||
def clear_info(self):
|
||||
self.name = None
|
||||
self.hash = None
|
||||
self.new_name = None
|
||||
|
||||
def print_result(self):
|
||||
sys.stdout.write(f"[{time.strftime('%X')}] 已完成对{self.torrent_count}个文件的检查" + '\n')
|
||||
sys.stdout.write(f"[{time.strftime('%X')}] 已对其中{self.count}个文件进行重命名" + '\n')
|
||||
sys.stdout.write(f"[{time.strftime('%X')}] 完成" + '\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
def run(self):
|
||||
if self.method not in ['pn', 'normal']:
|
||||
print('error method')
|
||||
elif self.method == 'normal':
|
||||
for i in range(0, self.torrent_count + 1):
|
||||
try:
|
||||
self.rename_normal(i)
|
||||
self.rename()
|
||||
self.clear_info()
|
||||
except:
|
||||
self.print_result()
|
||||
elif self.method == 'pn':
|
||||
for i in range(0, self.torrent_count + 1):
|
||||
try:
|
||||
self.rename_pn(i)
|
||||
self.rename()
|
||||
self.clear_info()
|
||||
except:
|
||||
self.print_result()
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"host_ip": "192.168.31.10:8181",
|
||||
"user_name": "admin",
|
||||
"password": "adminadmin",
|
||||
"method": "pn",
|
||||
"rss_link": "https://mikanani.me/RSS/MyBangumi?token=Td8ceWZZv3s2OZm5ji9RoMer8vk5VS3xzC1Hmg8A26E%3d",
|
||||
"download_path": "/downloads/Bangumi"
|
||||
}
|
||||
0
AutoBangumi2.0/config/rename_rule.txt
Normal file
0
AutoBangumi2.0/config/rename_rule.txt
Normal file
5
AutoBangumi2.0/requirements.txt
Normal file
5
AutoBangumi2.0/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
qbittorrent-api==2022.4.30
|
||||
requests-html==0.10.0
|
||||
requests-oauthlib==1.3.1
|
||||
requests==2.27.1
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
def collect_info():
|
||||
episode_rules = [r'(.*)\[(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)',
|
||||
r'(.*)\[E(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)',
|
||||
r'(.*)\[第(\d*\.*\d*)话(?:END)?\](.*)',
|
||||
r'(.*)\[第(\d*\.*\d*)話(?:END)?\](.*)',
|
||||
r'(.*)第(\d*\.*\d*)话(?:END)?(.*)',
|
||||
r'(.*)第(\d*\.*\d*)話(?:END)?(.*)',
|
||||
r'(.*)- (\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)? (.*)']
|
||||
with open('./config/config.json') as f:
|
||||
config = json.load(f)
|
||||
url = config["rss_link"]
|
||||
rss = requests.get(url, 'utf-8')
|
||||
soup = BeautifulSoup(rss.text, 'xml')
|
||||
item = soup.find_all('item')
|
||||
bangumi_title = []
|
||||
for a in item:
|
||||
name = str(a.find('title'))
|
||||
name = re.sub('<title>|</title>', '', name)
|
||||
parrten = r'\[|\]|\u3010|\u3011|\★|\*'
|
||||
symbol = [['[', ']'], ['【', '】'], ['★', '★']]
|
||||
for i in range(2):
|
||||
n = re.split(parrten, name)
|
||||
name = re.sub(f'\[{n[1]}\]|【{n[1]}】|★{n[1]}★', '', name)
|
||||
for rule in episode_rules:
|
||||
matchObj = re.match(rule, name, re.I)
|
||||
if matchObj is not None:
|
||||
new_name = re.sub(r'\[|\]', '', f'{matchObj.group(1)}')
|
||||
new_name = re.split(r'/', new_name)[-1].strip()
|
||||
if new_name not in bangumi_title:
|
||||
bangumi_title.append(new_name)
|
||||
|
||||
with open("./data/bangumi.json", encoding='utf-8') as f:
|
||||
bangumi_info = json.load(f)
|
||||
had_data = []
|
||||
for data in bangumi_info:
|
||||
had_data.append(data["title"])
|
||||
|
||||
season_rules = r'(.*)(S.\d)'
|
||||
for title in bangumi_title:
|
||||
a = re.match(season_rules, title, re.I)
|
||||
if a is not None:
|
||||
title = a.group(1).strip()
|
||||
season = a.group(2).strip()
|
||||
else:
|
||||
season = ''
|
||||
if title not in had_data:
|
||||
bangumi_info.append({
|
||||
"title": title,
|
||||
"season": season
|
||||
})
|
||||
print(f"add {title} {season}")
|
||||
# 写入数据
|
||||
with open("./data/bangumi.json", 'w', encoding='utf8') as f:
|
||||
json.dump(bangumi_info, f, indent=4, separators=(',', ': '), ensure_ascii=False)
|
||||
@@ -1,15 +0,0 @@
|
||||
import os
|
||||
import time
|
||||
from collect_bangumi_info import collect_info
|
||||
from rename_qb import rename_main
|
||||
from auto_set_rule import SetRule
|
||||
|
||||
sleep_time = os.environ["TIME"]
|
||||
|
||||
if __name__ == "__main__":
|
||||
while True:
|
||||
collect_info()
|
||||
rename_main()
|
||||
rule = SetRule()
|
||||
rule.set_rule_main()
|
||||
time.sleep(float(sleep_time))
|
||||
Reference in New Issue
Block a user