mirror of
https://github.com/d0zingcat/MoviePilot-Plugins.git
synced 2026-05-13 15:09:12 +00:00
fix plugins
This commit is contained in:
@@ -49,8 +49,6 @@ class AutoClean(_PluginBase):
|
||||
_cleantype = None
|
||||
_cleandate = None
|
||||
_cleanuser = None
|
||||
_downloadhis = None
|
||||
_transferhis = None
|
||||
|
||||
# 定时器
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
@@ -70,9 +68,6 @@ class AutoClean(_PluginBase):
|
||||
|
||||
# 加载模块
|
||||
if self._enabled:
|
||||
self._downloadhis = DownloadHistoryOper()
|
||||
self._transferhis = TransferHistoryOper()
|
||||
|
||||
if self._onlyonce:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
@@ -115,9 +110,10 @@ class AutoClean(_PluginBase):
|
||||
return
|
||||
|
||||
# 查询用户清理日期之前的下载历史,不填默认清理全部用户的下载
|
||||
_downloadhis = DownloadHistoryOper()
|
||||
if not self._cleanuser:
|
||||
clean_date = self.__get_clean_date()
|
||||
downloadhis_list = self._downloadhis.list_by_user_date(date=clean_date)
|
||||
downloadhis_list = _downloadhis.list_by_user_date(date=clean_date)
|
||||
logger.info(f'获取到日期 {clean_date} 之前的下载历史 {len(downloadhis_list)} 条')
|
||||
self.__clean_history(date=clean_date, clean_type=self._cleantype, downloadhis_list=downloadhis_list)
|
||||
|
||||
@@ -130,8 +126,8 @@ class AutoClean(_PluginBase):
|
||||
# 1.3.7版本及之前处理多位用户
|
||||
if str(self._cleanuser).count(','):
|
||||
for username in str(self._cleanuser).split(","):
|
||||
downloadhis_list = self._downloadhis.list_by_user_date(date=clean_date,
|
||||
username=username)
|
||||
downloadhis_list = _downloadhis.list_by_user_date(date=clean_date,
|
||||
username=username)
|
||||
logger.info(
|
||||
f'获取到用户 {username} 日期 {clean_date} 之前的下载历史 {len(downloadhis_list)} 条')
|
||||
self.__clean_history(date=clean_date, clean_type=self._cleantype, downloadhis_list=downloadhis_list)
|
||||
@@ -152,8 +148,8 @@ class AutoClean(_PluginBase):
|
||||
# 转strftime
|
||||
clean_date = self.__get_clean_date(clean_date)
|
||||
logger.info(f'{username} 使用 {clean_type} 清理方式,清理 {clean_date} 之前的下载历史')
|
||||
downloadhis_list = self._downloadhis.list_by_user_date(date=clean_date,
|
||||
username=username)
|
||||
downloadhis_list = _downloadhis.list_by_user_date(date=clean_date,
|
||||
username=username)
|
||||
logger.info(
|
||||
f'获取到用户 {username} 日期 {clean_date} 之前的下载历史 {len(downloadhis_list)} 条')
|
||||
self.__clean_history(date=clean_date, clean_type=clean_type,
|
||||
@@ -168,6 +164,7 @@ class AutoClean(_PluginBase):
|
||||
return
|
||||
|
||||
# 读取历史记录
|
||||
_transferhis = TransferHistoryOper()
|
||||
pulgin_history = self.get_data('history') or []
|
||||
|
||||
# 创建一个字典来保存分组结果
|
||||
@@ -197,7 +194,7 @@ class AutoClean(_PluginBase):
|
||||
logger.debug(f'下载历史 {downloadhis.id} {downloadhis.title} 未获取到download_hash,跳过处理')
|
||||
continue
|
||||
# 根据hash获取转移记录
|
||||
transferhis_list = self._transferhis.list_by_hash(download_hash=downloadhis.download_hash)
|
||||
transferhis_list = _transferhis.list_by_hash(download_hash=downloadhis.download_hash)
|
||||
if not transferhis_list:
|
||||
logger.warn(f"下载历史 {downloadhis.download_hash} 未查询到转移记录,跳过处理")
|
||||
continue
|
||||
@@ -208,7 +205,7 @@ class AutoClean(_PluginBase):
|
||||
dest_fileitem = schemas.FileItem(**history.dest_fileitem)
|
||||
StorageChain().delete_file(dest_fileitem)
|
||||
# 删除记录
|
||||
self._transferhis.delete(history.id)
|
||||
_transferhis.delete(history.id)
|
||||
# 删除源文件
|
||||
if clean_type in ["src", "all"]:
|
||||
src_fileitem = schemas.FileItem(**history.src_fileitem)
|
||||
|
||||
@@ -12,9 +12,8 @@ from apscheduler.triggers.cron import CronTrigger
|
||||
from ruamel.yaml import CommentedMap
|
||||
|
||||
from app import schemas
|
||||
from app.chain.site import SiteChain
|
||||
from app.core.config import settings
|
||||
from app.core.event import EventManager, eventmanager, Event
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.db.site_oper import SiteOper
|
||||
from app.helper.browser import PlaywrightHelper
|
||||
from app.helper.cloudflare import under_challenge
|
||||
@@ -49,12 +48,6 @@ class AutoSignIn(_PluginBase):
|
||||
# 可使用的用户级别
|
||||
auth_level = 2
|
||||
|
||||
# 私有属性
|
||||
sites: SitesHelper = None
|
||||
siteoper: SiteOper = None
|
||||
sitechain: SiteChain = None
|
||||
# 事件管理器
|
||||
event: EventManager = None
|
||||
# 定时器
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
# 加载的模块
|
||||
@@ -75,10 +68,6 @@ class AutoSignIn(_PluginBase):
|
||||
_auto_cf: int = 0
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.sites = SitesHelper()
|
||||
self.siteoper = SiteOper()
|
||||
self.event = EventManager()
|
||||
self.sitechain = SiteChain()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
@@ -97,8 +86,8 @@ class AutoSignIn(_PluginBase):
|
||||
self._clean = config.get("clean")
|
||||
|
||||
# 过滤掉已删除的站点
|
||||
all_sites = [site.id for site in self.siteoper.list_order_by_pri()] + [site.get("id") for site in
|
||||
self.__custom_sites()]
|
||||
all_sites = [site.id for site in SiteOper().list_order_by_pri()] + [site.get("id") for site in
|
||||
self.__custom_sites()]
|
||||
self._sign_sites = [site_id for site_id in all_sites if site_id in self._sign_sites]
|
||||
self._login_sites = [site_id for site_id in all_sites if site_id in self._login_sites]
|
||||
# 保存配置
|
||||
@@ -272,7 +261,7 @@ class AutoSignIn(_PluginBase):
|
||||
customSites = self.__custom_sites()
|
||||
|
||||
site_options = ([{"title": site.name, "value": site.id}
|
||||
for site in self.siteoper.list_order_by_pri()]
|
||||
for site in SiteOper().list_order_by_pri()]
|
||||
+ [{"title": site.get("name"), "value": site.get("id")}
|
||||
for site in customSites])
|
||||
return [
|
||||
@@ -565,7 +554,7 @@ class AutoSignIn(_PluginBase):
|
||||
sites_info = {} # 记录站点信息
|
||||
|
||||
# 获取站点信息
|
||||
site_indexers = self.sites.get_indexers()
|
||||
site_indexers = SitesHelper().get_indexers()
|
||||
for site in site_indexers:
|
||||
if not site.get("public"):
|
||||
sites_info[site.get("id")] = site.get("name")
|
||||
@@ -734,8 +723,8 @@ class AutoSignIn(_PluginBase):
|
||||
# 按日期排序,最新的在前面
|
||||
try:
|
||||
records.sort(key=lambda x: x.get("day_obj", datetime.now().date()), reverse=True)
|
||||
except:
|
||||
pass # 排序失败时跳过
|
||||
except Exception as e:
|
||||
logger.debug(f"排序失败: {str(e)}")
|
||||
|
||||
# 获取最新的状态作为站点概要
|
||||
latest_status = records[0].get("status", "未知状态")
|
||||
@@ -770,8 +759,8 @@ class AutoSignIn(_PluginBase):
|
||||
# 按日期排序,最新的在前面
|
||||
try:
|
||||
records.sort(key=lambda x: x.get("day_obj", datetime.now().date()), reverse=True)
|
||||
except:
|
||||
pass # 排序失败时跳过
|
||||
except Exception as e:
|
||||
logger.debug(f"排序失败: {str(e)}")
|
||||
|
||||
# 获取最新的状态作为站点概要
|
||||
latest_status = records[0].get("status", "未知状态")
|
||||
@@ -1142,7 +1131,8 @@ class AutoSignIn(_PluginBase):
|
||||
}
|
||||
]
|
||||
|
||||
def _create_expansion_panel(self, site_name, records, status_color, status_icon, latest_status):
|
||||
@staticmethod
|
||||
def _create_expansion_panel(site_name, records, status_color, status_icon, latest_status):
|
||||
"""创建站点折叠面板"""
|
||||
# 生成站点图标(使用站点名的首字母)
|
||||
site_initial = site_name[0].upper() if site_name else "?"
|
||||
@@ -1322,7 +1312,7 @@ class AutoSignIn(_PluginBase):
|
||||
today_history = self.get_data(key=type_str + "-" + today)
|
||||
|
||||
# 查询所有站点
|
||||
all_sites = [site for site in self.sites.get_indexers() if not site.get("public")] + self.__custom_sites()
|
||||
all_sites = [site for site in SitesHelper().get_indexers() if not site.get("public")] + self.__custom_sites()
|
||||
# 过滤掉没有选中的站点
|
||||
if do_sites:
|
||||
do_sites = [site for site in all_sites if site.get("id") in do_sites]
|
||||
@@ -1402,7 +1392,8 @@ class AutoSignIn(_PluginBase):
|
||||
# 失败|错误
|
||||
failed_msg = []
|
||||
|
||||
sites = {site.get('name'): site.get("id") for site in self.sites.get_indexers() if not site.get("public")}
|
||||
sites = {site.get('name'): site.get("id") for site in SitesHelper().get_indexers() if
|
||||
not site.get("public")}
|
||||
for s in status:
|
||||
site_name = s[0]
|
||||
site_id = None
|
||||
@@ -1501,7 +1492,7 @@ class AutoSignIn(_PluginBase):
|
||||
if apikey != settings.API_TOKEN:
|
||||
return schemas.Response(success=False, message="API密钥错误")
|
||||
domain = StringUtils.get_url_domain(url)
|
||||
site_info = self.sites.get_indexer(domain)
|
||||
site_info = SitesHelper().get_indexer(domain)
|
||||
if not site_info:
|
||||
return schemas.Response(
|
||||
success=True,
|
||||
@@ -1533,9 +1524,9 @@ class AutoSignIn(_PluginBase):
|
||||
seconds = (datetime.now() - start_time).seconds
|
||||
domain = StringUtils.get_url_domain(site_info.get('url'))
|
||||
if state:
|
||||
self.siteoper.success(domain=domain, seconds=seconds)
|
||||
SiteOper().success(domain=domain, seconds=seconds)
|
||||
else:
|
||||
self.siteoper.fail(domain)
|
||||
SiteOper().fail(domain)
|
||||
return site_info.get("name"), message
|
||||
|
||||
@staticmethod
|
||||
@@ -1635,9 +1626,9 @@ class AutoSignIn(_PluginBase):
|
||||
seconds = (datetime.now() - start_time).seconds
|
||||
domain = StringUtils.get_url_domain(site_info.get('url'))
|
||||
if state:
|
||||
self.siteoper.success(domain=domain, seconds=seconds)
|
||||
SiteOper().success(domain=domain, seconds=seconds)
|
||||
else:
|
||||
self.siteoper.fail(domain)
|
||||
SiteOper().fail(domain)
|
||||
return site_info.get("name"), message
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -54,7 +54,7 @@ class BrushConfig:
|
||||
self.exclude = config.get("exclude")
|
||||
self.size = config.get("size")
|
||||
self.seeder = config.get("seeder")
|
||||
self.timezone_offset = (self.__parse_number(config.get("timezone_offset", "+0")) or 0) * 60 # 转换到分钟
|
||||
self.timezone_offset = (self.__parse_number(config.get("timezone_offset", "+0")) or 0) * 60 # 转换到分钟
|
||||
self.pubtime = config.get("pubtime")
|
||||
self.seed_time = self.__parse_number(config.get("seed_time"))
|
||||
self.hr_seed_time = self.__parse_number(config.get("hr_seed_time"))
|
||||
@@ -271,12 +271,6 @@ class BrushFlow(_PluginBase):
|
||||
# 可使用的用户级别
|
||||
auth_level = 2
|
||||
|
||||
# 私有属性
|
||||
sites_helper = None
|
||||
site_oper = None
|
||||
torrents_chain = None
|
||||
subscribe_oper = None
|
||||
downloader_helper = None
|
||||
# 刷流配置
|
||||
_brush_config = None
|
||||
# Brush任务是否启动
|
||||
@@ -296,11 +290,7 @@ class BrushFlow(_PluginBase):
|
||||
# endregion
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.sites_helper = SitesHelper()
|
||||
self.site_oper = SiteOper()
|
||||
self.torrents_chain = TorrentsChain()
|
||||
self.subscribe_oper = SubscribeOper()
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
self._task_brush_enable = False
|
||||
|
||||
if not config:
|
||||
@@ -322,7 +312,7 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
# 这里先过滤掉已删除的站点并保存,特别注意的是,这里保留了界面选择站点时的顺序,以便后续站点随机刷流或顺序刷流
|
||||
if brush_config.brushsites:
|
||||
site_id_to_public_status = {site.get("id"): site.get("public") for site in self.sites_helper.get_indexers()}
|
||||
site_id_to_public_status = {site.get("id"): site.get("public") for site in SitesHelper().get_indexers()}
|
||||
brush_config.brushsites = [
|
||||
site_id for site_id in brush_config.brushsites
|
||||
if site_id in site_id_to_public_status and not site_id_to_public_status[site_id]
|
||||
@@ -394,7 +384,7 @@ class BrushFlow(_PluginBase):
|
||||
服务信息
|
||||
"""
|
||||
brush_config = self.__get_brush_config()
|
||||
service = self.downloader_helper.get_service(name=brush_config.downloader)
|
||||
service = DownloaderHelper().get_service(name=brush_config.downloader)
|
||||
if not service:
|
||||
self.__log_and_notify_error("站点刷流任务出错,获取下载器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -819,10 +809,10 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
# 站点选项
|
||||
site_options = [{"title": site.get("name"), "value": site.get("id")}
|
||||
for site in self.sites_helper.get_indexers()]
|
||||
for site in SitesHelper().get_indexers()]
|
||||
# 下载器选项
|
||||
downloader_options = [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
return [
|
||||
{
|
||||
'component': 'VForm',
|
||||
@@ -1971,7 +1961,7 @@ class BrushFlow(_PluginBase):
|
||||
# 获取所有站点的信息,并过滤掉不存在的站点
|
||||
site_infos = []
|
||||
for siteid in brush_config.brushsites:
|
||||
siteinfo = self.site_oper.get(siteid)
|
||||
siteinfo = SiteOper().get(siteid)
|
||||
if siteinfo:
|
||||
site_infos.append(siteinfo)
|
||||
|
||||
@@ -2006,13 +1996,13 @@ class BrushFlow(_PluginBase):
|
||||
"""
|
||||
针对站点进行刷流
|
||||
"""
|
||||
siteinfo = self.site_oper.get(siteid)
|
||||
siteinfo = SiteOper().get(siteid)
|
||||
if not siteinfo:
|
||||
logger.warning(f"站点不存在:{siteid}")
|
||||
return True
|
||||
|
||||
logger.info(f"开始获取站点 {siteinfo.name} 的新种子 ...")
|
||||
torrents = self.torrents_chain.browse(domain=siteinfo.domain)
|
||||
torrents = TorrentsChain().browse(domain=siteinfo.domain)
|
||||
if not torrents:
|
||||
logger.info(f"站点 {siteinfo.name} 没有获取到种子")
|
||||
return True
|
||||
@@ -2383,7 +2373,7 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
if need_delete_hashes:
|
||||
# 如果是QB,则重新汇报Tracker
|
||||
if self.downloader_helper.is_downloader("qbittorrent", service=self.service_info):
|
||||
if DownloaderHelper().is_downloader("qbittorrent", service=self.service_info):
|
||||
self.__qb_torrents_reannounce(torrent_hashes=need_delete_hashes)
|
||||
# 删除种子
|
||||
if downloader.delete_torrents(ids=need_delete_hashes, delete_file=True):
|
||||
@@ -2425,7 +2415,7 @@ class BrushFlow(_PluginBase):
|
||||
seeding_torrents_dict: Dict[str, Any]):
|
||||
brush_config = self.__get_brush_config()
|
||||
|
||||
if not self.downloader_helper.is_downloader("qbittorrent", service=self.service_info):
|
||||
if not DownloaderHelper().is_downloader("qbittorrent", service=self.service_info):
|
||||
logger.info("同步种子刷流标签记录目前仅支持qbittorrent")
|
||||
return
|
||||
|
||||
@@ -2546,7 +2536,8 @@ class BrushFlow(_PluginBase):
|
||||
freedate = freedate_origin.replace("T", " ").replace("Z", "")
|
||||
freedate = datetime.strptime(freedate, "%Y-%m-%d %H:%M:%S")
|
||||
delta_minutes = (((freedate - now).total_seconds() + 60) // 60) - brush_config.timezone_offset
|
||||
logger.debug(f"促销截止(站点时间): {freedate_origin}, 时区偏移: {brush_config.timezone_offset}, 用户当前时间: {now.strftime('%Y-%m-%d %H:%M:%S')}, 时间差: {delta_minutes}分")
|
||||
logger.debug(
|
||||
f"促销截止(站点时间): {freedate_origin}, 时区偏移: {brush_config.timezone_offset}, 用户当前时间: {now.strftime('%Y-%m-%d %H:%M:%S')}, 时间差: {delta_minutes}分")
|
||||
if delta_minutes <= 0:
|
||||
return True, "促销过期"
|
||||
except Exception as e:
|
||||
@@ -2576,7 +2567,8 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
return True, reason if not hit_and_run else "H&R种子(未设置H&R条件)," + reason
|
||||
|
||||
def __evaluate_proxy_pre_conditions_for_delete(self, site_name: str, torrent_info: dict, torrent_task: dict) -> Tuple[bool, str]:
|
||||
def __evaluate_proxy_pre_conditions_for_delete(self, site_name: str,
|
||||
torrent_info: dict, torrent_task: dict) -> Tuple[bool, str]:
|
||||
"""
|
||||
评估动态删除前置条件并返回是否应删除种子及其原因
|
||||
"""
|
||||
@@ -2595,7 +2587,8 @@ class BrushFlow(_PluginBase):
|
||||
freedate = freedate_origin.replace("T", " ").replace("Z", "")
|
||||
freedate = datetime.strptime(freedate, "%Y-%m-%d %H:%M:%S")
|
||||
delta_minutes = (((freedate - now).total_seconds() + 60) // 60) - brush_config.timezone_offset
|
||||
logger.debug(f"促销截止(站点时间): {freedate_origin}, 时区偏移: {brush_config.timezone_offset}, 用户当前时间: {now.strftime('%Y-%m-%d %H:%M:%S')}, 时间差: {delta_minutes}分")
|
||||
logger.debug(
|
||||
f"促销截止(站点时间): {freedate_origin}, 时区偏移: {brush_config.timezone_offset}, 用户当前时间: {now.strftime('%Y-%m-%d %H:%M:%S')}, 时间差: {delta_minutes}分")
|
||||
if delta_minutes <= 0:
|
||||
return True, f"促销已过期"
|
||||
except Exception as e:
|
||||
@@ -3116,7 +3109,8 @@ class BrushFlow(_PluginBase):
|
||||
return data
|
||||
return None
|
||||
|
||||
def __reset_download_url(self, torrent_url, site_id) -> str:
|
||||
@staticmethod
|
||||
def __reset_download_url(torrent_url, site_id) -> str:
|
||||
"""
|
||||
处理下载地址
|
||||
"""
|
||||
@@ -3125,7 +3119,7 @@ class BrushFlow(_PluginBase):
|
||||
if not torrent_url or torrent_url.startswith("magnet"):
|
||||
return torrent_url
|
||||
|
||||
indexers = self.sites_helper.get_indexers()
|
||||
indexers = SitesHelper().get_indexers()
|
||||
if not indexers:
|
||||
return torrent_url
|
||||
|
||||
@@ -3190,7 +3184,8 @@ class BrushFlow(_PluginBase):
|
||||
if not downloader:
|
||||
return None
|
||||
|
||||
if self.downloader_helper.is_downloader("qbittorrent", service=self.service_info):
|
||||
downloader_helper = DownloaderHelper()
|
||||
if downloader_helper.is_downloader("qbittorrent", service=self.service_info):
|
||||
# 限速值转为bytes
|
||||
up_speed = up_speed * 1024 if up_speed else None
|
||||
down_speed = down_speed * 1024 if down_speed else None
|
||||
@@ -3224,7 +3219,7 @@ class BrushFlow(_PluginBase):
|
||||
return torrent_hash
|
||||
return None
|
||||
|
||||
elif self.downloader_helper.is_downloader("transmission", service=self.service_info):
|
||||
elif downloader_helper.is_downloader("transmission", service=self.service_info):
|
||||
# 如果开启代理下载以及种子地址不是磁力地址,则请求种子到内存再传入下载器
|
||||
if not torrent_content.startswith("magnet"):
|
||||
response = RequestUtils(cookies=cookies,
|
||||
@@ -3272,7 +3267,7 @@ class BrushFlow(_PluginBase):
|
||||
获取种子hash
|
||||
"""
|
||||
try:
|
||||
return torrent.get("hash") if self.downloader_helper.is_downloader("qbittorrent", service=self.service_info) \
|
||||
return torrent.get("hash") if DownloaderHelper().is_downloader("qbittorrent", service=self.service_info) \
|
||||
else torrent.hashString
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
@@ -3289,8 +3284,8 @@ class BrushFlow(_PluginBase):
|
||||
all_hashes = []
|
||||
for torrent in torrents:
|
||||
# 根据下载器类型获取Hash值
|
||||
hash_value = torrent.get("hash") if self.downloader_helper.is_downloader("qbittorrent",
|
||||
service=self.service_info) \
|
||||
hash_value = torrent.get("hash") if DownloaderHelper().is_downloader("qbittorrent",
|
||||
service=self.service_info) \
|
||||
else torrent.hashString
|
||||
if hash_value:
|
||||
all_hashes.append(hash_value)
|
||||
@@ -3305,8 +3300,8 @@ class BrushFlow(_PluginBase):
|
||||
"""
|
||||
try:
|
||||
return [str(tag).strip() for tag in torrent.get("tags").split(',')] \
|
||||
if self.downloader_helper.is_downloader("qbittorrent",
|
||||
service=self.service_info) else torrent.labels or []
|
||||
if DownloaderHelper().is_downloader("qbittorrent",
|
||||
service=self.service_info) else torrent.labels or []
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
return []
|
||||
@@ -3317,7 +3312,7 @@ class BrushFlow(_PluginBase):
|
||||
"""
|
||||
date_now = int(time.time())
|
||||
# QB
|
||||
if self.downloader_helper.is_downloader("qbittorrent", service=self.service_info):
|
||||
if DownloaderHelper().is_downloader("qbittorrent", service=self.service_info):
|
||||
"""
|
||||
{
|
||||
"added_on": 1693359031,
|
||||
@@ -3724,7 +3719,7 @@ class BrushFlow(_PluginBase):
|
||||
if not self._subscribe_infos:
|
||||
self._subscribe_infos = {}
|
||||
|
||||
subscribes = self.subscribe_oper.list()
|
||||
subscribes = SubscribeOper().list()
|
||||
if subscribes:
|
||||
# 遍历订阅
|
||||
for subscribe in subscribes:
|
||||
@@ -3937,7 +3932,8 @@ class BrushFlow(_PluginBase):
|
||||
# 情况2: 时间段跨越午夜
|
||||
return now >= start_time or now <= end_time
|
||||
|
||||
def __get_site_by_torrent(self, torrent: Any) -> Tuple[int, str]:
|
||||
@staticmethod
|
||||
def __get_site_by_torrent(torrent: Any) -> Tuple[int, str]:
|
||||
"""
|
||||
根据tracker获取站点信息
|
||||
"""
|
||||
@@ -3980,7 +3976,7 @@ class BrushFlow(_PluginBase):
|
||||
# 使用StringUtils工具类获取tracker的域名
|
||||
domain = StringUtils.get_url_domain(tracker)
|
||||
|
||||
site_info = self.sites_helper.get_indexer(domain)
|
||||
site_info = SitesHelper().get_indexer(domain)
|
||||
if site_info:
|
||||
return site_info.get("id"), site_info.get("name")
|
||||
|
||||
|
||||
@@ -337,7 +337,8 @@ class ChatGPT(_PluginBase):
|
||||
def get_page(self) -> List[dict]:
|
||||
pass
|
||||
|
||||
def is_api_error(self, response):
|
||||
@staticmethod
|
||||
def is_api_error(response):
|
||||
"""
|
||||
判断响应是否表示API错误
|
||||
:param response: API响应
|
||||
@@ -486,4 +487,4 @@ class ChatGPT(_PluginBase):
|
||||
"""
|
||||
退出插件
|
||||
"""
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
import requests
|
||||
import re
|
||||
from typing import Any, Optional, List, Dict, Tuple, Union
|
||||
import time
|
||||
import yaml
|
||||
import hashlib
|
||||
from fastapi import Body, Response
|
||||
import re
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
import pytz
|
||||
from typing import Any, Optional, List, Dict, Tuple, Union
|
||||
|
||||
import pytz
|
||||
import yaml
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from cachetools import cached, TTLCache
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from fastapi import Body, Response
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.core.event import eventmanager
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas.types import EventType, NotificationType
|
||||
from app.utils.http import RequestUtils
|
||||
from app.plugins.clashruleprovider.clash_rule_parser import ClashRuleParser
|
||||
from app.plugins.clashruleprovider.clash_rule_parser import Action, RuleType, ClashRule, MatchRule, LogicRule
|
||||
from app.plugins.clashruleprovider.clash_rule_parser import ClashRuleParser
|
||||
from app.schemas.types import EventType
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
class ClashRuleProvider(_PluginBase):
|
||||
@@ -82,7 +80,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
self._ruleset_rules = self.get_data("ruleset_rules")
|
||||
self._top_rules = self.get_data("top_rules")
|
||||
self._subscription_info = self.get_data("subscription_info") or \
|
||||
{"download": 0, "upload": 0, "total": 0, "expire": 0, "last_update": 0}
|
||||
{"download": 0, "upload": 0, "total": 0, "expire": 0, "last_update": 0}
|
||||
self._rule_provider = self.get_data("rule_provider") or {}
|
||||
self._ruleset_names = self.get_data("ruleset_names") or {}
|
||||
if config:
|
||||
@@ -301,7 +299,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
def test_connectivity(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
if not self._enabled:
|
||||
return {"success": False, "message": ""}
|
||||
if not params.get('clash_dashboard_url') or not params.get('clash_dashboard_secret')\
|
||||
if not params.get('clash_dashboard_url') or not params.get('clash_dashboard_secret') \
|
||||
or not params.get('sub_link'):
|
||||
return {"success": False, "message": "missing params"}
|
||||
clash_version_url = f"{params.get('clash_dashboard_url')}/version"
|
||||
@@ -363,7 +361,8 @@ class ClashRuleProvider(_PluginBase):
|
||||
if params.get('type') == 'ruleset':
|
||||
res = self.delete_rule_by_priority(params.get('priority'), self._ruleset_rule_parser)
|
||||
if res:
|
||||
self.__add_notification_job(f"{self._ruleset_prefix}{res.action.value if isinstance(res.action, Action) else res.action}")
|
||||
self.__add_notification_job(
|
||||
f"{self._ruleset_prefix}{res.action.value if isinstance(res.action, Action) else res.action}")
|
||||
else:
|
||||
res = self.delete_rule_by_priority(params.get('priority'), self._clash_rule_parser)
|
||||
return {"success": res, "message": None}
|
||||
@@ -403,7 +402,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
res = self.update_rule_by_priority(params.get('rule_data'), self._clash_rule_parser)
|
||||
return {"success": bool(res), "message": None}
|
||||
|
||||
def add_rule(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def add_rule(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
if not self._enabled:
|
||||
return {"success": False, "message": ""}
|
||||
if params.get('type') == 'ruleset':
|
||||
|
||||
@@ -282,7 +282,8 @@ class ClashRuleParser:
|
||||
|
||||
return self.rules
|
||||
|
||||
def validate_rule(self, rule: ClashRule) -> bool:
|
||||
@staticmethod
|
||||
def validate_rule(rule: ClashRule) -> bool:
|
||||
"""Validate a parsed rule"""
|
||||
try:
|
||||
# Basic validation based on rule type
|
||||
@@ -305,7 +306,8 @@ class ClashRuleParser:
|
||||
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print(f"Invalid rule '{rule.raw_rule}': {e}")
|
||||
return False
|
||||
|
||||
def to_string(self) -> List[str]:
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
import glob
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from typing import Any, List, Dict, Tuple, Optional
|
||||
|
||||
import pytz
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from app.utils.string import StringUtils
|
||||
from app.schemas.types import EventType
|
||||
from app.schemas import ServiceInfo
|
||||
from app.core.event import eventmanager, Event
|
||||
|
||||
from app.core.config import settings
|
||||
from app.plugins import _PluginBase
|
||||
from typing import Any, List, Dict, Tuple, Optional
|
||||
from app.log import logger
|
||||
from app.schemas import NotificationType
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.helper.downloader import DownloaderHelper
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas import NotificationType
|
||||
from app.schemas import ServiceInfo
|
||||
from app.schemas.types import EventType
|
||||
from app.utils.string import StringUtils
|
||||
|
||||
|
||||
class CleanInvalidSeed(_PluginBase):
|
||||
# 插件名称
|
||||
@@ -56,6 +54,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
_exclude_categories = ""
|
||||
_exclude_labels = ""
|
||||
_more_logs = False
|
||||
_downloaders = []
|
||||
# 定时器
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
_error_msg = [
|
||||
@@ -67,7 +66,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
_custom_error_msg = ""
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
|
||||
@@ -97,8 +96,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
self._scheduler.add_job(
|
||||
func=self.clean_invalid_seed,
|
||||
trigger="date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ))
|
||||
+ timedelta(seconds=3),
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="清理无效种子",
|
||||
)
|
||||
# 关闭一次性开关
|
||||
@@ -137,7 +135,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
)
|
||||
|
||||
@property
|
||||
def service_info(self) -> Optional[ServiceInfo]:
|
||||
def service_info(self) -> Optional[Dict[str, ServiceInfo]]:
|
||||
"""
|
||||
服务信息
|
||||
"""
|
||||
@@ -145,7 +143,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.downloader_helper.get_services(name_filters=self._downloaders)
|
||||
services = DownloaderHelper().get_services(name_filters=self._downloaders)
|
||||
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
@@ -166,11 +164,12 @@ class CleanInvalidSeed(_PluginBase):
|
||||
|
||||
return active_services
|
||||
|
||||
def check_is_qb(self, service_info) -> bool:
|
||||
@staticmethod
|
||||
def check_is_qb(service_info) -> bool:
|
||||
"""
|
||||
检查下载器类型是否为 qbittorrent 或 transmission
|
||||
"""
|
||||
if self.downloader_helper.is_downloader(service_type="qbittorrent", service=service_info):
|
||||
if DownloaderHelper().is_downloader(service_type="qbittorrent", service=service_info):
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -225,11 +224,11 @@ class CleanInvalidSeed(_PluginBase):
|
||||
event_data = event.event_data
|
||||
if event_data:
|
||||
if not (
|
||||
event_data.get("action") == "detect_invalid_torrents"
|
||||
or event_data.get("action") == "delete_invalid_torrents"
|
||||
or event_data.get("action") == "detect_invalid_files"
|
||||
or event_data.get("action") == "delete_invalid_files"
|
||||
or event_data.get("action") == "toggle_notify_all"
|
||||
event_data.get("action") == "detect_invalid_torrents"
|
||||
or event_data.get("action") == "delete_invalid_torrents"
|
||||
or event_data.get("action") == "detect_invalid_files"
|
||||
or event_data.get("action") == "delete_invalid_files"
|
||||
or event_data.get("action") == "toggle_notify_all"
|
||||
):
|
||||
return
|
||||
self.post_message(
|
||||
@@ -344,7 +343,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
logger.info(f"开始清理 {downloader_name} 无效做种...")
|
||||
all_torrents = self.get_all_torrents(service)
|
||||
@@ -376,13 +375,14 @@ class CleanInvalidSeed(_PluginBase):
|
||||
is_tracker_working = True
|
||||
|
||||
if not (
|
||||
(tracker.get("status") == 4) and (tracker.get("msg") in error_msgs)
|
||||
(tracker.get("status") == 4) and (tracker.get("msg") in error_msgs)
|
||||
):
|
||||
is_invalid = False
|
||||
working_tracker_set.add(tracker_domian)
|
||||
|
||||
if self._more_logs:
|
||||
logger.info(f"处理 [{torrent.name}] tracker [{tracker_domian}]: 分类: [{torrent.category}], 标签: [{torrent.tags}], 状态: [{tracker.get('status')}], msg: [{tracker.get('msg')}], is_invalid: [{is_invalid}], is_working: [{is_tracker_working}]")
|
||||
logger.info(
|
||||
f"处理 [{torrent.name}] tracker [{tracker_domian}]: 分类: [{torrent.category}], 标签: [{torrent.tags}], 状态: [{tracker.get('status')}], msg: [{tracker.get('msg')}], is_invalid: [{is_invalid}], is_working: [{is_tracker_working}]")
|
||||
if is_invalid:
|
||||
temp_invalid_torrents.append(torrent)
|
||||
elif not is_tracker_working:
|
||||
@@ -433,25 +433,30 @@ class CleanInvalidSeed(_PluginBase):
|
||||
if not is_excluded:
|
||||
if self._label_only:
|
||||
# 仅标记
|
||||
downloader_obj.set_torrents_tag(ids=torrent.get("hash"), tags=[self._label if self._label != "" else "无效做种"])
|
||||
downloader_obj.set_torrents_tag(ids=torrent.get("hash"), tags=[
|
||||
self._label if self._label != "" else "无效做种"])
|
||||
else:
|
||||
# 只删除种子不删除文件,以防其它站点辅种
|
||||
downloader_obj.delete_torrents(False, torrent.get("hash"))
|
||||
# 标记已处理种子信息
|
||||
deleted_torrent_tuple_list.append(
|
||||
(
|
||||
torrent.name,
|
||||
torrent.category,
|
||||
torrent.tags,
|
||||
torrent.size,
|
||||
tracker_domian,
|
||||
tracker.msg,
|
||||
)
|
||||
(
|
||||
torrent.name,
|
||||
torrent.category,
|
||||
torrent.tags,
|
||||
torrent.size,
|
||||
tracker_domian,
|
||||
tracker.msg,
|
||||
)
|
||||
)
|
||||
break
|
||||
invalid_msg = f"检测到{len(invalid_torrent_tuple_list)}个失效做种\n"
|
||||
tracker_not_working_msg = f"检测到{len(tracker_not_working_torrents)}个tracker未工作做种,请检查种子状态\n"
|
||||
|
||||
exclude_categories_msg = ""
|
||||
exclude_labels_msg = ""
|
||||
deleted_msg = ""
|
||||
|
||||
if self._label_only or self._delete_invalid_torrents:
|
||||
if self._label_only:
|
||||
deleted_msg = f"标记了{len(deleted_torrent_tuple_list)}个失效种子\n"
|
||||
@@ -513,34 +518,34 @@ class CleanInvalidSeed(_PluginBase):
|
||||
logger.info(exclude_labels_msg)
|
||||
# 通知
|
||||
if self._notify:
|
||||
invalid_msg = invalid_msg.replace("_", "\_")
|
||||
invalid_msg = invalid_msg.replace("_", "\\_")
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=invalid_msg,
|
||||
)
|
||||
if self._notify_all:
|
||||
tracker_not_working_msg = tracker_not_working_msg.replace("_", "\_")
|
||||
tracker_not_working_msg = tracker_not_working_msg.replace("_", "\\_")
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=tracker_not_working_msg,
|
||||
)
|
||||
if self._label_only or self._delete_invalid_torrents:
|
||||
deleted_msg = deleted_msg.replace("_", "\_")
|
||||
deleted_msg = deleted_msg.replace("_", "\\_")
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=deleted_msg,
|
||||
)
|
||||
if self._notify_all:
|
||||
exclude_categories_msg = exclude_categories_msg.replace("_", "\_")
|
||||
exclude_categories_msg = exclude_categories_msg.replace("_", "\\_")
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=exclude_categories_msg,
|
||||
)
|
||||
exclude_labels_msg = exclude_labels_msg.replace("_", "\_")
|
||||
exclude_labels_msg = exclude_labels_msg.replace("_", "\\_")
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
@@ -559,7 +564,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
all_torrents += self.get_all_torrents(service)
|
||||
|
||||
@@ -638,7 +643,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
message += f"***已删除无效源文件,释放{StringUtils.str_filesize(total_size)}空间!***\n"
|
||||
logger.info(message)
|
||||
if self._notify:
|
||||
message = message.replace("_", "\_")
|
||||
message = message.replace("_", "\\_")
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
@@ -646,7 +651,8 @@ class CleanInvalidSeed(_PluginBase):
|
||||
)
|
||||
logger.info("检测无效源文件任务结束")
|
||||
|
||||
def get_size(self, path: Path):
|
||||
@staticmethod
|
||||
def get_size(path: Path):
|
||||
total_size = 0
|
||||
if path.is_file():
|
||||
return path.stat().st_size
|
||||
@@ -801,7 +807,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
'model': 'downloaders',
|
||||
'label': '请选择下载器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -813,7 +819,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": { "cols": 12, "md": 6 },
|
||||
"props": {"cols": 12, "md": 6},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
@@ -826,7 +832,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": { "cols": 12, "md": 6 },
|
||||
"props": {"cols": 12, "md": 6},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
|
||||
@@ -194,10 +194,6 @@ class CrossSeed(_PluginBase):
|
||||
# 私有属性
|
||||
_scheduler = None
|
||||
cross_helper = None
|
||||
sites = None
|
||||
siteoper = None
|
||||
torrent = None
|
||||
downloader_helper = None
|
||||
# 开关
|
||||
_enabled = False
|
||||
_cron = None
|
||||
@@ -233,10 +229,7 @@ class CrossSeed(_PluginBase):
|
||||
cached = 0
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.sites = SitesHelper()
|
||||
self.siteoper = SiteOper()
|
||||
self.torrent = TorrentHelper()
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
# 读取配置
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
@@ -257,7 +250,7 @@ class CrossSeed(_PluginBase):
|
||||
self._success_caches = [] if self._clearcache else config.get("success_caches") or []
|
||||
|
||||
# 过滤掉已删除的站点
|
||||
inner_site_list = self.siteoper.list_order_by_pri()
|
||||
inner_site_list = SiteOper().list_order_by_pri()
|
||||
all_sites = [(site.id, site.name) for site in inner_site_list] + [
|
||||
(site.get("id"), site.get("name")) for site in self.__custom_sites()
|
||||
]
|
||||
@@ -363,7 +356,7 @@ class CrossSeed(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.downloader_helper.get_services(name_filters=self._downloaders)
|
||||
services = DownloaderHelper().get_services(name_filters=self._downloaders)
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -445,7 +438,7 @@ class CrossSeed(_PluginBase):
|
||||
|
||||
# 站点的可选项
|
||||
site_options = ([{"title": site.name, "value": site.id}
|
||||
for site in self.siteoper.list_order_by_pri()]
|
||||
for site in SiteOper().list_order_by_pri()]
|
||||
+ [{"title": site.get("name"), "value": site.get("id")}
|
||||
for site in customSites])
|
||||
# 测试版本,只支持青蛙
|
||||
@@ -557,7 +550,7 @@ class CrossSeed(_PluginBase):
|
||||
'model': 'downloaders',
|
||||
'label': '辅种下载器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -852,7 +845,7 @@ class CrossSeed(_PluginBase):
|
||||
if not torrent_info.site_name:
|
||||
# 尝试通过域名获取站点信息
|
||||
tracker_domain = StringUtils.get_url_domain(tracker)
|
||||
site_info = self.sites.get_indexer(tracker_domain)
|
||||
site_info = SitesHelper().get_indexer(tracker_domain)
|
||||
if site_info:
|
||||
torrent_info.site_name = site_info.get("name")
|
||||
|
||||
@@ -983,7 +976,7 @@ class CrossSeed(_PluginBase):
|
||||
chunk_size = 100
|
||||
for site_config in self._site_cs_infos:
|
||||
# 检查站点是否已经停用
|
||||
db_site = self.siteoper.get(site_config.id)
|
||||
db_site = SiteOper().get(site_config.id)
|
||||
if db_site and not db_site.is_active:
|
||||
logger.info(f"站点{site_config.name}已停用,跳过辅种")
|
||||
continue
|
||||
@@ -1045,7 +1038,8 @@ class CrossSeed(_PluginBase):
|
||||
|
||||
logger.info(f"下载器 {service.name} 辅种完成")
|
||||
|
||||
def __download(self, service: ServiceInfo, content: Union[bytes, str],
|
||||
@staticmethod
|
||||
def __download(service: ServiceInfo, content: Union[bytes, str],
|
||||
save_path: str) -> Optional[str]:
|
||||
"""
|
||||
添加下载任务
|
||||
@@ -1055,9 +1049,9 @@ class CrossSeed(_PluginBase):
|
||||
tag = StringUtils.generate_random_str(10)
|
||||
|
||||
state = service.instance.add_torrent(content=content,
|
||||
download_dir=save_path,
|
||||
is_paused=True,
|
||||
tag=["已整理", "辅种", tag])
|
||||
download_dir=save_path,
|
||||
is_paused=True,
|
||||
tag=["已整理", "辅种", tag])
|
||||
if not state:
|
||||
return None
|
||||
else:
|
||||
@@ -1070,9 +1064,9 @@ class CrossSeed(_PluginBase):
|
||||
elif service.type == "transmission":
|
||||
# 添加任务
|
||||
torrent = service.instance.add_torrent(content=content,
|
||||
download_dir=save_path,
|
||||
is_paused=True,
|
||||
labels=["已整理", "辅种"])
|
||||
download_dir=save_path,
|
||||
is_paused=True,
|
||||
labels=["已整理", "辅种"])
|
||||
if not torrent:
|
||||
return None
|
||||
else:
|
||||
@@ -1099,7 +1093,7 @@ class CrossSeed(_PluginBase):
|
||||
torrent_url = site_config.get_torrent_url(tor.torrent_id)
|
||||
|
||||
# 下载种子文件
|
||||
_, content, _, _, error_msg = self.torrent.download_torrent(
|
||||
_, content, _, _, error_msg = TorrentHelper().download_torrent(
|
||||
url=torrent_url,
|
||||
cookie=site_config.cookie,
|
||||
ua=site_config.ua or settings.USER_AGENT,
|
||||
|
||||
@@ -45,9 +45,6 @@ class DoubanRank(_PluginBase):
|
||||
# 退出事件
|
||||
_event = Event()
|
||||
# 私有属性
|
||||
downloadchain: DownloadChain = None
|
||||
subscribechain: SubscribeChain = None
|
||||
mediachain: MediaChain = None
|
||||
_scheduler = None
|
||||
_douban_address = {
|
||||
'movie-ustop': 'https://rsshub.app/douban/movie/ustop',
|
||||
@@ -70,9 +67,6 @@ class DoubanRank(_PluginBase):
|
||||
_proxy = False
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.downloadchain = DownloadChain()
|
||||
self.subscribechain = SubscribeChain()
|
||||
self.mediachain = MediaChain()
|
||||
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
@@ -574,9 +568,10 @@ class DoubanRank(_PluginBase):
|
||||
if douban_id:
|
||||
# 识别豆瓣信息
|
||||
if settings.RECOGNIZE_SOURCE == "themoviedb":
|
||||
tmdbinfo = self.mediachain.get_tmdbinfo_by_doubanid(doubanid=douban_id, mtype=meta.type)
|
||||
tmdbinfo = MediaChain().get_tmdbinfo_by_doubanid(doubanid=douban_id, mtype=meta.type)
|
||||
if not tmdbinfo:
|
||||
logger.warn(f'未能通过豆瓣ID {douban_id} 获取到TMDB信息,标题:{title},豆瓣ID:{douban_id}')
|
||||
logger.warn(
|
||||
f'未能通过豆瓣ID {douban_id} 获取到TMDB信息,标题:{title},豆瓣ID:{douban_id}')
|
||||
continue
|
||||
mediainfo = self.chain.recognize_media(meta=meta, tmdbid=tmdbinfo.get("id"))
|
||||
if not mediainfo:
|
||||
@@ -598,22 +593,23 @@ class DoubanRank(_PluginBase):
|
||||
logger.info(f'{mediainfo.title_year} 评分不符合要求')
|
||||
continue
|
||||
# 查询缺失的媒体信息
|
||||
exist_flag, _ = self.downloadchain.get_no_exists_info(meta=meta, mediainfo=mediainfo)
|
||||
exist_flag, _ = DownloadChain().get_no_exists_info(meta=meta, mediainfo=mediainfo)
|
||||
if exist_flag:
|
||||
logger.info(f'{mediainfo.title_year} 媒体库中已存在')
|
||||
continue
|
||||
# 判断用户是否已经添加订阅
|
||||
if self.subscribechain.exists(mediainfo=mediainfo, meta=meta):
|
||||
subscribechain = SubscribeChain()
|
||||
if subscribechain.exists(mediainfo=mediainfo, meta=meta):
|
||||
logger.info(f'{mediainfo.title_year} 订阅已存在')
|
||||
continue
|
||||
# 添加订阅
|
||||
self.subscribechain.add(title=mediainfo.title,
|
||||
year=mediainfo.year,
|
||||
mtype=mediainfo.type,
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
season=meta.begin_season,
|
||||
exist_ok=True,
|
||||
username="豆瓣榜单")
|
||||
subscribechain.add(title=mediainfo.title,
|
||||
year=mediainfo.year,
|
||||
mtype=mediainfo.type,
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
season=meta.begin_season,
|
||||
exist_ok=True,
|
||||
username="豆瓣榜单")
|
||||
# 存储历史记录
|
||||
history.append({
|
||||
"title": title,
|
||||
|
||||
@@ -9,6 +9,7 @@ from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
from app import schemas
|
||||
from app.chain.media import MediaChain
|
||||
from app.db.subscribe_oper import SubscribeOper
|
||||
from app.db.user_oper import UserOper
|
||||
from app.schemas.types import MediaType, EventType, SystemConfigKey
|
||||
|
||||
@@ -50,12 +51,6 @@ class DoubanSync(_PluginBase):
|
||||
_interests_url: str = "https://www.douban.com/feed/people/%s/interests"
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
_cache_path: Optional[Path] = None
|
||||
rsshelper = None
|
||||
downloadchain = None
|
||||
searchchain = None
|
||||
subscribechain = None
|
||||
mediachain = None
|
||||
useroper = None
|
||||
|
||||
# 配置属性
|
||||
_enabled: bool = False
|
||||
@@ -69,12 +64,6 @@ class DoubanSync(_PluginBase):
|
||||
_search_download = False
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.rsshelper = RssHelper()
|
||||
self.downloadchain = DownloadChain()
|
||||
self.searchchain = SearchChain()
|
||||
self.subscribechain = SubscribeChain()
|
||||
self.mediachain = MediaChain()
|
||||
self.useroper = UserOper()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
@@ -337,7 +326,7 @@ class DoubanSync(_PluginBase):
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -546,12 +535,13 @@ class DoubanSync(_PluginBase):
|
||||
except Exception as e:
|
||||
logger.error("退出插件失败:%s" % str(e))
|
||||
|
||||
def __get_username_by_douban(self, user_id: str) -> Optional[str]:
|
||||
@staticmethod
|
||||
def __get_username_by_douban(user_id: str) -> Optional[str]:
|
||||
"""
|
||||
根据豆瓣ID获取用户名
|
||||
"""
|
||||
try:
|
||||
return self.useroper.get_name(douban_userid=user_id)
|
||||
return UserOper().get_name(douban_userid=user_id)
|
||||
except Exception as err:
|
||||
logger.warn(f'{err}, 需要 MoviePilot v2.2.6+ 版本')
|
||||
return None
|
||||
@@ -579,23 +569,28 @@ class DoubanSync(_PluginBase):
|
||||
logger.info(f"开始同步用户 {user_id} 的豆瓣想看数据 ...")
|
||||
url = self._interests_url % user_id
|
||||
if version == "v2":
|
||||
results = self.rsshelper.parse(url, headers={
|
||||
results = RssHelper().parse(url, headers={
|
||||
"User-Agent": settings.USER_AGENT
|
||||
})
|
||||
else:
|
||||
results = self.rsshelper.parse(url)
|
||||
results = RssHelper().parse(url)
|
||||
if not results:
|
||||
logger.warn(f"未获取到用户 {user_id} 豆瓣RSS数据:{url}")
|
||||
continue
|
||||
else:
|
||||
logger.info(f"获取到用户 {user_id} 豆瓣RSS数据:{len(results)}")
|
||||
# 解析数据
|
||||
mediachain = MediaChain()
|
||||
downloadchain = DownloadChain()
|
||||
subscribechain = SubscribeChain()
|
||||
searchchain = SearchChain()
|
||||
subscribeoper = SubscribeOper()
|
||||
for result in results:
|
||||
try:
|
||||
dtype = result.get("title", "")[:2]
|
||||
title = result.get("title", "")[2:]
|
||||
# 增加豆瓣昵称,数据来源自app.helper.rss.py
|
||||
nickname = result.get("nickname","")
|
||||
nickname = result.get("nickname", "")
|
||||
if nickname:
|
||||
nickname = f"[{nickname}]"
|
||||
if dtype not in ["想看"]:
|
||||
@@ -620,7 +615,7 @@ class DoubanSync(_PluginBase):
|
||||
douban_info = self.chain.douban_info(doubanid=douban_id)
|
||||
meta.type = MediaType.MOVIE if douban_info.get("type") == "movie" else MediaType.TV
|
||||
if settings.RECOGNIZE_SOURCE == "themoviedb":
|
||||
tmdbinfo = self.mediachain.get_tmdbinfo_by_doubanid(doubanid=douban_id, mtype=meta.type)
|
||||
tmdbinfo = mediachain.get_tmdbinfo_by_doubanid(doubanid=douban_id, mtype=meta.type)
|
||||
if not tmdbinfo:
|
||||
logger.warn(f'未能通过豆瓣ID {douban_id} 获取到TMDB信息,标题:{title},豆瓣ID:{douban_id}')
|
||||
continue
|
||||
@@ -634,7 +629,7 @@ class DoubanSync(_PluginBase):
|
||||
logger.warn(f'豆瓣ID {douban_id} 未识别到媒体信息')
|
||||
continue
|
||||
# 查询缺失的媒体信息
|
||||
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=meta, mediainfo=mediainfo)
|
||||
exist_flag, no_exists = downloadchain.get_no_exists_info(meta=meta, mediainfo=mediainfo)
|
||||
if exist_flag:
|
||||
logger.info(f'{mediainfo.title_year} 媒体库中已存在')
|
||||
action = "exist"
|
||||
@@ -643,9 +638,10 @@ class DoubanSync(_PluginBase):
|
||||
real_name = self.__get_username_by_douban(user_id)
|
||||
if self._search_download:
|
||||
# 先搜索资源
|
||||
logger.info(f'媒体库中不存在或不完整,开启搜索下载,开始搜索 {mediainfo.title_year} 的资源...')
|
||||
# 按订阅优先级规则组搜索过滤,站点为设置的订阅站点
|
||||
filter_results = self.searchchain.process(
|
||||
logger.info(
|
||||
f'媒体库中不存在或不完整,开启搜索下载,开始搜索 {mediainfo.title_year} 的资源...')
|
||||
# 按订阅优先级规则组搜索过滤,站点为设置的订阅站点
|
||||
filter_results = searchchain.process(
|
||||
mediainfo=mediainfo,
|
||||
no_exists=no_exists,
|
||||
sites=self.systemconfig.get(SystemConfigKey.RssSites),
|
||||
@@ -656,7 +652,7 @@ class DoubanSync(_PluginBase):
|
||||
action = "download"
|
||||
if mediainfo.type == MediaType.MOVIE:
|
||||
# 电影类型调用单次下载
|
||||
download_id = self.downloadchain.download_single(
|
||||
download_id = downloadchain.download_single(
|
||||
context=filter_results[0],
|
||||
username=real_name or f"豆瓣{nickname}想看"
|
||||
)
|
||||
@@ -666,7 +662,7 @@ class DoubanSync(_PluginBase):
|
||||
action = "subscribe"
|
||||
else:
|
||||
# 电视剧类型调用批量下载
|
||||
downloaded_list, no_exists = self.downloadchain.batch_download(
|
||||
downloaded_list, no_exists = downloadchain.batch_download(
|
||||
contexts=filter_results,
|
||||
no_exists=no_exists,
|
||||
username=real_name or f"豆瓣{nickname}想看"
|
||||
@@ -678,13 +674,13 @@ class DoubanSync(_PluginBase):
|
||||
|
||||
# 更新订阅信息
|
||||
logger.info(f'根据缺失剧集更新订阅信息 {mediainfo.title_year} ...')
|
||||
subscribe = self.subscribechain.subscribeoper.get(sub_id)
|
||||
subscribe = subscribeoper.get(sub_id)
|
||||
if subscribe:
|
||||
self.subscribechain.finish_subscribe_or_not(subscribe=subscribe,
|
||||
meta=meta,
|
||||
mediainfo=mediainfo,
|
||||
downloads=downloaded_list,
|
||||
lefts=no_exists)
|
||||
subscribechain.finish_subscribe_or_not(subscribe=subscribe,
|
||||
meta=meta,
|
||||
mediainfo=mediainfo,
|
||||
downloads=downloaded_list,
|
||||
lefts=no_exists)
|
||||
|
||||
else:
|
||||
logger.info(f'未找到符合条件资源,添加订阅 {mediainfo.title_year} ...')
|
||||
@@ -714,8 +710,9 @@ class DoubanSync(_PluginBase):
|
||||
# 缓存只清理一次
|
||||
self._clearflag = False
|
||||
|
||||
def add_subscribe(self, mediainfo, meta, nickname, real_name):
|
||||
return self.subscribechain.add(
|
||||
@staticmethod
|
||||
def add_subscribe(mediainfo, meta, nickname, real_name):
|
||||
return SubscribeChain().add(
|
||||
title=mediainfo.title,
|
||||
year=mediainfo.year,
|
||||
mtype=mediainfo.type,
|
||||
|
||||
@@ -45,9 +45,6 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 退出事件
|
||||
_event = threading.Event()
|
||||
# 私有属性
|
||||
downloadhistory_oper = None
|
||||
sites_helper = None
|
||||
downloader_helper = None
|
||||
_scheduler = None
|
||||
_enabled = False
|
||||
_onlyonce = False
|
||||
@@ -64,9 +61,6 @@ class DownloadSiteTag(_PluginBase):
|
||||
_downloaders = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.downloadhistory_oper = DownloadHistoryOper()
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
self.sites_helper = SitesHelper()
|
||||
# 读取配置
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
@@ -113,7 +107,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.downloader_helper.get_services(name_filters=self._downloaders)
|
||||
services = DownloaderHelper().get_services(name_filters=self._downloaders)
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -205,7 +199,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 记录处理的种子, 供辅种(无下载历史)使用
|
||||
dispose_history = {}
|
||||
# 所有站点索引
|
||||
indexers = [indexer.get("name") for indexer in self.sites_helper.get_indexers()]
|
||||
indexers = [indexer.get("name") for indexer in SitesHelper().get_indexers()]
|
||||
# JackettIndexers索引器支持多个站点, 如果不存在历史记录, 则通过tracker会再次附加其他站点名称
|
||||
indexers.append("JackettIndexers")
|
||||
indexers = set(indexers)
|
||||
@@ -230,6 +224,8 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 按添加时间进行排序, 时间靠前的按大小和名称加入处理历史, 判定为原始种子, 其他为辅种
|
||||
torrents = self._torrents_sort(torrents=torrents, dl_type=service.type)
|
||||
logger.info(f"{self.LOG_TAG}下载器 {downloader} 分析种子信息中 ...")
|
||||
downloadhis = DownloadHistoryOper()
|
||||
siteshelper = SitesHelper()
|
||||
for torrent in torrents:
|
||||
try:
|
||||
if self._event.is_set():
|
||||
@@ -246,7 +242,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
torrent_tags = self._get_label(torrent=torrent, dl_type=service.type)
|
||||
torrent_cat = self._get_category(torrent=torrent, dl_type=service.type)
|
||||
# 提取种子hash对应的下载历史
|
||||
history: DownloadHistory = self.downloadhistory_oper.get_by_hash(_hash)
|
||||
history: DownloadHistory = downloadhis.get_by_hash(_hash)
|
||||
if not history:
|
||||
# 如果找到已处理种子的历史, 表明当前种子是辅种, 否则创建一个空DownloadHistory
|
||||
if _key and _key in dispose_history:
|
||||
@@ -273,7 +269,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
break
|
||||
else:
|
||||
domain = StringUtils.get_url_domain(tracker)
|
||||
site_info = self.sites_helper.get_indexer(domain)
|
||||
site_info = siteshelper.get_indexer(domain)
|
||||
if site_info:
|
||||
history.torrent_site = site_info.get("name")
|
||||
break
|
||||
@@ -652,7 +648,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
'model': 'downloaders',
|
||||
'label': '下载器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -856,4 +852,4 @@ class DownloadSiteTag(_PluginBase):
|
||||
self._event.clear()
|
||||
self._scheduler = None
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
print(str(e))
|
||||
|
||||
@@ -30,7 +30,6 @@ class HistoryToV2(_PluginBase):
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
historyoper = None
|
||||
_enabled = False
|
||||
_host = None
|
||||
_username = None
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import re
|
||||
import json
|
||||
from typing import Optional, Any, List, Dict, Tuple
|
||||
from datetime import datetime
|
||||
from typing import Optional, Any, List, Dict, Tuple
|
||||
|
||||
from app import schemas
|
||||
from app.core.config import settings
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.plugins.imdbsource.imdb_helper import ImdbHelper
|
||||
from app.schemas import DiscoverSourceEventData, MediaRecognizeConvertEventData, RecommendSourceEventData
|
||||
from app.schemas.types import ChainEventType, MediaType
|
||||
from app.core.meta import MetaBase
|
||||
from app.core.context import MediaInfo
|
||||
from app.plugins.imdbsource.imdb_helper import ImdbHelper
|
||||
from app import schemas
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
@@ -128,135 +123,8 @@ class ImdbSource(_PluginBase):
|
||||
"id2": self.xxx2,
|
||||
}
|
||||
"""
|
||||
# return {"recognize_media": (self.recognize_media, ModuleExecutionType.Hijack)}
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
# @MediaInfo.source_processor("imdb")
|
||||
def process_imdb_info(mediainfo: MediaInfo, info: dict):
|
||||
"""处理 IMDB 信息"""
|
||||
mediainfo.source_info["imdb"] = info
|
||||
if isinstance(info.get('media_type'), MediaType):
|
||||
mediainfo.type = info.get('media_type')
|
||||
elif info.get('media_type'):
|
||||
mediainfo.type = MediaType.MOVIE if info.get("type") == "movie" else MediaType.TV
|
||||
mediainfo.title = info.get("title")
|
||||
mediainfo.release_date = info.get('release_date')
|
||||
if info.get("id"):
|
||||
mediainfo.source_id["imdb"] = info.get("id")
|
||||
mediainfo.imdb_id = info.get('id')
|
||||
if not mediainfo.source_id:
|
||||
return
|
||||
mediainfo.vote_average = round(float(info.get("rating").get("aggregate_rating")), 1) if info.get("rating") else 0
|
||||
mediainfo.overview = info.get('plot')
|
||||
mediainfo.genre_ids = info.get('genre') or []
|
||||
# 风格
|
||||
if not mediainfo.genres:
|
||||
mediainfo.genres = [{"id": genre, "name": genre} for genre in info.get("genres") or []]
|
||||
if info.get('spoken_languages', []):
|
||||
mediainfo.original_language = info.get('spoken_languages', [])[0].get("name")
|
||||
mediainfo.en_title = info.get('primary_title')
|
||||
mediainfo.title = info.get('primary_title')
|
||||
mediainfo.original_title = info.get('original_title')
|
||||
# mediainfo.release_date = info.get('start_year')
|
||||
mediainfo.year = info.get('start_year')
|
||||
if info.get('posters', []):
|
||||
mediainfo.poster_path = info.get("posters", [])[0].get("url")
|
||||
directors = []
|
||||
if info.get('directors', []):
|
||||
for dn in info.get('directors', []):
|
||||
director = dn.get("name")
|
||||
if not director:
|
||||
continue
|
||||
d_ = {"name": director.get("display_name"), "id": director.get("id"), "avatars": director.get("avatars")}
|
||||
directors.append(d_)
|
||||
if info.get('writers', []):
|
||||
for wn in info.get('writers', []):
|
||||
writer = wn.get("name")
|
||||
d_ = {"name": writer.get("display_name"), "id": writer.get("id"), "avatars": writer.get("avatars")}
|
||||
directors.append(d_)
|
||||
mediainfo.directors = directors
|
||||
actors = []
|
||||
if info.get('casts', []):
|
||||
for cast in info.get('casts', []):
|
||||
cn = cast.get("name", {})
|
||||
character_name = cast.get("characters")[0] if cast.get("characters") else ''
|
||||
d_ = {"name": cn.get("display_name"), "id": cn.get("id"),
|
||||
"avatars": cn.get("avatars"), "character": character_name}
|
||||
actors.append(d_)
|
||||
|
||||
def recognize_media(self, meta: MetaBase = None,
|
||||
mtype: MediaType = None,
|
||||
imdbid: Optional[str] = None,
|
||||
episode_group: Optional[str] = None,
|
||||
cache: Optional[bool] = True,
|
||||
**kwargs) -> Optional[MediaInfo]:
|
||||
logger.warn(f"IMDb Source: {MetaBase.title}")
|
||||
if not self._imdb_helper:
|
||||
return None
|
||||
if not imdbid and not meta:
|
||||
return None
|
||||
if not meta:
|
||||
# 未提供元数据时,直接使用imdbid查询,不使用缓存
|
||||
cache_info = {}
|
||||
elif not meta.name:
|
||||
logger.warn("识别媒体信息时未提供元数据名称")
|
||||
return None
|
||||
cache_info = {}
|
||||
if not cache_info or not cache:
|
||||
info = None
|
||||
if imdbid:
|
||||
info = self._imdb_helper.get_info(mtype=mtype, imdbid=imdbid)
|
||||
if not info and meta:
|
||||
info = {}
|
||||
names = list(dict.fromkeys([k for k in [meta.cn_name, meta.en_name] if k]))
|
||||
for name in names:
|
||||
if meta.begin_season:
|
||||
logger.info(f"正在识别 {name} 第{meta.begin_season}季 ...")
|
||||
else:
|
||||
logger.info(f"正在识别 {name} ...")
|
||||
if meta.type == MediaType.UNKNOWN and not meta.year:
|
||||
info = self._imdb_helper.match_multi(name)
|
||||
else:
|
||||
if meta.type == MediaType.TV:
|
||||
# 确定是电视
|
||||
info = self._imdb_helper.match(name=name,
|
||||
year=meta.year,
|
||||
mtype=meta.type,season_year=meta.year,
|
||||
season_number=meta.begin_season)
|
||||
if not info:
|
||||
# 去掉年份再查一次
|
||||
info = self._imdb_helper.match(name=name, mtype=meta.type)
|
||||
else:
|
||||
# 有年份先按电影查
|
||||
info = self._imdb_helper.match(name=name, year=meta.year, mtype=MediaType.MOVIE)
|
||||
# 没有再按电视剧查
|
||||
if not info:
|
||||
info = self._imdb_helper.match(name=name,
|
||||
year=meta.year,
|
||||
mtype=MediaType.TV)
|
||||
if not info:
|
||||
# 去掉年份和类型再查一次
|
||||
info = self._imdb_helper.match_multi(name=name)
|
||||
if info:
|
||||
break
|
||||
else:
|
||||
info = None
|
||||
if info:
|
||||
# mediainfo = MediaInfo(source_info={"imdb": info})
|
||||
mediainfo = MediaInfo()
|
||||
if meta:
|
||||
logger.info(f"{meta.name} IMDB识别结果:{mediainfo.type.value} "
|
||||
f"{mediainfo.title_year} "
|
||||
f"{mediainfo.imdb_id}")
|
||||
else:
|
||||
logger.info(f"{imdbid} IMDB识别结果:{mediainfo.type.value} "
|
||||
f"{mediainfo.title_year}")
|
||||
return mediainfo
|
||||
|
||||
logger.info(f"{meta.name if meta else imdbid} 未匹配到IMDB媒体信息")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __movie_to_media(movie_info: dict) -> schemas.MediaInfo:
|
||||
title = ""
|
||||
|
||||
@@ -48,10 +48,6 @@ class IYUUAutoSeed(_PluginBase):
|
||||
# 私有属性
|
||||
_scheduler = None
|
||||
iyuu_helper = None
|
||||
downloader_helper = None
|
||||
sites_helper = None
|
||||
site_oper = None
|
||||
torrent_helper = None
|
||||
# 开关
|
||||
_enabled = False
|
||||
_cron = None
|
||||
@@ -72,6 +68,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
_addhosttotag = False
|
||||
_size = None
|
||||
_clearcache = False
|
||||
_auto_start = False
|
||||
# 退出事件
|
||||
_event = Event()
|
||||
# 种子链接xpaths
|
||||
@@ -99,10 +96,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
cached = 0
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.sites_helper = SitesHelper()
|
||||
self.site_oper = SiteOper()
|
||||
self.torrent_helper = TorrentHelper()
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
# 读取配置
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
@@ -128,8 +122,8 @@ class IYUUAutoSeed(_PluginBase):
|
||||
self._success_caches = [] if self._clearcache else config.get("success_caches") or []
|
||||
|
||||
# 过滤掉已删除的站点
|
||||
all_sites = [site.id for site in self.site_oper.list_order_by_pri()] + [site.get("id") for site in
|
||||
self.__custom_sites()]
|
||||
all_sites = [site.id for site in SiteOper().list_order_by_pri()] + [site.get("id") for site in
|
||||
self.__custom_sites()]
|
||||
self._sites = [site_id for site_id in all_sites if site_id in self._sites]
|
||||
self.__update_config()
|
||||
|
||||
@@ -171,7 +165,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.downloader_helper.get_services(name_filters=self._downloaders)
|
||||
services = DownloaderHelper().get_services(name_filters=self._downloaders)
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -198,7 +192,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
logger.debug("尚未配置主辅分离下载器,辅种不分离")
|
||||
return None
|
||||
|
||||
service = self.downloader_helper.get_service(name=self._auto_downloader)
|
||||
service = DownloaderHelper().get_service(name=self._auto_downloader)
|
||||
if not service:
|
||||
logger.warning("获取主辅分离下载器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -248,7 +242,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
|
||||
# 站点的可选项
|
||||
site_options = ([{"title": site.name, "value": site.id}
|
||||
for site in self.site_oper.list_order_by_pri()]
|
||||
for site in SiteOper().list_order_by_pri()]
|
||||
+ [{"title": site.get("name"), "value": site.get("id")}
|
||||
for site in customSites])
|
||||
return [
|
||||
@@ -381,7 +375,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
'model': 'downloaders',
|
||||
'label': '下载器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -401,7 +395,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
'model': 'auto_downloader',
|
||||
'label': '主辅分离',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1048,7 +1042,8 @@ class IYUUAutoSeed(_PluginBase):
|
||||
# 查询站点
|
||||
site_domain = StringUtils.get_url_domain(site_url)
|
||||
# 站点信息
|
||||
site_info = self.sites_helper.get_indexer(site_domain)
|
||||
sites_helper = SitesHelper()
|
||||
site_info = sites_helper.get_indexer(site_domain)
|
||||
if not site_info or not site_info.get('url'):
|
||||
logger.debug(f"没有维护种子对应的站点:{site_url}")
|
||||
return False
|
||||
@@ -1064,7 +1059,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
self.exist += 1
|
||||
return False
|
||||
# 站点流控
|
||||
check, checkmsg = self.sites_helper.check(site_domain)
|
||||
check, checkmsg = sites_helper.check(site_domain)
|
||||
if check:
|
||||
logger.warn(checkmsg)
|
||||
self.fail += 1
|
||||
@@ -1086,7 +1081,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
else:
|
||||
torrent_url += "?https=1"
|
||||
# 下载种子文件
|
||||
_, content, _, _, error_msg = self.torrent_helper.download_torrent(
|
||||
_, content, _, _, error_msg = TorrentHelper().download_torrent(
|
||||
url=torrent_url,
|
||||
cookie=site_info.get("cookie"),
|
||||
ua=site_info.get("ua") or settings.USER_AGENT,
|
||||
|
||||
@@ -40,8 +40,6 @@ class LibraryScraper(_PluginBase):
|
||||
user_level = 1
|
||||
|
||||
# 私有属性
|
||||
transferhis = None
|
||||
mediachain = None
|
||||
_scheduler = None
|
||||
_scraper = None
|
||||
# 限速开关
|
||||
@@ -55,7 +53,7 @@ class LibraryScraper(_PluginBase):
|
||||
_event = Event()
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.mediachain = MediaChain()
|
||||
|
||||
# 读取配置
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
@@ -70,7 +68,6 @@ class LibraryScraper(_PluginBase):
|
||||
|
||||
# 启动定时任务 & 立即运行一次
|
||||
if self._enabled or self._onlyonce:
|
||||
self.transferhis = TransferHistoryOper()
|
||||
|
||||
if self._onlyonce:
|
||||
logger.info(f"媒体库刮削服务,立即运行一次")
|
||||
@@ -401,14 +398,14 @@ class LibraryScraper(_PluginBase):
|
||||
|
||||
# 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title
|
||||
if not settings.SCRAP_FOLLOW_TMDB:
|
||||
transfer_history = self.transferhis.get_by_type_tmdbid(tmdbid=mediainfo.tmdb_id,
|
||||
mtype=mediainfo.type.value)
|
||||
transfer_history = TransferHistoryOper().get_by_type_tmdbid(tmdbid=mediainfo.tmdb_id,
|
||||
mtype=mediainfo.type.value)
|
||||
if transfer_history:
|
||||
mediainfo.title = transfer_history.title
|
||||
# 获取图片
|
||||
self.chain.obtain_images(mediainfo)
|
||||
# 刮削
|
||||
self.mediachain.scrape_metadata(
|
||||
MediaChain().scrape_metadata(
|
||||
fileitem=schemas.FileItem(
|
||||
storage="local",
|
||||
type="dir",
|
||||
|
||||
@@ -31,7 +31,6 @@ class MediaServerMsg(_PluginBase):
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
mediaserver_helper = None
|
||||
_enabled = False
|
||||
_add_play_link = False
|
||||
_mediaservers = None
|
||||
@@ -59,7 +58,7 @@ class MediaServerMsg(_PluginBase):
|
||||
}
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.mediaserver_helper = MediaServerHelper()
|
||||
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._types = config.get("types") or []
|
||||
@@ -74,7 +73,7 @@ class MediaServerMsg(_PluginBase):
|
||||
logger.warning("尚未配置媒体服务器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.mediaserver_helper.get_services(type_filter=type_filter, name_filters=self._mediaservers)
|
||||
services = MediaServerHelper().get_services(type_filter=type_filter, name_filters=self._mediaservers)
|
||||
if not services:
|
||||
logger.warning("获取媒体服务器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -181,7 +180,7 @@ class MediaServerMsg(_PluginBase):
|
||||
'model': 'mediaservers',
|
||||
'label': '媒体服务器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.mediaserver_helper.get_configs().values()]
|
||||
for config in MediaServerHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -341,7 +340,7 @@ class MediaServerMsg(_PluginBase):
|
||||
if service:
|
||||
play_link = service.instance.get_play_url(event_info.item_id)
|
||||
elif event_info.channel:
|
||||
services = self.mediaserver_helper.get_services(type_filter=event_info.channel)
|
||||
services = MediaServerHelper().get_services(type_filter=event_info.channel)
|
||||
for service in services.values():
|
||||
play_link = service.instance.get_play_url(event_info.item_id)
|
||||
if play_link:
|
||||
|
||||
@@ -32,13 +32,12 @@ class MediaServerRefresh(_PluginBase):
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
mediaserver_helper = None
|
||||
_enabled = False
|
||||
_delay = 0
|
||||
_mediaservers = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.mediaserver_helper = MediaServerHelper()
|
||||
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._delay = config.get("delay") or 0
|
||||
@@ -53,7 +52,7 @@ class MediaServerRefresh(_PluginBase):
|
||||
logger.warning("尚未配置媒体服务器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.mediaserver_helper.get_services(name_filters=self._mediaservers)
|
||||
services = MediaServerHelper().get_services(name_filters=self._mediaservers)
|
||||
if not services:
|
||||
logger.warning("获取媒体服务器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -128,7 +127,7 @@ class MediaServerRefresh(_PluginBase):
|
||||
'model': 'mediaservers',
|
||||
'label': '媒体服务器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.mediaserver_helper.get_configs().values()]
|
||||
for config in MediaServerHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -55,9 +55,6 @@ class PersonMeta(_PluginBase):
|
||||
|
||||
# 私有属性
|
||||
_scheduler = None
|
||||
tmdbchain = None
|
||||
mschain = None
|
||||
mediaserver_helper = None
|
||||
_enabled = False
|
||||
_onlyonce = False
|
||||
_cron = None
|
||||
@@ -67,9 +64,7 @@ class PersonMeta(_PluginBase):
|
||||
_mediaservers = []
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.tmdbchain = TmdbChain()
|
||||
self.mschain = MediaServerChain()
|
||||
self.mediaserver_helper = MediaServerHelper()
|
||||
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._onlyonce = config.get("onlyonce")
|
||||
@@ -266,7 +261,7 @@ class PersonMeta(_PluginBase):
|
||||
'model': 'mediaservers',
|
||||
'label': '媒体服务器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.mediaserver_helper.get_configs().values()]
|
||||
for config in MediaServerHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -316,7 +311,7 @@ class PersonMeta(_PluginBase):
|
||||
logger.warning("尚未配置媒体服务器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.mediaserver_helper.get_services(type_filter=type_filter, name_filters=self._mediaservers)
|
||||
services = MediaServerHelper().get_services(type_filter=type_filter, name_filters=self._mediaservers)
|
||||
if not services:
|
||||
logger.warning("获取媒体服务器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -355,7 +350,7 @@ class PersonMeta(_PluginBase):
|
||||
logger.warn(f"{mediainfo.title_year} 在媒体库中不存在")
|
||||
return
|
||||
# 查询条目详情
|
||||
iteminfo = self.mschain.iteminfo(server=existsinfo.server, item_id=existsinfo.itemid)
|
||||
iteminfo = MediaServerChain().iteminfo(server=existsinfo.server, item_id=existsinfo.itemid)
|
||||
if not iteminfo:
|
||||
logger.warn(f"{mediainfo.title_year} 条目详情获取失败")
|
||||
return
|
||||
@@ -371,12 +366,13 @@ class PersonMeta(_PluginBase):
|
||||
service_infos = self.service_infos()
|
||||
if not service_infos:
|
||||
return
|
||||
mediaserverchain = MediaServerChain()
|
||||
for server, service in service_infos.items():
|
||||
# 扫描所有媒体库
|
||||
logger.info(f"开始刮削服务器 {server} 的演员信息 ...")
|
||||
for library in self.mschain.librarys(server):
|
||||
for library in mediaserverchain.librarys(server):
|
||||
logger.info(f"开始刮削媒体库 {library.name} 的演员信息 ...")
|
||||
for item in self.mschain.items(server, library.id):
|
||||
for item in mediaserverchain.items(server, library.id):
|
||||
if not item:
|
||||
continue
|
||||
if not item.item_id:
|
||||
@@ -577,7 +573,7 @@ class PersonMeta(_PluginBase):
|
||||
# 从TMDB信息中更新人物信息
|
||||
person_tmdbid, person_imdbid = __get_peopleid(personinfo)
|
||||
if person_tmdbid:
|
||||
person_detail = self.tmdbchain.person_detail(int(person_tmdbid))
|
||||
person_detail = TmdbChain().person_detail(int(person_tmdbid))
|
||||
if person_detail:
|
||||
cn_name = self.__get_chinese_name(person_detail)
|
||||
# 图片优先从TMDB获取
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import random
|
||||
import time
|
||||
import shutil
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any, List, Dict, Tuple
|
||||
|
||||
@@ -12,7 +12,6 @@ from app.core.event import eventmanager, Event
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas import TransferInfo
|
||||
from app.schemas.file import FileItem
|
||||
from app.schemas.types import EventType, MediaType, NotificationType
|
||||
from app.utils.system import SystemUtils
|
||||
|
||||
@@ -320,9 +319,7 @@ class PlayletCategory(_PluginBase):
|
||||
try:
|
||||
# 相对路径
|
||||
relative_path = file.relative_to(target_path)
|
||||
logger.debug(f"relative_path:{to_path}")
|
||||
to_path = new_path / relative_path
|
||||
logger.debug(f"to_path:{to_path}")
|
||||
shutil.move(file, to_path)
|
||||
except Exception as e:
|
||||
logger.error(f"移动文件失败:{e}")
|
||||
|
||||
@@ -41,8 +41,6 @@ class QbCommand(_PluginBase):
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
_sites = None
|
||||
_siteoper = None
|
||||
_qb = None
|
||||
_enabled: bool = False
|
||||
_notify: bool = False
|
||||
@@ -62,10 +60,10 @@ class QbCommand(_PluginBase):
|
||||
_multi_level_root_domain = ["edu.cn", "com.cn", "net.cn", "org.cn"]
|
||||
_scheduler = None
|
||||
_exclude_dirs = ""
|
||||
_downloaders = []
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self._sites = SitesHelper()
|
||||
self._siteoper = SiteOper()
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
# 读取配置
|
||||
@@ -87,7 +85,7 @@ class QbCommand(_PluginBase):
|
||||
self._op_site_ids = config.get("op_site_ids") or []
|
||||
self._downloaders = config.get("downloaders")
|
||||
# 查询所有站点
|
||||
all_sites = [site for site in self._sites.get_indexers() if not site.get("public")] + self.__custom_sites()
|
||||
all_sites = [site for site in SitesHelper().get_indexers() if not site.get("public")] + self.__custom_sites()
|
||||
# 过滤掉没有选中的站点
|
||||
self._op_sites = [site for site in all_sites if site.get("id") in self._op_site_ids]
|
||||
self._exclude_dirs = config.get("exclude_dirs") or ""
|
||||
@@ -101,8 +99,7 @@ class QbCommand(_PluginBase):
|
||||
self._scheduler.add_job(
|
||||
self.pause_torrent,
|
||||
"date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ))
|
||||
+ timedelta(seconds=3),
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
)
|
||||
elif self._only_resume_once:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
@@ -110,8 +107,7 @@ class QbCommand(_PluginBase):
|
||||
self._scheduler.add_job(
|
||||
self.resume_torrent,
|
||||
"date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ))
|
||||
+ timedelta(seconds=3),
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
)
|
||||
|
||||
self._only_resume_once = False
|
||||
@@ -136,9 +132,9 @@ class QbCommand(_PluginBase):
|
||||
self._scheduler.start()
|
||||
|
||||
if (
|
||||
self._only_pause_upload
|
||||
or self._only_pause_download
|
||||
or self._only_pause_checking
|
||||
self._only_pause_upload
|
||||
or self._only_pause_download
|
||||
or self._only_pause_checking
|
||||
):
|
||||
if self._only_pause_upload:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
@@ -146,8 +142,7 @@ class QbCommand(_PluginBase):
|
||||
self._scheduler.add_job(
|
||||
self.pause_torrent,
|
||||
"date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ))
|
||||
+ timedelta(seconds=3),
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
kwargs={
|
||||
'type': self.TorrentType.UPLOADING
|
||||
}
|
||||
@@ -158,8 +153,7 @@ class QbCommand(_PluginBase):
|
||||
self._scheduler.add_job(
|
||||
self.pause_torrent,
|
||||
"date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ))
|
||||
+ timedelta(seconds=3),
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
kwargs={
|
||||
'type': self.TorrentType.DOWNLOADING
|
||||
}
|
||||
@@ -170,8 +164,7 @@ class QbCommand(_PluginBase):
|
||||
self._scheduler.add_job(
|
||||
self.pause_torrent,
|
||||
"date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ))
|
||||
+ timedelta(seconds=3),
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
kwargs={
|
||||
'type': self.TorrentType.CHECKING
|
||||
}
|
||||
@@ -201,7 +194,7 @@ class QbCommand(_PluginBase):
|
||||
self.set_limit(self._upload_limit, self._download_limit)
|
||||
|
||||
@property
|
||||
def service_info(self) -> Optional[ServiceInfo]:
|
||||
def service_info(self) -> Optional[Dict[str, ServiceInfo]]:
|
||||
"""
|
||||
服务信息
|
||||
"""
|
||||
@@ -209,7 +202,7 @@ class QbCommand(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.downloader_helper.get_services(name_filters=self._downloaders)
|
||||
services = DownloaderHelper().get_services(name_filters=self._downloaders)
|
||||
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
@@ -230,15 +223,17 @@ class QbCommand(_PluginBase):
|
||||
|
||||
return active_services
|
||||
|
||||
def check_is_qb(self, service_info) -> bool:
|
||||
@staticmethod
|
||||
def check_is_qb(service_info) -> bool:
|
||||
"""
|
||||
检查下载器类型是否为 qbittorrent 或 transmission
|
||||
"""
|
||||
if self.downloader_helper.is_downloader(service_type="qbittorrent", service=service_info):
|
||||
if DownloaderHelper().is_downloader(service_type="qbittorrent", service=service_info):
|
||||
return True
|
||||
elif self.downloader_helper.is_downloader(service_type="transmission", service=service_info):
|
||||
elif DownloaderHelper().is_downloader(service_type="transmission", service=service_info):
|
||||
return False
|
||||
return False
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@@ -409,9 +404,9 @@ class QbCommand(_PluginBase):
|
||||
if torrent.state_enum.is_uploading and not torrent.state_enum.is_paused:
|
||||
uploading_torrents.append(torrent.get("hash"))
|
||||
elif (
|
||||
torrent.state_enum.is_downloading
|
||||
and not torrent.state_enum.is_paused
|
||||
and not torrent.state_enum.is_checking
|
||||
torrent.state_enum.is_downloading
|
||||
and not torrent.state_enum.is_paused
|
||||
and not torrent.state_enum.is_checking
|
||||
):
|
||||
downloading_torrents.append(torrent.get("hash"))
|
||||
elif torrent.state_enum.is_checking:
|
||||
@@ -476,7 +471,7 @@ class QbCommand(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
all_torrents = self.get_all_torrents(service)
|
||||
hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = (
|
||||
@@ -498,12 +493,12 @@ class QbCommand(_PluginBase):
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【下载器{downloader_name}暂停任务启动】",
|
||||
text=f"种子总数: {len(all_torrents)} \n"
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n"
|
||||
f"暂停操作中请稍等...\n",
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n"
|
||||
f"暂停操作中请稍等...\n",
|
||||
)
|
||||
pause_torrents = self.filter_pause_torrents(all_torrents)
|
||||
hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = (
|
||||
@@ -551,11 +546,11 @@ class QbCommand(_PluginBase):
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【下载器{downloader_name}暂停任务完成】",
|
||||
text=f"种子总数: {len(all_torrents)} \n"
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n",
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n",
|
||||
)
|
||||
|
||||
def __is_excluded(self, file_path) -> bool:
|
||||
@@ -566,6 +561,7 @@ class QbCommand(_PluginBase):
|
||||
if exclude_dir and exclude_dir in str(file_path):
|
||||
return True
|
||||
return False
|
||||
|
||||
def filter_pause_torrents(self, all_torrents):
|
||||
torrents = []
|
||||
for torrent in all_torrents:
|
||||
@@ -592,7 +588,7 @@ class QbCommand(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
all_torrents = self.get_all_torrents(service)
|
||||
hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = (
|
||||
@@ -613,12 +609,12 @@ class QbCommand(_PluginBase):
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【下载器{downloader_name}开始任务启动】",
|
||||
text=f"种子总数: {len(all_torrents)} \n"
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n"
|
||||
f"开始操作中请稍等...\n",
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n"
|
||||
f"开始操作中请稍等...\n",
|
||||
)
|
||||
|
||||
resume_torrents = self.filter_resume_torrents(all_torrents)
|
||||
@@ -655,11 +651,11 @@ class QbCommand(_PluginBase):
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【下载器{downloader_name}开始任务完成】",
|
||||
text=f"种子总数: {len(all_torrents)} \n"
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n",
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n",
|
||||
)
|
||||
|
||||
def filter_resume_torrents(self, all_torrents):
|
||||
@@ -714,7 +710,7 @@ class QbCommand(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
all_torrents = self.get_all_torrents(service)
|
||||
hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = (
|
||||
@@ -734,11 +730,11 @@ class QbCommand(_PluginBase):
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【下载器{downloader_name}任务状态】",
|
||||
text=f"种子总数: {len(all_torrents)} \n"
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n"
|
||||
f"做种数量: {len(hash_uploading)}\n"
|
||||
f"下载数量: {len(hash_downloading)}\n"
|
||||
f"检查数量: {len(hash_checking)}\n"
|
||||
f"暂停数量: {len(hash_paused)}\n"
|
||||
f"错误数量: {len(hash_error)}\n"
|
||||
)
|
||||
|
||||
@eventmanager.register(EventType.PluginAction)
|
||||
@@ -766,10 +762,10 @@ class QbCommand(_PluginBase):
|
||||
return True
|
||||
|
||||
if (
|
||||
not upload_limit
|
||||
or not upload_limit.isdigit()
|
||||
or not download_limit
|
||||
or not download_limit.isdigit()
|
||||
not upload_limit
|
||||
or not upload_limit.isdigit()
|
||||
or not download_limit
|
||||
or not download_limit.isdigit()
|
||||
):
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
@@ -783,7 +779,7 @@ class QbCommand(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
flag = flag and downloader_obj.set_speed_limit(
|
||||
download_limit=int(download_limit), upload_limit=int(upload_limit)
|
||||
@@ -806,7 +802,7 @@ class QbCommand(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
download_limit_current_val, _ = downloader_obj.get_speed_limit()
|
||||
flag = flag and downloader_obj.set_speed_limit(
|
||||
@@ -831,7 +827,7 @@ class QbCommand(_PluginBase):
|
||||
downloader_name = service.name
|
||||
downloader_obj = service.instance
|
||||
if not downloader_obj:
|
||||
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader_name}")
|
||||
logger.error(f"获取下载器失败 {downloader_name}")
|
||||
continue
|
||||
_, upload_limit_current_val = downloader_obj.get_speed_limit()
|
||||
flag = flag and downloader_obj.set_speed_limit(
|
||||
@@ -856,7 +852,7 @@ class QbCommand(_PluginBase):
|
||||
elif flag is None and self._enabled and self._enable_upload_limit:
|
||||
flag = self.set_upload_limit(upload_limit)
|
||||
|
||||
if flag == True:
|
||||
if flag is True:
|
||||
logger.info(f"设置QB限速成功")
|
||||
if self._notify:
|
||||
if upload_limit == 0:
|
||||
@@ -872,7 +868,7 @@ class QbCommand(_PluginBase):
|
||||
title=f"【QB远程操作】",
|
||||
text=text,
|
||||
)
|
||||
elif flag == False:
|
||||
elif flag is False:
|
||||
logger.error(f"QB设置限速失败")
|
||||
if self._notify:
|
||||
self.post_message(
|
||||
@@ -881,7 +877,8 @@ class QbCommand(_PluginBase):
|
||||
text=f"设置QB限速失败",
|
||||
)
|
||||
|
||||
def get_torrent_tracker(self, torrent):
|
||||
@staticmethod
|
||||
def get_torrent_tracker(torrent):
|
||||
"""
|
||||
qb解析 tracker
|
||||
:return: tracker url
|
||||
@@ -937,11 +934,11 @@ class QbCommand(_PluginBase):
|
||||
customSites = self.__custom_sites()
|
||||
|
||||
site_options = [
|
||||
{"title": site.name, "value": site.id}
|
||||
for site in self._siteoper.list_order_by_pri()
|
||||
] + [
|
||||
{"title": site.get("name"), "value": site.get("id")} for site in customSites
|
||||
]
|
||||
{"title": site.name, "value": site.id}
|
||||
for site in SiteOper().list_order_by_pri()
|
||||
] + [
|
||||
{"title": site.get("name"), "value": site.get("id")} for site in customSites
|
||||
]
|
||||
return [
|
||||
{
|
||||
"component": "VForm",
|
||||
@@ -1021,7 +1018,7 @@ class QbCommand(_PluginBase):
|
||||
'model': 'downloaders',
|
||||
'label': '下载器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -11,7 +11,6 @@ from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
from app import schemas
|
||||
from app.chain.download import DownloadChain
|
||||
from app.chain.search import SearchChain
|
||||
from app.chain.subscribe import SubscribeChain
|
||||
from app.core.config import settings
|
||||
from app.core.context import MediaInfo, TorrentInfo, Context
|
||||
@@ -48,10 +47,6 @@ class RssSubscribe(_PluginBase):
|
||||
# 私有变量
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
_cache_path: Optional[Path] = None
|
||||
rsshelper = None
|
||||
downloadchain = None
|
||||
searchchain = None
|
||||
subscribechain = None
|
||||
|
||||
# 配置属性
|
||||
_enabled: bool = False
|
||||
@@ -70,10 +65,6 @@ class RssSubscribe(_PluginBase):
|
||||
_size_range: str = ""
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.rsshelper = RssHelper()
|
||||
self.downloadchain = DownloadChain()
|
||||
self.searchchain = SearchChain()
|
||||
self.subscribechain = SubscribeChain()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
@@ -618,12 +609,14 @@ class RssSubscribe(_PluginBase):
|
||||
history = []
|
||||
else:
|
||||
history: List[dict] = self.get_data('history') or []
|
||||
downloadchain = DownloadChain()
|
||||
subscribechain = SubscribeChain()
|
||||
for url in self._address.split("\n"):
|
||||
# 处理每一个RSS链接
|
||||
if not url:
|
||||
continue
|
||||
logger.info(f"开始刷新RSS:{url} ...")
|
||||
results = self.rsshelper.parse(url, proxy=self._proxy)
|
||||
results = RssHelper().parse(url, proxy=self._proxy)
|
||||
if not results:
|
||||
logger.error(f"未获取到RSS数据:{url}")
|
||||
return
|
||||
@@ -704,7 +697,7 @@ class RssSubscribe(_PluginBase):
|
||||
# 下载或订阅
|
||||
if self._action == "download":
|
||||
# 添加下载
|
||||
result = self.downloadchain.download_single(
|
||||
result = downloadchain.download_single(
|
||||
context=Context(
|
||||
meta_info=meta,
|
||||
media_info=mediainfo,
|
||||
@@ -718,18 +711,18 @@ class RssSubscribe(_PluginBase):
|
||||
continue
|
||||
else:
|
||||
# 检查是否在订阅中
|
||||
subflag = self.subscribechain.exists(mediainfo=mediainfo, meta=meta)
|
||||
subflag = subscribechain.exists(mediainfo=mediainfo, meta=meta)
|
||||
if subflag:
|
||||
logger.info(f'{mediainfo.title_year} {meta.season} 正在订阅中')
|
||||
continue
|
||||
# 添加订阅
|
||||
self.subscribechain.add(title=mediainfo.title,
|
||||
year=mediainfo.year,
|
||||
mtype=mediainfo.type,
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
season=meta.begin_season,
|
||||
exist_ok=True,
|
||||
username="RSS订阅")
|
||||
subscribechain.add(title=mediainfo.title,
|
||||
year=mediainfo.year,
|
||||
mtype=mediainfo.type,
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
season=meta.begin_season,
|
||||
exist_ok=True,
|
||||
username="RSS订阅")
|
||||
# 存储历史记录
|
||||
history.append({
|
||||
"title": f"{mediainfo.title} {meta.season}",
|
||||
@@ -772,4 +765,4 @@ class RssSubscribe(_PluginBase):
|
||||
"""
|
||||
检查字符串是否表示单个数字或数字范围(如'5', '5.5', '5-10' 或 '5.5-10.2')
|
||||
"""
|
||||
return bool(re.match(r"^\d+(\.\d+)?(-\d+(\.\d+)?)?$", value))
|
||||
return bool(re.match(r"^\d+(\.\d+)?(-\d+(\.\d+)?)?$", value))
|
||||
|
||||
@@ -45,9 +45,6 @@ class SiteStatistic(_PluginBase):
|
||||
auth_level = 2
|
||||
|
||||
# 配置属性
|
||||
siteoper = None
|
||||
siteshelper = None
|
||||
sitechain = None
|
||||
_enabled: bool = False
|
||||
_onlyonce: bool = False
|
||||
_dashboard_type: str = "today"
|
||||
@@ -55,9 +52,6 @@ class SiteStatistic(_PluginBase):
|
||||
_scheduler = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.siteoper = SiteOper()
|
||||
self.siteshelper = SitesHelper()
|
||||
self.sitechain = SiteChain()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
@@ -72,7 +66,7 @@ class SiteStatistic(_PluginBase):
|
||||
if self._onlyonce:
|
||||
config["onlyonce"] = False
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
self._scheduler.add_job(self.sitechain.refresh_userdatas, "date",
|
||||
self._scheduler.add_job(SiteChain().refresh_userdatas, "date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="站点数据统计服务")
|
||||
self._scheduler.print_jobs()
|
||||
@@ -263,13 +257,14 @@ class SiteStatistic(_PluginBase):
|
||||
self.post_message(mtype=NotificationType.SiteMessage,
|
||||
title="站点数据统计", text="\n".join(sorted_messages))
|
||||
|
||||
def __get_data(self) -> Tuple[str, List[SiteUserData], List[SiteUserData]]:
|
||||
@staticmethod
|
||||
def __get_data() -> Tuple[str, List[SiteUserData], List[SiteUserData]]:
|
||||
"""
|
||||
获取最近一次统计的日期、最近一次统计的站点数据、上一次的站点数据
|
||||
如果上一次某个站点数据缺失,则 fallback 到该站点之前最近有数据的日期
|
||||
"""
|
||||
# 获取所有原始数据
|
||||
raw_data_list: List[SiteUserData] = self.siteoper.get_userdata()
|
||||
raw_data_list: List[SiteUserData] = SiteOper().get_userdata()
|
||||
if not raw_data_list:
|
||||
return "", [], []
|
||||
|
||||
@@ -1009,13 +1004,14 @@ class SiteStatistic(_PluginBase):
|
||||
def stop_service(self):
|
||||
pass
|
||||
|
||||
def refresh_by_domain(self, domain: str, apikey: str) -> schemas.Response:
|
||||
@staticmethod
|
||||
def refresh_by_domain(domain: str, apikey: str) -> schemas.Response:
|
||||
"""
|
||||
刷新一个站点数据,可由API调用
|
||||
"""
|
||||
if apikey != settings.API_TOKEN:
|
||||
return schemas.Response(success=False, message="API密钥错误")
|
||||
site_info = self.siteshelper.get_indexer(domain)
|
||||
site_info = SitesHelper().get_indexer(domain)
|
||||
if site_info:
|
||||
site_data = SiteChain().refresh_userdata(site=site_info)
|
||||
if site_data:
|
||||
|
||||
@@ -32,8 +32,6 @@ class SpeedLimiter(_PluginBase):
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
downloader_helper = None
|
||||
mediaserver_helper = None
|
||||
_scheduler = None
|
||||
_enabled: bool = False
|
||||
_notify: bool = False
|
||||
@@ -54,8 +52,7 @@ class SpeedLimiter(_PluginBase):
|
||||
_exclude_path = ""
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
self.mediaserver_helper = MediaServerHelper()
|
||||
|
||||
# 读取配置
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
@@ -183,7 +180,7 @@ class SpeedLimiter(_PluginBase):
|
||||
'model': 'downloader',
|
||||
'label': '下载器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -402,7 +399,7 @@ class SpeedLimiter(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.downloader_helper.get_services(name_filters=self._downloader)
|
||||
services = DownloaderHelper().get_services(name_filters=self._downloader)
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
return None
|
||||
@@ -442,7 +439,7 @@ class SpeedLimiter(_PluginBase):
|
||||
return
|
||||
# 当前播放的总比特率
|
||||
total_bit_rate = 0
|
||||
media_servers = self.mediaserver_helper.get_services()
|
||||
media_servers = MediaServerHelper().get_services()
|
||||
if not media_servers:
|
||||
return
|
||||
# 查询所有媒体服务器状态
|
||||
|
||||
@@ -33,10 +33,9 @@ class SubscribeClear(_PluginBase):
|
||||
# 私有属性
|
||||
_titles = []
|
||||
_episodes = []
|
||||
downloader_helper = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
if config:
|
||||
self._titles = config.get("titles") or []
|
||||
self._episodes = config.get("episodes") or []
|
||||
@@ -48,11 +47,10 @@ class SubscribeClear(_PluginBase):
|
||||
|
||||
def clear_history(self, titles: List[str], episodes: List[str]):
|
||||
logger.info(f"清除下载历史记录:{titles} {episodes}")
|
||||
data = self.get_data()
|
||||
down_oper = DownloadHistoryOper()
|
||||
downloader_history ={}
|
||||
data = self.get_download_data()
|
||||
downloader_history = {}
|
||||
for d in data:
|
||||
if d.title in titles or d.id in episodes:
|
||||
if d.title in titles or d.id in episodes:
|
||||
tmp = downloader_history.get(d.downloader)
|
||||
if not tmp:
|
||||
tmp = []
|
||||
@@ -70,7 +68,7 @@ class SubscribeClear(_PluginBase):
|
||||
history_torrents = {}
|
||||
for t in torrents:
|
||||
logger.info(f"种子信息: {t}")
|
||||
history_torrents[t.hash]=t
|
||||
history_torrents[t.hash] = t
|
||||
for h in history:
|
||||
# 判断当前历史记录的hash是否在未找到的hash列表中
|
||||
if h.download_hash not in history_torrents.keys():
|
||||
@@ -79,43 +77,39 @@ class SubscribeClear(_PluginBase):
|
||||
else:
|
||||
# 从下载器删除种子
|
||||
self.delete_download_history(h, history_torrents[h.download_hash])
|
||||
|
||||
|
||||
|
||||
|
||||
def delete_data(self, history: DownloadHistory):
|
||||
@staticmethod
|
||||
def delete_data(history: DownloadHistory):
|
||||
"""
|
||||
从订阅记录中删除该信息
|
||||
"""
|
||||
try:
|
||||
down_oper = DownloadHistoryOper()
|
||||
down_oper.delete_history(history.id)
|
||||
logger.info(f"删除下载历史记录:{history.id} {history.title} {history.seasons} {history.episodes} {history.download_hash}")
|
||||
logger.info(
|
||||
f"删除下载历史记录:{history.id} {history.title} {history.seasons} {history.episodes} {history.download_hash}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"删除下载历史记录失败:{str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def delete_download_history(self,history: DownloadHistory, torrent: Any):
|
||||
def delete_download_history(self, history: DownloadHistory, torrent: Any):
|
||||
downloader_name = history.downloader
|
||||
downloader_obj = self.__get_downloader(downloader_name)
|
||||
logger.info(f"删除种子信息:{history.id} {history.title} {history.seasons} {history.episodes} {history.download_hash}")
|
||||
logger.info(
|
||||
f"删除种子信息:{history.id} {history.title} {history.seasons} {history.episodes} {history.download_hash}")
|
||||
hashs = [history.download_hash]
|
||||
# 处理辅种
|
||||
torrents, error = downloader_obj.get_torrents()
|
||||
if error :
|
||||
if error:
|
||||
logger.error(f"获取辅种信息失败: {error}")
|
||||
else:
|
||||
for t in torrents:
|
||||
if t.name == torrent.name and t.size == torrent.size:
|
||||
hashs.append(t.hash)
|
||||
downloader_obj.delete_torrents(delete_file=True,ids=hashs)
|
||||
downloader_obj.delete_torrents(delete_file=True, ids=hashs)
|
||||
self.delete_data(history)
|
||||
|
||||
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return True
|
||||
|
||||
@@ -141,17 +135,17 @@ class SubscribeClear(_PluginBase):
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
# 获取下载历史数据
|
||||
histories = self.get_data()
|
||||
|
||||
histories = self.get_download_data()
|
||||
|
||||
# 构造标题和剧集列表
|
||||
titles = []
|
||||
episode_options = []
|
||||
|
||||
|
||||
for history in histories:
|
||||
# 标题列表
|
||||
if history.title not in titles:
|
||||
titles.append(history.title)
|
||||
|
||||
|
||||
# 剧集列表
|
||||
episode_str = history.title
|
||||
if history.seasons:
|
||||
@@ -160,7 +154,6 @@ class SubscribeClear(_PluginBase):
|
||||
episode_str += f" {history.episodes}"
|
||||
episode_options.append({"title": episode_str, "value": history.id})
|
||||
|
||||
|
||||
# 将列表转换为选择框选项格式
|
||||
title_options = [{"title": t, "value": t} for t in titles]
|
||||
|
||||
@@ -189,9 +182,9 @@ class SubscribeClear(_PluginBase):
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
episode_select = {
|
||||
'component': 'VRow',
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
@@ -220,15 +213,16 @@ class SubscribeClear(_PluginBase):
|
||||
'content': [
|
||||
title_select,
|
||||
episode_select
|
||||
]
|
||||
]
|
||||
}
|
||||
], {
|
||||
"titles": [],
|
||||
"episodes": []
|
||||
}
|
||||
|
||||
def get_data(self) -> List[DownloadHistory]:
|
||||
down_oper = DownloadHistoryOper()
|
||||
@staticmethod
|
||||
def get_download_data() -> List[DownloadHistory]:
|
||||
down_oper = DownloadHistoryOper()
|
||||
downs = []
|
||||
page = 1
|
||||
while True:
|
||||
@@ -241,7 +235,7 @@ class SubscribeClear(_PluginBase):
|
||||
|
||||
def get_page(self) -> List[dict]:
|
||||
items = []
|
||||
for down in self.get_data():
|
||||
for down in self.get_download_data():
|
||||
items.append({
|
||||
'component': 'tr',
|
||||
'content': [
|
||||
@@ -255,7 +249,7 @@ class SubscribeClear(_PluginBase):
|
||||
},
|
||||
{
|
||||
'component': 'td',
|
||||
'text':down.seasons + " " + down.episodes
|
||||
'text': down.seasons + " " + down.episodes
|
||||
},
|
||||
{
|
||||
'component': 'td',
|
||||
@@ -300,7 +294,7 @@ class SubscribeClear(_PluginBase):
|
||||
},
|
||||
'text': '名称'
|
||||
},
|
||||
{
|
||||
{
|
||||
'component': 'th',
|
||||
'props': {
|
||||
'class': 'text-start ps-4'
|
||||
@@ -330,14 +324,6 @@ class SubscribeClear(_PluginBase):
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册API
|
||||
"""
|
||||
pass
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
退出插件
|
||||
@@ -349,7 +335,7 @@ class SubscribeClear(_PluginBase):
|
||||
"""
|
||||
服务信息
|
||||
"""
|
||||
services = self.downloader_helper.get_services(type_filter="qbittorrent")
|
||||
services = DownloaderHelper().get_services(type_filter="qbittorrent")
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
return None
|
||||
|
||||
@@ -40,11 +40,9 @@ class SyncCookieCloud(_PluginBase):
|
||||
_enabled: bool = False
|
||||
_onlyonce: bool = False
|
||||
_cron: str = ""
|
||||
siteoper = None
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.siteoper = SiteOper()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
@@ -92,7 +90,7 @@ class SyncCookieCloud(_PluginBase):
|
||||
同步站点cookie到cookiecloud
|
||||
"""
|
||||
# 获取所有站点
|
||||
sites = self.siteoper.list_order_by_pri()
|
||||
sites = SiteOper().list_order_by_pri()
|
||||
if not sites:
|
||||
return
|
||||
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
from typing import Any, List, Dict, Tuple, Optional
|
||||
from datetime import datetime, timedelta
|
||||
import ipaddress
|
||||
import socket
|
||||
import base64
|
||||
import json
|
||||
import asyncio
|
||||
import base64
|
||||
import ipaddress
|
||||
import json
|
||||
import socket
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, List, Dict, Tuple, Optional
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from fastapi import Response
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
import pytz
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from fastapi import Response
|
||||
|
||||
from app.chain.site import SiteChain
|
||||
from app.core.config import settings
|
||||
from app.core.event import EventManager, eventmanager
|
||||
from app.core.event import eventmanager
|
||||
from app.db.site_oper import SiteOper
|
||||
from app.helper.sites import SitesHelper
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.utils.http import RequestUtils
|
||||
from app.schemas.types import EventType, NotificationType
|
||||
from app.plugins.tobypasstrackers.dns_helper import DnsHelper
|
||||
from app.schemas.types import EventType, NotificationType
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
class ToBypassTrackers(_PluginBase):
|
||||
@@ -43,13 +41,6 @@ class ToBypassTrackers(_PluginBase):
|
||||
# 可使用的用户级别
|
||||
auth_level = 2
|
||||
|
||||
# 私有属性
|
||||
sites: SitesHelper = None
|
||||
site_chain: SiteChain = None
|
||||
siteoper: SiteOper = None
|
||||
|
||||
# 事件管理器
|
||||
event: EventManager = None
|
||||
# 定时器
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
# 开关
|
||||
@@ -67,13 +58,12 @@ class ToBypassTrackers(_PluginBase):
|
||||
_dns_input: str = ""
|
||||
ipv6_txt: str = ""
|
||||
ipv4_txt: str = ""
|
||||
trackers: Dict[str, List[str]] = {}
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.sites = SitesHelper()
|
||||
# self.event = EventManager()
|
||||
self.site_chain = SiteChain()
|
||||
|
||||
self.stop_service()
|
||||
self.siteoper = SiteOper()
|
||||
|
||||
self.trackers = {}
|
||||
self.ipv6_txt = self.get_data("ipv6_txt") if self.get_data("ipv6_txt") else ""
|
||||
self.ipv4_txt = self.get_data("ipv4_txt") if self.get_data("ipv4_txt") else ""
|
||||
@@ -98,7 +88,7 @@ class ToBypassTrackers(_PluginBase):
|
||||
self._china_ipv6_route = config.get("china_ipv6_route")
|
||||
self._china_ip_route = config.get("china_ip_route")
|
||||
# 过滤掉已删除的站点
|
||||
all_sites = [site.id for site in self.siteoper.list_order_by_pri()]
|
||||
all_sites = [site.id for site in SiteOper().list_order_by_pri()]
|
||||
self._bypassed_sites = [site_id for site_id in all_sites if site_id in self._bypassed_sites]
|
||||
self.__update_config()
|
||||
if self._enabled or self._onlyonce:
|
||||
@@ -160,8 +150,7 @@ class ToBypassTrackers(_PluginBase):
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
site_options = ([{"title": site.name, "value": site.id}
|
||||
for site in self.siteoper.list_order_by_pri()]
|
||||
)
|
||||
for site in SiteOper().list_order_by_pri()])
|
||||
return [
|
||||
{
|
||||
'component': 'VForm',
|
||||
@@ -629,7 +618,7 @@ class ToBypassTrackers(_PluginBase):
|
||||
chnroute_lists = res.text[:-1].split('\n')
|
||||
for ipr in chnroute_lists:
|
||||
ip_list.append(ipr)
|
||||
do_sites = {site.domain: site.name for site in self.siteoper.list_order_by_pri() if
|
||||
do_sites = {site.domain: site.name for site in SiteOper().list_order_by_pri() if
|
||||
site.id in self._bypassed_sites}
|
||||
domain_name_map = {}
|
||||
for site in do_sites:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import re
|
||||
from typing import Optional, List, Callable
|
||||
|
||||
import aioquic
|
||||
import dns.asyncresolver
|
||||
import dns.resolver
|
||||
|
||||
@@ -74,7 +73,6 @@ class DnsHelper:
|
||||
使用 UDP 异步方式解析域名
|
||||
|
||||
:param domain: 域名
|
||||
:param port: DNS服务器端口(默认53)
|
||||
:param dns_type: 记录类型,如 A、AAAA
|
||||
:return: IP地址列表 或 None
|
||||
"""
|
||||
|
||||
@@ -39,7 +39,6 @@ class TorrentRemover(_PluginBase):
|
||||
auth_level = 2
|
||||
|
||||
# 私有属性
|
||||
downloader_helper = None
|
||||
_event = threading.Event()
|
||||
_scheduler = None
|
||||
_enabled = False
|
||||
@@ -63,7 +62,7 @@ class TorrentRemover(_PluginBase):
|
||||
_torrentcategorys = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._onlyonce = config.get("onlyonce")
|
||||
@@ -257,7 +256,7 @@ class TorrentRemover(_PluginBase):
|
||||
'model': 'downloaders',
|
||||
'label': '下载器',
|
||||
'items': [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -593,7 +592,7 @@ class TorrentRemover(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
services = self.downloader_helper.get_services(name_filters=self._downloaders)
|
||||
services = DownloaderHelper().get_services(name_filters=self._downloaders)
|
||||
if not services:
|
||||
logger.warning("获取下载器实例失败,请检查配置")
|
||||
return None
|
||||
|
||||
@@ -12,7 +12,6 @@ from qbittorrentapi import TorrentDictionary
|
||||
|
||||
from app.core.config import settings
|
||||
from app.helper.downloader import DownloaderHelper
|
||||
from app.helper.torrent import TorrentHelper
|
||||
from app.log import logger
|
||||
from app.modules.qbittorrent import Qbittorrent
|
||||
from app.modules.transmission import Transmission
|
||||
@@ -43,8 +42,7 @@ class TorrentTransfer(_PluginBase):
|
||||
|
||||
# 私有属性
|
||||
_scheduler = None
|
||||
torrent_helper = None
|
||||
downloader_helper = None
|
||||
|
||||
# 开关
|
||||
_enabled = False
|
||||
_cron = None
|
||||
@@ -76,8 +74,7 @@ class TorrentTransfer(_PluginBase):
|
||||
_torrent_tags = []
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.torrent_helper = TorrentHelper()
|
||||
self.downloader_helper = DownloaderHelper()
|
||||
|
||||
# 读取配置
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
@@ -136,7 +133,8 @@ class TorrentTransfer(_PluginBase):
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def service_info(self, name: str) -> Optional[ServiceInfo]:
|
||||
@staticmethod
|
||||
def service_info(name: str) -> Optional[ServiceInfo]:
|
||||
"""
|
||||
服务信息
|
||||
"""
|
||||
@@ -144,7 +142,7 @@ class TorrentTransfer(_PluginBase):
|
||||
logger.warning("尚未配置下载器,请检查配置")
|
||||
return None
|
||||
|
||||
service = self.downloader_helper.get_service(name)
|
||||
service = DownloaderHelper().get_service(name)
|
||||
if not service or not service.instance:
|
||||
logger.warning(f"获取下载器 {name} 实例失败,请检查配置")
|
||||
return None
|
||||
@@ -197,7 +195,7 @@ class TorrentTransfer(_PluginBase):
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
"""
|
||||
downloader_options = [{"title": config.name, "value": config.name}
|
||||
for config in self.downloader_helper.get_configs().values()]
|
||||
for config in DownloaderHelper().get_configs().values()]
|
||||
return [
|
||||
{
|
||||
'component': 'VForm',
|
||||
@@ -622,7 +620,8 @@ class TorrentTransfer(_PluginBase):
|
||||
return
|
||||
downloader = service.instance
|
||||
from_service = self.service_info(self._fromdownloader)
|
||||
if self.downloader_helper.is_downloader("qbittorrent", service=service):
|
||||
downloader_helper = DownloaderHelper()
|
||||
if downloader_helper.is_downloader("qbittorrent", service=service):
|
||||
# 生成随机Tag
|
||||
tag = StringUtils.generate_random_str(10)
|
||||
if self._remainoldtag:
|
||||
@@ -651,7 +650,7 @@ class TorrentTransfer(_PluginBase):
|
||||
logger.error(f"{downloader} 下载任务添加成功,但获取任务信息失败!")
|
||||
return None
|
||||
return torrent_hash
|
||||
elif self.downloader_helper.is_downloader("transmission", service=service):
|
||||
elif downloader_helper.is_downloader("transmission", service=service):
|
||||
# 添加任务
|
||||
if self._remainoldtag:
|
||||
# 获取种子标签
|
||||
@@ -780,6 +779,7 @@ class TorrentTransfer(_PluginBase):
|
||||
# 删除重复数
|
||||
del_dup = 0
|
||||
|
||||
downloader_helper = DownloaderHelper()
|
||||
for torrent_item in trans_torrents:
|
||||
# 检查种子文件是否存在
|
||||
torrent_file = Path(self._fromtorrentpath) / f"{torrent_item.get('hash')}.torrent"
|
||||
@@ -814,7 +814,7 @@ class TorrentTransfer(_PluginBase):
|
||||
continue
|
||||
|
||||
# 如果源下载器是QB检查是否有Tracker,没有的话额外获取
|
||||
if self.downloader_helper.is_downloader("qbittorrent", service=from_service):
|
||||
if downloader_helper.is_downloader("qbittorrent", service=from_service):
|
||||
# 读取种子内容、解析种子文件
|
||||
content = torrent_file.read_bytes()
|
||||
if not content:
|
||||
@@ -878,7 +878,7 @@ class TorrentTransfer(_PluginBase):
|
||||
logger.info(f"成功添加转移做种任务,种子文件:{torrent_file}")
|
||||
|
||||
# TR会自动校验,QB需要手动校验
|
||||
if self.downloader_helper.is_downloader("qbittorrent", service=to_service):
|
||||
if downloader_helper.is_downloader("qbittorrent", service=to_service):
|
||||
if self._skipverify:
|
||||
if self._autostart:
|
||||
logger.info(f"{download_id} 跳过校验,开启自动开始,注意观察种子的完整性")
|
||||
|
||||
Reference in New Issue
Block a user