Merge pull request #315 from EstrellaXD/3.0-dev

3.0.4
This commit is contained in:
Estrella Pan
2023-06-08 20:28:28 +08:00
committed by GitHub
16 changed files with 183 additions and 78 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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=?;",

View File

@@ -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()

View File

@@ -59,8 +59,3 @@ def eps_complete():
bd.update_list(datas)
if __name__ == "__main__":
from module.conf import setup_logger
setup_logger()
eps_complete()

View File

@@ -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)

View File

@@ -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

View File

@@ -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}")

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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,

View File

@@ -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)