Merge pull request #282 from EstrellaXD/3.0-dev

3.0.1
This commit is contained in:
Estrella Pan
2023-06-03 14:49:14 +08:00
committed by GitHub
11 changed files with 128 additions and 92 deletions

2
.gitignore vendored
View File

@@ -173,7 +173,7 @@ cython_debug/
test.*
.run
/dev.sh
/src/templates/
/src/config/
/src/debuger.py
/src/dist.zip

24
dev.sh Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
# This script is used to run the development environment.
python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple install -r requirements.txt
cd src || exit
CONFIG_DIR="config"
if [ ! -d "$CONFIG_DIR" ]; then
echo "The directory '$CONFIG_DIR' is missing."
mkdir config
fi
VERSION_FILE="module/__version__.py"
if [ ! -f "$VERSION_FILE" ]; then
echo "The file '$VERSION_FILE' is missing."
echo "VERSION='DEV_VERSION'" >> "$VERSION_FILE"
fi
python3 main.py

View File

@@ -1,9 +1,9 @@
from fastapi import Depends, HTTPException, status
from fastapi.responses import JSONResponse
from .log import router
from module.models import BangumiData
from module.database import BangumiDatabase
from module.manager import TorrentManager
from module.security import get_current_user
@@ -33,7 +33,7 @@ async def get_data(bangumi_id: str, current_user=Depends(get_current_user)):
@router.post("/api/v1/bangumi/updateRule", tags=["bangumi"])
async def update_data(data: BangumiData, current_user=Depends(get_current_user)):
async def update_rule(data: BangumiData, current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
@@ -43,7 +43,7 @@ async def update_data(data: BangumiData, current_user=Depends(get_current_user))
@router.delete("/api/v1/bangumi/deleteRule/{bangumi_id}", tags=["bangumi"])
async def delete_data(bangumi_id: str, file:bool = False, current_user=Depends(get_current_user)):
async def delete_rule(bangumi_id: str, file: bool = False, current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
@@ -53,7 +53,7 @@ async def delete_data(bangumi_id: str, file:bool = False, current_user=Depends(g
@router.delete("/api/v1/bangumi/disableRule/{bangumi_id}", tags=["bangumi"])
async def delete_rule(
async def disable_rule(
bangumi_id: str, file: bool = False, current_user=Depends(get_current_user)
):
if not current_user:
@@ -80,6 +80,6 @@ async def reset_all(current_user=Depends(get_current_user)):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
)
with BangumiDatabase() as database:
database.delete_all()
return {"status": "ok"}
with TorrentManager() as torrent:
torrent.delete_all()
return JSONResponse(status_code=200, content={"message": "OK"})

View File

@@ -54,8 +54,8 @@ async def get_search_result(searchstr: str):
@router.get("/RSS/Bangumi", tags=["proxy"])
async def get_bangumi(bangumiId: str, groupid: str):
full_path = "Bangumi?bangumiId=" + bangumiId + "&groupid=" + groupid
async def get_bangumi(bangumiId: str, subgroupid: str):
full_path = "Bangumi?bangumiId=" + bangumiId + "&subgroupid=" + subgroupid
content = get_rss_content(full_path)
return Response(content, media_type="application/xml")

View File

@@ -9,14 +9,16 @@ class Checker:
def __init__(self):
pass
def check_renamer(self) -> bool:
if self.check_downloader() and settings.bangumi_manage.enable:
@staticmethod
def check_renamer() -> bool:
if settings.bangumi_manage.enable:
return True
else:
return False
def check_analyser(self) -> bool:
if self.check_downloader() and settings.rss_parser.enable:
@staticmethod
def check_analyser() -> bool:
if settings.rss_parser.enable:
return True
else:
return False

View File

@@ -31,7 +31,6 @@ class Program(RenameThread, RSSThread):
"Legacy data detected, starting data migration, please wait patiently."
)
data_migration()
add_rss_feed()
self.start()
def start(self):
@@ -39,12 +38,16 @@ class Program(RenameThread, RSSThread):
return {"status": "Not ready to start."}
self.stop_event.clear()
settings.load()
if self.enable_renamer:
self.rename_start()
if self.enable_rss:
self.rss_start()
logger.info("Program running.")
return {"status": "Program started."}
if self.downloader_status:
if self.enable_renamer:
self.rename_start()
if self.enable_rss:
add_rss_feed()
self.rss_start()
logger.info("Program running.")
return {"status": "Program started."}
else:
return {"status": "Can't connect to downloader. Program not paused."}
def stop(self):
if self.is_running:

View File

@@ -9,7 +9,6 @@ from qbittorrentapi.exceptions import (
)
from module.ab_decorator import qb_connect_failed_wait
from module.downloader.exceptions import ConflictError
logger = logging.getLogger(__name__)
@@ -27,9 +26,9 @@ class QbDownloader:
self.host = host
self.username = username
def auth(self):
def auth(self, retry=3):
times = 0
while times < 3:
while times < retry:
try:
self._client.auth_log_in()
return True
@@ -46,7 +45,8 @@ class QbDownloader:
except APIConnectionError:
logger.error(f"Cannot connect to qBittorrent Server")
logger.info(f"Please check the IP and port in WebUI settings")
time.sleep(30)
time.sleep(10)
times += 1
except Exception as e:
logger.error(f"Unknown error: {e}")
break
@@ -55,6 +55,16 @@ class QbDownloader:
def logout(self):
self._client.auth_log_out()
def check_host(self):
try:
self._client.app_version()
return True
except APIConnectionError:
return False
def check_rss(self, rss_link: str):
pass
@qb_connect_failed_wait
def prefs_init(self, prefs):
return self._client.app_set_preferences(prefs=prefs)
@@ -93,15 +103,16 @@ class QbDownloader:
return False
def rss_add_feed(self, url, item_path):
self._client.rss_add_feed(url, item_path)
try:
self._client.rss_add_feed(url, item_path)
except Conflict409Error:
logger.warning(f"[Downloader] RSS feed {url} already exists")
def rss_remove_item(self, item_path):
try:
self._client.rss_remove_item(item_path)
except Conflict409Error as e:
logger.debug(e)
logger.info("Add new RSS")
raise ConflictError()
except Conflict409Error:
logger.warning(f"[Downloader] RSS item {item_path} does not exist")
def rss_get_feeds(self):
return self._client.rss_items()

View File

@@ -33,6 +33,8 @@ class DownloadClient(TorrentPath):
def __enter__(self):
if not self.authed:
self.auth()
else:
logger.error("[Downloader] Already authed.")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
@@ -42,7 +44,13 @@ class DownloadClient(TorrentPath):
def auth(self):
self.authed = self.client.auth()
logger.debug("Authed.")
if self.authed:
logger.info("[Downloader] Authed.")
else:
logger.error("[Downloader] Auth failed.")
def check_host(self):
return self.client.check_host()
def init_downloader(self):
prefs = {

View File

@@ -13,8 +13,8 @@ logger = logging.getLogger(__name__)
class TorrentPath:
def __init__(self):
self.download_path = settings.downloader.path
def __init__(self, download_path: str = settings.downloader.path):
self.download_path = download_path
@staticmethod
def check_files(info):
@@ -44,11 +44,11 @@ class TorrentPath:
return bangumi_name, season
@staticmethod
def _file_depth(path):
return len(path.split(path.sep))
def _file_depth(file_path):
return len(file_path.split(path.sep))
def is_ep(self, path):
return self._file_depth(path) <= 2
def is_ep(self, file_path):
return self._file_depth(file_path) <= 2
def _gen_save_path(self, data: BangumiData):
folder = (

View File

@@ -1,5 +1,7 @@
import logging
from fastapi.responses import JSONResponse
from module.downloader import DownloadClient
from module.models import BangumiData
from module.database import BangumiDatabase
@@ -31,9 +33,9 @@ class SeasonCollector(DownloadClient):
with BangumiDatabase() as db:
data.added = True
data.eps_collect = True
self.set_rule(data)
db.insert(data)
self.add_rss_feed(data.rss_link[0], item_path=data.official_title)
self.set_rule(data)
def eps_complete():

View File

@@ -1,4 +1,5 @@
import logging
from fastapi.responses import JSONResponse
from module.downloader import DownloadClient
from module.models import BangumiData
@@ -20,49 +21,30 @@ class TorrentManager(BangumiDatabase):
if hash_list:
client.delete_torrent(hash_list)
logger.info(f"Delete rule and torrents for {data.official_title}")
return {
"status": "success",
"msg": f"Delete torrents for {data.official_title}",
}
return f"Delete {data.official_title} torrents."
else:
return {
"status": "error",
"msg": f"Can't find torrents for {data.official_title}",
}
return f"Can't find {data.official_title} torrents."
def delete_rule(self, _id: int | str, file: bool = False):
data = self.search_id(int(_id))
if isinstance(data, BangumiData):
with DownloadClient() as client:
client.remove_rule(data.rule_name)
client.remove_rss_feed(data.official_title)
self.delete_one(int(_id))
if file:
self.delete_torrents(data, client)
return {
"status": "success",
"msg": f"Delete rule and torrents for {data.official_title}",
}
torrent_message = self.delete_torrents(data, client)
return JSONResponse(status_code=200, content={
"msg": f"Delete {data.official_title} rule. {torrent_message}"
})
logger.info(f"[Manager] Delete rule for {data.official_title}")
return {
"status": "success",
"msg": f"Delete rule for {data.official_title}",
}
return JSONResponse(status_code=200, content={
"msg": f"Delete rule for {data.official_title}"
})
else:
return {"status": "error", "msg": f"Can't find id {_id}"}
# data = self.search_id(int(_id))
# if isinstance(data, BangumiData):
# self.delete_one(int(_id))
# if file:
# self.delete_torrents(data)
# logger.info(f"Delete {data.official_title} and torrents.")
# return {
# "status": "success",
# "msg": f"Delete {data.official_title} and torrents.",
# }
# logger.info(f"Delete {data.official_title}")
# return {"status": "success", "msg": f"Delete {data.official_title}"}
# else:
# return data
return JSONResponse(status_code=406, content={
"msg": f"Can't find id {_id}"
})
def disable_rule(self, _id: str | int, file: bool = False):
data = self.search_id(int(_id))
@@ -72,18 +54,18 @@ class TorrentManager(BangumiDatabase):
data.deleted = True
self.update_one(data)
if file:
self.delete_torrents(data, client)
return {
"status": "success",
"msg": f"Disable rule and delete torrents for {data.official_title}",
}
torrent_message = self.delete_torrents(data, client)
return JSONResponse(status_code=200, content={
"msg": f"Disable {data.official_title} rule. {torrent_message}"
})
logger.info(f"[Manager] Disable rule for {data.official_title}")
return {
"status": "success",
"msg": f"Disable rule for {data.official_title}",
}
return JSONResponse(status_code=200, content={
"msg": f"Disable {data.official_title} rule.",
})
else:
return {"status": "error", "msg": f"Can't find data with id {_id}"}
return JSONResponse(status_code=406, content={
"msg": f"Can't find id {_id}"
})
def enable_rule(self, _id: str | int):
data = self.search_id(int(_id))
@@ -93,18 +75,23 @@ class TorrentManager(BangumiDatabase):
with DownloadClient() as client:
client.set_rule(data)
logger.info(f"[Manager] Enable rule for {data.official_title}")
return {
"status": "success",
"msg": f"Enable rule for {data.official_title}",
}
return JSONResponse(status_code=200, content={
"msg": f"Enable {data.official_title} rule.",
})
else:
return JSONResponse(status_code=406, content={
"msg": f"Can't find bangumi id {_id}"
})
def update_rule(self, data: BangumiData):
old_data = self.search_id(data.id)
if not old_data:
logger.error(f"[Manager] Can't find data with id {data.id}")
return {"status": "error", "msg": f"Can't find data with id {data.id}"}
logger.error(f"[Manager] Can't find data with {data.id}")
return JSONResponse(status_code=406, content={
"msg": f"Can't find data with {data.id}"
})
else:
# Set torrent path
# Move torrent
match_list = self.__match_torrents_list(data)
with DownloadClient() as client:
path = client._gen_save_path(data)
@@ -114,10 +101,9 @@ class TorrentManager(BangumiDatabase):
client.remove_rule(data.rule_name)
client.set_rule(data)
self.update_one(data)
return {
"status": "success",
return JSONResponse(status_code=200, content={
"msg": f"Set new path for {data.official_title}",
}
})
def search_all_bangumi(self):
datas = self.search_all()
@@ -128,7 +114,7 @@ class TorrentManager(BangumiDatabase):
def search_one(self, _id: int | str):
data = self.search_id(int(_id))
if not data:
logger.error(f"[Manager] Can't find data with id {_id}")
return {"status": "error", "msg": f"Can't find data with id {_id}"}
logger.error(f"[Manager] Can't find data with {_id}")
return {"status": "error", "msg": f"Can't find data with {_id}"}
else:
return data