mirror of
https://github.com/jxxghp/MoviePilot-Plugins.git
synced 2026-03-27 10:05:57 +00:00
feat:插件移植公共定时服务
This commit is contained in:
56
package.json
56
package.json
@@ -2,7 +2,7 @@
|
||||
"AutoSignIn": {
|
||||
"name": "站点自动签到",
|
||||
"description": "自动模拟登录站点、签到。",
|
||||
"version": "1.3.1",
|
||||
"version": "1.4",
|
||||
"icon": "signin.png",
|
||||
"author": "thsrite",
|
||||
"level": 2
|
||||
@@ -18,7 +18,7 @@
|
||||
"SiteStatistic": {
|
||||
"name": "站点数据统计",
|
||||
"description": "自动统计和展示站点数据。",
|
||||
"version": "1.6",
|
||||
"version": "1.7",
|
||||
"icon": "statistic.png",
|
||||
"author": "lightolly",
|
||||
"level": 2
|
||||
@@ -26,7 +26,7 @@
|
||||
"SiteRefresh": {
|
||||
"name": "站点自动更新",
|
||||
"description": "使用浏览器模拟登录站点获取Cookie和UA。",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "Chrome_A.png",
|
||||
"author": "thsrite",
|
||||
"level": 2
|
||||
@@ -34,7 +34,7 @@
|
||||
"DoubanSync": {
|
||||
"name": "豆瓣想看",
|
||||
"description": "同步豆瓣想看数据,自动添加订阅。",
|
||||
"version": "1.2",
|
||||
"version": "1.3",
|
||||
"icon": "douban.png",
|
||||
"author": "jxxghp",
|
||||
"level": 2
|
||||
@@ -42,7 +42,7 @@
|
||||
"DirMonitor": {
|
||||
"name": "目录监控",
|
||||
"description": "监控目录文件发生变化时实时整理到媒体库。",
|
||||
"version": "1.6",
|
||||
"version": "1.7",
|
||||
"icon": "directory.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
@@ -58,7 +58,7 @@
|
||||
"DoubanRank": {
|
||||
"name": "豆瓣榜单订阅",
|
||||
"description": "监控豆瓣热门榜单,自动添加订阅。",
|
||||
"version": "1.4",
|
||||
"version": "1.5",
|
||||
"icon": "movie.jpg",
|
||||
"author": "jxxghp",
|
||||
"level": 2
|
||||
@@ -66,7 +66,7 @@
|
||||
"LibraryScraper": {
|
||||
"name": "媒体库刮削",
|
||||
"description": "定时对媒体库进行刮削,补齐缺失元数据和图片。",
|
||||
"version": "1.2",
|
||||
"version": "1.3",
|
||||
"icon": "scraper.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
@@ -74,7 +74,7 @@
|
||||
"TorrentRemover": {
|
||||
"name": "自动删种",
|
||||
"description": "自动删除下载器中的下载任务。",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "delete.jpg",
|
||||
"author": "jxxghp",
|
||||
"level": 2
|
||||
@@ -82,7 +82,7 @@
|
||||
"MediaSyncDel": {
|
||||
"name": "媒体文件同步删除",
|
||||
"description": "同步删除历史记录、源文件和下载任务。",
|
||||
"version": "1.2",
|
||||
"version": "1.3",
|
||||
"icon": "mediasyncdel.png",
|
||||
"author": "thsrite",
|
||||
"level": 1
|
||||
@@ -98,7 +98,7 @@
|
||||
"SpeedLimiter": {
|
||||
"name": "播放限速",
|
||||
"description": "外网播放媒体库视频时,自动对下载器进行限速。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "Librespeed_A.png",
|
||||
"author": "Shurelol",
|
||||
"level": 1
|
||||
@@ -106,7 +106,7 @@
|
||||
"CloudflareSpeedTest": {
|
||||
"name": "Cloudflare IP优选",
|
||||
"description": "🌩 测试 Cloudflare CDN 延迟和速度,自动优选IP。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "cloudflare.jpg",
|
||||
"author": "thsrite",
|
||||
"level": 1
|
||||
@@ -114,7 +114,7 @@
|
||||
"BestFilmVersion": {
|
||||
"name": "收藏洗版",
|
||||
"description": "Jellyfin/Emby/Plex点击收藏电影后,自动订阅洗版。",
|
||||
"version": "2.0",
|
||||
"version": "2.1",
|
||||
"icon": "like.jpg",
|
||||
"author": "wlj",
|
||||
"level": 2
|
||||
@@ -130,7 +130,7 @@
|
||||
"MediaServerRefresh": {
|
||||
"name": "媒体库服务器刷新",
|
||||
"description": "入库后自动刷新Emby/Jellyfin/Plex服务器海报墙。",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "refresh2.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
@@ -170,7 +170,7 @@
|
||||
"AutoBackup": {
|
||||
"name": "自动备份",
|
||||
"description": "自动备份数据和配置文件。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "Time_machine_B.png",
|
||||
"author": "thsrite",
|
||||
"level": 1
|
||||
@@ -178,7 +178,7 @@
|
||||
"IYUUAutoSeed": {
|
||||
"name": "IYUU自动辅种",
|
||||
"description": "基于IYUU官方Api实现自动辅种。",
|
||||
"version": "1.2",
|
||||
"version": "1.3",
|
||||
"icon": "IYUU.png",
|
||||
"author": "jxxghp",
|
||||
"level": 2
|
||||
@@ -186,7 +186,7 @@
|
||||
"TorrentTransfer": {
|
||||
"name": "自动转移做种",
|
||||
"description": "定期转移下载器中的做种任务到另一个下载器。",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "seed.png",
|
||||
"author": "jxxghp",
|
||||
"level": 2
|
||||
@@ -194,7 +194,7 @@
|
||||
"RssSubscribe": {
|
||||
"name": "自定义订阅",
|
||||
"description": "定时刷新RSS报文,识别内容后添加订阅或直接下载。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "rss.png",
|
||||
"author": "jxxghp",
|
||||
"level": 2
|
||||
@@ -202,7 +202,7 @@
|
||||
"SyncDownloadFiles": {
|
||||
"name": "下载器文件同步",
|
||||
"description": "同步下载器的文件信息到数据库,删除文件时联动删除下载任务。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "Youtube-dl_A.png",
|
||||
"author": "thsrite",
|
||||
"level": 1
|
||||
@@ -210,7 +210,7 @@
|
||||
"BrushFlow": {
|
||||
"name": "站点刷流",
|
||||
"description": "自动托管刷流,将会提高对应站点的访问频率。",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "brush.jpg",
|
||||
"author": "jxxghp",
|
||||
"level": 2
|
||||
@@ -218,7 +218,7 @@
|
||||
"DownloadingMsg": {
|
||||
"name": "下载进度推送",
|
||||
"description": "定时推送正在下载进度。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "downloadmsg.png",
|
||||
"author": "thsrite",
|
||||
"level": 2
|
||||
@@ -226,7 +226,7 @@
|
||||
"AutoClean": {
|
||||
"name": "定时清理媒体库",
|
||||
"description": "定时清理用户下载的种子、源文件、媒体库文件。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "clean.png",
|
||||
"author": "thsrite",
|
||||
"level": 2
|
||||
@@ -234,7 +234,7 @@
|
||||
"InvitesSignin": {
|
||||
"name": "药丸签到",
|
||||
"description": "药丸论坛签到。",
|
||||
"version": "1.2",
|
||||
"version": "1.3",
|
||||
"icon": "invites.png",
|
||||
"author": "thsrite",
|
||||
"level": 2
|
||||
@@ -242,7 +242,7 @@
|
||||
"PersonMeta": {
|
||||
"name": "演职人员刮削",
|
||||
"description": "刮削演职人员图片以及中文名称。",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "actor.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
@@ -250,7 +250,7 @@
|
||||
"MoviePilotUpdateNotify": {
|
||||
"name": "MoviePilot更新推送",
|
||||
"description": "MoviePilot推送release更新通知、自动重启。",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "Moviepilot_A.png",
|
||||
"author": "thsrite",
|
||||
"level": 1
|
||||
@@ -306,7 +306,7 @@
|
||||
"EpisodeGroupMeta": {
|
||||
"name": "TMDB剧集组刮削",
|
||||
"description": "从TMDB剧集组刮削季集的实际顺序",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"icon": "Element_A.png",
|
||||
"author": "叮叮当",
|
||||
"level": 1
|
||||
@@ -338,7 +338,7 @@
|
||||
"DownloadSiteTag": {
|
||||
"name": "下载任务分类与标签",
|
||||
"description": "自动给下载任务分类与打站点标签、剧集名称标签",
|
||||
"version": "1.7",
|
||||
"version": "1.8",
|
||||
"icon": "Youtube-dl_B.png",
|
||||
"author": "叮叮当",
|
||||
"level": 1
|
||||
@@ -346,7 +346,7 @@
|
||||
"RemoveLink": {
|
||||
"name": "清理硬链接",
|
||||
"description": "监控目录内文件被删除时,同步删除监控目录内所有和它硬链接的文件",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "Ombi_A.png",
|
||||
"author": "DzAvril",
|
||||
"level": 1
|
||||
@@ -354,7 +354,7 @@
|
||||
"LinkMonitor": {
|
||||
"name": "实时硬链接",
|
||||
"description": "监控目录文件变化,实时硬链接。",
|
||||
"version": "1.2",
|
||||
"version": "1.3",
|
||||
"icon": "Linkace_C.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
|
||||
@@ -25,7 +25,7 @@ class AutoBackup(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Time_machine_B.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -60,32 +60,21 @@ class AutoBackup(_PluginBase):
|
||||
self._onlyonce = config.get("onlyonce")
|
||||
|
||||
# 加载模块
|
||||
if self._enabled:
|
||||
# 定时服务
|
||||
if self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__backup,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="自动备份")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
|
||||
if self._onlyonce:
|
||||
logger.info(f"自动备份服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__backup, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="自动备份")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.update_config({
|
||||
"onlyonce": False,
|
||||
"cron": self._cron,
|
||||
"enabled": self._enabled,
|
||||
"cnt": self._cnt,
|
||||
"notify": self._notify,
|
||||
})
|
||||
logger.info(f"自动备份服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__backup, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="自动备份")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.update_config({
|
||||
"onlyonce": False,
|
||||
"cron": self._cron,
|
||||
"enabled": self._enabled,
|
||||
"cnt": self._cnt,
|
||||
"notify": self._notify,
|
||||
})
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
@@ -186,6 +175,26 @@ class AutoBackup(_PluginBase):
|
||||
"description": "MoviePilot备份",
|
||||
}]
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "AutoBackup",
|
||||
"name": "自动备份定时服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.__backup,
|
||||
"kwargs": {}
|
||||
}]
|
||||
|
||||
def backup(self) -> schemas.Response:
|
||||
"""
|
||||
API调用备份
|
||||
|
||||
@@ -27,7 +27,7 @@ class AutoClean(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "clean.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -72,18 +72,10 @@ class AutoClean(_PluginBase):
|
||||
if self._enabled:
|
||||
self._downloadhis = DownloadHistoryOper()
|
||||
self._transferhis = TransferHistoryOper()
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__clean,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="定时清理媒体库")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
|
||||
if self._onlyonce:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info(f"定时清理媒体库服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__clean, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
@@ -100,10 +92,10 @@ class AutoClean(_PluginBase):
|
||||
"notify": self._notify,
|
||||
})
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def __get_clean_date(self, deltatime: str = None):
|
||||
# 清理日期
|
||||
@@ -263,6 +255,28 @@ class AutoClean(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [
|
||||
{
|
||||
"id": "AutoClean",
|
||||
"name": "清理媒体库定时服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.__clean,
|
||||
"kwargs": {}
|
||||
}
|
||||
]
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -36,7 +36,7 @@ class AutoSignIn(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "signin.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.3.1"
|
||||
plugin_version = "1.4"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -107,11 +107,10 @@ class AutoSignIn(_PluginBase):
|
||||
self._site_schema = ModuleHelper.load('app.plugins.autosignin.sites',
|
||||
filter_func=lambda _, obj: hasattr(obj, 'match'))
|
||||
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
# 立即运行一次
|
||||
if self._onlyonce:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info("站点自动签到服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.sign_in, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
@@ -122,75 +121,10 @@ class AutoSignIn(_PluginBase):
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
# 周期运行
|
||||
if self._enabled:
|
||||
if self._cron:
|
||||
try:
|
||||
if str(self._cron).strip().count(" ") == 4:
|
||||
self._scheduler.add_job(func=self.sign_in,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="站点自动签到")
|
||||
logger.info(f"站点自动签到服务启动,执行周期 {self._cron}")
|
||||
else:
|
||||
# 2.3/9-23
|
||||
crons = str(self._cron).strip().split("/")
|
||||
if len(crons) == 2:
|
||||
# 2.3
|
||||
cron = crons[0]
|
||||
# 9-23
|
||||
times = crons[1].split("-")
|
||||
if len(times) == 2:
|
||||
# 9
|
||||
self._start_time = int(times[0])
|
||||
# 23
|
||||
self._end_time = int(times[1])
|
||||
if self._start_time and self._end_time:
|
||||
self._scheduler.add_job(func=self.sign_in,
|
||||
trigger="interval",
|
||||
hours=float(str(cron).strip()),
|
||||
name="站点自动签到")
|
||||
logger.info(
|
||||
f"站点自动签到服务启动,执行周期 {self._start_time}点-{self._end_time}点 每{cron}小时执行一次")
|
||||
else:
|
||||
logger.error("站点自动签到服务启动失败,周期格式错误")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误")
|
||||
self._cron = ""
|
||||
self._enabled = False
|
||||
self.__update_config()
|
||||
else:
|
||||
# 默认0-24 按照周期运行
|
||||
self._start_time = 0
|
||||
self._end_time = 24
|
||||
self._scheduler.add_job(func=self.sign_in,
|
||||
trigger="interval",
|
||||
hours=float(str(self._cron).strip()),
|
||||
name="站点自动签到")
|
||||
logger.info(
|
||||
f"站点自动签到服务启动,执行周期 {self._start_time}点-{self._end_time}点 每{self._cron}小时执行一次")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
self._cron = ""
|
||||
self._enabled = False
|
||||
self.__update_config()
|
||||
else:
|
||||
# 随机时间
|
||||
triggers = TimerUtils.random_scheduler(num_executions=2,
|
||||
begin_hour=9,
|
||||
end_hour=23,
|
||||
max_interval=6 * 60,
|
||||
min_interval=2 * 60)
|
||||
for trigger in triggers:
|
||||
self._scheduler.add_job(self.sign_in, "cron",
|
||||
hour=trigger.hour, minute=trigger.minute,
|
||||
name="站点自动签到")
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
@@ -246,6 +180,87 @@ class AutoSignIn(_PluginBase):
|
||||
"description": "使用站点域名签到站点",
|
||||
}]
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
try:
|
||||
if str(self._cron).strip().count(" ") == 4:
|
||||
return [{
|
||||
"id": "AutoSignIn",
|
||||
"name": "站点自动签到服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.sign_in,
|
||||
"kwargs": {}
|
||||
}]
|
||||
else:
|
||||
# 2.3/9-23
|
||||
crons = str(self._cron).strip().split("/")
|
||||
if len(crons) == 2:
|
||||
# 2.3
|
||||
cron = crons[0]
|
||||
# 9-23
|
||||
times = crons[1].split("-")
|
||||
if len(times) == 2:
|
||||
# 9
|
||||
self._start_time = int(times[0])
|
||||
# 23
|
||||
self._end_time = int(times[1])
|
||||
if self._start_time and self._end_time:
|
||||
return [{
|
||||
"id": "AutoSignIn",
|
||||
"name": "站点自动签到服务",
|
||||
"trigger": "interval",
|
||||
"func": self.sign_in,
|
||||
"kwargs": {
|
||||
"hours": float(str(cron).strip()),
|
||||
}
|
||||
}]
|
||||
else:
|
||||
logger.error("站点自动签到服务启动失败,周期格式错误")
|
||||
else:
|
||||
# 默认0-24 按照周期运行
|
||||
return [{
|
||||
"id": "AutoSignIn",
|
||||
"name": "站点自动签到服务",
|
||||
"trigger": "interval",
|
||||
"func": self.sign_in,
|
||||
"kwargs": {
|
||||
"hours": float(str(self._cron).strip()),
|
||||
}
|
||||
}]
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
elif self._enabled:
|
||||
# 随机时间
|
||||
triggers = TimerUtils.random_scheduler(num_executions=2,
|
||||
begin_hour=9,
|
||||
end_hour=23,
|
||||
max_interval=6 * 60,
|
||||
min_interval=2 * 60)
|
||||
ret_jobs = []
|
||||
for trigger in triggers:
|
||||
ret_jobs.append({
|
||||
"id": f"AutoSignIn|{trigger.hour}:{trigger.minute}",
|
||||
"name": "站点自动签到服务",
|
||||
"trigger": "cron",
|
||||
"func": self.sign_in,
|
||||
"kwargs": {
|
||||
"hour": trigger.hour,
|
||||
"minute": trigger.minute
|
||||
}
|
||||
})
|
||||
return ret_jobs
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -34,7 +34,7 @@ class BestFilmVersion(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "like.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "2.0"
|
||||
plugin_version = "2.1"
|
||||
# 插件作者
|
||||
plugin_author = "wlj"
|
||||
# 作者主页
|
||||
@@ -73,33 +73,19 @@ class BestFilmVersion(_PluginBase):
|
||||
self._webhook_enabled = config.get("webhook_enabled")
|
||||
self._only_once = config.get("only_once")
|
||||
|
||||
if self._enabled:
|
||||
if self._only_once:
|
||||
self._only_once = False
|
||||
self.update_config({
|
||||
"enabled": self._enabled,
|
||||
"cron": self._cron,
|
||||
"notify": self._notify,
|
||||
"webhook_enabled": self._webhook_enabled,
|
||||
"only_once": self._only_once
|
||||
})
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if not self._webhook_enabled:
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.sync,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="收藏洗版")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
else:
|
||||
self._scheduler.add_job(self.sync, "interval", minutes=30, name="收藏洗版")
|
||||
|
||||
if self._only_once:
|
||||
self._only_once = False
|
||||
self.update_config({
|
||||
"enabled": self._enabled,
|
||||
"cron": self._cron,
|
||||
"notify": self._notify,
|
||||
"webhook_enabled": self._webhook_enabled,
|
||||
"only_once": self._only_once
|
||||
})
|
||||
self._scheduler.add_job(self.sync, 'date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="立即运行收藏洗版")
|
||||
self._scheduler.add_job(self.sync, 'date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="立即运行收藏洗版")
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
@@ -124,6 +110,39 @@ class BestFilmVersion(_PluginBase):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and not self._webhook_enabled:
|
||||
if self._cron:
|
||||
return [{
|
||||
"id": "BestFilmVersion",
|
||||
"name": "收藏洗版定时服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.sync,
|
||||
"kwargs": {}
|
||||
}]
|
||||
return [
|
||||
{
|
||||
"id": "BestFilmVersion",
|
||||
"name": "收藏洗版定时服务",
|
||||
"trigger": "interval",
|
||||
"func": self.sync,
|
||||
"kwargs": {
|
||||
"minutes": 30
|
||||
}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -31,7 +31,7 @@ class BrushFlow(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "brush.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -50,8 +50,9 @@ class BrushFlow(_PluginBase):
|
||||
sites = None
|
||||
qb = None
|
||||
tr = None
|
||||
# 添加种子定时
|
||||
# 添加种子定时 分钟
|
||||
_cron = 10
|
||||
_task_enable = False
|
||||
# 检查种子定时
|
||||
_check_interval = 5
|
||||
# 退出事件
|
||||
@@ -137,6 +138,7 @@ class BrushFlow(_PluginBase):
|
||||
self.stop_service()
|
||||
|
||||
# 启动定时任务 & 立即运行一次
|
||||
self._task_enable = False
|
||||
if self.get_state() or self._onlyonce:
|
||||
self.qb = Qbittorrent()
|
||||
self.tr = Transmission()
|
||||
@@ -231,15 +233,11 @@ class BrushFlow(_PluginBase):
|
||||
return
|
||||
|
||||
# 启动任务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info(f"站点刷流服务启动,周期:{self._cron}分钟")
|
||||
try:
|
||||
self._scheduler.add_job(self.brush, 'interval', minutes=self._cron)
|
||||
except Exception as e:
|
||||
logger.error(f"站点刷流服务启动失败:{str(e)}")
|
||||
self.systemmessage.put(f"站点刷流服务启动失败:{str(e)}")
|
||||
return
|
||||
self._task_enable = True
|
||||
|
||||
# 仅一次
|
||||
if self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info(f"站点刷流服务启动,立即运行一次")
|
||||
self._scheduler.add_job(self.brush, 'date',
|
||||
run_date=datetime.now(
|
||||
@@ -249,14 +247,14 @@ class BrushFlow(_PluginBase):
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.__update_config()
|
||||
if self._scheduler.get_jobs():
|
||||
# 增加检查任务
|
||||
self._scheduler.add_job(self.check, 'interval',
|
||||
minutes=self._check_interval,
|
||||
name="站点刷流检查服务")
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
if self._scheduler.get_jobs():
|
||||
# 增加检查任务
|
||||
self._scheduler.add_job(self.check, 'interval',
|
||||
minutes=self._check_interval,
|
||||
name="站点刷流检查服务")
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return True if self._enabled and self._brushsites and self._downloader else False
|
||||
@@ -268,6 +266,27 @@ class BrushFlow(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._task_enable:
|
||||
return [{
|
||||
"id": "BrushFlow",
|
||||
"name": "站点刷流服务",
|
||||
"trigger": "interval",
|
||||
"func": self.brush,
|
||||
"kwargs": {"minutes": self._cron}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
@@ -756,26 +775,26 @@ class BrushFlow(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VAlert',
|
||||
'props': {
|
||||
'type': 'info',
|
||||
'variant': 'tonal',
|
||||
'text': '注意:排除H&R并不保证能完全适配所有站点(部分站点在列表页不显示H&R标志,但实际上是有H&R的),请注意核对使用!'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VAlert',
|
||||
'props': {
|
||||
'type': 'info',
|
||||
'variant': 'tonal',
|
||||
'text': '注意:排除H&R并不保证能完全适配所有站点(部分站点在列表页不显示H&R标志,但实际上是有H&R的),请注意核对使用!'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
], {
|
||||
@@ -1921,7 +1940,7 @@ class BrushFlow(_PluginBase):
|
||||
return len(torrents) or 0
|
||||
|
||||
@staticmethod
|
||||
def __get_pubminutes(pubdate: str) -> int:
|
||||
def __get_pubminutes(pubdate: str) -> float:
|
||||
"""
|
||||
将字符串转换为时间,并计算与当前时间差)(分钟)
|
||||
"""
|
||||
|
||||
@@ -32,7 +32,7 @@ class CloudflareSpeedTest(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "cloudflare.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -81,34 +81,25 @@ class CloudflareSpeedTest(_PluginBase):
|
||||
self._notify = config.get("notify")
|
||||
self._check = config.get("check")
|
||||
|
||||
if self.get_state() or self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
if self.get_state() and self._onlyonce:
|
||||
try:
|
||||
if self.get_state() and self._cron:
|
||||
logger.info(f"Cloudflare CDN优选服务启动,周期:{self._cron}")
|
||||
self._scheduler.add_job(func=self.__cloudflareSpeedTest,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="Cloudflare优选")
|
||||
|
||||
if self._onlyonce:
|
||||
logger.info(f"Cloudflare CDN优选服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__cloudflareSpeedTest, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="Cloudflare优选")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.__update_config()
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info(f"Cloudflare CDN优选服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__cloudflareSpeedTest, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="Cloudflare优选")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.__update_config()
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
except Exception as err:
|
||||
logger.error(f"Cloudflare CDN优选服务出错:{str(err)}")
|
||||
self.systemmessage.put(f"Cloudflare CDN优选服务出错:{str(err)}")
|
||||
return
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
@eventmanager.register(EventType.PluginAction)
|
||||
def __cloudflareSpeedTest(self, event: Event = None):
|
||||
"""
|
||||
@@ -324,9 +315,11 @@ class CloudflareSpeedTest(_PluginBase):
|
||||
install_flag = True
|
||||
|
||||
# 重装后数据库有版本数据,但是本地没有则重装
|
||||
if not install_flag and release_version == self._version and not Path(
|
||||
f'{self._cf_path}/{self._binary_name}').exists() and not Path(
|
||||
f'{self._cf_path}/CloudflareST.exe').exists():
|
||||
if not install_flag \
|
||||
and release_version == self._version \
|
||||
and not Path(
|
||||
f'{self._cf_path}/{self._binary_name}').exists() \
|
||||
and not Path(f'{self._cf_path}/CloudflareST.exe').exists():
|
||||
logger.warn(f"未检测到CloudflareSpeedTest本地版本,重新安装")
|
||||
install_flag = True
|
||||
|
||||
@@ -503,6 +496,29 @@ class CloudflareSpeedTest(_PluginBase):
|
||||
"description": "Cloudflare IP优选",
|
||||
}]
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self.get_state():
|
||||
return [
|
||||
{
|
||||
"id": "CloudflareSpeedTest",
|
||||
"name": "Cloudflare IP优选服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.__cloudflareSpeedTest,
|
||||
"kwargs": {}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -59,7 +59,7 @@ class DirMonitor(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "directory.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.6"
|
||||
plugin_version = "1.7"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -216,17 +216,6 @@ class DirMonitor(_PluginBase):
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
# 全量同步定时
|
||||
if self._enabled and self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.sync_all,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="目录监控全量同步")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
|
||||
# 启动定时服务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
@@ -643,6 +632,27 @@ class DirMonitor(_PluginBase):
|
||||
"description": "目录监控同步",
|
||||
}]
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "DirMonitor",
|
||||
"name": "目录监控全量同步服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.sync_all,
|
||||
"kwargs": {}
|
||||
}]
|
||||
return []
|
||||
|
||||
def sync(self) -> schemas.Response:
|
||||
"""
|
||||
API调用目录同步
|
||||
|
||||
@@ -27,7 +27,7 @@ class DoubanRank(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "movie.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "1.4"
|
||||
plugin_version = "1.5"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -90,28 +90,19 @@ class DoubanRank(_PluginBase):
|
||||
|
||||
# 启动服务
|
||||
if self._enabled or self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if self._cron:
|
||||
logger.info(f"豆瓣榜单订阅服务启动,周期:{self._cron}")
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__refresh_rss,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="豆瓣榜单订阅")
|
||||
except Exception as e:
|
||||
logger.error(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
|
||||
self.systemmessage.put(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
|
||||
else:
|
||||
self._scheduler.add_job(func=self.__refresh_rss, trigger=CronTrigger.from_crontab("0 8 * * *"),
|
||||
name="豆瓣榜单订阅")
|
||||
logger.info("豆瓣榜单订阅服务启动,周期:每天 08:00")
|
||||
|
||||
if self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info("豆瓣榜单订阅服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__refresh_rss, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
|
||||
if self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
if self._onlyonce or self._clear:
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
@@ -122,11 +113,6 @@ class DoubanRank(_PluginBase):
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
if self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@@ -137,6 +123,39 @@ class DoubanRank(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [
|
||||
{
|
||||
"id": "DoubanRank",
|
||||
"name": "豆瓣榜单订阅服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.__refresh_rss,
|
||||
"kwargs": {}
|
||||
}
|
||||
]
|
||||
elif self._enabled:
|
||||
return [
|
||||
{
|
||||
"id": "DoubanRank",
|
||||
"name": "豆瓣榜单订阅服务",
|
||||
"trigger": CronTrigger.from_crontab("0 8 * * *"),
|
||||
"func": self.__refresh_rss,
|
||||
"kwargs": {}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ class DoubanSync(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "douban.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.2"
|
||||
plugin_version = "1.3"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -82,27 +82,19 @@ class DoubanSync(_PluginBase):
|
||||
self._clear = config.get("clear")
|
||||
|
||||
if self._enabled or self._onlyonce:
|
||||
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.sync,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="豆瓣想看")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
else:
|
||||
self._scheduler.add_job(self.sync, "interval", minutes=30, name="豆瓣想看")
|
||||
|
||||
if self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info(f"豆瓣想看服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.sync, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
if self._onlyonce or self._clear:
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
@@ -113,11 +105,6 @@ class DoubanSync(_PluginBase):
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@@ -149,6 +136,39 @@ class DoubanSync(_PluginBase):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [
|
||||
{
|
||||
"id": "DoubanSync",
|
||||
"name": "豆瓣想看同步服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.sync,
|
||||
"kwargs": {}
|
||||
}
|
||||
]
|
||||
elif self._enabled:
|
||||
return [
|
||||
{
|
||||
"id": "DoubanSync",
|
||||
"name": "豆瓣想看同步服务",
|
||||
"trigger": "interval",
|
||||
"func": self.sync,
|
||||
"kwargs": {"minutes": 30}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from typing import Any, List, Dict, Tuple, Optional, Union
|
||||
|
||||
from app.chain.download import DownloadChain
|
||||
from app.chain.media import MediaChain
|
||||
from app.core.config import settings
|
||||
from app.core.metainfo import MetaInfo
|
||||
from app.db.downloadhistory_oper import DownloadHistoryOper
|
||||
from app.plugins import _PluginBase
|
||||
from typing import Any, List, Dict, Tuple, Optional, Union
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas import NotificationType, TransferTorrent, DownloadingTorrent
|
||||
from app.schemas.types import TorrentStatus, MessageChannel
|
||||
from app.utils.string import StringUtils
|
||||
@@ -20,7 +19,7 @@ class DownloadingMsg(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "downloadmsg.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -40,10 +39,8 @@ class DownloadingMsg(_PluginBase):
|
||||
_adminuser = None
|
||||
_downloadhis = None
|
||||
|
||||
# 定时器
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self._downloadhis = DownloadHistoryOper()
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
|
||||
@@ -53,26 +50,6 @@ class DownloadingMsg(_PluginBase):
|
||||
self._type = config.get("type") or 'admin'
|
||||
self._adminuser = config.get("adminuser")
|
||||
|
||||
# 加载模块
|
||||
if self._enabled:
|
||||
self._downloadhis = DownloadHistoryOper()
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
if self._seconds:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__downloading,
|
||||
trigger='interval',
|
||||
seconds=int(self._seconds),
|
||||
name="下载进度推送")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def __downloading(self):
|
||||
"""
|
||||
定时推送正在下载进度
|
||||
@@ -154,10 +131,10 @@ class DownloadingMsg(_PluginBase):
|
||||
channel_value = downloadhis.channel
|
||||
else:
|
||||
try:
|
||||
context = MediaChain().recognize_by_title(title=torrent.title)
|
||||
if not context or not context.media_info:
|
||||
meta = MetaInfo(torrent.title)
|
||||
media_info = MediaChain().recognize_media(meta)
|
||||
if not media_info:
|
||||
continue
|
||||
media_info = context.media_info
|
||||
year = media_info.year
|
||||
name = media_info.title
|
||||
if media_info.number_of_seasons:
|
||||
@@ -207,6 +184,31 @@ class DownloadingMsg(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._seconds:
|
||||
return [
|
||||
{
|
||||
"id": "downloading",
|
||||
"name": "下载进度推送服务",
|
||||
"trigger": "interval",
|
||||
"func": self.__downloading,
|
||||
"kwargs": {
|
||||
"seconds": int(self._seconds)
|
||||
}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
@@ -309,14 +311,4 @@ class DownloadingMsg(_PluginBase):
|
||||
pass
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
退出插件
|
||||
"""
|
||||
try:
|
||||
if self._scheduler:
|
||||
self._scheduler.remove_all_jobs()
|
||||
if self._scheduler.running:
|
||||
self._scheduler.shutdown()
|
||||
self._scheduler = None
|
||||
except Exception as e:
|
||||
logger.error("退出插件失败:%s" % str(e))
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import datetime
|
||||
import pytz
|
||||
import threading
|
||||
from typing import List, Tuple, Dict, Any
|
||||
from typing import List, Tuple, Dict, Any, Optional
|
||||
|
||||
from app.core.context import Context
|
||||
from app.core.event import eventmanager, Event
|
||||
@@ -19,6 +19,7 @@ from apscheduler.triggers.cron import CronTrigger
|
||||
from app.helper.sites import SitesHelper
|
||||
from app.utils.string import StringUtils
|
||||
|
||||
|
||||
class DownloadSiteTag(_PluginBase):
|
||||
# 插件名称
|
||||
plugin_name = "下载任务分类与标签"
|
||||
@@ -27,7 +28,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Youtube-dl_B.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.7"
|
||||
plugin_version = "1.8"
|
||||
# 插件作者
|
||||
plugin_author = "叮叮当"
|
||||
# 作者主页
|
||||
@@ -40,7 +41,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
auth_level = 1
|
||||
# 日志前缀
|
||||
LOG_TAG = "[DownloadSiteTag] "
|
||||
|
||||
|
||||
# 退出事件
|
||||
_event = threading.Event()
|
||||
# 私有属性
|
||||
@@ -86,57 +87,32 @@ class DownloadSiteTag(_PluginBase):
|
||||
if not ("interval_cron" in config):
|
||||
# 新版本v1.6更新插件配置默认配置
|
||||
config["interval"] = self._interval
|
||||
config["interval_cron"] = self._interval_cron
|
||||
config["interval_cron"] = self._interval_cron
|
||||
config["interval_time"] = self._interval_time
|
||||
config["interval_unit"] = self._interval_unit
|
||||
self.update_config(config)
|
||||
logger.warn(f"{self.LOG_TAG}新版本v{self.plugin_version} 配置修正 ...")
|
||||
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
|
||||
if self._enabled or self._onlyonce:
|
||||
if self._onlyonce:
|
||||
# 创建定时任务控制器
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
if self._onlyonce:
|
||||
# 执行一次, 关闭onlyonce
|
||||
self._onlyonce = False
|
||||
config.update({"onlyonce": self._onlyonce})
|
||||
self.update_config(config)
|
||||
# 添加 补全下载历史的标签与分类 任务
|
||||
self._scheduler.add_job(func= self._complemented_history, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
if self._enabled:
|
||||
if self._interval == "计划任务" or self._interval == "固定间隔":
|
||||
args = {}
|
||||
if self._interval == "固定间隔":
|
||||
args["trigger"] = "interval"
|
||||
if self._interval_unit == "小时":
|
||||
args["hours"] = self._interval_time
|
||||
else:
|
||||
args["minutes"] = self._interval_time
|
||||
if args["minutes"] < 5:
|
||||
args["minutes"] = 5
|
||||
logger.info(f"{self.LOG_TAG}启动定时服务: 最小不少于5分钟, 防止执行间隔太短任务冲突")
|
||||
else:
|
||||
args["trigger"] = CronTrigger.from_crontab(self._interval_cron)
|
||||
try:
|
||||
self._scheduler.add_job(func=lambda: self._complemented_history(interval=True),
|
||||
**args,
|
||||
name="补全下载历史的标签与分类")
|
||||
logger.info(
|
||||
f"{self.LOG_TAG}添加定时服务: 补全下载历史的标签与分类" + (f"(每){args.get('hours') or args.get('minutes')}{self._interval_unit}执行一次" if args["trigger"] == "interval" else f",计划任务: {self._interval_cron}"))
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"{self.LOG_TAG}添加定时服务发生了错误: {str(e)}")
|
||||
self._scheduler.add_job(func=self._complemented_history, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
|
||||
if self._scheduler and self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
if self._scheduler and self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
@@ -145,21 +121,68 @@ class DownloadSiteTag(_PluginBase):
|
||||
def get_command() -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def str_to_number(self, s: str, i: int) -> int:
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled:
|
||||
if self._interval == "计划任务" or self._interval == "固定间隔":
|
||||
if self._interval == "固定间隔":
|
||||
if self._interval_unit == "小时":
|
||||
return [{
|
||||
"id": "DownloadSiteTag",
|
||||
"name": "补全下载历史的标签与分类",
|
||||
"trigger": "interval",
|
||||
"func": self._complemented_history,
|
||||
"kwargs": {
|
||||
"hours": self._interval_time
|
||||
}
|
||||
}]
|
||||
else:
|
||||
if self._interval_time < 5:
|
||||
self._interval_time = 5
|
||||
logger.info(f"{self.LOG_TAG}启动定时服务: 最小不少于5分钟, 防止执行间隔太短任务冲突")
|
||||
return [{
|
||||
"id": "DownloadSiteTag",
|
||||
"name": "补全下载历史的标签与分类",
|
||||
"trigger": "interval",
|
||||
"func": self._complemented_history,
|
||||
"kwargs": {
|
||||
"minutes": self._interval_time
|
||||
}
|
||||
}]
|
||||
else:
|
||||
return [{
|
||||
"id": "DownloadSiteTag",
|
||||
"name": "补全下载历史的标签与分类",
|
||||
"trigger": CronTrigger.from_crontab(self._interval_cron),
|
||||
"func": self._complemented_history,
|
||||
"kwargs": {}
|
||||
}]
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def str_to_number(s: str, i: int) -> int:
|
||||
try:
|
||||
return int(s)
|
||||
except:
|
||||
except ValueError:
|
||||
return i
|
||||
|
||||
def _complemented_history(self, interval: bool = False):
|
||||
def _complemented_history(self):
|
||||
"""
|
||||
补全下载历史的标签与分类
|
||||
"""
|
||||
logger.info(f"{self.LOG_TAG}开始执行{'(定时任务)' if interval else ''}: 补全下载历史的标签与分类 ...")
|
||||
logger.info(f"{self.LOG_TAG}开始执行 ...")
|
||||
# 记录处理的种子, 供辅种(无下载历史)使用
|
||||
dispose_history = {}
|
||||
# 所有站点索引
|
||||
@@ -185,7 +208,8 @@ class DownloadSiteTag(_PluginBase):
|
||||
for torrent in torrents:
|
||||
try:
|
||||
if self._event.is_set():
|
||||
logger.info(f"{self.LOG_TAG}停止服务{'(定时任务)' if interval else ''}: 补全下载历史的标签与分类")
|
||||
logger.info(
|
||||
f"{self.LOG_TAG}停止服务")
|
||||
return
|
||||
# 获取已处理种子的key (size, name)
|
||||
_key = self._torrent_key(torrent=torrent, dl_type=DOWNLOADER)
|
||||
@@ -205,11 +229,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 因为辅种站点必定不同, 所以需要更新站点名字 history.torrent_site
|
||||
history.torrent_site = None
|
||||
else:
|
||||
history = DownloadHistory(
|
||||
torrent_site=None,
|
||||
title=None,
|
||||
type=None,
|
||||
tmdbid=None)
|
||||
history = DownloadHistory()
|
||||
else:
|
||||
# 加入历史记录
|
||||
if _key:
|
||||
@@ -243,13 +263,14 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 如果是电视剧 需要区分是否动漫
|
||||
genre_ids = None
|
||||
# 因允许tmdbid为空时运行到此, 因此需要判断tmdbid不为空
|
||||
if history.tmdbid and (history.type == MediaType.TV or history.type == MediaType.TV.value):
|
||||
history_type = MediaType(history.type) if history.type else None
|
||||
if history.tmdbid and history_type == MediaType.TV:
|
||||
# tmdb_id获取tmdb信息
|
||||
tmdb_info = self.tmdb_helper.get_info(mtype=history.type, tmdbid=history.tmdbid)
|
||||
tmdb_info = self.tmdb_helper.get_info(mtype=history_type, tmdbid=history.tmdbid)
|
||||
if tmdb_info:
|
||||
genre_ids = tmdb_info.get("genre_ids")
|
||||
_cat = self._genre_ids_get_cat(history.type, genre_ids)
|
||||
|
||||
|
||||
# 去除种子已经存在的标签
|
||||
if _tags and torrent_tags:
|
||||
_tags = list(set(_tags) - set(torrent_tags))
|
||||
@@ -260,15 +281,15 @@ class DownloadSiteTag(_PluginBase):
|
||||
if not _cat and not _tags:
|
||||
continue
|
||||
# 执行通用方法, 设置种子标签与分类
|
||||
self._set_torrent_info(DOWNLOADER=DOWNLOADER, _hash=_hash, _torrent=torrent, _tags=_tags, _cat=_cat, _original_tags=torrent_tags)
|
||||
self._set_torrent_info(DOWNLOADER=DOWNLOADER, _hash=_hash, _torrent=torrent, _tags=_tags, _cat=_cat,
|
||||
_original_tags=torrent_tags)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"{self.LOG_TAG}分析种子信息时发生了错误: {str(e)}")
|
||||
|
||||
logger.info(f"{self.LOG_TAG}执行完成")
|
||||
|
||||
logger.info(f"{self.LOG_TAG}执行完成{'(定时任务)' if interval else ''}: 补全下载历史的标签与分类 ...")
|
||||
|
||||
def _genre_ids_get_cat(self, mtype, genre_ids = None):
|
||||
def _genre_ids_get_cat(self, mtype, genre_ids=None):
|
||||
"""
|
||||
根据genre_ids判断是否<动漫>分类
|
||||
"""
|
||||
@@ -298,12 +319,11 @@ class DownloadSiteTag(_PluginBase):
|
||||
else:
|
||||
return None
|
||||
|
||||
def _torrent_key(self, torrent: Any, dl_type: str):
|
||||
@staticmethod
|
||||
def _torrent_key(torrent: Any, dl_type: str) -> Optional[Tuple[int, str]]:
|
||||
"""
|
||||
按种子大小和时间返回key
|
||||
"""
|
||||
size = None
|
||||
name = None
|
||||
if dl_type == "qbittorrent":
|
||||
size = torrent.get('size')
|
||||
name = torrent.get('name')
|
||||
@@ -313,9 +333,10 @@ class DownloadSiteTag(_PluginBase):
|
||||
if not size or not name:
|
||||
return None
|
||||
else:
|
||||
return (size, name)
|
||||
return size, name
|
||||
|
||||
def _torrents_sort(self, torrents: Any, dl_type: str):
|
||||
@staticmethod
|
||||
def _torrents_sort(torrents: Any, dl_type: str):
|
||||
"""
|
||||
按种子添加时间排序
|
||||
"""
|
||||
@@ -325,7 +346,8 @@ class DownloadSiteTag(_PluginBase):
|
||||
torrents = sorted(torrents, key=lambda x: x.added_date, reverse=False)
|
||||
return torrents
|
||||
|
||||
def _get_hash(self, torrent: Any, dl_type: str):
|
||||
@staticmethod
|
||||
def _get_hash(torrent: Any, dl_type: str):
|
||||
"""
|
||||
获取种子hash
|
||||
"""
|
||||
@@ -335,7 +357,8 @@ class DownloadSiteTag(_PluginBase):
|
||||
print(str(e))
|
||||
return ""
|
||||
|
||||
def _get_trackers(self, torrent: Any, dl_type: str):
|
||||
@staticmethod
|
||||
def _get_trackers(torrent: Any, dl_type: str):
|
||||
"""
|
||||
获取种子trackers
|
||||
"""
|
||||
@@ -351,7 +374,8 @@ class DownloadSiteTag(_PluginBase):
|
||||
num_downloaded 整数 跟踪器报告的当前 torrent 的已完成下载次数
|
||||
msg 字符串 跟踪器消息(无法知道此消息是什么 - 由跟踪器管理员决定)
|
||||
"""
|
||||
return [tracker.get("url") for tracker in (torrent.trackers or []) if tracker.get("tier", -1) >= 0 and tracker.get("url")]
|
||||
return [tracker.get("url") for tracker in (torrent.trackers or []) if
|
||||
tracker.get("tier", -1) >= 0 and tracker.get("url")]
|
||||
else:
|
||||
"""
|
||||
class Tracker(Container):
|
||||
@@ -371,12 +395,14 @@ class DownloadSiteTag(_PluginBase):
|
||||
def tier(self) -> int:
|
||||
return self.fields["tier"]
|
||||
"""
|
||||
return [tracker.announce for tracker in (torrent.trackers or []) if tracker.tier >= 0 and tracker.announce]
|
||||
return [tracker.announce for tracker in (torrent.trackers or []) if
|
||||
tracker.tier >= 0 and tracker.announce]
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
return []
|
||||
|
||||
def _get_label(self, torrent: Any, dl_type: str):
|
||||
@staticmethod
|
||||
def _get_label(torrent: Any, dl_type: str):
|
||||
"""
|
||||
获取种子标签
|
||||
"""
|
||||
@@ -387,7 +413,8 @@ class DownloadSiteTag(_PluginBase):
|
||||
print(str(e))
|
||||
return []
|
||||
|
||||
def _get_category(self, torrent: Any, dl_type: str):
|
||||
@staticmethod
|
||||
def _get_category(torrent: Any, dl_type: str):
|
||||
"""
|
||||
获取种子分类
|
||||
"""
|
||||
@@ -397,20 +424,23 @@ class DownloadSiteTag(_PluginBase):
|
||||
print(str(e))
|
||||
return None
|
||||
|
||||
def _set_torrent_info(self, DOWNLOADER: str, _hash: str, _torrent: Any = None, _tags: list = [], _cat: str = None, _original_tags: list = None):
|
||||
def _set_torrent_info(self, DOWNLOADER: str, _hash: str, _torrent: Any = None, _tags=None, _cat: str = None,
|
||||
_original_tags: list = None):
|
||||
"""
|
||||
设置种子标签与分类
|
||||
"""
|
||||
# 当前下载器
|
||||
if _tags is None:
|
||||
_tags = []
|
||||
downloader_obj = self._get_downloader(DOWNLOADER)
|
||||
if not _torrent:
|
||||
_torrent, error = downloader_obj.get_torrents(ids=_hash)
|
||||
if not _torrent or error:
|
||||
logger.error(
|
||||
f"{self.LOG_TAG}设置种子标签与分类时发生了错误: 通过 {_hash} 查询不到任何种子!")
|
||||
f"{self.LOG_TAG}设置种子标签与分类时发生了错误: 通过 {_hash} 查询不到任何种子!")
|
||||
return
|
||||
logger.info(
|
||||
f"{self.LOG_TAG}设置种子标签与分类: {_hash} 查询到 {len(_torrent)} 个种子")
|
||||
f"{self.LOG_TAG}设置种子标签与分类: {_hash} 查询到 {len(_torrent)} 个种子")
|
||||
_torrent = _torrent[0]
|
||||
# 判断是否可执行
|
||||
if DOWNLOADER and downloader_obj and _hash and _torrent:
|
||||
@@ -424,20 +454,23 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 尝试设置种子分类, 如果失败, 则创建再设置一遍
|
||||
try:
|
||||
_torrent.setCategory(category=_cat)
|
||||
except:
|
||||
except Exception as e:
|
||||
logger.warn(f"下载器 {DOWNLOADER} 种子id: {_hash} 设置分类 {_cat} 失败:{str(e)}, "
|
||||
f"尝试创建分类再设置 ...")
|
||||
downloader_obj.qbc.torrents_createCategory(name=_cat)
|
||||
_torrent.setCategory(category=_cat)
|
||||
else:
|
||||
# 设置标签
|
||||
if _tags:
|
||||
# _original_tags = None表示未指定, 因此需要获取原始标签
|
||||
if _original_tags == None:
|
||||
if _original_tags is None:
|
||||
_original_tags = self._get_label(torrent=_torrent, dl_type=DOWNLOADER)
|
||||
# 如果原始标签不是空的, 那么合并原始标签
|
||||
if _original_tags:
|
||||
_tags = list(set(_original_tags).union(set(_tags)))
|
||||
downloader_obj.set_torrent_tag(ids=_hash, tags=_tags)
|
||||
logger.warn(f"{self.LOG_TAG}下载器: {DOWNLOADER} 种子id: {_hash} {(' 标签: ' + ','.join(_tags)) if _tags else ''} {(' 分类: ' + _cat) if _cat else ''}")
|
||||
logger.warn(
|
||||
f"{self.LOG_TAG}下载器: {DOWNLOADER} 种子id: {_hash} {(' 标签: ' + ','.join(_tags)) if _tags else ''} {(' 分类: ' + _cat) if _cat else ''}")
|
||||
|
||||
@eventmanager.register(EventType.DownloadAdded)
|
||||
def DownloadAdded(self, event: Event):
|
||||
@@ -449,7 +482,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
|
||||
if not event.event_data:
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
context: Context = event.event_data.get("context")
|
||||
_hash = event.event_data.get("hash")
|
||||
@@ -473,7 +506,6 @@ class DownloadSiteTag(_PluginBase):
|
||||
logger.error(
|
||||
f"{self.LOG_TAG}分析下载事件时发生了错误: {str(e)}")
|
||||
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -5,8 +5,10 @@ import time
|
||||
from pathlib import Path
|
||||
from typing import Any, List, Dict, Tuple, Optional, Union
|
||||
|
||||
from pydantic import BaseModel
|
||||
from requests import RequestException
|
||||
|
||||
from app import schemas
|
||||
from app.chain.mediaserver import MediaServerChain
|
||||
from app.core.config import settings
|
||||
from app.core.event import eventmanager, Event
|
||||
@@ -15,16 +17,12 @@ from app.log import logger
|
||||
from app.modules.emby import Emby
|
||||
from app.modules.jellyfin import Jellyfin
|
||||
from app.modules.plex import Plex
|
||||
from app.modules.themoviedb.tmdbv3api import TV
|
||||
from app.plugins import _PluginBase
|
||||
from app import schemas
|
||||
from app.schemas.types import EventType, MediaType
|
||||
from app.schemas.types import EventType
|
||||
from app.utils.common import retry
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
from app.modules.themoviedb.tmdbv3api import TV
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ExistMediaInfo(BaseModel):
|
||||
# 类型 电影、电视剧
|
||||
@@ -49,7 +47,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
# 主题色
|
||||
plugin_color = "#098663"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "叮叮当"
|
||||
# 作者主页
|
||||
@@ -67,6 +65,10 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
# 私有属性
|
||||
mschain = None
|
||||
tv = None
|
||||
emby = None
|
||||
plex = None
|
||||
jellyfin = None
|
||||
|
||||
_enabled = False
|
||||
_ignorelock = False
|
||||
_delay = 0
|
||||
@@ -75,6 +77,9 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.mschain = MediaServerChain()
|
||||
self.tv = TV()
|
||||
self.emby = Emby()
|
||||
self.plex = Plex()
|
||||
self.jellyfin = Jellyfin()
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._ignorelock = config.get("ignorelock")
|
||||
@@ -259,7 +264,8 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
if not mediainfo.tmdb_id:
|
||||
self.log_warn(f"{mediainfo.title} 没有tmdbID, 无需处理")
|
||||
return
|
||||
if len(self._allowlist) != 0 and not mediainfo.title in self._allowlist:
|
||||
if len(self._allowlist) != 0 \
|
||||
and mediainfo.title not in self._allowlist:
|
||||
self.log_warn(f"{mediainfo.title} 不在白名单, 无需处理")
|
||||
return
|
||||
# 获取剧集组信息
|
||||
@@ -335,8 +341,8 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
# 是否无视项目锁定
|
||||
if not self._ignorelock:
|
||||
if iteminfo.get("LockData") or (
|
||||
"Name" in iteminfo.get("LockedFields", []) and "Overview" in iteminfo.get(
|
||||
"LockedFields", [])):
|
||||
"Name" in iteminfo.get("LockedFields", [])
|
||||
and "Overview" in iteminfo.get("LockedFields", [])):
|
||||
self.log_warn(f"已锁定媒体项 - itemid: {_id}, 第 {order} 季, 第 {ep_num} 集")
|
||||
continue
|
||||
# 替换项目数据
|
||||
@@ -371,7 +377,8 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
|
||||
self.log_info(f"{mediainfo.title_year} 已经运行完毕了..")
|
||||
|
||||
def __append_to_list(self, list, item):
|
||||
@staticmethod
|
||||
def __append_to_list(list, item):
|
||||
if item not in list:
|
||||
list.append(item)
|
||||
|
||||
@@ -387,15 +394,15 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
# 获取系列id
|
||||
item_id = None
|
||||
try:
|
||||
res = Emby().get_data(("[HOST]emby/Items?"
|
||||
"IncludeItemTypes=Series"
|
||||
"&Fields=ProductionYear"
|
||||
"&StartIndex=0"
|
||||
"&Recursive=true"
|
||||
"&SearchTerm=%s"
|
||||
"&Limit=10"
|
||||
"&IncludeSearchTypes=false"
|
||||
"&api_key=[APIKEY]") % (mediainfo.title))
|
||||
res = self.emby.get_data(("[HOST]emby/Items?"
|
||||
"IncludeItemTypes=Series"
|
||||
"&Fields=ProductionYear"
|
||||
"&StartIndex=0"
|
||||
"&Recursive=true"
|
||||
"&SearchTerm=%s"
|
||||
"&Limit=10"
|
||||
"&IncludeSearchTypes=false"
|
||||
"&api_key=[APIKEY]") % mediainfo.title)
|
||||
res_items = res.json().get("Items")
|
||||
if res_items:
|
||||
for res_item in res_items:
|
||||
@@ -407,15 +414,15 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
if not item_id:
|
||||
return None
|
||||
# 验证tmdbid是否相同
|
||||
item_info = Emby().get_iteminfo(item_id)
|
||||
item_info = self.emby.get_iteminfo(item_id)
|
||||
if item_info:
|
||||
if mediainfo.tmdb_id and item_info.tmdbid:
|
||||
if str(mediainfo.tmdb_id) != str(item_info.tmdbid):
|
||||
self.log_error(f"tmdbid不匹配或不存在")
|
||||
return None
|
||||
try:
|
||||
res_json = Emby().get_data(
|
||||
"[HOST]emby/Shows/%s/Episodes?Season=&IsMissing=false&api_key=[APIKEY]" % (item_id))
|
||||
res_json = self.emby.get_data(
|
||||
"[HOST]emby/Shows/%s/Episodes?Season=&IsMissing=false&api_key=[APIKEY]" % item_id)
|
||||
if res_json:
|
||||
tv_item = res_json.json()
|
||||
res_items = tv_item.get("Items")
|
||||
@@ -452,9 +459,10 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
# 获取系列id
|
||||
item_id = None
|
||||
try:
|
||||
res = Jellyfin.get_data(("[HOST]Users/[USER]/Items?"
|
||||
"api_key=[APIKEY]&searchTerm=%s&IncludeItemTypes=Series&Limit=10&Recursive=true") % (
|
||||
mediainfo.title))
|
||||
res = self.jellyfin.get_data(url=f"[HOST]Users/[USER]/Items?api_key=[APIKEY]"
|
||||
f"&searchTerm={mediainfo.title}"
|
||||
f"&IncludeItemTypes=Series"
|
||||
f"&Limit=10&Recursive=true")
|
||||
res_items = res.json().get("Items")
|
||||
if res_items:
|
||||
for res_item in res_items:
|
||||
@@ -466,15 +474,15 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
if not item_id:
|
||||
return None
|
||||
# 验证tmdbid是否相同
|
||||
item_info = Jellyfin().get_iteminfo(item_id)
|
||||
item_info = self.jellyfin.get_iteminfo(item_id)
|
||||
if item_info:
|
||||
if mediainfo.tmdb_id and item_info.tmdbid:
|
||||
if str(mediainfo.tmdb_id) != str(item_info.tmdbid):
|
||||
self.log_error(f"tmdbid不匹配或不存在")
|
||||
return None
|
||||
try:
|
||||
res_json = Jellyfin().get_data(
|
||||
"[HOST]emby/Shows/%s/Episodes?Season=&IsMissing=false&api_key=[APIKEY]" % (item_id))
|
||||
res_json = self.jellyfin.get_data(
|
||||
"[HOST]emby/Shows/%s/Episodes?Season=&IsMissing=false&api_key=[APIKEY]" % item_id)
|
||||
if res_json:
|
||||
tv_item = res_json.json()
|
||||
res_items = tv_item.get("Items")
|
||||
@@ -509,7 +517,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
|
||||
def __plex_media_exists():
|
||||
try:
|
||||
_plex = Plex().get_plex()
|
||||
_plex = self.plex.get_plex()
|
||||
if not _plex:
|
||||
return None
|
||||
if existsinfo.itemid:
|
||||
@@ -609,7 +617,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
try:
|
||||
url = f'[HOST]emby/Users/[USER]/Items/{itemid}?' \
|
||||
f'Fields=ChannelMappingInfo&api_key=[APIKEY]'
|
||||
res = Emby().get_data(url=url)
|
||||
res = self.emby.get_data(url=url)
|
||||
if res:
|
||||
return res.json()
|
||||
except Exception as err:
|
||||
@@ -622,7 +630,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
"""
|
||||
try:
|
||||
url = f'[HOST]Users/[USER]/Items/{itemid}?Fields=ChannelMappingInfo&api_key=[APIKEY]'
|
||||
res = Jellyfin().get_data(url=url)
|
||||
res = self.jellyfin.get_data(url=url)
|
||||
if res:
|
||||
result = res.json()
|
||||
if result:
|
||||
@@ -638,7 +646,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
"""
|
||||
iteminfo = {}
|
||||
try:
|
||||
plexitem = Plex().get_plex().library.fetchItem(ekey=itemid)
|
||||
plexitem = self.plex.get_plex().library.fetchItem(ekey=itemid)
|
||||
if 'movie' in plexitem.METADATA_TYPE:
|
||||
iteminfo['Type'] = 'Movie'
|
||||
iteminfo['IsFolder'] = False
|
||||
@@ -667,11 +675,13 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
if plexitem.title.locked:
|
||||
iteminfo['LockedFields'].append('Name')
|
||||
except Exception as err:
|
||||
logger.warn(f"获取Plex媒体项详情失败:{str(err)}")
|
||||
pass
|
||||
try:
|
||||
if plexitem.summary.locked:
|
||||
iteminfo['LockedFields'].append('Overview')
|
||||
except Exception as err:
|
||||
logger.warn(f"获取Plex媒体项详情失败:{str(err)}")
|
||||
pass
|
||||
return iteminfo
|
||||
except Exception as err:
|
||||
@@ -695,7 +705,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
更新Emby媒体项详情
|
||||
"""
|
||||
try:
|
||||
res = Emby().post_data(
|
||||
res = self.emby.post_data(
|
||||
url=f'[HOST]emby/Items/{itemid}?api_key=[APIKEY]&reqformat=json',
|
||||
data=json.dumps(iteminfo),
|
||||
headers={
|
||||
@@ -716,7 +726,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
更新Jellyfin媒体项详情
|
||||
"""
|
||||
try:
|
||||
res = Jellyfin().post_data(
|
||||
res = self.jellyfin.post_data(
|
||||
url=f'[HOST]Items/{itemid}?api_key=[APIKEY]',
|
||||
data=json.dumps(iteminfo),
|
||||
headers={
|
||||
@@ -737,7 +747,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
更新Plex媒体项详情
|
||||
"""
|
||||
try:
|
||||
plexitem = Plex().get_plex().library.fetchItem(ekey=itemid)
|
||||
plexitem = self.plex.get_plex().library.fetchItem(ekey=itemid)
|
||||
if 'CommunityRating' in iteminfo and iteminfo['CommunityRating']:
|
||||
edits = {
|
||||
'audienceRating.value': iteminfo['CommunityRating'],
|
||||
@@ -788,7 +798,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
"""
|
||||
try:
|
||||
url = f'[HOST]emby/Items/{itemid}/Images/Primary?api_key=[APIKEY]'
|
||||
res = Emby().post_data(
|
||||
res = self.emby.post_data(
|
||||
url=url,
|
||||
data=_base64,
|
||||
headers={
|
||||
@@ -812,7 +822,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
try:
|
||||
url = f'[HOST]Items/{itemid}/RemoteImages/Download?' \
|
||||
f'Type=Primary&ImageUrl={imageurl}&ProviderName=TheMovieDb&api_key=[APIKEY]'
|
||||
res = Jellyfin().post_data(url=url)
|
||||
res = self.jellyfin.post_data(url=url)
|
||||
if res and res.status_code in [200, 204]:
|
||||
return True
|
||||
else:
|
||||
@@ -828,7 +838,7 @@ class EpisodeGroupMeta(_PluginBase):
|
||||
# FIXME 改为预下载图片
|
||||
"""
|
||||
try:
|
||||
plexitem = Plex().get_plex().library.fetchItem(ekey=itemid)
|
||||
plexitem = self.plex.get_plex().library.fetchItem(ekey=itemid)
|
||||
plexitem.uploadPoster(url=imageurl)
|
||||
return True
|
||||
except Exception as err:
|
||||
|
||||
@@ -22,7 +22,7 @@ class InvitesSignin(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "invites.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.2"
|
||||
plugin_version = "1.3"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -56,33 +56,22 @@ class InvitesSignin(_PluginBase):
|
||||
self._notify = config.get("notify")
|
||||
self._onlyonce = config.get("onlyonce")
|
||||
|
||||
# 加载模块
|
||||
if self._enabled:
|
||||
if self._onlyonce:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__signin,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="药丸签到")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
|
||||
if self._onlyonce:
|
||||
logger.info(f"药丸签到服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__signin, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="药丸签到")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.update_config({
|
||||
"onlyonce": False,
|
||||
"cron": self._cron,
|
||||
"enabled": self._enabled,
|
||||
"cookie": self._cookie,
|
||||
"notify": self._notify,
|
||||
})
|
||||
logger.info(f"药丸签到服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.__signin, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="药丸签到")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.update_config({
|
||||
"onlyonce": False,
|
||||
"cron": self._cron,
|
||||
"enabled": self._enabled,
|
||||
"cookie": self._cookie,
|
||||
"notify": self._notify,
|
||||
})
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
@@ -183,6 +172,27 @@ class InvitesSignin(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "InvitesSignin",
|
||||
"name": "药丸签到服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.__signin,
|
||||
"kwargs": {}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -34,7 +34,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "IYUU.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.2"
|
||||
plugin_version = "1.3"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -128,22 +128,21 @@ class IYUUAutoSeed(_PluginBase):
|
||||
self.qb = Qbittorrent()
|
||||
self.tr = Transmission()
|
||||
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(self.auto_seed,
|
||||
CronTrigger.from_crontab(self._cron))
|
||||
logger.info(f"辅种服务启动,周期:{self._cron}")
|
||||
except Exception as err:
|
||||
logger.error(f"辅种服务启动失败:{str(err)}")
|
||||
self.systemmessage.put(f"辅种服务启动失败:{str(err)}")
|
||||
if self._onlyonce:
|
||||
logger.info(f"辅种服务启动,立即运行一次")
|
||||
self._scheduler.add_job(self.auto_seed, 'date',
|
||||
run_date=datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3)
|
||||
)
|
||||
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
if self._scheduler.get_jobs():
|
||||
# 追加种子校验服务
|
||||
self._scheduler.add_job(self.check_recheck, 'interval', minutes=3)
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
if self._clearcache:
|
||||
# 关闭清除缓存开关
|
||||
@@ -153,13 +152,6 @@ class IYUUAutoSeed(_PluginBase):
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
if self._scheduler.get_jobs():
|
||||
# 追加种子校验服务
|
||||
self._scheduler.add_job(self.check_recheck, 'interval', minutes=3)
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return True if self._enabled and self._cron and self._token and self._downloaders else False
|
||||
|
||||
@@ -170,6 +162,27 @@ class IYUUAutoSeed(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self.get_state():
|
||||
return [{
|
||||
"id": "IYUUAutoSeed",
|
||||
"name": "IYUU自动辅种服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.auto_seed,
|
||||
"kwargs": {}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -25,7 +25,7 @@ class LibraryScraper(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "scraper.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.2"
|
||||
plugin_version = "1.3"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -67,23 +67,10 @@ class LibraryScraper(_PluginBase):
|
||||
# 启动定时任务 & 立即运行一次
|
||||
if self._enabled or self._onlyonce:
|
||||
self.transferhis = TransferHistoryOper()
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if self._cron:
|
||||
logger.info(f"媒体库刮削服务启动,周期:{self._cron}")
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__libraryscraper,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="媒体库刮削")
|
||||
except Exception as e:
|
||||
logger.error(f"媒体库刮削服务启动失败,原因:{str(e)}")
|
||||
self.systemmessage.put(f"媒体库刮削服务启动失败,原因:{str(e)}")
|
||||
else:
|
||||
logger.info(f"媒体库刮削服务启动,周期:每7天")
|
||||
self._scheduler.add_job(func=self.__libraryscraper,
|
||||
trigger=CronTrigger.from_crontab("0 0 */7 * *"),
|
||||
name="媒体库刮削")
|
||||
|
||||
if self._onlyonce:
|
||||
logger.info(f"媒体库刮削服务,立即运行一次")
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
self._scheduler.add_job(func=self.__libraryscraper, trigger='date',
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="媒体库刮削")
|
||||
@@ -97,10 +84,10 @@ class LibraryScraper(_PluginBase):
|
||||
"scraper_paths": self._scraper_paths,
|
||||
"exclude_paths": self._exclude_paths
|
||||
})
|
||||
if self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
if self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
@@ -112,6 +99,35 @@ class LibraryScraper(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "LibraryScraper",
|
||||
"name": "媒体库刮削",
|
||||
"trigger": "cron",
|
||||
"func": self.__libraryscraper,
|
||||
"kwargs": {}
|
||||
}]
|
||||
elif self._enabled:
|
||||
return [{
|
||||
"id": "LibraryScraper",
|
||||
"name": "媒体库刮削",
|
||||
"trigger": CronTrigger.from_crontab("0 0 */7 * *"),
|
||||
"func": self.__libraryscraper,
|
||||
"kwargs": {}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ class LinkMonitor(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Linkace_C.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.2"
|
||||
plugin_version = "1.3"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -104,8 +104,6 @@ class LinkMonitor(_PluginBase):
|
||||
self.stop_service()
|
||||
|
||||
if self._enabled or self._onlyonce:
|
||||
# 定时服务管理器
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
# 读取目录配置
|
||||
monitor_dirs = self._monitor_dirs.split("\n")
|
||||
@@ -176,6 +174,8 @@ class LinkMonitor(_PluginBase):
|
||||
|
||||
# 运行一次定时服务
|
||||
if self._onlyonce:
|
||||
# 定时服务管理器
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info("目录监控服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.sync_all, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
@@ -186,21 +186,10 @@ class LinkMonitor(_PluginBase):
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
# 全量同步定时
|
||||
if self._enabled and self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.sync_all,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="实时硬链接")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
|
||||
# 启动定时服务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
# 启动定时服务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def __update_config(self):
|
||||
"""
|
||||
@@ -380,6 +369,26 @@ class LinkMonitor(_PluginBase):
|
||||
"description": "实时硬链接",
|
||||
}]
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "LinkMonitor",
|
||||
"name": "全量硬链接定时服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.sync_all,
|
||||
"kwargs": {}
|
||||
}]
|
||||
|
||||
def sync(self) -> schemas.Response:
|
||||
"""
|
||||
API调用目录同步
|
||||
|
||||
@@ -21,7 +21,7 @@ class MediaServerRefresh(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "refresh2.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -36,8 +36,14 @@ class MediaServerRefresh(_PluginBase):
|
||||
# 私有属性
|
||||
_enabled = False
|
||||
_delay = 0
|
||||
_emby = None
|
||||
_jellyfin = None
|
||||
_plex = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self._emby = Emby()
|
||||
self._jellyfin = Jellyfin()
|
||||
self._plex = Plex()
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._delay = config.get("delay") or 0
|
||||
@@ -146,16 +152,16 @@ class MediaServerRefresh(_PluginBase):
|
||||
]
|
||||
# Emby
|
||||
if "emby" in settings.MEDIASERVER:
|
||||
Emby().refresh_library_by_items(items)
|
||||
self._emby.refresh_library_by_items(items)
|
||||
|
||||
# Jeyllyfin
|
||||
if "jellyfin" in settings.MEDIASERVER:
|
||||
# FIXME Jellyfin未找到刷新单个项目的API
|
||||
Jellyfin().refresh_root_library()
|
||||
self._jellyfin.refresh_root_library()
|
||||
|
||||
# Plex
|
||||
if "plex" in settings.MEDIASERVER:
|
||||
Plex().refresh_library_by_items(items)
|
||||
self._plex.refresh_library_by_items(items)
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
|
||||
@@ -31,7 +31,7 @@ class MediaSyncDel(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "mediasyncdel.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.2"
|
||||
plugin_version = "1.3"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -96,27 +96,6 @@ class MediaSyncDel(_PluginBase):
|
||||
"library_path": self._library_path
|
||||
})
|
||||
|
||||
if self._enabled and str(self._sync_type) == "log":
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
# 媒体库同步删除日志方式
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.sync_del_by_log,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="媒体库同步删除日志方式")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
else:
|
||||
self._scheduler.add_job(self.sync_del_by_log, "interval", minutes=30,
|
||||
name="媒体库同步删除日志方式")
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
@staticmethod
|
||||
def get_command() -> List[Dict[str, Any]]:
|
||||
"""
|
||||
@@ -128,6 +107,37 @@ class MediaSyncDel(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and str(self._sync_type) == "log":
|
||||
# 媒体库同步删除日志方式
|
||||
if self._cron:
|
||||
return [{
|
||||
"id": "MediaSyncDel",
|
||||
"name": "媒体库同步删除服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.sync_del_by_log,
|
||||
"kwargs": {}
|
||||
}]
|
||||
else:
|
||||
return [{
|
||||
"id": "MediaSyncDel",
|
||||
"name": "媒体库同步删除服务",
|
||||
"trigger": "interval",
|
||||
"func": self.sync_del_by_log,
|
||||
"kwargs": {"minutes": 30}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
@@ -1325,7 +1335,7 @@ class MediaSyncDel(_PluginBase):
|
||||
获取emby日志列表、解析emby日志
|
||||
"""
|
||||
|
||||
def __parse_log(file_name: str, del_list: list, last_time):
|
||||
def __parse_log(file_name: str, del_list: list):
|
||||
"""
|
||||
解析emby日志
|
||||
"""
|
||||
@@ -1419,8 +1429,7 @@ class MediaSyncDel(_PluginBase):
|
||||
log_files.reverse()
|
||||
for log_file in log_files:
|
||||
del_medias = __parse_log(file_name=log_file,
|
||||
del_list=del_medias,
|
||||
last_time=last_time)
|
||||
del_list=del_medias)
|
||||
|
||||
return del_medias
|
||||
|
||||
@@ -1430,7 +1439,7 @@ class MediaSyncDel(_PluginBase):
|
||||
获取jellyfin日志列表、解析jellyfin日志
|
||||
"""
|
||||
|
||||
def __parse_log(file_name: str, del_list: list, last_time):
|
||||
def __parse_log(file_name: str, del_list: list):
|
||||
"""
|
||||
解析jellyfin日志
|
||||
"""
|
||||
@@ -1524,8 +1533,7 @@ class MediaSyncDel(_PluginBase):
|
||||
log_files.reverse()
|
||||
for log_file in log_files:
|
||||
del_medias = __parse_log(file_name=log_file,
|
||||
del_list=del_medias,
|
||||
last_time=last_time)
|
||||
del_list=del_medias)
|
||||
|
||||
return del_medias
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class MoviePilotUpdateNotify(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Moviepilot_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -54,24 +54,6 @@ class MoviePilotUpdateNotify(_PluginBase):
|
||||
self._restart = config.get("restart")
|
||||
self._notify = config.get("notify")
|
||||
|
||||
# 加载模块
|
||||
if self._enabled:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__check_update,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="检查MoviePilot更新")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def __check_update(self):
|
||||
"""
|
||||
检查MoviePilot更新
|
||||
@@ -136,6 +118,29 @@ class MoviePilotUpdateNotify(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [
|
||||
{
|
||||
"id": "MoviePilotUpdateNotify",
|
||||
"name": "MoviePilot更新检查服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.__check_update,
|
||||
"kwargs": {}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -39,7 +39,7 @@ class PersonMeta(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "actor.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -80,31 +80,19 @@ class PersonMeta(_PluginBase):
|
||||
self.stop_service()
|
||||
|
||||
# 启动服务
|
||||
if self._enabled or self._onlyonce:
|
||||
if self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if self._cron or self._onlyonce:
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.scrap_library,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="演职人员刮削")
|
||||
logger.info(f"演职人员刮削服务启动,周期:{self._cron}")
|
||||
except Exception as e:
|
||||
logger.error(f"演职人员刮削服务启动失败,错误信息:{str(e)}")
|
||||
self.systemmessage.put(f"演职人员刮削服务启动失败,错误信息:{str(e)}")
|
||||
if self._onlyonce:
|
||||
self._scheduler.add_job(func=self.scrap_library, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
logger.info(f"演职人员刮削服务启动,立即运行一次")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
self._scheduler.add_job(func=self.scrap_library, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
logger.info(f"演职人员刮削服务启动,立即运行一次")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
# 启动服务
|
||||
if self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
@@ -131,6 +119,26 @@ class PersonMeta(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "PersonMeta",
|
||||
"name": "演职人员刮削服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.scrap_library,
|
||||
"kwargs": {}
|
||||
}]
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -25,26 +25,26 @@ class FileMonitorHandler(FileSystemEventHandler):
|
||||
|
||||
def on_created(self, event):
|
||||
logger.info("监测到新增文件:%s" % event.src_path)
|
||||
if self.sync._exclude_keywords:
|
||||
for keyword in self.sync._exclude_keywords.split("\n"):
|
||||
if self.sync.exclude_keywords:
|
||||
for keyword in self.sync.exclude_keywords.split("\n"):
|
||||
if keyword and re.findall(keyword, event.src_path):
|
||||
logger.info(f"{event.src_path} 命中过滤关键字 {keyword},不处理")
|
||||
print(f"{event.src_path} 命中过滤关键字 {keyword},不处理")
|
||||
return
|
||||
new_file = Path(event.src_path)
|
||||
try:
|
||||
self.sync._state_set.add((Path(event.src_path), new_file.stat().st_ino))
|
||||
self.sync.state_set.add((Path(event.src_path), new_file.stat().st_ino))
|
||||
except Exception as e:
|
||||
logger.error("文件丢失:%s" % event.src_path)
|
||||
logger.error(f"文件丢失:%s - {e}" % event.src_path)
|
||||
|
||||
def on_deleted(self, event):
|
||||
if Path(event.src_path) in self.sync._ignored_files:
|
||||
self.sync._ignored_files.remove(Path(event.src_path))
|
||||
if Path(event.src_path) in self.sync.ignored_files:
|
||||
self.sync.ignored_files.remove(Path(event.src_path))
|
||||
return
|
||||
logger.info("监测到删除:%s" % event.src_path)
|
||||
# 命中过滤关键字不处理
|
||||
if self.sync._exclude_keywords:
|
||||
for keyword in self.sync._exclude_keywords.split("\n"):
|
||||
if self.sync.exclude_keywords:
|
||||
for keyword in self.sync.exclude_keywords.split("\n"):
|
||||
if keyword and re.findall(keyword, event.src_path):
|
||||
logger.info(f"{event.src_path} 命中过滤关键字 {keyword},不处理")
|
||||
print(f"{event.src_path} 命中过滤关键字 {keyword},不处理")
|
||||
@@ -80,7 +80,7 @@ class RemoveLink(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Ombi_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "DzAvril"
|
||||
# 作者主页
|
||||
@@ -93,27 +93,27 @@ class RemoveLink(_PluginBase):
|
||||
auth_level = 1
|
||||
|
||||
# preivate property
|
||||
_monitor_dirs = ""
|
||||
_exclude_keywords = ""
|
||||
monitor_dirs = ""
|
||||
exclude_keywords = ""
|
||||
_enabled = False
|
||||
_notify = False
|
||||
_observer = []
|
||||
_state_set = set()
|
||||
_ignored_files = set()
|
||||
state_set = set()
|
||||
ignored_files = set()
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
logger.info(f"Hello, RemoveLink! config {config}")
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._notify = config.get("notify")
|
||||
self._monitor_dirs = config.get("monitor_dirs")
|
||||
self._exclude_keywords = config.get("exclude_keywords") or ""
|
||||
self.monitor_dirs = config.get("monitor_dirs")
|
||||
self.exclude_keywords = config.get("exclude_keywords") or ""
|
||||
self.__update_config()
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
if self._enabled:
|
||||
# 读取目录配置
|
||||
monitor_dirs = self._monitor_dirs.split("\n")
|
||||
monitor_dirs = self.monitor_dirs.split("\n")
|
||||
logger.info(f"监控目录:{monitor_dirs}")
|
||||
if not monitor_dirs:
|
||||
return
|
||||
@@ -134,7 +134,7 @@ class RemoveLink(_PluginBase):
|
||||
err_msg = str(e)
|
||||
logger.error(f"{mon_path} 启动目录监控失败:{err_msg}")
|
||||
self.systemmessage.put(f"{mon_path} 启动目录监控失败:{err_msg}")
|
||||
self._state_set = updateState(monitor_dirs)
|
||||
self.state_set = updateState(monitor_dirs)
|
||||
|
||||
def __update_config(self):
|
||||
"""
|
||||
@@ -144,8 +144,8 @@ class RemoveLink(_PluginBase):
|
||||
{
|
||||
"enabled": self._enabled,
|
||||
"notify": self._notify,
|
||||
"monitor_dirs": self._monitor_dirs,
|
||||
"exclude_keywords": self._exclude_keywords,
|
||||
"monitor_dirs": self.monitor_dirs,
|
||||
"exclude_keywords": self.exclude_keywords,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -289,15 +289,15 @@ class RemoveLink(_PluginBase):
|
||||
"""
|
||||
处理删除事件
|
||||
"""
|
||||
current_set = updateState(self._monitor_dirs.split("\n"))
|
||||
deleted_set = self._state_set - current_set
|
||||
current_set = updateState(self.monitor_dirs.split("\n"))
|
||||
deleted_set = self.state_set - current_set
|
||||
deleted_inode = [x[1] for x in deleted_set]
|
||||
try:
|
||||
# 在current_set中查找与deleted_inode有相同inode的文件并删除
|
||||
for path, inode in current_set:
|
||||
if inode in deleted_inode:
|
||||
file = Path(path)
|
||||
self._ignored_files.add(file)
|
||||
self.ignored_files.add(file)
|
||||
file.unlink()
|
||||
logger.info(f"删除硬链接文件:{path}")
|
||||
if self._notify:
|
||||
@@ -316,4 +316,4 @@ class RemoveLink(_PluginBase):
|
||||
except Exception as e:
|
||||
logger.error("目录监控发生错误:%s - %s" % (str(e), traceback.format_exc()))
|
||||
|
||||
self._state_set = updateState(self._monitor_dirs.split("\n"))
|
||||
self.state_set = updateState(self.monitor_dirs.split("\n"))
|
||||
|
||||
@@ -30,7 +30,7 @@ class RssSubscribe(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "rss.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -89,43 +89,29 @@ class RssSubscribe(_PluginBase):
|
||||
self._action = config.get("action")
|
||||
self._save_path = config.get("save_path")
|
||||
|
||||
if self._enabled or self._onlyonce:
|
||||
|
||||
if self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.check,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="RSS订阅")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
else:
|
||||
self._scheduler.add_job(self.check, "interval", minutes=30, name="RSS订阅")
|
||||
|
||||
if self._onlyonce:
|
||||
logger.info(f"RSS订阅服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.check, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
|
||||
if self._onlyonce or self._clear:
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
# 记录清理缓存设置
|
||||
self._clearflag = self._clear
|
||||
# 关闭清理缓存开关
|
||||
self._clear = False
|
||||
# 保存设置
|
||||
self.__update_config()
|
||||
logger.info(f"自定义订阅服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.check, trigger='date',
|
||||
run_date=datetime.datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
|
||||
)
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
if self._onlyonce or self._clear:
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
# 记录清理缓存设置
|
||||
self._clearflag = self._clear
|
||||
# 关闭清理缓存开关
|
||||
self._clear = False
|
||||
# 保存设置
|
||||
self.__update_config()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@@ -149,6 +135,35 @@ class RssSubscribe(_PluginBase):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "RssSubscribe",
|
||||
"name": "自定义订阅服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.check,
|
||||
"kwargs": {}
|
||||
}]
|
||||
elif self._enabled:
|
||||
return [{
|
||||
"id": "RssSubscribe",
|
||||
"name": "自定义订阅服务",
|
||||
"trigger": "interval",
|
||||
"func": self.check,
|
||||
"kwargs": {"minutes": 30}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -17,7 +17,7 @@ class SiteRefresh(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Chrome_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -77,7 +77,7 @@ class SiteRefresh(_PluginBase):
|
||||
|
||||
site_name = site.name
|
||||
logger.info(f"开始尝试登录站点 {site_name}")
|
||||
siteurl, siteuser, sitepwd = None, None, None
|
||||
siteurl, siteuser, sitepwd, sitecode = None, None, None, None
|
||||
# 判断site是否已配置用户名密码
|
||||
for site_conf in self._siteconf:
|
||||
if not site_conf:
|
||||
|
||||
@@ -43,7 +43,7 @@ class SiteStatistic(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "statistic.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.6"
|
||||
plugin_version = "1.7"
|
||||
# 插件作者
|
||||
plugin_author = "lightolly"
|
||||
# 作者主页
|
||||
@@ -101,9 +101,6 @@ class SiteStatistic(_PluginBase):
|
||||
self._site_schema = ModuleHelper.load('app.plugins.sitestatistic.siteuserinfo',
|
||||
filter_func=lambda _, obj: hasattr(obj, 'schema'))
|
||||
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
self._site_schema.sort(key=lambda x: x.order)
|
||||
# 站点上一次更新时间
|
||||
self._last_update_time = None
|
||||
@@ -112,6 +109,8 @@ class SiteStatistic(_PluginBase):
|
||||
|
||||
# 立即运行一次
|
||||
if self._onlyonce:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info(f"站点数据统计服务启动,立即运行一次")
|
||||
self._scheduler.add_job(self.refresh_all_site_data, 'date',
|
||||
run_date=datetime.now(
|
||||
@@ -123,31 +122,10 @@ class SiteStatistic(_PluginBase):
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
# 周期运行
|
||||
if self._enabled and self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.refresh_all_site_data,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="站点数据统计")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{str(err)}")
|
||||
else:
|
||||
triggers = TimerUtils.random_scheduler(num_executions=1,
|
||||
begin_hour=0,
|
||||
end_hour=1,
|
||||
min_interval=1,
|
||||
max_interval=60)
|
||||
for trigger in triggers:
|
||||
self._scheduler.add_job(self.refresh_all_site_data, "cron",
|
||||
hour=trigger.hour, minute=trigger.minute,
|
||||
name="站点数据统计")
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
@@ -186,6 +164,46 @@ class SiteStatistic(_PluginBase):
|
||||
"description": "刷新对应域名的站点数据",
|
||||
}]
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._cron:
|
||||
return [{
|
||||
"id": "SiteStatistic",
|
||||
"name": "站点数据统计服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.refresh_all_site_data,
|
||||
"kwargs": {}
|
||||
}]
|
||||
elif self._enabled:
|
||||
triggers = TimerUtils.random_scheduler(num_executions=1,
|
||||
begin_hour=0,
|
||||
end_hour=1,
|
||||
min_interval=1,
|
||||
max_interval=60)
|
||||
ret_jobs = []
|
||||
for trigger in triggers:
|
||||
ret_jobs.append({
|
||||
"id": f"SiteStatistic|{trigger.hour}:{trigger.minute}",
|
||||
"name": "站点数据统计服务",
|
||||
"trigger": "cron",
|
||||
"func": self.refresh_all_site_data,
|
||||
"kwargs": {
|
||||
"hour": trigger.hour,
|
||||
"minute": trigger.minute
|
||||
}
|
||||
})
|
||||
return ret_jobs
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import ipaddress
|
||||
from typing import List, Tuple, Dict, Any
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.log import logger
|
||||
@@ -25,7 +23,7 @@ class SpeedLimiter(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Librespeed_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "Shurelol"
|
||||
# 作者主页
|
||||
@@ -96,20 +94,6 @@ class SpeedLimiter(_PluginBase):
|
||||
if 'transmission' in self._downloader:
|
||||
self._tr = Transmission()
|
||||
|
||||
# 移出现有任务
|
||||
self.stop_service()
|
||||
|
||||
# 启动限速任务
|
||||
if self._enabled and self._limit_enabled:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
self._scheduler.add_job(func=self.check_playing_sessions,
|
||||
trigger='interval',
|
||||
seconds=self._interval,
|
||||
name="播放限速检查")
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
logger.info("播放限速检查服务启动")
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@@ -120,6 +104,29 @@ class SpeedLimiter(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self._enabled and self._limit_enabled and self._interval:
|
||||
return [
|
||||
{
|
||||
"id": "SpeedLimiter",
|
||||
"name": "播放限速检查服务",
|
||||
"trigger": "interval",
|
||||
"func": self.check_playing_sessions,
|
||||
"kwargs": {"seconds": self._interval}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
@@ -614,14 +621,4 @@ class SpeedLimiter(_PluginBase):
|
||||
return False
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
退出插件
|
||||
"""
|
||||
try:
|
||||
if self._scheduler:
|
||||
self._scheduler.remove_all_jobs()
|
||||
if self._scheduler.running:
|
||||
self._scheduler.shutdown()
|
||||
self._scheduler = None
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
pass
|
||||
|
||||
@@ -22,7 +22,7 @@ class SyncDownloadFiles(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Youtube-dl_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -88,27 +88,6 @@ class SyncDownloadFiles(_PluginBase):
|
||||
|
||||
self.sync()
|
||||
|
||||
if self._enabled:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if self._time:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.sync,
|
||||
trigger="interval",
|
||||
hours=float(str(self._time).strip()),
|
||||
name="自动同步下载器文件记录")
|
||||
logger.info(f"自动同步下载器文件记录服务启动,时间间隔 {self._time} 小时")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{str(err)}")
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
else:
|
||||
self._enabled = False
|
||||
self.__update_config()
|
||||
|
||||
def sync(self):
|
||||
"""
|
||||
同步所选下载器种子记录
|
||||
@@ -378,7 +357,7 @@ class SyncDownloadFiles(_PluginBase):
|
||||
return None
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
return True if self._enabled and self._time else False
|
||||
|
||||
@staticmethod
|
||||
def get_command() -> List[Dict[str, Any]]:
|
||||
@@ -387,6 +366,27 @@ class SyncDownloadFiles(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self.get_state():
|
||||
return [{
|
||||
"id": "SyncDownloadFiles",
|
||||
"name": "同步下载器文件记录服务",
|
||||
"trigger": "interval",
|
||||
"func": self.sync,
|
||||
"kwargs": {"seconds": float(str(self._time).strip()) * 3600}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
@@ -478,7 +478,7 @@ class SyncDownloadFiles(_PluginBase):
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'time',
|
||||
'label': '同步时间间隔'
|
||||
'label': '同步时间间隔(小时)'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -27,7 +27,7 @@ class TorrentRemover(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "delete.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -88,19 +88,10 @@ class TorrentRemover(_PluginBase):
|
||||
self.stop_service()
|
||||
|
||||
if self.get_state() or self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
self.qb = Qbittorrent()
|
||||
self.tr = Transmission()
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.delete_torrents,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="自动删种服务")
|
||||
logger.info(f"自动删种服务启动,周期:{self._cron}")
|
||||
except Exception as err:
|
||||
logger.error(f"自动删种服务启动失败:{str(err)}")
|
||||
self.systemmessage.put(f"自动删种服务启动失败:{str(err)}")
|
||||
if self._onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
logger.info(f"自动删种服务启动,立即运行一次")
|
||||
self._scheduler.add_job(func=self.delete_torrents, trigger='date',
|
||||
run_date=datetime.now(
|
||||
@@ -130,10 +121,10 @@ class TorrentRemover(_PluginBase):
|
||||
"torrentcategorys": self._torrentcategorys
|
||||
|
||||
})
|
||||
if self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
if self._scheduler.get_jobs():
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return True if self._enabled and self._cron and self._downloaders else False
|
||||
@@ -145,6 +136,27 @@ class TorrentRemover(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self.get_state():
|
||||
return [{
|
||||
"id": "TorrentRemover",
|
||||
"name": "自动删种服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.delete_torrents,
|
||||
"kwargs": {}
|
||||
}]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ class TorrentTransfer(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "seed.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -102,16 +102,14 @@ class TorrentTransfer(_PluginBase):
|
||||
logger.error(f"源下载器和目的下载器不能相同")
|
||||
self.systemmessage.put(f"源下载器和目的下载器不能相同")
|
||||
return
|
||||
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
if self._cron:
|
||||
logger.info(f"转移做种服务启动,周期:{self._cron}")
|
||||
try:
|
||||
self._scheduler.add_job(self.transfer,
|
||||
CronTrigger.from_crontab(self._cron))
|
||||
except Exception as e:
|
||||
logger.error(f"转移做种服务启动失败:{str(e)}")
|
||||
self.systemmessage.put(f"转移做种服务启动失败:{str(e)}")
|
||||
return
|
||||
|
||||
if self._autostart:
|
||||
# 追加种子校验服务
|
||||
self._scheduler.add_job(self.check_recheck, 'interval', minutes=3)
|
||||
|
||||
if self._onlyonce:
|
||||
logger.info(f"转移做种服务启动,立即运行一次")
|
||||
self._scheduler.add_job(self.transfer, 'date',
|
||||
@@ -135,11 +133,9 @@ class TorrentTransfer(_PluginBase):
|
||||
"nopaths": self._nopaths,
|
||||
"autostart": self._autostart
|
||||
})
|
||||
|
||||
# 启动服务
|
||||
if self._scheduler.get_jobs():
|
||||
if self._autostart:
|
||||
# 追加种子校验服务
|
||||
self._scheduler.add_job(self.check_recheck, 'interval', minutes=3)
|
||||
# 启动服务
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
@@ -157,6 +153,29 @@ class TorrentTransfer(_PluginBase):
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_service(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
注册插件公共服务
|
||||
[{
|
||||
"id": "服务ID",
|
||||
"name": "服务名称",
|
||||
"trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 定时器参数
|
||||
}]
|
||||
"""
|
||||
if self.get_state():
|
||||
return [
|
||||
{
|
||||
"id": "TorrentTransfer",
|
||||
"name": "转移做种服务",
|
||||
"trigger": CronTrigger.from_crontab(self._cron),
|
||||
"func": self.transfer,
|
||||
"kwargs": {}
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
from urllib.parse import urlencode
|
||||
from typing import Any, List, Dict, Tuple
|
||||
|
||||
from app.plugins import _PluginBase
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas.types import EventType, NotificationType
|
||||
from app.utils.http import RequestUtils
|
||||
from typing import Any, List, Dict, Tuple
|
||||
from app.log import logger
|
||||
|
||||
|
||||
class WorkWechatMsg(_PluginBase):
|
||||
@@ -186,18 +185,18 @@ class WorkWechatMsg(_PluginBase):
|
||||
payload = {
|
||||
"msgtype": "news",
|
||||
"news": {
|
||||
"articles" : [
|
||||
"articles": [
|
||||
{
|
||||
"title" : title,
|
||||
"description" : text,
|
||||
"url" : "moviepilot",
|
||||
"picurl" : image
|
||||
"title": title,
|
||||
"description": text,
|
||||
"url": "moviepilot",
|
||||
"picurl": image
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
res = RequestUtils().post_res(url = self._webhookurl, json = payload)
|
||||
res = RequestUtils().post_res(url=self._webhookurl, json=payload)
|
||||
if res and res.status_code == 200:
|
||||
ret_json = res.json()
|
||||
errno = ret_json.get('errcode')
|
||||
|
||||
Reference in New Issue
Block a user