This commit is contained in:
InfinityPacer
2024-06-01 01:26:26 +08:00
18 changed files with 1200 additions and 288 deletions

View File

@@ -38,7 +38,7 @@ class AutoSignIn(_PluginBase):
# 插件图标
plugin_icon = "signin.png"
# 插件版本
plugin_version = "2.3.1"
plugin_version = "2.3.2"
# 插件作者
plugin_author = "thsrite"
# 作者主页

View File

@@ -8,9 +8,9 @@ from app.plugins.autosignin.sites import _ISiteSigninHandler
from app.utils.http import RequestUtils
class MTorrent(_ISiteSigninHandler):
class YemaPT(_ISiteSigninHandler):
"""
m-team签到
YemaPT 签到
"""
# 匹配的站点Url每一个实现类都需要设置为自己的站点Url
site_url = "yemapt.org"
@@ -26,7 +26,7 @@ class MTorrent(_ISiteSigninHandler):
def signin(self, site_info: CommentedMap) -> Tuple[bool, str]:
"""
执行签到操作,馒头实际没有签到,非仿真模式下需要更新访问时间
执行签到操作
:param site_info: 站点信息含有站点Url、站点Cookie、UA等信息
:return: 签到结果信息
"""
@@ -35,19 +35,20 @@ class MTorrent(_ISiteSigninHandler):
"User-Agent": site_info.get("ua"),
"Accept": "application/json, text/plain, */*",
}
# 更新最后访问时间
res = RequestUtils(headers=headers,
timeout=15,
cookies=site_info.get("cookie"),
proxies=settings.PROXY if site_info.get("proxy") else None,
referer=site_info.get('url')
).post_res(url=urljoin(site_info.get('url'), "api/user/profile"))
# 获取用户信息,更新最后访问时间
res = (RequestUtils(headers=headers,
timeout=15,
cookies=site_info.get("cookie"),
proxies=settings.PROXY if site_info.get("proxy") else None,
referer=site_info.get('url')
).get_res(urljoin(site_info.get('url'), "api/consumer/checkIn")))
if res and res.json().get("success"):
return True, "模拟登录成功"
return True, "签到成功"
elif res is not None:
return False, f"模拟登录失败,状态码{res.status_code}"
return False, f"签到失败,签到结果{res.json().get('errorMessage')}"
else:
return False, "模拟登录失败,无法打开网站"
return False, "签到失败,无法打开网站"
def login(self, site_info: CommentedMap) -> Tuple[bool, str]:
"""
@@ -55,4 +56,23 @@ class MTorrent(_ISiteSigninHandler):
:param site_info: 站点信息含有站点Url、站点Cookie、UA等信息
:return: 登录结果信息
"""
return self.signin(site_info)
headers = {
"Content-Type": "application/json",
"User-Agent": site_info.get("ua"),
"Accept": "application/json, text/plain, */*",
}
# 获取用户信息,更新最后访问时间
res = (RequestUtils(headers=headers,
timeout=15,
cookies=site_info.get("cookie"),
proxies=settings.PROXY if site_info.get("proxy") else None,
referer=site_info.get('url')
).get_res(urljoin(site_info.get('url'), "api/user/profile")))
if res and res.json().get("success"):
return True, "模拟登录成功"
elif res is not None:
return False, f"模拟登录失败,状态码:{res.status_code}"
else:
return False, "模拟登录失败,无法打开网站"

View File

@@ -13,7 +13,7 @@ class CategoryEditor(_PluginBase):
# 插件图标
plugin_icon = "Bookstack_A.png"
# 插件版本
plugin_version = "1.1"
plugin_version = "1.2"
# 插件作者
plugin_author = "jxxghp"
# 作者主页
@@ -39,12 +39,9 @@ class CategoryEditor(_PluginBase):
# 写入文件
if self._enabled:
self.user_yaml.write_text(self._content, encoding="utf-8")
if not settings.LIBRARY_CATEGORY:
self.systemmessage.put("二级分类未开启,策略已保存但未生效!", title="二级分类策略")
return
# 立即生效
CategoryHelper().init()
self.systemmessage.put("二级分类策略已更新!", title="二级分类策略")
self.systemmessage.put("二级分类策略已更新,请注意同步调整目录设置", title="二级分类策略")
def get_state(self) -> bool:
return self._enabled

View File

