Merge pull request #516 from InfinityPacer/main

This commit is contained in:
jxxghp
2024-10-26 17:12:22 +08:00
committed by GitHub
3 changed files with 106 additions and 96 deletions

View File

@@ -210,7 +210,7 @@
"name": "IYUU自动辅种",
"description": "基于IYUU官方Api实现自动辅种。",
"labels": "做种,IYUU",
"version": "2.0",
"version": "2.0.1",
"icon": "IYUU.png",
"author": "jxxghp",
"level": 2,

View File

@@ -214,21 +214,22 @@ class DownloadSiteTag(_PluginBase):
"agsvpt.trackers.work": "agsvpt.com",
"tracker.cinefiles.info": "audiences.me",
}
for name, service in self.service_infos.items():
logger.info(f"{self.LOG_TAG}开始扫描下载器 {name} ...")
# 获取下载器中的种子
for service in self.service_infos.values():
downloader = service.name
downloader_obj = service.instance
logger.info(f"{self.LOG_TAG}开始扫描下载器 {downloader} ...")
if not downloader_obj:
logger.error(f"{self.LOG_TAG} 获取下载器失败 {name}")
logger.error(f"{self.LOG_TAG} 获取下载器失败 {downloader}")
continue
# 获取下载器中的种子
torrents, error = downloader_obj.get_torrents()
# 如果下载器获取种子发生错误 或 没有种子 则跳过
if error or not torrents:
continue
logger.info(f"{self.LOG_TAG}按时间重新排序 {name} 种子数:{len(torrents)}")
logger.info(f"{self.LOG_TAG}按时间重新排序 {downloader} 种子数:{len(torrents)}")
# 按添加时间进行排序, 时间靠前的按大小和名称加入处理历史, 判定为原始种子, 其他为辅种
torrents = self._torrents_sort(torrents=torrents, dl_type=service.type)
logger.info(f"{self.LOG_TAG}下载器 {name} 分析种子信息中 ...")
logger.info(f"{self.LOG_TAG}下载器 {downloader} 分析种子信息中 ...")
for torrent in torrents:
try:
if self._event.is_set():
@@ -855,4 +856,4 @@ class DownloadSiteTag(_PluginBase):
self._event.clear()
self._scheduler = None
except Exception as e:
print(str(e))
print(str(e))

View File

