fix IYUUAutoSeed
This commit is contained in:
parent
0210217d1e
commit
4ea48a4e11
@ -325,3 +325,15 @@ class Qbittorrent(metaclass=Singleton):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"设置速度限制出错:{err}")
|
logger.error(f"设置速度限制出错:{err}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def recheck_torrents(self, ids: Union[str, list]):
|
||||||
|
"""
|
||||||
|
重新校验种子
|
||||||
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return self.qbc.torrents_recheck(torrent_hashes=ids)
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"重新校验种子出错:{err}")
|
||||||
|
return False
|
||||||
|
@ -264,3 +264,15 @@ class Transmission(metaclass=Singleton):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"设置速度限制出错:{err}")
|
logger.error(f"设置速度限制出错:{err}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def recheck_torrents(self, ids: Union[str, list]):
|
||||||
|
"""
|
||||||
|
重新校验种子
|
||||||
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return self.trc.verify_torrent(ids=ids)
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"重新校验种子出错:{err}")
|
||||||
|
return False
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from threading import Event
|
from threading import Event
|
||||||
from typing import Any, List, Dict, Tuple
|
from typing import Any, List, Dict, Tuple, Optional
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
@ -9,10 +9,15 @@ from apscheduler.triggers.cron import CronTrigger
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.helper.sites import SitesHelper
|
||||||
|
from app.helper.torrent import TorrentHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
|
from app.modules.qbittorrent import Qbittorrent
|
||||||
|
from app.modules.transmission import Transmission
|
||||||
from app.plugins import _PluginBase
|
from app.plugins import _PluginBase
|
||||||
from app.plugins.iyuuautoseed.iyuu_helper import IyuuHelper
|
from app.plugins.iyuuautoseed.iyuu_helper import IyuuHelper
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils
|
||||||
|
from app.utils.string import StringUtils
|
||||||
|
|
||||||
|
|
||||||
class IYUUAutoSeed(_PluginBase):
|
class IYUUAutoSeed(_PluginBase):
|
||||||
@ -40,7 +45,10 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
# 私有属性
|
# 私有属性
|
||||||
_scheduler = None
|
_scheduler = None
|
||||||
iyuuhelper = None
|
iyuuhelper = None
|
||||||
|
qb = None
|
||||||
|
tr = None
|
||||||
sites = None
|
sites = None
|
||||||
|
torrent = None
|
||||||
# 开关
|
# 开关
|
||||||
_enabled = False
|
_enabled = False
|
||||||
_cron = None
|
_cron = None
|
||||||
@ -79,6 +87,8 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
cached = 0
|
cached = 0
|
||||||
|
|
||||||
def init_plugin(self, config: dict = None):
|
def init_plugin(self, config: dict = None):
|
||||||
|
self.sites = SitesHelper()
|
||||||
|
self.torrent = TorrentHelper()
|
||||||
# 读取配置
|
# 读取配置
|
||||||
if config:
|
if config:
|
||||||
self._enabled = config.get("enabled")
|
self._enabled = config.get("enabled")
|
||||||
@ -101,6 +111,9 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
if self.get_state() or self._onlyonce:
|
if self.get_state() or self._onlyonce:
|
||||||
self.iyuuhelper = IyuuHelper(token=self._token)
|
self.iyuuhelper = IyuuHelper(token=self._token)
|
||||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||||
|
self.qb = Qbittorrent()
|
||||||
|
self.tr = Transmission()
|
||||||
|
|
||||||
if self._cron:
|
if self._cron:
|
||||||
try:
|
try:
|
||||||
self._scheduler.add_job(self.auto_seed,
|
self._scheduler.add_job(self.auto_seed,
|
||||||
@ -147,6 +160,9 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
"""
|
"""
|
||||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||||
"""
|
"""
|
||||||
|
# 站点的可选项
|
||||||
|
site_options = [{"title": site.get("name"), "value": site.get("id")}
|
||||||
|
for site in self.sites.get_indexers()]
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
'component': 'VForm',
|
'component': 'VForm',
|
||||||
@ -187,6 +203,146 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'token',
|
||||||
|
'label': 'IYUU Token',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'cron',
|
||||||
|
'label': '执行周期',
|
||||||
|
'placeholder': '0 0 0 ? *'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'nolabels',
|
||||||
|
'label': '不辅种标签',
|
||||||
|
'placeholder': '使用,分隔多个标签'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSelect',
|
||||||
|
'props': {
|
||||||
|
'chips': True,
|
||||||
|
'multiple': True,
|
||||||
|
'model': 'downloaders',
|
||||||
|
'label': '辅种下载器',
|
||||||
|
'items': [
|
||||||
|
{'title': 'Qbittorrent', 'value': 'qbittorrent'},
|
||||||
|
{'title': 'Transmission', 'value': 'transmission'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSelect',
|
||||||
|
'props': {
|
||||||
|
'chips': True,
|
||||||
|
'multiple': True,
|
||||||
|
'model': 'sites',
|
||||||
|
'label': '辅种站点',
|
||||||
|
'items': site_options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSwitch',
|
||||||
|
'props': {
|
||||||
|
'model': 'onlyonce',
|
||||||
|
'label': '立即运行一次',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSwitch',
|
||||||
|
'props': {
|
||||||
|
'model': 'clearcache',
|
||||||
|
'label': '清除缓存后运行',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -221,6 +377,17 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
"permanent_error_caches": self._permanent_error_caches
|
"permanent_error_caches": self._permanent_error_caches
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def __get_downloader(self, dtype: str):
|
||||||
|
"""
|
||||||
|
根据类型返回下载器实例
|
||||||
|
"""
|
||||||
|
if dtype == "qbittorrent":
|
||||||
|
return self.qb
|
||||||
|
elif dtype == "transmission":
|
||||||
|
return self.tr
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def auto_seed(self):
|
def auto_seed(self):
|
||||||
"""
|
"""
|
||||||
开始辅种
|
开始辅种
|
||||||
@ -241,8 +408,9 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
# 扫描下载器辅种
|
# 扫描下载器辅种
|
||||||
for downloader in self._downloaders:
|
for downloader in self._downloaders:
|
||||||
logger.info(f"开始扫描下载器 {downloader} ...")
|
logger.info(f"开始扫描下载器 {downloader} ...")
|
||||||
# TODO 获取下载器中已完成的种子
|
downloader_obj = self.__get_downloader(downloader)
|
||||||
torrents = []
|
# 获取下载器中已完成的种子
|
||||||
|
torrents = downloader_obj.get_completed_torrents()
|
||||||
if torrents:
|
if torrents:
|
||||||
logger.info(f"下载器 {downloader} 已完成种子数:{len(torrents)}")
|
logger.info(f"下载器 {downloader} 已完成种子数:{len(torrents)}")
|
||||||
else:
|
else:
|
||||||
@ -319,9 +487,10 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
if not recheck_torrents:
|
if not recheck_torrents:
|
||||||
continue
|
continue
|
||||||
logger.info(f"开始检查下载器 {downloader} 的校验任务 ...")
|
logger.info(f"开始检查下载器 {downloader} 的校验任务 ...")
|
||||||
# 下载器类型
|
# 下载器
|
||||||
# TODO 获取下载器中的种子
|
downloader_obj = self.__get_downloader(downloader)
|
||||||
torrents = []
|
# 获取下载器中的种子状态
|
||||||
|
torrents = downloader_obj.get_torrents(ids=recheck_torrents)
|
||||||
if torrents:
|
if torrents:
|
||||||
can_seeding_torrents = []
|
can_seeding_torrents = []
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
@ -331,7 +500,8 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
can_seeding_torrents.append(hash_str)
|
can_seeding_torrents.append(hash_str)
|
||||||
if can_seeding_torrents:
|
if can_seeding_torrents:
|
||||||
logger.info(f"共 {len(can_seeding_torrents)} 个任务校验完成,开始辅种 ...")
|
logger.info(f"共 {len(can_seeding_torrents)} 个任务校验完成,开始辅种 ...")
|
||||||
# TODO 开始任务
|
# 开始任务
|
||||||
|
downloader_obj.start_torrents(ids=can_seeding_torrents)
|
||||||
# 去除已经处理过的种子
|
# 去除已经处理过的种子
|
||||||
self._recheck_torrents[downloader] = list(
|
self._recheck_torrents[downloader] = list(
|
||||||
set(recheck_torrents).difference(set(can_seeding_torrents)))
|
set(recheck_torrents).difference(set(can_seeding_torrents)))
|
||||||
@ -457,6 +627,41 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(str(e))
|
print(str(e))
|
||||||
|
|
||||||
|
def __download(self, downloader: str, content: bytes,
|
||||||
|
save_path: str) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
添加下载任务
|
||||||
|
"""
|
||||||
|
if downloader == "qbittorrent":
|
||||||
|
# 生成随机Tag
|
||||||
|
tag = StringUtils.generate_random_str(10)
|
||||||
|
state = self.qb.add_torrent(content=content,
|
||||||
|
download_dir=save_path,
|
||||||
|
is_paused=True,
|
||||||
|
tag=["已整理", "辅种", tag])
|
||||||
|
if not state:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# 获取种子Hash
|
||||||
|
torrent_hash = self.qb.get_torrent_id_by_tag(tags=tag)
|
||||||
|
if not torrent_hash:
|
||||||
|
logger.error(f"{downloader} 获取种子Hash失败")
|
||||||
|
return None
|
||||||
|
return torrent_hash
|
||||||
|
elif downloader == "transmission":
|
||||||
|
# 添加任务
|
||||||
|
torrent = self.tr.add_torrent(content=content,
|
||||||
|
download_dir=save_path,
|
||||||
|
is_paused=True,
|
||||||
|
labels=["已整理", "辅种"])
|
||||||
|
if not torrent:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return torrent.hashString
|
||||||
|
|
||||||
|
logger.error(f"不支持的下载器:{downloader}")
|
||||||
|
return None
|
||||||
|
|
||||||
def __download_torrent(self, seed: dict, downloader: str, save_path: str):
|
def __download_torrent(self, seed: dict, downloader: str, save_path: str):
|
||||||
"""
|
"""
|
||||||
下载种子
|
下载种子
|
||||||
@ -476,22 +681,25 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
self.cached += 1
|
self.cached += 1
|
||||||
return False
|
return False
|
||||||
# 查询站点
|
# 查询站点
|
||||||
site_info = self.sites.get_sites(siteurl=site_url)
|
site_domain = StringUtils.get_url_domain(site_url)
|
||||||
|
# 站点信息
|
||||||
|
site_info = self.sites.get_indexer(site_domain)
|
||||||
if not site_info:
|
if not site_info:
|
||||||
logger.debug(f"没有维护种子对应的站点:{site_url}")
|
logger.debug(f"没有维护种子对应的站点:{site_url}")
|
||||||
return False
|
return False
|
||||||
if self._sites and str(site_info.get("id")) not in self._sites:
|
if self._sites and str(site_info.get('id')) not in self._sites:
|
||||||
logger.info("当前站点不在选择的辅助站点范围,跳过 ...")
|
logger.info("当前站点不在选择的辅助站点范围,跳过 ...")
|
||||||
return False
|
return False
|
||||||
self.realtotal += 1
|
self.realtotal += 1
|
||||||
# TODO 查询hash值是否已经在下载器中
|
# 查询hash值是否已经在下载器中
|
||||||
torrent_info = []
|
downloader_obj = self.__get_downloader(downloader)
|
||||||
|
torrent_info = downloader_obj.get_torrents(ids=[seed.get("info_hash")])
|
||||||
if torrent_info:
|
if torrent_info:
|
||||||
logger.debug(f"{seed.get('info_hash')} 已在下载器中,跳过 ...")
|
logger.debug(f"{seed.get('info_hash')} 已在下载器中,跳过 ...")
|
||||||
self.exist += 1
|
self.exist += 1
|
||||||
return False
|
return False
|
||||||
# 站点流控
|
# 站点流控
|
||||||
if self.sites.check_ratelimit(site_info.get("id")):
|
if self.sites.check(site_domain):
|
||||||
self.fail += 1
|
self.fail += 1
|
||||||
return False
|
return False
|
||||||
# 下载种子
|
# 下载种子
|
||||||
@ -509,20 +717,33 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
torrent_url += "&https=1"
|
torrent_url += "&https=1"
|
||||||
else:
|
else:
|
||||||
torrent_url += "?https=1"
|
torrent_url += "?https=1"
|
||||||
# TODO 添加下载,辅种任务默认暂停
|
# 下载种子文件
|
||||||
download_id, retmsg = None, ""
|
_, content, _, _, error_msg = self.torrent.download_torrent(
|
||||||
if not download_id:
|
url=torrent_url,
|
||||||
|
cookie=site_info.get("cookie"),
|
||||||
|
ua=site_info.get("ua") or settings.USER_AGENT,
|
||||||
|
proxy=site_info.get("proxy"))
|
||||||
|
if not content:
|
||||||
# 下载失败
|
# 下载失败
|
||||||
logger.warn(f"添加下载任务出错,"
|
|
||||||
f"错误原因:{retmsg or '下载器添加任务失败'},"
|
|
||||||
f"种子链接:{torrent_url}")
|
|
||||||
self.fail += 1
|
self.fail += 1
|
||||||
# 加入失败缓存
|
# 加入失败缓存
|
||||||
if retmsg and ('无法打开链接' in retmsg or '触发站点流控' in retmsg):
|
if error_msg and ('无法打开链接' in error_msg or '触发站点流控' in error_msg):
|
||||||
self._error_caches.append(seed.get("info_hash"))
|
self._error_caches.append(seed.get("info_hash"))
|
||||||
else:
|
else:
|
||||||
# 种子不存在的情况
|
# 种子不存在的情况
|
||||||
self._permanent_error_caches.append(seed.get("info_hash"))
|
self._permanent_error_caches.append(seed.get("info_hash"))
|
||||||
|
logger.error(f"下载种子文件失败:{torrent_url}")
|
||||||
|
return False
|
||||||
|
# 添加下载,辅种任务默认暂停
|
||||||
|
logger.info(f"添加下载任务:{torrent_url} ...")
|
||||||
|
download_id = self.__download(downloader=downloader,
|
||||||
|
content=content,
|
||||||
|
save_path=save_path)
|
||||||
|
if not download_id:
|
||||||
|
# 下载失败
|
||||||
|
self.fail += 1
|
||||||
|
# 加入失败缓存
|
||||||
|
self._error_caches.append(seed.get("info_hash"))
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.success += 1
|
self.success += 1
|
||||||
@ -535,9 +756,8 @@ class IYUUAutoSeed(_PluginBase):
|
|||||||
logger.info(f"成功添加辅种下载,站点:{site_info.get('name')},种子链接:{torrent_url}")
|
logger.info(f"成功添加辅种下载,站点:{site_info.get('name')},种子链接:{torrent_url}")
|
||||||
# TR会自动校验
|
# TR会自动校验
|
||||||
if downloader == "qbittorrent":
|
if downloader == "qbittorrent":
|
||||||
# TODO 开始校验种子
|
# 开始校验种子
|
||||||
pass
|
downloader_obj.recheck_torrents(ids=[download_id])
|
||||||
|
|
||||||
# 成功也加入缓存,有一些改了路径校验不通过的,手动删除后,下一次又会辅上
|
# 成功也加入缓存,有一些改了路径校验不通过的,手动删除后,下一次又会辅上
|
||||||
self._success_caches.append(seed.get("info_hash"))
|
self._success_caches.append(seed.get("info_hash"))
|
||||||
return True
|
return True
|
||||||
|
Loading…
x
Reference in New Issue
Block a user