@@ -28,7 +28,7 @@ class CleanInvalidSeed(_PluginBase):
# 插件图标
plugin_icon = "clean_a.png"
# 插件版本
plugin_version = "1.5"
plugin_version = "1.8"
# 插件作者
plugin_author = "DzAvril"
# 作者主页
@@ -94,22 +94,7 @@ class CleanInvalidSeed(_PluginBase):
)
# 关闭一次性开关
self._onlyonce = False
self.update_config(
{
"onlyonce": False,
"cron": self._cron,
"enabled": self._enabled,
"notify": self._notify,
"delete_invalid_torrents": self._delete_invalid_torrents,
"delete_invalid_files": self._delete_invalid_files,
"detect_invalid_files": self._detect_invalid_files,
"notify_all": self._notify_all,
"download_dirs": self._download_dirs,
"exclude_keywords": self._exclude_keywords,
"exclude_categories": self._exclude_categories,
"exclude_labels": self._exclude_labels,
}
)
self._update_config()
# 启动任务
if self._scheduler.get_jobs():
@@ -119,6 +104,24 @@ class CleanInvalidSeed(_PluginBase):
def get_state(self) -> bool:
return self._enabled
def _update_config(self):
self.update_config(
{
"onlyonce": False,
"cron": self._cron,
"enabled": self._enabled,
"notify": self._notify,
"delete_invalid_torrents": self._delete_invalid_torrents,
"delete_invalid_files": self._delete_invalid_files,
"detect_invalid_files": self._detect_invalid_files,
"notify_all": self._notify_all,
"download_dirs": self._download_dirs,
"exclude_keywords": self._exclude_keywords,
"exclude_categories": self._exclude_categories,
"exclude_labels": self._exclude_labels,
}
)
@staticmethod
def get_command() -> List[Dict[str, Any]]:
"""
@@ -154,6 +157,13 @@ class CleanInvalidSeed(_PluginBase):
"category": "QB",
"data": {"action": "delete_invalid_files"},
},
{
"cmd": "/toggle_notify_all",
"event": EventType.PluginAction,
"desc": "QB清理插件切换全量通知",
"category": "QB",
"data": {"action": "toggle_notify_all"},
},
]
@eventmanager.register(EventType.PluginAction)
@@ -189,6 +199,22 @@ class CleanInvalidSeed(_PluginBase):
logger.info("收到远程命令,开始清理无效源文件")
self._delete_invalid_files = True
self.detect_invalid_files()
elif event_data.get("action") == "toggle_notify_all":
self._notify_all = not self._notify_all
self._update_config()
if self._notify_all:
self.post_message(
channel=event.event_data.get("channel"),
title="已开启全量通知",
userid=event.event_data.get("user"),
)
else:
self.post_message(
channel=event.event_data.get("channel"),
title="已关闭全量通知",
userid=event.event_data.get("user"),
)
return
else:
logger.error("收到未知远程命令")
return
@@ -256,8 +282,8 @@ class CleanInvalidSeed(_PluginBase):
# tracker未工作但暂时不能判定为失效做种需人工判断
tracker_not_working_torrents = []
working_tracker_set = set()
exclude_categories = self._exclude_categories.split("\n")
exclude_labels = self._exclude_labels.split("\n")
exclude_categories = self._exclude_categories.split("\n") if self._exclude_categories else []
exclude_labels = self._exclude_labels.split("\n") if self._exclude_labels else []
# 第一轮筛选出所有未工作的种子
for torrent in all_torrents:
trackers = torrent.trackers
@@ -307,7 +333,7 @@ class CleanInvalidSeed(_PluginBase):
if torrent.category in exclude_categories:
is_excluded = True
invalid_torrents_exclude_categories.append(torrent)
torrent_labels = torrent.tags.split(",")
torrent_labels = [tag.strip() for tag in torrent.tags.split(",")]
for label in torrent_labels:
if label in exclude_labels:
is_excluded = True
@@ -398,29 +424,34 @@ class CleanInvalidSeed(_PluginBase):
logger.info(exclude_labels_msg)
# 通知
if self._notify:
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('_', '\_')
self.post_message(
mtype=NotificationType.SiteMessage,
title=f"【清理无效做种】",
text=tracker_not_working_msg,
)
if self._delete_invalid_torrents:
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('_', '\_')
self.post_message(
mtype=NotificationType.SiteMessage,
title=f"【清理无效做种】",
text=exclude_categories_msg,
)
exclude_labels_msg = exclude_labels_msg.replace('_', '\_')
self.post_message(
mtype=NotificationType.SiteMessage,
title=f"【清理无效做种】",
@@ -437,7 +468,15 @@ class CleanInvalidSeed(_PluginBase):
source_paths = []
total_size = 0
deleted_file_cnt = 0
exclude_key_words = self._exclude_keywords.split("\n")
exclude_key_words = self._exclude_keywords.split("\n") if self._exclude_keywords else []
if not self._download_dirs:
logger.error("未配置下载目录,无法检测未做种无效源文件")
self.post_message(
mtype=NotificationType.SiteMessage,
title=f"【检测无效源文件】",
text="未配置下载目录,无法检测未做种无效源文件",
)
return
for path in self._download_dirs.split("\n"):
mp_path, qb_path = path.split(":")
source_path_map[mp_path] = qb_path
@@ -489,6 +528,7 @@ class CleanInvalidSeed(_PluginBase):
message += f"***已删除无效源文件,释放{StringUtils.str_filesize(total_size)}空间!***\n"
logger.info(message)
if self._notify:
message = message.replace('_', '\_')
self.post_message(
mtype=NotificationType.SiteMessage,
title=f"【清理无效做种】",
@@ -754,3 +794,23 @@ class CleanInvalidSeed(_PluginBase):
self._scheduler = None
except Exception as e:
logger.error("退出插件失败:%s" % str(e))
if __name__ == "__main__":
clean = CleanInvalidSeed()
config = {
"enabled": True,
"notify": True,
"download_dirs": "/sata16t/春天:/保种/春天\n/sata16t/观众:/保种/观众\n/sata16t/UB:/保种/UB\n/sata16t/听听歌:/保种/听听歌\n/ssd/Download/shualiu:/Downloads/shualiu",
"delete_invalid_torrents": False,
"delete_invalid_files": False,
"detect_invalid_files": True,
"notify_all": False,
"onlyonce": False,
"cron": "0 0 * * *",
"exclude_keywords": "ABF-075\nIPZZ-002-C_GG5\nIPZZ-061\n.!qB",
"exclude_categories": "电影",
"exclude_labels": "春天",
}
clean.init_plugin(config)
clean.clean_invalid_seed()

View File

@@ -294,7 +294,8 @@ class CrossSeed(_PluginBase):
for site_key in self._token.strip().split("\n"):
site_key_arr = re.split(r"[\s:]+", site_key.strip())
site_name = site_key_arr[0]
site_name_key_map[site_name] = site_key_arr[1]
if len(site_key_arr) > 1:
site_name_key_map[site_name] = site_key_arr[1]
if len(site_key_arr) > 2:
if str.isdigit(site_key_arr[2]):
site_name_gap_map[site_name] = int(site_key_arr[2])

View File

@@ -0,0 +1,250 @@
from datetime import datetime
from functools import lru_cache
from typing import List, Tuple, Dict, Any, Optional
from app.plugins import _PluginBase
from app.utils.http import RequestUtils
class DailyWord(_PluginBase):
# 插件名称
plugin_name = "每日一言"
# 插件描述
plugin_desc = "在仪表板中显示每日一言卡片。"
# 插件图标
plugin_icon = "Calibre_B.png"
# 插件版本
plugin_version = "1.1"
# 插件作者
plugin_author = "jxxghp"
# 作者主页
author_url = "https://github.com/jxxghp"
# 插件配置项ID前缀
plugin_config_prefix = "dailyowrd_"
# 加载顺序
plugin_order = 99
# 可使用的用户级别
auth_level = 1
_enable: bool = False
_size: str = "mini"
def init_plugin(self, config: dict = None):
self._enable = config.get("enable")
self._size = config.get("size")
@staticmethod
def get_command() -> List[Dict[str, Any]]:
pass
def get_api(self) -> List[Dict[str, Any]]:
pass
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
return [
{
'component': 'VForm',
'content': [
{
'component': 'VRow',
'content': [
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 6
},
'content': [
{
'component': 'VSwitch',
'props': {
'model': 'enable',
'label': '启用插件',
}
}
]
}
]
},
{
'component': 'VRow',
'content': [
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
{
'component': 'VSelect',
'props': {
'model': 'size',
'label': '组件规格',
'items': [
{"title": "迷你", "value": "mini"},
{"title": "小型", "value": "small"},
{"title": "中型", "value": "medium"},
{"title": "大型", "value": "large"}
]
}
}
]
}
]
}
]
}
], {
"enable": self._enable,
"size": self._size
}
def get_page(self) -> List[dict]:
pass
def get_dashboard_meta(self) -> Optional[List[Dict[str, str]]]:
"""
获取插件仪表盘元信息
返回示例:
[{
"key": "dashboard1", // 仪表盘的key在当前插件范围唯一
"name": "仪表盘1" // 仪表盘的名称
}, {
"key": "dashboard2",
"name": "仪表盘2"
}]
"""
return [{
"key": "dailyword_dashboard",
"name": "每日一言"
}]
@lru_cache(maxsize=1)
def __get_youngam(self, **kwargs) -> Optional[dict]:
"""
获取每日一言缓存12小时
"""
res = RequestUtils().get_res("https://apier.youngam.cn/essay/one")
if res:
datalist = res.json().get("dataList")
return datalist[0] if datalist else {}
return {}
def get_dashboard(self, key: str = None, **kwargs) -> Optional[Tuple[Dict[str, Any], Dict[str, Any], List[dict]]]:
"""
获取插件仪表盘页面需要返回1、仪表板col配置字典2、全局配置自动刷新等3、仪表板页面元素配置json含数据
1、col配置参考
{
"cols": 12, "md": 6
}
2、全局配置参考
{
"refresh": 10 // 自动刷新时间,单位秒
}
3、页面配置使用Vuetify组件拼装参考https://vuetifyjs.com/
"""
# 列配置
if self._size == "mini":
cols = {
"cols": 12,
"md": 4
}
height = 160
elif self._size == "small":
cols = {
"cols": 12,
"md": 6
}
height = 262
elif self._size == "medium":
cols = {
"cols": 12,
"md": 8
}
height = 335
else:
cols = {
"cols": 12,
"md": 12
}
height = 500
# 全局配置
attrs = {
"border": False
}
# 获取流行越势数据
data = self.__get_youngam(today=datetime.now().strftime("%Y-%m-%d"))
if not data:
elements = [
{
'component': 'VCard',
'content': [
{
'component': 'VCardText',
'props': {
'class': 'text-center',
},
'content': [
{
'component': 'span',
'props': {
'class': 'text-h6'
},
'text': '无数据'
}
]
}
]
}
]
else:
elements = [
{
'component': 'VCard',
'props': {
'class': 'p-0'
},
'content': [
{
'component': 'VImg',
'props': {
'src': data.get('src'),
'cover': True,
'height': height
},
'content': [
{
'component': 'VCardText',
'props': {
'class': 'w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 pa-4',
},
'content': [
{
'component': 'h1',
'props': {
'class': 'mb-1 text-white text-shadow text-xl line-clamp-4 overflow-hidden text-ellipsis ...'
},
'html': data.get('text'),
},
{
'component': 'span',
'props': {
'class': 'text-right text-shadow line-clamp-2 overflow-hidden text-ellipsis ...'
},
'text': f"{data.get('year')}{data.get('month')}{data.get('day')}",
}
]
}
]
}
]
}]
return cols, attrs, elements
def get_state(self) -> bool:
return self._enable
def stop_service(self):
pass

View File

@@ -59,7 +59,7 @@ class DirMonitor(_PluginBase):
# 插件图标
plugin_icon = "directory.png"
# 插件版本
plugin_version = "2.0"
plugin_version = "2.2"
# 插件作者
plugin_author = "jxxghp"
# 作者主页
@@ -83,10 +83,11 @@ class DirMonitor(_PluginBase):
_onlyonce = False
_cron = None
_size = 0
_scrape = True
# 模式 compatibility/fast
_mode = "fast"
# 转移方式
_transfer_type = settings.TRANSFER_TYPE
_transfer_type = "link"
_monitor_dirs = ""
_exclude_keywords = ""
_interval: int = 10
@@ -119,6 +120,7 @@ class DirMonitor(_PluginBase):
self._interval = config.get("interval") or 10
self._cron = config.get("cron")
self._size = config.get("size") or 0
self._scrape = config.get("scrape") or False
# 停止现有任务
self.stop_service()
@@ -235,7 +237,8 @@ class DirMonitor(_PluginBase):
"exclude_keywords": self._exclude_keywords,
"interval": self._interval,
"cron": self._cron,
"size": self._size
"size": self._size,
"scrape": self._scrape
})
@eventmanager.register(EventType.PluginAction)
@@ -457,7 +460,7 @@ class DirMonitor(_PluginBase):
)
# 刮削单个文件
if settings.SCRAP_METADATA:
if self._scrape:
self.chain.scrape_metadata(path=transferinfo.target_path,
mediainfo=mediainfo,
transfer_type=transfer_type)
@@ -756,7 +759,7 @@ class DirMonitor(_PluginBase):
'component': 'VSelect',
'props': {
'model': 'transfer_type',
'label': '转移方式',
'label': '整理方式',
'items': [
{'title': '移动', 'value': 'move'},
{'title': '复制', 'value': 'copy'},
@@ -824,6 +827,22 @@ class DirMonitor(_PluginBase):
}
}
]
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
{
'component': 'VSwitch',
'props': {
'model': 'scrape',
'label': '刮削元数据',
}
}
]
}
]
},
@@ -844,9 +863,9 @@ class DirMonitor(_PluginBase):
'rows': 5,
'placeholder': '每一行一个目录,支持以下几种配置方式,转移方式支持 move、copy、link、softlink、rclone_copy、rclone_move\n'
'监控目录\n'
'监控目录#转移方式\n'
'监控目录:转移目的目录\n'
'监控目录:转移目的目录#转移方式'
'监控目录#整理方式\n'
'监控目录:整理目的目录\n'
'监控目录:整理目的目录#转移方式'
}
}
]
@@ -889,7 +908,7 @@ class DirMonitor(_PluginBase):
'props': {
'type': 'info',
'variant': 'tonal',
'text': '监控目录不指定目的目录时,将转移到媒体库目录,并自动创建一级分类目录,同时按配置创建二级分类目录;监控目录指定了目的目录时,不会自动创建一级目录,但会根据配置创建二级分类目录'
'text': '支持4种配置方式1、监控目录2、监控目录#整理方式3、监控目录:整理目的目录4、监控目录:整理目的目录#转移方式。监控目录不指定目的目录时,将按媒体库目录设置整理到媒体库目录,并根据目录的分类设置自动创建一二级分类目录;监控目录指定了目的目录时,会尝试在媒体库目录设定中查找对应路径的目录配置,如存在则以目录设定的分类选项创建子目录,否则直接整理到该目的目录下。建议不设置目的目录,由系统根据目录设定自动分类整理'
}
}
]
@@ -945,12 +964,13 @@ class DirMonitor(_PluginBase):
"notify": False,
"onlyonce": False,
"mode": "fast",
"transfer_type": settings.TRANSFER_TYPE,
"transfer_type": "link",
"monitor_dirs": "",
"exclude_keywords": "",
"interval": 10,
"cron": "",
"size": 0
"size": 0,
"scrape": True
}
def get_page(self) -> List[dict]:

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,10 @@ class Downloader(Enum):
self.short_name: str = short_name
# Downloader 映射
DownloaderMap = dict((d.id, d) for d in Downloader)
class TaskResult:
"""
任务执行结果
@@ -304,3 +308,20 @@ class TorrentField(Enum):
# TorrentField 映射
TorrentFieldMap = dict((field.name, field) for field in TorrentField)
class DownloaderTransferInfo():
"""
下载器传输信息
"""
# 下载速度
download_speed: Optional[str] = '0.00B/s'
# 上传速度
upload_speed: Optional[str] = '0.00B/s'
# 下载量
download_size: Optional[str] = '0.00B'
# 上传量
upload_size: Optional[str] = '0.00B'
# 剩余空间
free_space: Optional[str] = '0.00B'