@@ -2,7 +2,7 @@ import os
import re
from datetime import datetime, timedelta
from threading import Event
from typing import Any, List, Dict, Tuple, Optional
from typing import Any, Dict, List, Optional, Tuple
import pytz
from apscheduler.schedulers.background import BackgroundScheduler
@@ -33,7 +33,7 @@ class IYUUAutoSeed(_PluginBase):
# 插件图标
plugin_icon = "IYUU.png"
# 插件版本
plugin_version = "2.0"
plugin_version = "2.0.1"
# 插件作者
plugin_author = "jxxghp"
# 作者主页
@@ -47,11 +47,11 @@ class IYUUAutoSeed(_PluginBase):
# 私有属性
_scheduler = None
iyuuhelper = None
sites = None
siteoper = None
torrent = None
iyuu_helper = None
downloader_helper = None
sites_helper = None
site_oper = None
torrent_helper = None
# 开关
_enabled = False
_cron = None
@@ -95,9 +95,9 @@ class IYUUAutoSeed(_PluginBase):
cached = 0
def init_plugin(self, config: dict = None):
self.sites = SitesHelper()
self.siteoper = SiteOper()
self.torrent = TorrentHelper()
self.sites_helper = SitesHelper()
self.site_oper = SiteOper()
self.torrent_helper = TorrentHelper()
self.downloader_helper = DownloaderHelper()
# 读取配置
if config:
@@ -121,8 +121,8 @@ class IYUUAutoSeed(_PluginBase):
self._success_caches = [] if self._clearcache else config.get("success_caches") or []
# 过滤掉已删除的站点
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 self.site_oper.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()
@@ -131,7 +131,7 @@ class IYUUAutoSeed(_PluginBase):
# 启动定时任务 & 立即运行一次
if self.get_state() or self._onlyonce:
self.iyuuhelper = IyuuHelper(token=self._token)
self.iyuu_helper = IyuuHelper(token=self._token)
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
if self._onlyonce:
@@ -153,10 +153,35 @@ class IYUUAutoSeed(_PluginBase):
if self._clearcache:
# 关闭清除缓存开关
self._clearcache = False
# 保存配置
self.__update_config()
if self._clearcache or self._onlyonce:
# 保存配置
self.__update_config()
@property
def service_infos(self) -> Optional[Dict[str, ServiceInfo]]:
"""
服务信息
"""
if not self._downloaders:
logger.warning("尚未配置下载器,请检查配置")
return None
services = self.downloader_helper.get_services(name_filters=self._downloaders)
if not services:
logger.warning("获取下载器实例失败,请检查配置")
return None
active_services = {}
for service_name, service_info in services.items():
if service_info.instance.is_inactive():
logger.warning(f"下载器 {service_name} 未连接,请检查配置")
else:
active_services[service_name] = service_info
if not active_services:
logger.warning("没有已连接的下载器,请检查配置")
return None
return active_services
def get_state(self) -> bool:
return True if self._enabled and self._cron and self._token and self._downloaders else False
@@ -198,7 +223,7 @@ class IYUUAutoSeed(_PluginBase):
# 站点的可选项
site_options = ([{"title": site.name, "value": site.id}
for site in self.siteoper.list_order_by_pri()]
for site in self.site_oper.list_order_by_pri()]
+ [{"title": site.get("name"), "value": site.get("id")}
for site in customSites])
return [
@@ -302,14 +327,15 @@ class IYUUAutoSeed(_PluginBase):
{
'component': 'VCol',
'props': {
'cols': 12
'cols': 12,
'md': 6
},
'content': [
{
'component': 'VSelect',
'props': {
'multiple': True,
'chips': True,
'multiple': True,
'clearable': True,
'model': 'downloaders',
'label': '下载器',
@@ -318,6 +344,23 @@ class IYUUAutoSeed(_PluginBase):
}
}
]
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 6
},
'content': [
{
'component': 'VTextField',
'props': {
'model': 'size',
'label': '辅种体积大于(GB)',
'placeholder': '只有大于该值的才辅种'
}
}
]
}
]
},
@@ -493,33 +536,6 @@ class IYUUAutoSeed(_PluginBase):
def get_page(self) -> List[dict]:
pass
@property
def service_infos(self) -> Optional[Dict[str, ServiceInfo]]:
"""
服务信息
"""
if not self._downloaders:
logger.warning("尚未配置下载器,请检查配置")
return None
services = self.downloader_helper.get_services(name_filters=self._downloaders)
if not services:
logger.warning("获取下载器实例失败,请检查配置")
return None
active_services = {}
for service_name, service_info in services.items():
if service_info.instance.is_inactive():
logger.warning(f"下载器 {service_name} 未连接,请检查配置")
else:
active_services[service_name] = service_info
if not active_services:
logger.warning("没有已连接的下载器,请检查配置")
return None
return active_services
def __update_config(self):
self.update_config({
"enabled": self._enabled,
@@ -542,17 +558,11 @@ class IYUUAutoSeed(_PluginBase):
"permanent_error_caches": self._permanent_error_caches
})
def __get_downloader(self, name: str):
"""
根据类型返回下载器实例
"""
return self.service_infos.get(name).instance
def auto_seed(self):
"""
开始辅种
"""
if not self.iyuuhelper:
if not self.iyuu_helper or not self.service_infos:
return
logger.info("开始辅种任务 ...")
@@ -564,9 +574,10 @@ class IYUUAutoSeed(_PluginBase):
self.fail = 0
self.cached = 0
# 扫描下载器辅种
for downloader in self._downloaders:
for service in self.service_infos.values():
downloader = service.name
downloader_obj = service.instance
logger.info(f"开始扫描下载器 {downloader} ...")
downloader_obj = self.__get_downloader(downloader)
# 获取下载器中已完成的种子
torrents = downloader_obj.get_completed_torrents()
if torrents:
@@ -580,11 +591,11 @@ class IYUUAutoSeed(_PluginBase):
logger.info(f"辅种服务停止")
return
# 获取种子hash
hash_str = self.__get_hash(torrent, downloader)
hash_str = self.__get_hash(torrent=torrent, dl_type=service.type)
if hash_str in self._error_caches or hash_str in self._permanent_error_caches:
logger.info(f"种子 {hash_str} 辅种失败且已缓存,跳过 ...")
continue
save_path = self.__get_save_path(torrent, downloader)
save_path = self.__get_save_path(torrent=torrent, dl_type=service.type)
if self._nopaths and save_path:
# 过滤不需要转移的路径
@@ -598,7 +609,7 @@ class IYUUAutoSeed(_PluginBase):
continue
# 获取种子标签
torrent_labels = self.__get_label(torrent, downloader)
torrent_labels = self.__get_label(torrent=torrent, dl_type=service.type)
if torrent_labels and self._nolabels:
is_skip = False
for label in self._nolabels.split(','):
@@ -610,7 +621,7 @@ class IYUUAutoSeed(_PluginBase):
continue
# 体积排除辅种
torrent_size = self.__get_torrent_size(torrent, downloader) / 1024 / 1024 / 1024
torrent_size = self.__get_torrent_size(torrent=torrent, dl_type=service.type) / 1024 / 1024 / 1024
if self._size and torrent_size < self._size:
logger.info(f"种子 {hash_str} 大小:{torrent_size:.2f}GB小于设定 {self._size}GB跳过 ...")
continue
@@ -628,7 +639,7 @@ class IYUUAutoSeed(_PluginBase):
chunk = hash_strs[i:i + chunk_size]
# 处理分组
self.__seed_torrents(hash_strs=chunk,
downloader=downloader)
service=service)
# 触发校验检查
self.check_recheck()
else:
@@ -654,27 +665,29 @@ class IYUUAutoSeed(_PluginBase):
"""
定时检查下载器中种子是否校验完成,校验完成且完整的自动开始辅种
"""
if not self.service_infos:
return
if not self._recheck_torrents:
return
if self._is_recheck_running:
return
self._is_recheck_running = True
for downloader in self._downloaders:
for service in self.service_infos.values():
# 需要检查的种子
downloader = service.name
downloader_obj = service.instance
recheck_torrents = self._recheck_torrents.get(downloader) or []
if not recheck_torrents:
continue
logger.info(f"开始检查下载器 {downloader} 的校验任务 ...")
# 下载器
downloader_obj = self.__get_downloader(downloader)
# 获取下载器中的种子状态
torrents, _ = downloader_obj.get_torrents(ids=recheck_torrents)
if torrents:
can_seeding_torrents = []
for torrent in torrents:
# 获取种子hash
hash_str = self.__get_hash(torrent, downloader)
if self.__can_seeding(torrent, downloader):
hash_str = self.__get_hash(torrent=torrent, dl_type=service.type)
if self.__can_seeding(torrent=torrent, dl_type=service.type):
can_seeding_torrents.append(hash_str)
if can_seeding_torrents:
logger.info(f"{len(can_seeding_torrents)} 个任务校验完成,开始辅种 ...")
@@ -691,13 +704,13 @@ class IYUUAutoSeed(_PluginBase):
self._recheck_torrents[downloader] = []
self._is_recheck_running = False
def __seed_torrents(self, hash_strs: list, downloader: str):
def __seed_torrents(self, hash_strs: list, service: ServiceInfo):
"""
执行一批种子的辅种
"""
if not hash_strs:
return
logger.info(f"下载器 {downloader} 开始查询辅种,数量:{len(hash_strs)} ...")
logger.info(f"下载器 {service.name} 开始查询辅种,数量:{len(hash_strs)} ...")
# 下载器中的Hashs
hashs = [item.get("hash") for item in hash_strs]
# 每个Hash的保存目录
@@ -705,7 +718,7 @@ class IYUUAutoSeed(_PluginBase):
for item in hash_strs:
save_paths[item.get("hash")] = item.get("save_path")
# 查询可辅种数据
seed_list, msg = self.iyuuhelper.get_seed_info(hashs)
seed_list, msg = self.iyuu_helper.get_seed_info(hashs)
if not isinstance(seed_list, dict):
# 判断辅种异常是否是由于Token未认证导致的由于没有解决接口只能从返回值来判断
if self._token and msg == '请求缺少token':
@@ -744,7 +757,7 @@ class IYUUAutoSeed(_PluginBase):
continue
# 添加任务
success = self.__download_torrent(seed=seed,
downloader=downloader,
service=service,
save_path=save_paths.get(current_hash))
if success:
success_torrents.append(seed.get("info_hash"))
@@ -752,10 +765,10 @@ class IYUUAutoSeed(_PluginBase):
# 辅种成功的去重放入历史
if len(success_torrents) > 0:
self.__save_history(current_hash=current_hash,
downloader=downloader,
downloader=service.name,
success_torrents=success_torrents)
logger.info(f"下载器 {downloader} 辅种完成")
logger.info(f"下载器 {service.name} 辅种完成")
def __save_history(self, current_hash: str, downloader: str, success_torrents: []):
"""
@@ -809,7 +822,7 @@ class IYUUAutoSeed(_PluginBase):
except Exception as e:
print(str(e))
def __download(self, downloader: str, content: bytes,
def __download(self, service: ServiceInfo, content: bytes,
save_path: str, site_name: str) -> Optional[str]:
torrent_tags = self._labelsafterseed.split(',')
@@ -821,10 +834,6 @@ class IYUUAutoSeed(_PluginBase):
"""
添加下载任务
"""
service = self.service_infos.get(downloader)
if not service:
logger.error(f"下载器 {downloader} 未连接,添加下载任务失败!")
return None
if service.type == "qbittorrent":
# 生成随机Tag
tag = StringUtils.generate_random_str(10)
@@ -843,7 +852,7 @@ class IYUUAutoSeed(_PluginBase):
# 获取种子Hash
torrent_hash = service.instance.get_torrent_id_by_tag(tags=tag)
if not torrent_hash:
logger.error(f"{downloader} 下载任务添加成功,但获取任务信息失败!")
logger.error(f"{service.name} 下载任务添加成功,但获取任务信息失败!")
return None
return torrent_hash
elif service.type == "transmission":
@@ -857,10 +866,10 @@ class IYUUAutoSeed(_PluginBase):
else:
return torrent.hashString
logger.error(f"不支持的下载器:{downloader}")
logger.error(f"不支持的下载器:{service.type}")
return None
def __download_torrent(self, seed: dict, downloader: str, save_path: str):
def __download_torrent(self, seed: dict, service: ServiceInfo, save_path: str):
"""
下载种子
torrent: {
@@ -880,7 +889,7 @@ class IYUUAutoSeed(_PluginBase):
self.total += 1
# 获取种子站点及下载地址模板
site_url, download_page = self.iyuuhelper.get_torrent_url(seed.get("sid"))
site_url, download_page = self.iyuu_helper.get_torrent_url(seed.get("sid"))
if not site_url or not download_page:
# 加入缓存
self._error_caches.append(seed.get("info_hash"))
@@ -890,7 +899,7 @@ class IYUUAutoSeed(_PluginBase):
# 查询站点
site_domain = StringUtils.get_url_domain(site_url)
# 站点信息
site_info = self.sites.get_indexer(site_domain)
site_info = self.sites_helper.get_indexer(site_domain)
if not site_info or not site_info.get('url'):
logger.debug(f"没有维护种子对应的站点:{site_url}")
return False
@@ -899,14 +908,14 @@ class IYUUAutoSeed(_PluginBase):
return False
self.realtotal += 1
# 查询hash值是否已经在下载器中
downloader_obj = self.__get_downloader(downloader)
downloader_obj = service.instance
torrent_info, _ = downloader_obj.get_torrents(ids=[seed.get("info_hash")])
if torrent_info:
logger.info(f"{seed.get('info_hash')} 已在下载器中,跳过 ...")
self.exist += 1
return False
# 站点流控
check, checkmsg = self.sites.check(site_domain)
check, checkmsg = self.sites_helper.check(site_domain)
if check:
logger.warn(checkmsg)
self.fail += 1
@@ -928,7 +937,7 @@ class IYUUAutoSeed(_PluginBase):
else:
torrent_url += "?https=1"
# 下载种子文件
_, content, _, _, error_msg = self.torrent.download_torrent(
_, content, _, _, error_msg = self.torrent_helper.download_torrent(
url=torrent_url,
cookie=site_info.get("cookie"),
ua=site_info.get("ua") or settings.USER_AGENT,
@@ -946,7 +955,7 @@ class IYUUAutoSeed(_PluginBase):
return False
# 添加下载,辅种任务默认暂停
logger.info(f"添加下载任务:{torrent_url} ...")
download_id = self.__download(downloader=downloader,
download_id = self.__download(service=service,
content=content,
save_path=save_path,
site_name=site_info.get("name"))
@@ -968,11 +977,11 @@ class IYUUAutoSeed(_PluginBase):
else:
# 追加校验任务
logger.info(f"添加校验检查任务:{download_id} ...")
if not self._recheck_torrents.get(downloader):
self._recheck_torrents[downloader] = []
self._recheck_torrents[downloader].append(download_id)
if not self._recheck_torrents.get(service.name):
self._recheck_torrents[service.name] = []
self._recheck_torrents[service.name].append(download_id)
# TR会自动校验
if downloader == "qbittorrent":
if service.type == "qbittorrent":
# 开始校验种子
downloader_obj.recheck_torrents(ids=[download_id])
# 下载成功