mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-04-14 02:20:53 +08:00
Submodule docs/wiki updated: d0bb98f004...519e381e8a
@@ -1,7 +1,9 @@
|
||||
import logging
|
||||
import time
|
||||
import threading
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
lock = threading.Lock()
|
||||
|
||||
|
||||
def qb_connect_failed_wait(func):
|
||||
@@ -30,3 +32,10 @@ def api_failed(func):
|
||||
logger.debug(e)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def locked(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
with lock:
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
@@ -2,7 +2,8 @@ import os.path
|
||||
|
||||
from module.downloader import DownloadClient
|
||||
from module.network import RequestContent
|
||||
from module.conf import settings, DATA_PATH
|
||||
from module.conf import settings
|
||||
from module.models import Config
|
||||
|
||||
|
||||
class Checker:
|
||||
@@ -46,8 +47,7 @@ class Checker:
|
||||
|
||||
@staticmethod
|
||||
def check_first_run() -> bool:
|
||||
token_exist = False if settings.rss_parser.token in ["", "token"] else True
|
||||
if token_exist:
|
||||
return False
|
||||
else:
|
||||
if settings.dict() == Config().dict():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -19,6 +19,8 @@ class RSSThread(ProgramStatus):
|
||||
)
|
||||
|
||||
def rss_loop(self):
|
||||
with DownloadClient() as client:
|
||||
client.init_downloader()
|
||||
while not self.stop_event.is_set():
|
||||
# Analyse RSS
|
||||
with BangumiDatabase() as db:
|
||||
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from module.database.connector import DataConnector
|
||||
from module.models import BangumiData
|
||||
from module.ab_decorator import locked
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -68,6 +69,7 @@ class BangumiDatabase(DataConnector):
|
||||
data_list = [self.__data_to_db(x) for x in data]
|
||||
self._update_list(data_list=data_list, table_name=self.__table_name)
|
||||
|
||||
@locked
|
||||
def update_rss(self, title_raw, rss_set: str):
|
||||
# Update rss and added
|
||||
self._cursor.execute(
|
||||
@@ -108,51 +110,59 @@ class BangumiDatabase(DataConnector):
|
||||
self._delete_all(self.__table_name)
|
||||
|
||||
def search_all(self) -> list[BangumiData]:
|
||||
self._cursor.execute(
|
||||
"""
|
||||
SELECT * FROM bangumi
|
||||
"""
|
||||
)
|
||||
return self.__fetch_data()
|
||||
dict_data = self._search_datas(self.__table_name)
|
||||
return [self.__db_to_data(x) for x in dict_data]
|
||||
|
||||
def search_id(self, _id: int) -> BangumiData | None:
|
||||
self._cursor.execute(
|
||||
"""
|
||||
SELECT * FROM bangumi WHERE id = :id
|
||||
""",
|
||||
{"id": _id},
|
||||
)
|
||||
values = self._cursor.fetchone()
|
||||
if values is None:
|
||||
condition = {"id": _id}
|
||||
value = self._search_data(table_name=self.__table_name, condition=condition)
|
||||
# self._cursor.execute(
|
||||
# """
|
||||
# SELECT * FROM bangumi WHERE id = :id
|
||||
# """,
|
||||
# {"id": _id},
|
||||
# )
|
||||
# values = self._cursor.fetchone()
|
||||
if value is None:
|
||||
return None
|
||||
keys = [x[0] for x in self._cursor.description]
|
||||
dict_data = dict(zip(keys, values))
|
||||
dict_data = dict(zip(keys, value))
|
||||
return self.__db_to_data(dict_data)
|
||||
|
||||
def search_official_title(self, official_title: str) -> BangumiData | None:
|
||||
self._cursor.execute(
|
||||
"""
|
||||
SELECT * FROM bangumi WHERE official_title = :official_title
|
||||
""",
|
||||
{"official_title": official_title},
|
||||
value = self._search_data(
|
||||
table_name=self.__table_name, condition={"official_title": official_title}
|
||||
)
|
||||
values = self._cursor.fetchone()
|
||||
if values is None:
|
||||
# self._cursor.execute(
|
||||
# """
|
||||
# SELECT * FROM bangumi WHERE official_title = :official_title
|
||||
# """,
|
||||
# {"official_title": official_title},
|
||||
# )
|
||||
# values = self._cursor.fetchone()
|
||||
if value is None:
|
||||
return None
|
||||
keys = [x[0] for x in self._cursor.description]
|
||||
dict_data = dict(zip(keys, values))
|
||||
dict_data = dict(zip(keys, value))
|
||||
return self.__db_to_data(dict_data)
|
||||
|
||||
def match_poster(self, bangumi_name: str) -> str:
|
||||
self._cursor.execute(
|
||||
"""
|
||||
SELECT official_title, poster_link
|
||||
FROM bangumi
|
||||
WHERE INSTR(:bangumi_name, official_title) > 0
|
||||
""",
|
||||
{"bangumi_name": bangumi_name},
|
||||
condition = f"INSTR({bangumi_name}, official_title) > 0"
|
||||
keys = ["official_title", "poster_link"]
|
||||
data = self._search_data(
|
||||
table_name=self.__table_name,
|
||||
keys=keys,
|
||||
condition=condition,
|
||||
)
|
||||
data = self._cursor.fetchone()
|
||||
# self._cursor.execute(
|
||||
# """
|
||||
# SELECT official_title, poster_link
|
||||
# FROM bangumi
|
||||
# WHERE INSTR(:bangumi_name, official_title) > 0
|
||||
# """,
|
||||
# {"bangumi_name": bangumi_name},
|
||||
# )
|
||||
# data = self._cursor.fetchone()
|
||||
if not data:
|
||||
return ""
|
||||
official_title, poster_link = data
|
||||
@@ -160,14 +170,20 @@ class BangumiDatabase(DataConnector):
|
||||
return ""
|
||||
return poster_link
|
||||
|
||||
@locked
|
||||
def match_list(self, torrent_list: list, rss_link: str) -> list:
|
||||
# Match title_raw in database
|
||||
self._cursor.execute(
|
||||
"""
|
||||
SELECT title_raw, rss_link, poster_link FROM bangumi
|
||||
"""
|
||||
keys = ["title_raw", "rss_link", "poster_link"]
|
||||
data = self._search_datas(
|
||||
table_name=self.__table_name,
|
||||
keys=keys,
|
||||
)
|
||||
data = self._cursor.fetchall()
|
||||
# self._cursor.execute(
|
||||
# """
|
||||
# SELECT title_raw, rss_link, poster_link FROM bangumi
|
||||
# """
|
||||
# )
|
||||
# data = self._cursor.fetchall()
|
||||
if not data:
|
||||
return torrent_list
|
||||
# Match title
|
||||
@@ -189,6 +205,12 @@ class BangumiDatabase(DataConnector):
|
||||
|
||||
def not_complete(self) -> list[BangumiData]:
|
||||
# Find eps_complete = False
|
||||
condition = "eps_complete = 0"
|
||||
data = self._search_datas(
|
||||
table_name=self.__table_name,
|
||||
condition=condition,
|
||||
)
|
||||
|
||||
self._cursor.execute(
|
||||
"""
|
||||
SELECT * FROM bangumi WHERE eps_collect = 0
|
||||
|
||||
@@ -2,6 +2,7 @@ import os
|
||||
import sqlite3
|
||||
import logging
|
||||
|
||||
|
||||
from module.conf import DATA_PATH
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -93,10 +94,35 @@ class DataConnector:
|
||||
)
|
||||
self._conn.commit()
|
||||
|
||||
|
||||
def _delete_all(self, table_name: str):
|
||||
self._cursor.execute(f"DELETE FROM {table_name}")
|
||||
self._conn.commit()
|
||||
|
||||
|
||||
def _search_data(self, table_name: str, keys: list[str] | None, condition: str) -> dict:
|
||||
if keys is None:
|
||||
self._cursor.execute(f"SELECT * FROM {table_name} WHERE {condition}")
|
||||
else:
|
||||
self._cursor.execute(
|
||||
f"SELECT {', '.join(keys)} FROM {table_name} WHERE {condition}"
|
||||
)
|
||||
return dict(zip(keys, self._cursor.fetchone()))
|
||||
|
||||
|
||||
def _search_datas(self, table_name: str, keys: list[str] | None, condition: str = None) -> list[dict]:
|
||||
if keys is None:
|
||||
select_sql = "*"
|
||||
else:
|
||||
select_sql = ", ".join(keys)
|
||||
if condition is None:
|
||||
self._cursor.execute(f"SELECT {select_sql} FROM {table_name}")
|
||||
else:
|
||||
self._cursor.execute(
|
||||
f"SELECT {select_sql} FROM {table_name} WHERE {condition}"
|
||||
)
|
||||
return [dict(zip(keys, row)) for row in self._cursor.fetchall()]
|
||||
|
||||
def _table_exists(self, table_name: str) -> bool:
|
||||
self._cursor.execute(
|
||||
f"SELECT name FROM sqlite_master WHERE type='table' AND name=?;",
|
||||
|
||||
@@ -132,7 +132,12 @@ class QbDownloader:
|
||||
return self._client.torrents_info(hashes=_hash)[0].save_path
|
||||
|
||||
def set_category(self, _hash, category):
|
||||
self._client.torrents_set_category(category, hashes=_hash)
|
||||
try:
|
||||
self._client.torrents_set_category(category, hashes=_hash)
|
||||
except Conflict409Error:
|
||||
logger.warning(f"[Downloader] Category {category} does not exist")
|
||||
self.add_category(category)
|
||||
self._client.torrents_set_category(category, hashes=_hash)
|
||||
|
||||
def check_connection(self):
|
||||
return self._client.app_version()
|
||||
|
||||
@@ -59,8 +59,3 @@ def eps_complete():
|
||||
bd.update_list(datas)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from module.conf import setup_logger
|
||||
|
||||
setup_logger()
|
||||
eps_complete()
|
||||
|
||||
@@ -106,7 +106,7 @@ class Renamer(DownloadClient):
|
||||
_hash=_hash, old_path=media_path, new_path=new_path
|
||||
)
|
||||
if not renamed:
|
||||
logger.warning(f"[Renamrr] {media_path} rename failed")
|
||||
logger.warning(f"[Renamer] {media_path} rename failed")
|
||||
# Delete bad torrent.
|
||||
if settings.bangumi_manage.remove_bad_torrent:
|
||||
self.delete_torrent(_hash)
|
||||
|
||||
@@ -28,6 +28,7 @@ class Notification(BaseModel):
|
||||
official_title: str = Field(..., alias="official_title", title="番剧名")
|
||||
season: int = Field(..., alias="season", title="番剧季度")
|
||||
episode: int = Field(..., alias="episode", title="番剧集数")
|
||||
poster_path: str | None = Field(None, alias="poster_path", title="番剧海报路径")
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -32,24 +32,25 @@ class PostNotification:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _gen_message(notify: Notification) -> str:
|
||||
def _get_poster(notify: Notification):
|
||||
with BangumiDatabase() as db:
|
||||
poster_path = db.match_poster(notify.official_title)
|
||||
if poster_path:
|
||||
poster_link = "https://mikanani.me" + poster_path
|
||||
text = f"""
|
||||
番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n{poster_link}\n
|
||||
"""
|
||||
# text = f"""
|
||||
# 番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n{poster_link}\n
|
||||
# """
|
||||
else:
|
||||
text = f"""
|
||||
番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n
|
||||
"""
|
||||
return text
|
||||
poster_link = "https://mikanani.me"
|
||||
# text = f"""
|
||||
# 番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n
|
||||
# """
|
||||
notify.poster_path = poster_link
|
||||
|
||||
def send_msg(self, notify: Notification) -> bool:
|
||||
text = self._gen_message(notify)
|
||||
self._get_poster(notify)
|
||||
try:
|
||||
self.notifier.post_msg(text)
|
||||
self.notifier.post_msg(notify)
|
||||
logger.debug(f"Send notification: {notify.official_title}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to send notification: {e}")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import logging
|
||||
|
||||
from module.network import RequestContent
|
||||
from module.models import Notification
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -11,8 +13,16 @@ class BarkNotification(RequestContent):
|
||||
self.token = token
|
||||
self.notification_url = "https://api.day.app/push"
|
||||
|
||||
def post_msg(self, text) -> bool:
|
||||
data = {"title": "AutoBangumi 番剧更新", "body": text, "device_key": self.token}
|
||||
@staticmethod
|
||||
def gen_message(notify: Notification) -> str:
|
||||
text = f"""
|
||||
番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n{notify.poster_path}\n
|
||||
"""
|
||||
return text
|
||||
|
||||
def post_msg(self, notify: Notification) -> bool:
|
||||
text = self.gen_message(notify)
|
||||
data = {"title": notify.official_title, "body": text, "device_key": self.token}
|
||||
resp = self.post_data(self.notification_url, data)
|
||||
logger.debug(f"Bark notification: {resp.status_code}")
|
||||
return resp.status_code == 200
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
from module.network import RequestContent
|
||||
from module.models import Notification
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -12,9 +13,17 @@ class ServerChanNotification(RequestContent):
|
||||
super().__init__()
|
||||
self.notification_url = f"https://sctapi.ftqq.com/{token}.send"
|
||||
|
||||
def post_msg(self, text: str) -> bool:
|
||||
@staticmethod
|
||||
def gen_message(notify: Notification) -> str:
|
||||
text = f"""
|
||||
番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n{notify.poster_path}\n
|
||||
"""
|
||||
return text
|
||||
|
||||
def post_msg(self, notify: Notification) -> bool:
|
||||
text = self.gen_message(notify)
|
||||
data = {
|
||||
"title": "AutoBangumi 番剧更新",
|
||||
"title": notify.official_title,
|
||||
"desp": text,
|
||||
}
|
||||
resp = self.post_data(self.notification_url, data)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
from module.network import RequestContent
|
||||
from module.models import Notification
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -11,8 +12,16 @@ class SlackNotification(RequestContent):
|
||||
self.token = token
|
||||
self.notification_url = "https://api.day.app/push"
|
||||
|
||||
def post_msg(self, text) -> bool:
|
||||
data = {"title": "AutoBangumi 番剧更新", "body": text, "device_key": self.token}
|
||||
@staticmethod
|
||||
def gen_message(notify: Notification) -> str:
|
||||
text = f"""
|
||||
番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n{notify.poster_path}\n
|
||||
"""
|
||||
return text
|
||||
|
||||
def post_msg(self, notify: Notification) -> bool:
|
||||
text = self.gen_message(notify)
|
||||
data = {"title": notify.official_title, "body": text, "device_key": self.token}
|
||||
resp = self.post_data(self.notification_url, data)
|
||||
logger.debug(f"Bark notification: {resp.status_code}")
|
||||
return resp.status_code == 200
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
from module.network.request_contents import RequestContent
|
||||
from module.network import RequestContent
|
||||
from module.models import Notification
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -11,7 +12,15 @@ class TelegramNotification(RequestContent):
|
||||
self.notification_url = f"https://api.telegram.org/bot{token}/sendMessage"
|
||||
self.chat_id = chat_id
|
||||
|
||||
def post_msg(self, text: str) -> bool:
|
||||
@staticmethod
|
||||
def gen_message(notify: Notification) -> str:
|
||||
text = f"""
|
||||
番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n{notify.poster_path}\n
|
||||
"""
|
||||
return text
|
||||
|
||||
def post_msg(self, notify: Notification) -> bool:
|
||||
text = self.gen_message(notify)
|
||||
data = {
|
||||
"chat_id": self.chat_id,
|
||||
"text": text,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import logging
|
||||
|
||||
from module.network import RequestContent
|
||||
from module.models import Notification
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -13,21 +15,26 @@ class WecomNotification(RequestContent):
|
||||
self.notification_url = f"{chat_id}"
|
||||
self.token = token
|
||||
|
||||
def post_msg(self, text: str) -> bool:
|
||||
@staticmethod
|
||||
def gen_message(notify: Notification) -> str:
|
||||
text = f"""
|
||||
番剧名称:{notify.official_title}\n季度: 第{notify.season}季\n更新集数: 第{notify.episode}集\n{notify.poster_path}\n
|
||||
"""
|
||||
return text
|
||||
|
||||
def post_msg(self, notify: Notification) -> bool:
|
||||
##Change message format to match Wecom push better
|
||||
info = text.split(":")
|
||||
print(info)
|
||||
title = "【番剧更新】" + info[1].split("\n")[0].strip()
|
||||
msg = info[2].split("\n")[0].strip()+" "+info[3].split("\n")[0].strip()
|
||||
picurl = info[3].split("\n")[1].strip()
|
||||
title = "【番剧更新】" + notify.official_title
|
||||
msg = self.gen_message(notify)
|
||||
picurl = notify.poster_path
|
||||
#Default pic to avoid blank in message. Resolution:1068*455
|
||||
if picurl == "":
|
||||
if picurl == "https://mikanani.me":
|
||||
picurl = "https://article.biliimg.com/bfs/article/d8bcd0408bf32594fd82f27de7d2c685829d1b2e.png"
|
||||
data = {
|
||||
"key":self.token,
|
||||
"type": "news",
|
||||
"title": title,
|
||||
"msg": msg,
|
||||
"key":self.token,
|
||||
"type": "news",
|
||||
"title": title,
|
||||
"msg": msg,
|
||||
"picurl":picurl
|
||||
}
|
||||
resp = self.post_data(self.notification_url, data)
|
||||
|
||||
Reference in New Issue
Block a user