View File

@@ -25,7 +25,7 @@ class LibraryScraper(_PluginBase):
# 插件图标
plugin_icon = "scraper.png"
# 插件版本
plugin_version = "1.4"
plugin_version = "1.4.1"
# 插件作者
plugin_author = "jxxghp"
# 作者主页
@@ -410,14 +410,14 @@ class LibraryScraper(_PluginBase):
"uniqueid[@type='TMDB']",
"tmdbid"
]
reader = NfoReader(file_path)
for xpath in xpaths:
try:
try:
reader = NfoReader(file_path)
for xpath in xpaths:
tmdbid = reader.get_element_value(xpath)
if tmdbid:
return tmdbid
except Exception as err:
print(str(err))
except Exception as err:
logger.warn(f"从nfo文件中获取tmdbid失败{str(err)}")
return None
def stop_service(self):

View File

@@ -17,9 +17,6 @@ from app.db.models.transferhistory import TransferHistory
from app.log import logger
from app.modules.emby import Emby
from app.modules.jellyfin import Jellyfin
from app.modules.qbittorrent import Qbittorrent
from app.modules.themoviedb.tmdbv3api import Episode
from app.modules.transmission import Transmission
from app.plugins import _PluginBase
from app.schemas.types import NotificationType, EventType, MediaType, MediaImageType
@@ -32,7 +29,7 @@ class MediaSyncDel(_PluginBase):
# 插件图标
plugin_icon = "mediasyncdel.png"
# 插件版本
plugin_version = "1.5"
plugin_version = "1.6"
# 插件作者
plugin_author = "thsrite"
# 作者主页
@@ -45,7 +42,6 @@ class MediaSyncDel(_PluginBase):
auth_level = 1
# 私有属性
episode = None
_scheduler: Optional[BackgroundScheduler] = None
_enabled = False
_sync_type: str = ""
@@ -58,16 +54,11 @@ class MediaSyncDel(_PluginBase):
_transferchain = None
_transferhis = None
_downloadhis = None
qb = None
tr = None
def init_plugin(self, config: dict = None):
self._transferchain = TransferChain()
self._transferhis = self._transferchain.transferhis
self._downloadhis = self._transferchain.downloadhis
self.episode = Episode()
self.qb = Qbittorrent()
self.tr = Transmission()
# 停止现有任务
self.stop_service()
@@ -1199,12 +1190,8 @@ class MediaSyncDel(_PluginBase):
# 删除转种后任务
logger.info(f"删除转种后下载任务:{download} - {download_id}")
# 删除转种后下载任务
if download == "transmission":
self.tr.delete_torrents(delete_file=True,
ids=download_id)
else:
self.qb.delete_torrents(delete_file=True,
ids=download_id)
self.chain.remove_torrents(hashs=torrent_hash,
downloader=download)
handle_torrent_hashs.append(download_id)
else:
# 暂停种子
@@ -1219,10 +1206,7 @@ class MediaSyncDel(_PluginBase):
logger.info(f"暂停转种后下载任务:{download} - {download_id}")
# 删除转种后下载任务
if download == "transmission":
self.tr.stop_torrents(ids=download_id)
else:
self.qb.stop_torrents(ids=download_id)
self.chain.stop_torrents(hashs=download_id, downloader=download)
handle_torrent_hashs.append(download_id)
else:
# 未转种de情况
@@ -1237,8 +1221,7 @@ class MediaSyncDel(_PluginBase):
handle_torrent_hashs.append(download_id)
# 处理辅种
handle_torrent_hashs = self.__del_seed(download=download,
download_id=download_id,
handle_torrent_hashs = self.__del_seed(download_id=download_id,
delete_flag=delete_flag,
handle_torrent_hashs=handle_torrent_hashs)
# 处理合集
@@ -1284,27 +1267,19 @@ class MediaSyncDel(_PluginBase):
# 删除合集种子
if delete_flag:
if str(download_file.downloader) == "transmission":
self.tr.delete_torrents(delete_file=True,
ids=download_file.download_hash)
else:
self.qb.delete_torrents(delete_file=True,
ids=download_file.download_hash)
self.chain.remove_torrents(hashs=download_file.download_hash,
downloader=download_file.downloader)
logger.info(f"删除合集种子 {download_file.downloader} {download_file.download_hash}")
else:
# 暂停合集种子
if str(download_file.downloader) == "transmission":
self.tr.stop_torrents(ids=download_file.download_hash)
else:
self.qb.stop_torrents(ids=download_file.download_hash)
self.chain.stop_torrents(hashs=download_file.download_hash,
downloader=download_file.downloader)
logger.info(f"暂停合集种子 {download_file.downloader} {download_file.download_hash}")
# 已处理种子+1
handle_torrent_hashs.append(download_file.download_hash)
# 处理合集辅种
handle_torrent_hashs = self.__del_seed(download=download_file.downloader,
download_id=download_file.download_hash,
handle_torrent_hashs = self.__del_seed(download_id=download_file.download_hash,
delete_flag=delete_flag,
handle_torrent_hashs=handle_torrent_hashs)
except Exception as e:
@@ -1313,7 +1288,7 @@ class MediaSyncDel(_PluginBase):
return handle_torrent_hashs
def __del_seed(self, download, download_id, delete_flag, handle_torrent_hashs):
def __del_seed(self, download_id, delete_flag, handle_torrent_hashs):
"""
删除辅种
"""
@@ -1337,30 +1312,18 @@ class MediaSyncDel(_PluginBase):
# 删除辅种历史
for torrent in torrents:
handle_torrent_hashs.append(torrent)
if str(download) == "qbittorrent":
# 删除辅种
if delete_flag:
logger.info(f"删除辅种:{downloader} - {torrent}")
self.qb.delete_torrents(delete_file=True,
ids=torrent)
# 暂停辅种
else:
self.qb.stop_torrents(ids=torrent)
logger.info(f"辅种:{downloader} - {torrent} 暂停")
# 删除辅种
if delete_flag:
logger.info(f"删除辅种:{downloader} - {torrent}")
self.chain.remove_torrents(hashs=torrent,
downloader=downloader)
# 暂停辅种
else:
# 删除辅种
if delete_flag:
logger.info(f"删除辅种:{downloader} - {torrent}")
self.tr.delete_torrents(delete_file=True,
ids=torrent)
# 暂停辅种
else:
self.tr.stop_torrents(ids=torrent)
logger.info(f"辅种:{downloader} - {torrent} 暂停")
self.chain.stop_torrents(hashs=torrent, download=downloader)
logger.info(f"辅种:{downloader} - {torrent} 暂停")
# 处理辅种的辅种
handle_torrent_hashs = self.__del_seed(download=downloader,
download_id=torrent,
handle_torrent_hashs = self.__del_seed(download_id=torrent,
delete_flag=delete_flag,
handle_torrent_hashs=handle_torrent_hashs)

View File

@@ -12,6 +12,7 @@ from app.helper.plugin import PluginHelper
from app.log import logger
from app.plugins import _PluginBase
from app.scheduler import Scheduler
from app.schemas import NotificationType
from app.schemas.types import SystemConfigKey
@@ -23,7 +24,7 @@ class PluginAutoUpgrade(_PluginBase):
# 插件图标
plugin_icon = "PluginAutoUpgrade.png"
# 插件版本
plugin_version = "1.8"
plugin_version = "1.9"
# 插件作者
plugin_author = "hotlcc"
# 作者主页
@@ -665,7 +666,7 @@ class PluginAutoUpgrade(_PluginBase):
text = self.__build_notify_message(results=results)
if not text:
return
self.post_message(title=f'{self.plugin_name}任务执行结果', text=text)
self.post_message(title=f'{self.plugin_name}任务执行结果', text=text, mtype=NotificationType.Plugin)
@staticmethod
def __build_notify_message(results: List[Dict[str, Any]]) -> str:

View File

@@ -19,6 +19,7 @@ from app.core.metainfo import MetaInfo
from app.helper.rss import RssHelper
from app.log import logger
from app.plugins import _PluginBase
from app.schemas import ExistMediaInfo
from app.schemas.types import SystemConfigKey, MediaType
lock = Lock()
@@ -32,7 +33,7 @@ class RssSubscribe(_PluginBase):
# 插件图标
plugin_icon = "rss.png"
# 插件版本
plugin_version = "1.3"
plugin_version = "1.4"
# 插件作者
plugin_author = "jxxghp"
# 作者主页
@@ -656,51 +657,49 @@ class RssSubscribe(_PluginBase):
if not result:
logger.info(f"{title} {description} 不匹配过滤规则")
continue
# 查询缺失的媒体信息
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=meta, mediainfo=mediainfo)
if exist_flag:
logger.info(f'{mediainfo.title_year} 媒体库中已存在')
# 媒体库已存在的剧集
exist_info: Optional[ExistMediaInfo] = self.chain.media_exists(mediainfo=mediainfo)
if mediainfo.type == MediaType.TV:
if exist_info:
exist_season = exist_info.seasons
if exist_season:
exist_episodes = exist_season.get(meta.begin_season)
if exist_episodes and set(meta.episode_list).issubset(set(exist_episodes)):
logger.info(f'{mediainfo.title_year} {meta.season_episode} 己存在')
continue
elif exist_info:
# 电影已存在
logger.info(f'{mediainfo.title_year} 己存在')
continue
# 下载或订阅
if self._action == "download":
# 添加下载
result = self.downloadchain.download_single(
context=Context(
meta_info=meta,
media_info=mediainfo,
torrent_info=torrentinfo,
),
save_path=self._save_path,
username="RSS订阅"
)
if not result:
logger.error(f'{title} 下载失败')
continue
else:
if self._action == "download":
if mediainfo.type == MediaType.TV:
if no_exists:
exist_info = no_exists.get(mediainfo.tmdb_id)
season_info = exist_info.get(meta.begin_season or 1)
if not season_info:
logger.info(f'{mediainfo.title_year} {meta.season} 己存在')
continue
if (season_info.episodes
and not set(meta.episode_list).issubset(set(season_info.episodes))):
logger.info(f'{mediainfo.title_year} {meta.season_episode} 己存在')
continue
# 添加下载
result = self.downloadchain.download_single(
context=Context(
meta_info=meta,
media_info=mediainfo,
torrent_info=torrentinfo,
),
save_path=self._save_path,
username="RSS订阅"
)
if not result:
logger.error(f'{title} 下载失败')
continue
else:
# 检查是否在订阅中
subflag = self.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订阅")
# 检查是否在订阅中
subflag = self.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订阅")
# 存储历史记录
history.append({
"title": f"{mediainfo.title} {meta.season}",

View File

@@ -10,7 +10,7 @@ class TrendingShow(_PluginBase):
# 插件描述
plugin_desc = "在仪表板中显示流行趋势海报轮播图。"
# 插件图标
plugin_icon = "Dsphoto_A.png"
plugin_icon = "TrendingShow.jpg"
# 插件版本
plugin_version = "1.0"
# 插件作者
@@ -183,7 +183,7 @@ class TrendingShow(_PluginBase):
'show-arrows': 'hover',
'hide-delimiters': True,
'cycle': True,
'interval': 5000,
'interval': 10000,
'height': height
},
'content': [
@@ -197,7 +197,7 @@ class TrendingShow(_PluginBase):
{
'component': 'VCardText',
'props': {
'class': 'w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 cursor-pointer pa-4',
'class': 'w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 pa-4',
},
'content': [
{

View File

@@ -77,7 +77,7 @@ class VCBAnimeMonitor(_PluginBase):
# 插件图标
plugin_icon = "vcbmonitor.png"
# 插件版本
plugin_version = "1.7.1"
plugin_version = "1.8"
# 插件作者
plugin_author = "pixel@qingwa"
# 作者主页
@@ -106,6 +106,7 @@ class VCBAnimeMonitor(_PluginBase):
_onlyonce = False
_cron = None
_size = 0
_scrape = True
# 模式 compatibility/fast
_mode = "fast"
# 转移方式
@@ -142,6 +143,7 @@ class VCBAnimeMonitor(_PluginBase):
self._interval = config.get("interval") or 10
self._cron = config.get("cron")
self._size = config.get("size") or 0
self._scrape = config.get("scrape")
self._switch_ova = config.get("ova")
self._high_mode = config.get("high_mode")
self._torrents_path = config.get("torrents_path") or ""
@@ -286,6 +288,7 @@ class VCBAnimeMonitor(_PluginBase):
"interval": self._interval,
"cron": self._cron,
"size": self._size,
"scrape": self._scrape,
"ova": self._switch_ova,
"high_mode": self._high_mode,
"torrents_path": self._torrents_path
@@ -508,7 +511,7 @@ class VCBAnimeMonitor(_PluginBase):
)
# 刮削单个文件
if settings.SCRAP_METADATA:
if self._scrape:
self.chain.scrape_metadata(path=transferinfo.target_path,
mediainfo=mediainfo,
transfer_type=transfer_type)
@@ -826,6 +829,22 @@ class VCBAnimeMonitor(_PluginBase):
}
]
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
{
'component': 'VSwitch',
'props': {
'model': 'scrape',
'label': '刮削元数据',
}
}
]
}
]
},
{