fix plugins

This commit is contained in:
jxxghp
2025-06-09 14:15:19 +08:00
parent 74113ca44b
commit 1ec1285563
29 changed files with 394 additions and 616 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,7 +30,6 @@ class HistoryToV2(_PluginBase):
auth_level = 1
# 私有属性
historyoper = None
_enabled = False
_host = None
_username = None

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
# 查询所有媒体服务器状态

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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} 跳过校验,开启自动开始,注意观察种子的完整性")