豆瓣想看移植为插件
This commit is contained in:
parent
3b5863befa
commit
478c0cb5b6
@ -26,8 +26,7 @@ ENV LANG="C.UTF-8" \
|
|||||||
QB_PASSWORD="adminadmin" \
|
QB_PASSWORD="adminadmin" \
|
||||||
MEDIASERVER="emby" \
|
MEDIASERVER="emby" \
|
||||||
EMBY_HOST="http://127.0.0.1:8096" \
|
EMBY_HOST="http://127.0.0.1:8096" \
|
||||||
EMBY_API_KEY="" \
|
EMBY_API_KEY=""
|
||||||
DOUBAN_USER_IDS=""
|
|
||||||
WORKDIR "/app"
|
WORKDIR "/app"
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
|
@ -55,7 +55,6 @@ docker pull jxxghp/moviepilot:latest
|
|||||||
- **TORRENT_TAG:** 种子标签,默认为`MOVIEPILOT`,设置后只有MoviePilot添加的下载才会处理,留空所有下载器中的任务均会处理
|
- **TORRENT_TAG:** 种子标签,默认为`MOVIEPILOT`,设置后只有MoviePilot添加的下载才会处理,留空所有下载器中的任务均会处理
|
||||||
- **LIBRARY_PATH:** 媒体库目录,**注意:需要将`moviepilot`的映射路径与宿主机`真实路径`保持一致**,多个目录使用`,`分隔
|
- **LIBRARY_PATH:** 媒体库目录,**注意:需要将`moviepilot`的映射路径与宿主机`真实路径`保持一致**,多个目录使用`,`分隔
|
||||||
- **LIBRARY_CATEGORY:** 媒体库二级分类开关,`true`/`false`,默认`false`,开启后会根据配置`category.yaml`自动在媒体库目录下建立二级目录分类
|
- **LIBRARY_CATEGORY:** 媒体库二级分类开关,`true`/`false`,默认`false`,开启后会根据配置`category.yaml`自动在媒体库目录下建立二级目录分类
|
||||||
- **DOUBAN_USER_IDS:** 豆瓣用户ID,用于同步豆瓣标记的`想看`数据,自动添加订阅,多个用户使用,分隔
|
|
||||||
- **TRANSFER_TYPE:** 转移方式,支持`link`/`copy`/`move`/`softlink`
|
- **TRANSFER_TYPE:** 转移方式,支持`link`/`copy`/`move`/`softlink`
|
||||||
- **COOKIECLOUD_HOST:** CookieCloud服务器地址,格式:`http://ip:port`,必须配置,否则无法添加站点
|
- **COOKIECLOUD_HOST:** CookieCloud服务器地址,格式:`http://ip:port`,必须配置,否则无法添加站点
|
||||||
- **COOKIECLOUD_KEY:** CookieCloud用户KEY
|
- **COOKIECLOUD_KEY:** CookieCloud用户KEY
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
from pathlib import Path
|
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.chain.download import DownloadChain
|
|
||||||
from app.chain.search import SearchChain
|
|
||||||
from app.chain.subscribe import SubscribeChain
|
|
||||||
from app.core.config import settings
|
|
||||||
from app.core.context import Context
|
from app.core.context import Context
|
||||||
from app.core.context import MediaInfo
|
from app.core.context import MediaInfo
|
||||||
from app.core.metainfo import MetaInfo
|
from app.core.metainfo import MetaInfo
|
||||||
from app.helper.rss import RssHelper
|
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import MediaType, Notification, MessageChannel
|
from app.schemas import MediaType
|
||||||
|
|
||||||
|
|
||||||
class DoubanChain(ChainBase):
|
class DoubanChain(ChainBase):
|
||||||
@ -20,17 +13,6 @@ class DoubanChain(ChainBase):
|
|||||||
豆瓣处理链
|
豆瓣处理链
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_interests_url: str = "https://www.douban.com/feed/people/%s/interests"
|
|
||||||
|
|
||||||
_cache_path: Path = settings.TEMP_PATH / "__doubansync_cache__"
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.rsshelper = RssHelper()
|
|
||||||
self.downloadchain = DownloadChain()
|
|
||||||
self.searchchain = SearchChain()
|
|
||||||
self.subscribechain = SubscribeChain()
|
|
||||||
|
|
||||||
def recognize_by_doubanid(self, doubanid: str) -> Optional[Context]:
|
def recognize_by_doubanid(self, doubanid: str) -> Optional[Context]:
|
||||||
"""
|
"""
|
||||||
根据豆瓣ID识别媒体信息
|
根据豆瓣ID识别媒体信息
|
||||||
@ -96,99 +78,3 @@ class DoubanChain(ChainBase):
|
|||||||
"""
|
"""
|
||||||
return self.run_module("douban_discover", mtype=mtype, sort=sort, tags=tags,
|
return self.run_module("douban_discover", mtype=mtype, sort=sort, tags=tags,
|
||||||
page=page, count=count)
|
page=page, count=count)
|
||||||
|
|
||||||
def remote_sync(self, channel: MessageChannel, userid: Union[int, str]):
|
|
||||||
"""
|
|
||||||
同步豆瓣想看数据,发送消息
|
|
||||||
"""
|
|
||||||
self.post_message(Notification(channel=channel,
|
|
||||||
title="开始同步豆瓣想看 ...", userid=userid))
|
|
||||||
self.sync()
|
|
||||||
self.post_message(Notification(channel=channel,
|
|
||||||
title="同步豆瓣想看数据完成!", userid=userid))
|
|
||||||
|
|
||||||
def sync(self):
|
|
||||||
"""
|
|
||||||
通过用户RSS同步豆瓣想看数据
|
|
||||||
"""
|
|
||||||
if not settings.DOUBAN_USER_IDS:
|
|
||||||
return
|
|
||||||
# 读取缓存
|
|
||||||
caches = self._cache_path.read_text().split("\n") if self._cache_path.exists() else []
|
|
||||||
for user_id in settings.DOUBAN_USER_IDS.split(","):
|
|
||||||
# 同步每个用户的豆瓣数据
|
|
||||||
if not user_id:
|
|
||||||
continue
|
|
||||||
logger.info(f"开始同步用户 {user_id} 的豆瓣想看数据 ...")
|
|
||||||
url = self._interests_url % user_id
|
|
||||||
results = self.rsshelper.parse(url)
|
|
||||||
if not results:
|
|
||||||
logger.error(f"未获取到用户 {user_id} 豆瓣RSS数据:{url}")
|
|
||||||
return
|
|
||||||
# 解析数据
|
|
||||||
for result in results:
|
|
||||||
dtype = result.get("title", "")[:2]
|
|
||||||
title = result.get("title", "")[2:]
|
|
||||||
if dtype not in ["想看"]:
|
|
||||||
continue
|
|
||||||
if not result.get("link"):
|
|
||||||
continue
|
|
||||||
douban_id = result.get("link", "").split("/")[-2]
|
|
||||||
if not douban_id or douban_id in caches:
|
|
||||||
continue
|
|
||||||
# 根据豆瓣ID获取豆瓣数据
|
|
||||||
doubaninfo: Optional[dict] = self.douban_info(doubanid=douban_id)
|
|
||||||
if not doubaninfo:
|
|
||||||
logger.warn(f'未获取到豆瓣信息,标题:{title},豆瓣ID:{douban_id}')
|
|
||||||
continue
|
|
||||||
logger.info(f'获取到豆瓣信息,标题:{title},豆瓣ID:{douban_id}')
|
|
||||||
# 识别媒体信息
|
|
||||||
meta = MetaInfo(doubaninfo.get("original_title") or doubaninfo.get("title"))
|
|
||||||
if doubaninfo.get("year"):
|
|
||||||
meta.year = doubaninfo.get("year")
|
|
||||||
mediainfo: MediaInfo = self.recognize_media(meta=meta)
|
|
||||||
if not mediainfo:
|
|
||||||
logger.warn(f'未识别到媒体信息,标题:{title},豆瓣ID:{douban_id}')
|
|
||||||
continue
|
|
||||||
# 加入缓存
|
|
||||||
caches.append(douban_id)
|
|
||||||
# 查询缺失的媒体信息
|
|
||||||
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=meta, mediainfo=mediainfo)
|
|
||||||
if exist_flag:
|
|
||||||
logger.info(f'{mediainfo.title_year} 媒体库中已存在')
|
|
||||||
continue
|
|
||||||
logger.info(f'{mediainfo.title_year} 媒体库中不存在,开始搜索 ...')
|
|
||||||
# 搜索
|
|
||||||
contexts = self.searchchain.process(mediainfo=mediainfo,
|
|
||||||
no_exists=no_exists)
|
|
||||||
if not contexts:
|
|
||||||
logger.warn(f'{mediainfo.title_year} 未搜索到资源')
|
|
||||||
# 添加订阅
|
|
||||||
self.subscribechain.add(title=mediainfo.title,
|
|
||||||
year=mediainfo.year,
|
|
||||||
mtype=mediainfo.type,
|
|
||||||
tmdbid=mediainfo.tmdb_id,
|
|
||||||
season=meta.begin_season,
|
|
||||||
exist_ok=True,
|
|
||||||
username="豆瓣想看")
|
|
||||||
continue
|
|
||||||
# 自动下载
|
|
||||||
downloads, lefts = self.downloadchain.batch_download(contexts=contexts, no_exists=no_exists)
|
|
||||||
if downloads and not lefts:
|
|
||||||
# 全部下载完成
|
|
||||||
logger.info(f'{mediainfo.title_year} 下载完成')
|
|
||||||
else:
|
|
||||||
# 未完成下载
|
|
||||||
logger.info(f'{mediainfo.title_year} 未下载未完整,添加订阅 ...')
|
|
||||||
# 添加订阅
|
|
||||||
self.subscribechain.add(title=mediainfo.title,
|
|
||||||
year=mediainfo.year,
|
|
||||||
mtype=mediainfo.type,
|
|
||||||
tmdbid=mediainfo.tmdb_id,
|
|
||||||
season=meta.begin_season,
|
|
||||||
exist_ok=True,
|
|
||||||
username="豆瓣想看")
|
|
||||||
|
|
||||||
logger.info(f"用户 {user_id} 豆瓣想看同步完成")
|
|
||||||
# 保存缓存
|
|
||||||
self._cache_path.write_text("\n".join(caches))
|
|
||||||
|
@ -4,19 +4,18 @@ from typing import Any, Union
|
|||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.chain.cookiecloud import CookieCloudChain
|
from app.chain.cookiecloud import CookieCloudChain
|
||||||
from app.chain.douban import DoubanChain
|
|
||||||
from app.chain.download import DownloadChain
|
from app.chain.download import DownloadChain
|
||||||
from app.chain.mediaserver import MediaServerChain
|
from app.chain.mediaserver import MediaServerChain
|
||||||
from app.chain.site import SiteChain
|
from app.chain.site import SiteChain
|
||||||
from app.chain.subscribe import SubscribeChain
|
from app.chain.subscribe import SubscribeChain
|
||||||
from app.chain.transfer import TransferChain
|
from app.chain.transfer import TransferChain
|
||||||
|
from app.core.event import Event as ManagerEvent
|
||||||
from app.core.event import eventmanager, EventManager
|
from app.core.event import eventmanager, EventManager
|
||||||
from app.core.plugin import PluginManager
|
from app.core.plugin import PluginManager
|
||||||
from app.core.event import Event as ManagerEvent
|
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
|
from app.schemas.types import EventType, MessageChannel
|
||||||
from app.utils.object import ObjectUtils
|
from app.utils.object import ObjectUtils
|
||||||
from app.utils.singleton import Singleton
|
from app.utils.singleton import Singleton
|
||||||
from app.schemas.types import EventType, MessageChannel
|
|
||||||
|
|
||||||
|
|
||||||
class CommandChian(ChainBase):
|
class CommandChian(ChainBase):
|
||||||
@ -70,11 +69,6 @@ class Command(metaclass=Singleton):
|
|||||||
"description": "禁用站点",
|
"description": "禁用站点",
|
||||||
"data": {}
|
"data": {}
|
||||||
},
|
},
|
||||||
"/douban_sync": {
|
|
||||||
"func": DoubanChain().remote_sync,
|
|
||||||
"description": "同步豆瓣想看",
|
|
||||||
"data": {}
|
|
||||||
},
|
|
||||||
"/mediaserver_sync": {
|
"/mediaserver_sync": {
|
||||||
"func": MediaServerChain().remote_sync,
|
"func": MediaServerChain().remote_sync,
|
||||||
"description": "同步媒体服务器",
|
"description": "同步媒体服务器",
|
||||||
|
@ -143,8 +143,6 @@ class Settings(BaseSettings):
|
|||||||
LIBRARY_PATH: str = None
|
LIBRARY_PATH: str = None
|
||||||
# 二级分类
|
# 二级分类
|
||||||
LIBRARY_CATEGORY: bool = True
|
LIBRARY_CATEGORY: bool = True
|
||||||
# 豆瓣用户ID,用于同步豆瓣数据,使用,分隔
|
|
||||||
DOUBAN_USER_IDS: str = ""
|
|
||||||
# 电影重命名格式
|
# 电影重命名格式
|
||||||
MOVIE_RENAME_FORMAT: str = "{{title}}{% if year %} ({{year}}){% endif %}" \
|
MOVIE_RENAME_FORMAT: str = "{{title}}{% if year %} ({{year}}){% endif %}" \
|
||||||
"/{{title}}{% if year %} ({{year}}){% endif %}{% if part %}-{{part}}{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}" \
|
"/{{title}}{% if year %} ({{year}}){% endif %}{% if part %}-{{part}}{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}" \
|
||||||
|
@ -7,6 +7,8 @@ from app.core.config import settings
|
|||||||
from app.db.models import Base
|
from app.db.models import Base
|
||||||
from app.db.plugindata_oper import PluginDataOper
|
from app.db.plugindata_oper import PluginDataOper
|
||||||
from app.db.systemconfig_oper import SystemConfigOper
|
from app.db.systemconfig_oper import SystemConfigOper
|
||||||
|
from app.helper.message import MessageHelper
|
||||||
|
from app.schemas import Notification, NotificationType, MessageChannel
|
||||||
|
|
||||||
|
|
||||||
class PluginChian(ChainBase):
|
class PluginChian(ChainBase):
|
||||||
@ -34,9 +36,14 @@ class _PluginBase(metaclass=ABCMeta):
|
|||||||
plugin_desc: str = ""
|
plugin_desc: str = ""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
# 插件数据
|
||||||
self.plugindata = PluginDataOper()
|
self.plugindata = PluginDataOper()
|
||||||
|
# 处理链
|
||||||
self.chain = PluginChian()
|
self.chain = PluginChian()
|
||||||
|
# 系统配置
|
||||||
self.systemconfig = SystemConfigOper()
|
self.systemconfig = SystemConfigOper()
|
||||||
|
# 系统消息
|
||||||
|
self.systemmessage = MessageHelper()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def init_plugin(self, config: dict = None):
|
def init_plugin(self, config: dict = None):
|
||||||
@ -139,3 +146,13 @@ class _PluginBase(metaclass=ABCMeta):
|
|||||||
:param key: 数据key
|
:param key: 数据key
|
||||||
"""
|
"""
|
||||||
return self.plugindata.get_data(key)
|
return self.plugindata.get_data(key)
|
||||||
|
|
||||||
|
def post_message(self, channel: MessageChannel = None, mtype: NotificationType = None, title: str = None,
|
||||||
|
text: str = None, image: str = None, link: str = None, userid: str = None):
|
||||||
|
"""
|
||||||
|
发送消息
|
||||||
|
"""
|
||||||
|
self.chain.post_message(Notification(
|
||||||
|
channel=channel, mtype=mtype, title=title, text=text,
|
||||||
|
image=image, link=link, userid=userid
|
||||||
|
))
|
||||||
|
@ -2,8 +2,7 @@ import traceback
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from multiprocessing.dummy import Pool as ThreadPool
|
from multiprocessing.dummy import Pool as ThreadPool
|
||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
from threading import Event
|
from typing import Any, List, Dict, Tuple, Optional
|
||||||
from typing import Any, List, Dict, Tuple
|
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
@ -11,20 +10,19 @@ from apscheduler.triggers.cron import CronTrigger
|
|||||||
from ruamel.yaml import CommentedMap
|
from ruamel.yaml import CommentedMap
|
||||||
|
|
||||||
from app import schemas
|
from app import schemas
|
||||||
from app.core.event import EventManager, eventmanager
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.core.event import EventManager, eventmanager, Event
|
||||||
from app.helper.browser import PlaywrightHelper
|
from app.helper.browser import PlaywrightHelper
|
||||||
from app.helper.cloudflare import under_challenge
|
from app.helper.cloudflare import under_challenge
|
||||||
from app.helper.module import ModuleHelper
|
from app.helper.module import ModuleHelper
|
||||||
from app.helper.sites import SitesHelper
|
from app.helper.sites import SitesHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.plugins import _PluginBase
|
from app.plugins import _PluginBase
|
||||||
from app.schemas import Notification
|
from app.schemas.types import EventType, NotificationType
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils
|
||||||
from app.utils.site import SiteUtils
|
from app.utils.site import SiteUtils
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils
|
||||||
from app.utils.timer import TimerUtils
|
from app.utils.timer import TimerUtils
|
||||||
from app.schemas.types import EventType
|
|
||||||
|
|
||||||
|
|
||||||
class AutoSignIn(_PluginBase):
|
class AutoSignIn(_PluginBase):
|
||||||
@ -54,7 +52,7 @@ class AutoSignIn(_PluginBase):
|
|||||||
# 事件管理器
|
# 事件管理器
|
||||||
event: EventManager = None
|
event: EventManager = None
|
||||||
# 定时器
|
# 定时器
|
||||||
_scheduler = None
|
_scheduler: Optional[BackgroundScheduler] = None
|
||||||
# 加载的模块
|
# 加载的模块
|
||||||
_site_schema: list = []
|
_site_schema: list = []
|
||||||
|
|
||||||
@ -92,9 +90,12 @@ class AutoSignIn(_PluginBase):
|
|||||||
if self._cron:
|
if self._cron:
|
||||||
try:
|
try:
|
||||||
self._scheduler.add_job(func=self.sign_in,
|
self._scheduler.add_job(func=self.sign_in,
|
||||||
trigger=CronTrigger.from_crontab(self._cron))
|
trigger=CronTrigger.from_crontab(self._cron),
|
||||||
|
name="站点自动签到")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"定时任务配置错误:{err}")
|
logger.error(f"定时任务配置错误:{err}")
|
||||||
|
# 推送实时消息
|
||||||
|
self.systemmessage.put(f"执行周期配置错误:{err}")
|
||||||
else:
|
else:
|
||||||
# 随机时间
|
# 随机时间
|
||||||
triggers = TimerUtils.random_scheduler(num_executions=2,
|
triggers = TimerUtils.random_scheduler(num_executions=2,
|
||||||
@ -104,7 +105,8 @@ class AutoSignIn(_PluginBase):
|
|||||||
min_interval=6 * 60)
|
min_interval=6 * 60)
|
||||||
for trigger in triggers:
|
for trigger in triggers:
|
||||||
self._scheduler.add_job(self.sign_in, "cron",
|
self._scheduler.add_job(self.sign_in, "cron",
|
||||||
hour=trigger.hour, minute=trigger.minute)
|
hour=trigger.hour, minute=trigger.minute,
|
||||||
|
name="站点自动签到")
|
||||||
|
|
||||||
# 启动任务
|
# 启动任务
|
||||||
if self._scheduler.get_jobs():
|
if self._scheduler.get_jobs():
|
||||||
@ -183,7 +185,7 @@ class AutoSignIn(_PluginBase):
|
|||||||
'component': 'VSwitch',
|
'component': 'VSwitch',
|
||||||
'props': {
|
'props': {
|
||||||
'model': 'notify',
|
'model': 'notify',
|
||||||
'label': '签到通知',
|
'label': '发送通知',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -205,7 +207,7 @@ class AutoSignIn(_PluginBase):
|
|||||||
'props': {
|
'props': {
|
||||||
'model': 'cron',
|
'model': 'cron',
|
||||||
'label': '执行周期',
|
'label': '执行周期',
|
||||||
'placeholder': '0 9,18 * * *'
|
'placeholder': '5位cron表达式,留空自动'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -253,7 +255,7 @@ class AutoSignIn(_PluginBase):
|
|||||||
], {
|
], {
|
||||||
"enabled": False,
|
"enabled": False,
|
||||||
"notify": True,
|
"notify": True,
|
||||||
"cron": "1 9,18 * * *",
|
"cron": "",
|
||||||
"queue_cnt": 5,
|
"queue_cnt": 5,
|
||||||
"sign_sites": []
|
"sign_sites": []
|
||||||
}
|
}
|
||||||
@ -270,7 +272,10 @@ class AutoSignIn(_PluginBase):
|
|||||||
自动签到
|
自动签到
|
||||||
"""
|
"""
|
||||||
if event:
|
if event:
|
||||||
logger.info("收到远程签到命令,开始执行签到任务 ...")
|
logger.info("收到命令,开始站点签到 ...")
|
||||||
|
self.post_message(channel=event.event_data.get("channel"),
|
||||||
|
title="开始站点签到 ...",
|
||||||
|
userid=event.event_data.get("user"))
|
||||||
# 查询签到站点
|
# 查询签到站点
|
||||||
sign_sites = [site for site in self.sites.get_indexers() if not site.get("public")]
|
sign_sites = [site for site in self.sites.get_indexers() if not site.get("public")]
|
||||||
# 过滤掉没有选中的站点
|
# 过滤掉没有选中的站点
|
||||||
@ -297,10 +302,17 @@ class AutoSignIn(_PluginBase):
|
|||||||
} for s in status])
|
} for s in status])
|
||||||
# 发送通知
|
# 发送通知
|
||||||
if self._notify:
|
if self._notify:
|
||||||
self.chain.post_message(Notification(title="站点自动签到",
|
self.post_message(title="站点自动签到",
|
||||||
text="\n".join([f'【{s[0]}】{s[1]}' for s in status if s])))
|
mtype=NotificationType.SiteMessage,
|
||||||
|
text="\n".join([f'【{s[0]}】{s[1]}' for s in status if s]))
|
||||||
|
if event:
|
||||||
|
self.post_message(channel=event.event_data.get("channel"),
|
||||||
|
title="站点签到完成!", userid=event.event_data.get("user"))
|
||||||
else:
|
else:
|
||||||
logger.error("站点签到任务失败!")
|
logger.error("站点签到任务失败!")
|
||||||
|
if event:
|
||||||
|
self.post_message(channel=event.event_data.get("channel"),
|
||||||
|
title="站点签到任务失败!", userid=event.event_data.get("user"))
|
||||||
|
|
||||||
def __build_class(self, url) -> Any:
|
def __build_class(self, url) -> Any:
|
||||||
for site_schema in self._site_schema:
|
for site_schema in self._site_schema:
|
||||||
|
356
app/plugins/doubansync/__init__.py
Normal file
356
app/plugins/doubansync/__init__.py
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from threading import Lock
|
||||||
|
from typing import Optional, Any, List, Dict, Tuple
|
||||||
|
|
||||||
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
|
|
||||||
|
from app.chain.download import DownloadChain
|
||||||
|
from app.chain.search import SearchChain
|
||||||
|
from app.chain.subscribe import SubscribeChain
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.core.context import MediaInfo
|
||||||
|
from app.core.event import Event
|
||||||
|
from app.core.event import eventmanager
|
||||||
|
from app.core.metainfo import MetaInfo
|
||||||
|
from app.helper.rss import RssHelper
|
||||||
|
from app.log import logger
|
||||||
|
from app.plugins import _PluginBase
|
||||||
|
from app.schemas.types import EventType
|
||||||
|
|
||||||
|
lock = Lock()
|
||||||
|
|
||||||
|
|
||||||
|
class DoubanSync(_PluginBase):
|
||||||
|
# 插件名称
|
||||||
|
plugin_name = "豆瓣想看"
|
||||||
|
# 插件描述
|
||||||
|
plugin_desc = "同步豆瓣想看数据,自动添加订阅。"
|
||||||
|
# 插件图标
|
||||||
|
plugin_icon = "douban.png"
|
||||||
|
# 主题色
|
||||||
|
plugin_color = "#05B711"
|
||||||
|
# 插件版本
|
||||||
|
plugin_version = "1.0"
|
||||||
|
# 插件作者
|
||||||
|
plugin_author = "jxxghp"
|
||||||
|
# 作者主页
|
||||||
|
author_url = "https://github.com/jxxghp"
|
||||||
|
# 插件配置项ID前缀
|
||||||
|
plugin_config_prefix = "doubansync_"
|
||||||
|
# 加载顺序
|
||||||
|
plugin_order = 3
|
||||||
|
# 可使用的用户级别
|
||||||
|
auth_level = 2
|
||||||
|
|
||||||
|
# 私有变量
|
||||||
|
_interests_url: str = "https://www.douban.com/feed/people/%s/interests"
|
||||||
|
_scheduler: Optional[BackgroundScheduler] = None
|
||||||
|
_cache_path: Optional[Path] = None
|
||||||
|
rsshelper = None
|
||||||
|
downloadchain = None
|
||||||
|
searchchain = None
|
||||||
|
subscribechain = None
|
||||||
|
|
||||||
|
# 配置属性
|
||||||
|
_enabled: bool = False
|
||||||
|
_cron: str = ""
|
||||||
|
_notify: bool = False
|
||||||
|
_days: int = 7
|
||||||
|
_users: str = ""
|
||||||
|
|
||||||
|
def init_plugin(self, config: dict = None):
|
||||||
|
self._cache_path = settings.TEMP_PATH / "__doubansync_cache__"
|
||||||
|
self.rsshelper = RssHelper()
|
||||||
|
self.downloadchain = DownloadChain()
|
||||||
|
self.searchchain = SearchChain()
|
||||||
|
self.subscribechain = SubscribeChain()
|
||||||
|
|
||||||
|
# 停止现有任务
|
||||||
|
self.stop_service()
|
||||||
|
|
||||||
|
# 配置
|
||||||
|
if config:
|
||||||
|
self._enabled = config.get("enabled")
|
||||||
|
self._cron = config.get("cron")
|
||||||
|
self._notify = config.get("notify")
|
||||||
|
self._days = config.get("days")
|
||||||
|
self._users = config.get("users")
|
||||||
|
|
||||||
|
if self._enabled:
|
||||||
|
|
||||||
|
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"定时任务配置错误:{err}")
|
||||||
|
# 推送实时消息
|
||||||
|
self.systemmessage.put(f"执行周期配置错误:{err}")
|
||||||
|
else:
|
||||||
|
self._scheduler.add_job(self.sync, "interval", minutes=30, name="豆瓣想看")
|
||||||
|
|
||||||
|
# 启动任务
|
||||||
|
if self._scheduler.get_jobs():
|
||||||
|
self._scheduler.print_jobs()
|
||||||
|
self._scheduler.start()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_command() -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
定义远程控制命令
|
||||||
|
:return: 命令关键字、事件、描述、附带数据
|
||||||
|
"""
|
||||||
|
return [{
|
||||||
|
"cmd": "/douban_sync",
|
||||||
|
"event": EventType.DoubanSync,
|
||||||
|
"desc": "同步豆瓣想看",
|
||||||
|
"data": {}
|
||||||
|
}]
|
||||||
|
|
||||||
|
def get_api(self) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取插件API
|
||||||
|
[{
|
||||||
|
"path": "/xx",
|
||||||
|
"endpoint": self.xxx,
|
||||||
|
"methods": ["GET", "POST"],
|
||||||
|
"summary": "API说明"
|
||||||
|
}]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'component': 'VForm',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSwitch',
|
||||||
|
'props': {
|
||||||
|
'model': 'enabled',
|
||||||
|
'label': '启用插件',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSwitch',
|
||||||
|
'props': {
|
||||||
|
'model': 'notify',
|
||||||
|
'label': '发送通知',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'cron',
|
||||||
|
'label': '执行周期',
|
||||||
|
'placeholder': '5位cron表达式,留空自动'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'days',
|
||||||
|
'label': '同步天数'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'users',
|
||||||
|
'label': '用户列表',
|
||||||
|
'placeholder': '豆瓣用户ID,多个用英文逗号分隔'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
], {
|
||||||
|
"enabled": False,
|
||||||
|
"notify": True,
|
||||||
|
"cron": "*/30 * * * *",
|
||||||
|
"days": 7,
|
||||||
|
"users": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_page(self) -> List[dict]:
|
||||||
|
"""
|
||||||
|
拼装插件详情页面,需要返回页面配置,同时附带数据
|
||||||
|
"""
|
||||||
|
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))
|
||||||
|
|
||||||
|
def sync(self):
|
||||||
|
"""
|
||||||
|
通过用户RSS同步豆瓣想看数据
|
||||||
|
"""
|
||||||
|
if not self._users:
|
||||||
|
return
|
||||||
|
# 读取缓存
|
||||||
|
caches = self._cache_path.read_text().split("\n") if self._cache_path.exists() else []
|
||||||
|
for user_id in self._users.split(","):
|
||||||
|
# 同步每个用户的豆瓣数据
|
||||||
|
if not user_id:
|
||||||
|
continue
|
||||||
|
logger.info(f"开始同步用户 {user_id} 的豆瓣想看数据 ...")
|
||||||
|
url = self._interests_url % user_id
|
||||||
|
results = self.rsshelper.parse(url)
|
||||||
|
if not results:
|
||||||
|
logger.error(f"未获取到用户 {user_id} 豆瓣RSS数据:{url}")
|
||||||
|
return
|
||||||
|
# 解析数据
|
||||||
|
for result in results:
|
||||||
|
dtype = result.get("title", "")[:2]
|
||||||
|
title = result.get("title", "")[2:]
|
||||||
|
if dtype not in ["想看"]:
|
||||||
|
continue
|
||||||
|
if not result.get("link"):
|
||||||
|
continue
|
||||||
|
# TODO 判断是否在天数范围
|
||||||
|
douban_id = result.get("link", "").split("/")[-2]
|
||||||
|
if not douban_id or douban_id in caches:
|
||||||
|
continue
|
||||||
|
# 根据豆瓣ID获取豆瓣数据
|
||||||
|
doubaninfo: Optional[dict] = self.chain.douban_info(doubanid=douban_id)
|
||||||
|
if not doubaninfo:
|
||||||
|
logger.warn(f'未获取到豆瓣信息,标题:{title},豆瓣ID:{douban_id}')
|
||||||
|
continue
|
||||||
|
logger.info(f'获取到豆瓣信息,标题:{title},豆瓣ID:{douban_id}')
|
||||||
|
# 识别媒体信息
|
||||||
|
meta = MetaInfo(doubaninfo.get("original_title") or doubaninfo.get("title"))
|
||||||
|
if doubaninfo.get("year"):
|
||||||
|
meta.year = doubaninfo.get("year")
|
||||||
|
mediainfo: MediaInfo = self.chain.recognize_media(meta=meta)
|
||||||
|
if not mediainfo:
|
||||||
|
logger.warn(f'未识别到媒体信息,标题:{title},豆瓣ID:{douban_id}')
|
||||||
|
continue
|
||||||
|
# 加入缓存
|
||||||
|
caches.append(douban_id)
|
||||||
|
# 查询缺失的媒体信息
|
||||||
|
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=meta, mediainfo=mediainfo)
|
||||||
|
if exist_flag:
|
||||||
|
logger.info(f'{mediainfo.title_year} 媒体库中已存在')
|
||||||
|
continue
|
||||||
|
logger.info(f'{mediainfo.title_year} 媒体库中不存在,开始搜索 ...')
|
||||||
|
# 搜索
|
||||||
|
contexts = self.searchchain.process(mediainfo=mediainfo,
|
||||||
|
no_exists=no_exists)
|
||||||
|
if not contexts:
|
||||||
|
logger.warn(f'{mediainfo.title_year} 未搜索到资源')
|
||||||
|
# 添加订阅
|
||||||
|
self.subscribechain.add(title=mediainfo.title,
|
||||||
|
year=mediainfo.year,
|
||||||
|
mtype=mediainfo.type,
|
||||||
|
tmdbid=mediainfo.tmdb_id,
|
||||||
|
season=meta.begin_season,
|
||||||
|
exist_ok=True,
|
||||||
|
username="豆瓣想看")
|
||||||
|
continue
|
||||||
|
# 自动下载
|
||||||
|
downloads, lefts = self.downloadchain.batch_download(contexts=contexts, no_exists=no_exists)
|
||||||
|
if downloads and not lefts:
|
||||||
|
# 全部下载完成
|
||||||
|
logger.info(f'{mediainfo.title_year} 下载完成')
|
||||||
|
else:
|
||||||
|
# 未完成下载
|
||||||
|
logger.info(f'{mediainfo.title_year} 未下载未完整,添加订阅 ...')
|
||||||
|
# 添加订阅
|
||||||
|
self.subscribechain.add(title=mediainfo.title,
|
||||||
|
year=mediainfo.year,
|
||||||
|
mtype=mediainfo.type,
|
||||||
|
tmdbid=mediainfo.tmdb_id,
|
||||||
|
season=meta.begin_season,
|
||||||
|
exist_ok=True,
|
||||||
|
username="豆瓣想看")
|
||||||
|
|
||||||
|
logger.info(f"用户 {user_id} 豆瓣想看同步完成")
|
||||||
|
# 保存缓存
|
||||||
|
self._cache_path.write_text("\n".join(caches))
|
||||||
|
|
||||||
|
@eventmanager.register(EventType.DoubanSync)
|
||||||
|
def remote_sync(self, event: Event):
|
||||||
|
"""
|
||||||
|
刷新站点数据
|
||||||
|
"""
|
||||||
|
if event:
|
||||||
|
logger.info("收到命令,开始执行豆瓣想看同步 ...")
|
||||||
|
self.post_message(channel=event.event_data.get("channel"),
|
||||||
|
title="开始同步豆瓣想看 ...",
|
||||||
|
userid=event.event_data.get("user"))
|
||||||
|
self.sync()
|
||||||
|
|
||||||
|
if event:
|
||||||
|
self.post_message(channel=event.event_data.get("channel"),
|
||||||
|
title="同步豆瓣想看数据完成!", userid=event.event_data.get("user"))
|
@ -1,3 +1,4 @@
|
|||||||
|
import warnings
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from multiprocessing.dummy import Pool as ThreadPool
|
from multiprocessing.dummy import Pool as ThreadPool
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
@ -10,23 +11,19 @@ from ruamel.yaml import CommentedMap
|
|||||||
|
|
||||||
from app import schemas
|
from app import schemas
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.core.event import eventmanager
|
|
||||||
from app.core.event import Event
|
from app.core.event import Event
|
||||||
|
from app.core.event import eventmanager
|
||||||
from app.helper.browser import PlaywrightHelper
|
from app.helper.browser import PlaywrightHelper
|
||||||
from app.helper.module import ModuleHelper
|
from app.helper.module import ModuleHelper
|
||||||
from app.helper.sites import SitesHelper
|
from app.helper.sites import SitesHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.plugins import _PluginBase
|
from app.plugins import _PluginBase
|
||||||
from app.plugins.sitestatistic.siteuserinfo import ISiteUserInfo
|
from app.plugins.sitestatistic.siteuserinfo import ISiteUserInfo
|
||||||
from app.schemas import Notification
|
from app.schemas.types import EventType, NotificationType
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils
|
||||||
from app.utils.timer import TimerUtils
|
from app.utils.timer import TimerUtils
|
||||||
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
from app.schemas.types import EventType
|
|
||||||
|
|
||||||
warnings.filterwarnings("ignore", category=FutureWarning)
|
warnings.filterwarnings("ignore", category=FutureWarning)
|
||||||
|
|
||||||
lock = Lock()
|
lock = Lock()
|
||||||
@ -56,7 +53,7 @@ class SiteStatistic(_PluginBase):
|
|||||||
|
|
||||||
# 私有属性
|
# 私有属性
|
||||||
sites = None
|
sites = None
|
||||||
_scheduler = None
|
_scheduler: Optional[BackgroundScheduler] = None
|
||||||
_last_update_time: Optional[datetime] = None
|
_last_update_time: Optional[datetime] = None
|
||||||
_sites_data: dict = {}
|
_sites_data: dict = {}
|
||||||
_site_schema: List[ISiteUserInfo] = None
|
_site_schema: List[ISiteUserInfo] = None
|
||||||
@ -95,9 +92,12 @@ class SiteStatistic(_PluginBase):
|
|||||||
if self._cron:
|
if self._cron:
|
||||||
try:
|
try:
|
||||||
self._scheduler.add_job(func=self.refresh_all_site_data,
|
self._scheduler.add_job(func=self.refresh_all_site_data,
|
||||||
trigger=CronTrigger.from_crontab(self._cron))
|
trigger=CronTrigger.from_crontab(self._cron),
|
||||||
|
name="站点数据统计")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"定时任务配置错误:{err}")
|
logger.error(f"定时任务配置错误:{err}")
|
||||||
|
# 推送实时消息
|
||||||
|
self.systemmessage.put(f"执行周期配置错误:{err}")
|
||||||
else:
|
else:
|
||||||
triggers = TimerUtils.random_scheduler(num_executions=1,
|
triggers = TimerUtils.random_scheduler(num_executions=1,
|
||||||
begin_hour=0,
|
begin_hour=0,
|
||||||
@ -106,7 +106,8 @@ class SiteStatistic(_PluginBase):
|
|||||||
max_interval=60)
|
max_interval=60)
|
||||||
for trigger in triggers:
|
for trigger in triggers:
|
||||||
self._scheduler.add_job(self.refresh_all_site_data, "cron",
|
self._scheduler.add_job(self.refresh_all_site_data, "cron",
|
||||||
hour=trigger.hour, minute=trigger.minute)
|
hour=trigger.hour, minute=trigger.minute,
|
||||||
|
name="站点数据统计")
|
||||||
|
|
||||||
# 启动任务
|
# 启动任务
|
||||||
if self._scheduler.get_jobs():
|
if self._scheduler.get_jobs():
|
||||||
@ -207,7 +208,7 @@ class SiteStatistic(_PluginBase):
|
|||||||
'props': {
|
'props': {
|
||||||
'model': 'cron',
|
'model': 'cron',
|
||||||
'label': '执行周期',
|
'label': '执行周期',
|
||||||
'placeholder': '0 9,18 * * *'
|
'placeholder': '5位cron表达式,留空自动'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -467,10 +468,11 @@ class SiteStatistic(_PluginBase):
|
|||||||
for head, date, content in site_user_info.message_unread_contents:
|
for head, date, content in site_user_info.message_unread_contents:
|
||||||
msg_title = f"【站点 {site_user_info.site_name} 消息】"
|
msg_title = f"【站点 {site_user_info.site_name} 消息】"
|
||||||
msg_text = f"时间:{date}\n标题:{head}\n内容:\n{content}"
|
msg_text = f"时间:{date}\n标题:{head}\n内容:\n{content}"
|
||||||
self.chain.post_message(Notification(title=msg_title, text=msg_text))
|
self.post_message(mtype=NotificationType.SiteMessage, title=msg_title, text=msg_text)
|
||||||
else:
|
else:
|
||||||
self.chain.post_message(Notification(title=f"站点 {site_user_info.site_name} 收到 "
|
self.post_message(mtype=NotificationType.SiteMessage,
|
||||||
f"{site_user_info.message_unread} 条新消息,请登陆查看"))
|
title=f"站点 {site_user_info.site_name} 收到 "
|
||||||
|
f"{site_user_info.message_unread} 条新消息,请登陆查看")
|
||||||
|
|
||||||
@eventmanager.register(EventType.SiteStatistic)
|
@eventmanager.register(EventType.SiteStatistic)
|
||||||
def refresh(self, event: Event):
|
def refresh(self, event: Event):
|
||||||
@ -478,8 +480,14 @@ class SiteStatistic(_PluginBase):
|
|||||||
刷新站点数据
|
刷新站点数据
|
||||||
"""
|
"""
|
||||||
if event:
|
if event:
|
||||||
logger.info("收到命令,开始执行站点数据刷新 ...")
|
logger.info("收到命令,开始刷新站点数据 ...")
|
||||||
|
self.post_message(channel=event.event_data.get("channel"),
|
||||||
|
title="开始刷新站点数据 ...",
|
||||||
|
userid=event.event_data.get("user"))
|
||||||
self.refresh_all_site_data(force=True)
|
self.refresh_all_site_data(force=True)
|
||||||
|
if event:
|
||||||
|
self.post_message(channel=event.event_data.get("channel"),
|
||||||
|
title="站点数据刷新完成!", userid=event.event_data.get("user"))
|
||||||
|
|
||||||
def refresh_all_site_data(self, force: bool = False, specify_sites: list = None):
|
def refresh_all_site_data(self, force: bool = False, specify_sites: list = None):
|
||||||
"""
|
"""
|
||||||
@ -555,6 +563,7 @@ class SiteStatistic(_PluginBase):
|
|||||||
f"总上传:{StringUtils.str_filesize(incUploads)}\n"
|
f"总上传:{StringUtils.str_filesize(incUploads)}\n"
|
||||||
f"总下载:{StringUtils.str_filesize(incDownloads)}\n"
|
f"总下载:{StringUtils.str_filesize(incDownloads)}\n"
|
||||||
f"————————————")
|
f"————————————")
|
||||||
self.chain.post_message(Notification(title="站点数据统计", text="\n".join(messages)))
|
self.post_message(mtype=NotificationType.SiteMessage,
|
||||||
|
title="站点数据统计", text="\n".join(messages))
|
||||||
|
|
||||||
logger.info("站点数据刷新完成")
|
logger.info("站点数据刷新完成")
|
||||||
|
@ -7,7 +7,6 @@ from apscheduler.schedulers.background import BackgroundScheduler
|
|||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.chain.cookiecloud import CookieCloudChain
|
from app.chain.cookiecloud import CookieCloudChain
|
||||||
from app.chain.douban import DoubanChain
|
|
||||||
from app.chain.mediaserver import MediaServerChain
|
from app.chain.mediaserver import MediaServerChain
|
||||||
from app.chain.subscribe import SubscribeChain
|
from app.chain.subscribe import SubscribeChain
|
||||||
from app.chain.transfer import TransferChain
|
from app.chain.transfer import TransferChain
|
||||||
@ -70,9 +69,6 @@ class Scheduler(metaclass=Singleton):
|
|||||||
self._scheduler.add_job(SubscribeChain().refresh, "cron",
|
self._scheduler.add_job(SubscribeChain().refresh, "cron",
|
||||||
hour=trigger.hour, minute=trigger.minute, name="订阅刷新")
|
hour=trigger.hour, minute=trigger.minute, name="订阅刷新")
|
||||||
|
|
||||||
# 豆瓣同步(每30分钟)
|
|
||||||
self._scheduler.add_job(DoubanChain().sync, "interval", minutes=30, name="同步豆瓣想看")
|
|
||||||
|
|
||||||
# 下载器文件转移(每5分钟)
|
# 下载器文件转移(每5分钟)
|
||||||
self._scheduler.add_job(TransferChain().process, "interval", minutes=5, name="下载文件整理")
|
self._scheduler.add_job(TransferChain().process, "interval", minutes=5, name="下载文件整理")
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ class EventType(Enum):
|
|||||||
SiteSignin = "site.signin"
|
SiteSignin = "site.signin"
|
||||||
# 站点数据统计
|
# 站点数据统计
|
||||||
SiteStatistic = "site.statistic"
|
SiteStatistic = "site.statistic"
|
||||||
|
# 豆瓣想看
|
||||||
|
DoubanSync = "douban.sync"
|
||||||
# Webhook消息
|
# Webhook消息
|
||||||
WebhookMessage = "webhook.message"
|
WebhookMessage = "webhook.message"
|
||||||
# 转移完成
|
# 转移完成
|
||||||
|
Loading…
x
Reference in New Issue
Block a user