feat 多通知渠道支持
This commit is contained in:
parent
c1e8b6d0ff
commit
6d2f4697b0
@ -222,5 +222,5 @@ docker pull jxxghp/moviepilot:latest
|
|||||||
- [x] 搜索结果过滤
|
- [x] 搜索结果过滤
|
||||||
- [ ] 媒体详情页面
|
- [ ] 媒体详情页面
|
||||||
- [ ] 洗版支持
|
- [ ] 洗版支持
|
||||||
- [ ] 多通知渠道支持
|
- [x] 多通知渠道支持
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ def add_downloading(
|
|||||||
|
|
||||||
@router.post("/notexists", summary="查询缺失媒体信息", response_model=List[NotExistMediaInfo])
|
@router.post("/notexists", summary="查询缺失媒体信息", response_model=List[NotExistMediaInfo])
|
||||||
def exists(media_in: schemas.MediaInfo,
|
def exists(media_in: schemas.MediaInfo,
|
||||||
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
|
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
|
||||||
"""
|
"""
|
||||||
查询缺失媒体信息
|
查询缺失媒体信息
|
||||||
"""
|
"""
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from typing import Any, List, Union
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, Depends
|
from fastapi import APIRouter, HTTPException, Depends
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
|
@ -10,8 +10,8 @@ from app.core.event import EventManager
|
|||||||
from app.core.meta import MetaBase
|
from app.core.meta import MetaBase
|
||||||
from app.core.module import ModuleManager
|
from app.core.module import ModuleManager
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage
|
from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage, Notification
|
||||||
from app.schemas.types import TorrentStatus, MediaType, MediaImageType, MessageChannel
|
from app.schemas.types import TorrentStatus, MediaType, MediaImageType
|
||||||
from app.utils.object import ObjectUtils
|
from app.utils.object import ObjectUtils
|
||||||
from app.utils.singleton import AbstractSingleton, Singleton
|
from app.utils.singleton import AbstractSingleton, Singleton
|
||||||
|
|
||||||
@ -287,42 +287,31 @@ class ChainBase(AbstractSingleton, metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
return self.run_module("refresh_mediaserver", mediainfo=mediainfo, file_path=file_path)
|
return self.run_module("refresh_mediaserver", mediainfo=mediainfo, file_path=file_path)
|
||||||
|
|
||||||
def post_message(self, title: str, text: str = None,
|
def post_message(self, message: Notification) -> Optional[bool]:
|
||||||
image: str = None, userid: Union[str, int] = None) -> Optional[bool]:
|
|
||||||
"""
|
"""
|
||||||
发送消息
|
发送消息
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param text: 内容
|
|
||||||
:param image: 图片
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.run_module("post_message", title=title, text=text, image=image, userid=userid)
|
return self.run_module("post_message", message=message)
|
||||||
|
|
||||||
def post_medias_message(self, title: str, items: List[MediaInfo],
|
def post_medias_message(self, message: Notification, medias: List[MediaInfo]) -> Optional[bool]:
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
|
||||||
"""
|
"""
|
||||||
发送媒体信息选择列表
|
发送媒体信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param items: 消息列表
|
:param medias: 媒体列表
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.run_module("post_medias_message", title=title, items=items, userid=userid)
|
return self.run_module("post_medias_message", message=message, medias=medias)
|
||||||
|
|
||||||
def post_torrents_message(self, title: str, items: List[Context],
|
def post_torrents_message(self, message: Notification, torrents: List[Context]) -> Optional[bool]:
|
||||||
mediainfo: MediaInfo,
|
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
|
||||||
"""
|
"""
|
||||||
发送种子信息选择列表
|
发送种子信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param items: 消息列表
|
:param torrents: 种子列表
|
||||||
:param mediainfo: 媒体信息
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.run_module("post_torrents_message", title=title, mediainfo=mediainfo,
|
return self.run_module("post_torrents_message", message=message, torrents=torrents)
|
||||||
items=items, userid=userid)
|
|
||||||
|
|
||||||
def scrape_metadata(self, path: Path, mediainfo: MediaInfo) -> None:
|
def scrape_metadata(self, path: Path, mediainfo: MediaInfo) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -13,6 +13,7 @@ from app.helper.cookiecloud import CookieCloudHelper
|
|||||||
from app.helper.message import MessageHelper
|
from app.helper.message import MessageHelper
|
||||||
from app.helper.sites import SitesHelper
|
from app.helper.sites import SitesHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
|
from app.schemas import Notification, NotificationType, MessageChannel
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils
|
||||||
|
|
||||||
|
|
||||||
@ -34,17 +35,20 @@ class CookieCloudChain(ChainBase):
|
|||||||
password=settings.COOKIECLOUD_PASSWORD
|
password=settings.COOKIECLOUD_PASSWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
def remote_sync(self, userid: Union[int, str]):
|
def remote_sync(self, channel: MessageChannel, userid: Union[int, str]):
|
||||||
"""
|
"""
|
||||||
远程触发同步站点,发送消息
|
远程触发同步站点,发送消息
|
||||||
"""
|
"""
|
||||||
self.post_message(title="开始同步CookieCloud站点 ...", userid=userid)
|
self.post_message(Notification(channel=channel, mtype=NotificationType.SiteMessage,
|
||||||
|
title="开始同步CookieCloud站点 ...", userid=userid))
|
||||||
# 开始同步
|
# 开始同步
|
||||||
success, msg = self.process()
|
success, msg = self.process()
|
||||||
if success:
|
if success:
|
||||||
self.post_message(title=f"同步站点成功,{msg}", userid=userid)
|
self.post_message(Notification(channel=channel, mtype=NotificationType.SiteMessage,
|
||||||
|
title=f"同步站点成功,{msg}", userid=userid))
|
||||||
else:
|
else:
|
||||||
self.post_message(title=f"同步站点失败:{msg}", userid=userid)
|
self.post_message(Notification(channel=channel, mtype=NotificationType.SiteMessage,
|
||||||
|
title=f"同步站点失败:{msg}", userid=userid))
|
||||||
|
|
||||||
def process(self, manual=False) -> Tuple[bool, str]:
|
def process(self, manual=False) -> Tuple[bool, str]:
|
||||||
"""
|
"""
|
||||||
|
@ -12,7 +12,7 @@ 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.helper.rss import RssHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import MediaType
|
from app.schemas import MediaType, Notification, MessageChannel, NotificationType
|
||||||
|
|
||||||
|
|
||||||
class DoubanChain(ChainBase):
|
class DoubanChain(ChainBase):
|
||||||
@ -91,13 +91,15 @@ 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, userid: Union[int, str]):
|
def remote_sync(self, channel: MessageChannel, userid: Union[int, str]):
|
||||||
"""
|
"""
|
||||||
同步豆瓣想看数据,发送消息
|
同步豆瓣想看数据,发送消息
|
||||||
"""
|
"""
|
||||||
self.post_message(title="开始同步豆瓣想看 ...", userid=userid)
|
self.post_message(Notification(channel=channel, mtype=NotificationType.Subscribe,
|
||||||
|
title="开始同步豆瓣想看 ...", userid=userid))
|
||||||
self.sync()
|
self.sync()
|
||||||
self.post_message(title="同步豆瓣想看数据完成!", userid=userid)
|
self.post_message(Notification(channel=channel, mtype=NotificationType.Subscribe,
|
||||||
|
title="同步豆瓣想看数据完成!", userid=userid))
|
||||||
|
|
||||||
def sync(self):
|
def sync(self):
|
||||||
"""
|
"""
|
||||||
|
@ -8,8 +8,8 @@ from app.core.meta import MetaBase
|
|||||||
from app.db.downloadhistory_oper import DownloadHistoryOper
|
from app.db.downloadhistory_oper import DownloadHistoryOper
|
||||||
from app.helper.torrent import TorrentHelper
|
from app.helper.torrent import TorrentHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import ExistMediaInfo, NotExistMediaInfo, DownloadingTorrent
|
from app.schemas import ExistMediaInfo, NotExistMediaInfo, DownloadingTorrent, Notification
|
||||||
from app.schemas.types import MediaType, TorrentStatus, EventType
|
from app.schemas.types import MediaType, TorrentStatus, EventType, MessageChannel, NotificationType
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils
|
||||||
|
|
||||||
|
|
||||||
@ -23,7 +23,9 @@ class DownloadChain(ChainBase):
|
|||||||
self.torrent = TorrentHelper()
|
self.torrent = TorrentHelper()
|
||||||
self.downloadhis = DownloadHistoryOper()
|
self.downloadhis = DownloadHistoryOper()
|
||||||
|
|
||||||
def post_download_message(self, meta: MetaBase, mediainfo: MediaInfo, torrent: TorrentInfo, userid: str = None):
|
def post_download_message(self, meta: MetaBase, mediainfo: MediaInfo, torrent: TorrentInfo,
|
||||||
|
channel: MessageChannel = None,
|
||||||
|
userid: str = None):
|
||||||
"""
|
"""
|
||||||
发送添加下载的消息
|
发送添加下载的消息
|
||||||
"""
|
"""
|
||||||
@ -51,13 +53,17 @@ class DownloadChain(ChainBase):
|
|||||||
torrent.description = re.sub(r'<[^>]+>', '', description)
|
torrent.description = re.sub(r'<[^>]+>', '', description)
|
||||||
msg_text = f"{msg_text}\n描述:{torrent.description}"
|
msg_text = f"{msg_text}\n描述:{torrent.description}"
|
||||||
|
|
||||||
self.post_message(title=f"{mediainfo.title_year}"
|
self.post_message(Notification(
|
||||||
f"{meta.season_episode} 开始下载",
|
channel=channel,
|
||||||
text=msg_text,
|
mtype=NotificationType.Download,
|
||||||
image=mediainfo.get_message_image(),
|
title=f"{mediainfo.title_year}"
|
||||||
userid=userid)
|
f"{meta.season_episode} 开始下载",
|
||||||
|
text=msg_text,
|
||||||
|
image=mediainfo.get_message_image(),
|
||||||
|
userid=userid))
|
||||||
|
|
||||||
def download_torrent(self, torrent: TorrentInfo,
|
def download_torrent(self, torrent: TorrentInfo,
|
||||||
|
channel: MessageChannel = None,
|
||||||
userid: Union[str, int] = None) -> Tuple[Optional[Path], str, list]:
|
userid: Union[str, int] = None) -> Tuple[Optional[Path], str, list]:
|
||||||
"""
|
"""
|
||||||
下载种子文件
|
下载种子文件
|
||||||
@ -70,14 +76,19 @@ class DownloadChain(ChainBase):
|
|||||||
proxy=torrent.site_proxy)
|
proxy=torrent.site_proxy)
|
||||||
if not torrent_file:
|
if not torrent_file:
|
||||||
logger.error(f"下载种子文件失败:{torrent.title} - {torrent.enclosure}")
|
logger.error(f"下载种子文件失败:{torrent.title} - {torrent.enclosure}")
|
||||||
self.post_message(title=f"{torrent.title} 种子下载失败!",
|
self.post_message(Notification(
|
||||||
text=f"错误信息:{error_msg}\n种子链接:{torrent.enclosure}",
|
channel=channel,
|
||||||
userid=userid)
|
mtype=NotificationType.Download,
|
||||||
|
title=f"{torrent.title} 种子下载失败!",
|
||||||
|
text=f"错误信息:{error_msg}\n种子链接:{torrent.enclosure}",
|
||||||
|
userid=userid))
|
||||||
return None, "", []
|
return None, "", []
|
||||||
return torrent_file, download_folder, files
|
return torrent_file, download_folder, files
|
||||||
|
|
||||||
def download_single(self, context: Context, torrent_file: Path = None,
|
def download_single(self, context: Context, torrent_file: Path = None,
|
||||||
episodes: Set[int] = None, userid: Union[str, int] = None) -> Optional[str]:
|
episodes: Set[int] = None,
|
||||||
|
channel: MessageChannel = None,
|
||||||
|
userid: Union[str, int] = None) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
下载及发送通知
|
下载及发送通知
|
||||||
"""
|
"""
|
||||||
@ -119,7 +130,8 @@ class DownloadChain(ChainBase):
|
|||||||
torrent_site=_torrent.site_name
|
torrent_site=_torrent.site_name
|
||||||
)
|
)
|
||||||
# 发送消息
|
# 发送消息
|
||||||
self.post_download_message(meta=_meta, mediainfo=_media, torrent=_torrent, userid=userid)
|
self.post_download_message(meta=_meta, mediainfo=_media, torrent=_torrent,
|
||||||
|
channel=channel, userid=userid)
|
||||||
# 下载成功后处理
|
# 下载成功后处理
|
||||||
self.download_added(context=context, torrent_path=torrent_file)
|
self.download_added(context=context, torrent_path=torrent_file)
|
||||||
# 广播事件
|
# 广播事件
|
||||||
@ -132,7 +144,9 @@ class DownloadChain(ChainBase):
|
|||||||
# 下载失败
|
# 下载失败
|
||||||
logger.error(f"{_media.title_year} 添加下载任务失败:"
|
logger.error(f"{_media.title_year} 添加下载任务失败:"
|
||||||
f"{_torrent.title} - {_torrent.enclosure},{error_msg}")
|
f"{_torrent.title} - {_torrent.enclosure},{error_msg}")
|
||||||
self.post_message(
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
mtype=NotificationType.Download,
|
||||||
title="添加下载任务失败:%s %s"
|
title="添加下载任务失败:%s %s"
|
||||||
% (_media.title_year, _meta.season_episode),
|
% (_media.title_year, _meta.season_episode),
|
||||||
text=f"站点:{_torrent.site_name}\n"
|
text=f"站点:{_torrent.site_name}\n"
|
||||||
@ -140,7 +154,7 @@ class DownloadChain(ChainBase):
|
|||||||
f"种子链接:{_torrent.enclosure}\n"
|
f"种子链接:{_torrent.enclosure}\n"
|
||||||
f"错误信息:{error_msg}",
|
f"错误信息:{error_msg}",
|
||||||
image=_media.get_message_image(),
|
image=_media.get_message_image(),
|
||||||
userid=userid)
|
userid=userid))
|
||||||
return _hash
|
return _hash
|
||||||
|
|
||||||
def batch_download(self,
|
def batch_download(self,
|
||||||
@ -324,12 +338,12 @@ class DownloadChain(ChainBase):
|
|||||||
if len(torrent_season) != 1 or torrent_season[0] != need_season:
|
if len(torrent_season) != 1 or torrent_season[0] != need_season:
|
||||||
continue
|
continue
|
||||||
# 种子集列表
|
# 种子集列表
|
||||||
torrent_episodes = meta.episode_list
|
torrent_episodes = set(meta.episode_list)
|
||||||
# 整季的不处理
|
# 整季的不处理
|
||||||
if not torrent_episodes:
|
if not torrent_episodes:
|
||||||
continue
|
continue
|
||||||
# 为需要集的子集则下载
|
# 为需要集的子集则下载
|
||||||
if set(torrent_episodes).issubset(set(need_episodes)):
|
if torrent_episodes.issubset(set(need_episodes)):
|
||||||
# 下载
|
# 下载
|
||||||
download_id = self.download_single(context, userid=userid)
|
download_id = self.download_single(context, userid=userid)
|
||||||
if download_id:
|
if download_id:
|
||||||
@ -517,13 +531,16 @@ class DownloadChain(ChainBase):
|
|||||||
# 全部存在
|
# 全部存在
|
||||||
return True, no_exists
|
return True, no_exists
|
||||||
|
|
||||||
def remote_downloading(self, userid: Union[str, int] = None):
|
def remote_downloading(self, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
查询正在下载的任务,并发送消息
|
查询正在下载的任务,并发送消息
|
||||||
"""
|
"""
|
||||||
torrents = self.list_torrents(status=TorrentStatus.DOWNLOADING)
|
torrents = self.list_torrents(status=TorrentStatus.DOWNLOADING)
|
||||||
if not torrents:
|
if not torrents:
|
||||||
self.post_message(title="没有正在下载的任务!")
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
mtype=NotificationType.Download,
|
||||||
|
title="没有正在下载的任务!"))
|
||||||
return
|
return
|
||||||
# 发送消息
|
# 发送消息
|
||||||
title = f"共 {len(torrents)} 个任务正在下载:"
|
title = f"共 {len(torrents)} 个任务正在下载:"
|
||||||
@ -534,7 +551,9 @@ class DownloadChain(ChainBase):
|
|||||||
f"{StringUtils.str_filesize(torrent.size)} "
|
f"{StringUtils.str_filesize(torrent.size)} "
|
||||||
f"{round(torrent.progress * 100, 1)}%")
|
f"{round(torrent.progress * 100, 1)}%")
|
||||||
index += 1
|
index += 1
|
||||||
self.post_message(title=title, text="\n".join(messages), userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel, mtype=NotificationType.Download,
|
||||||
|
title=title, text="\n".join(messages), userid=userid))
|
||||||
|
|
||||||
def downloading(self) -> List[DownloadingTorrent]:
|
def downloading(self) -> List[DownloadingTorrent]:
|
||||||
"""
|
"""
|
||||||
|
@ -7,7 +7,8 @@ from app.chain.subscribe import SubscribeChain
|
|||||||
from app.core.context import MediaInfo
|
from app.core.context import MediaInfo
|
||||||
from app.core.event import EventManager
|
from app.core.event import EventManager
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas.types import EventType
|
from app.schemas import Notification
|
||||||
|
from app.schemas.types import EventType, MessageChannel
|
||||||
|
|
||||||
|
|
||||||
class MessageChain(ChainBase):
|
class MessageChain(ChainBase):
|
||||||
@ -76,7 +77,7 @@ class MessageChain(ChainBase):
|
|||||||
or not cache_data.get('items') \
|
or not cache_data.get('items') \
|
||||||
or len(cache_data.get('items')) < int(text):
|
or len(cache_data.get('items')) < int(text):
|
||||||
# 发送消息
|
# 发送消息
|
||||||
self.post_message(title="输入有误!", userid=userid)
|
self.post_message(Notification(channel=channel, title="输入有误!", userid=userid))
|
||||||
return
|
return
|
||||||
# 缓存类型
|
# 缓存类型
|
||||||
cache_type: str = cache_data.get('type')
|
cache_type: str = cache_data.get('type')
|
||||||
@ -90,9 +91,11 @@ class MessageChain(ChainBase):
|
|||||||
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=self._current_meta,
|
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=self._current_meta,
|
||||||
mediainfo=self._current_media)
|
mediainfo=self._current_media)
|
||||||
if exist_flag:
|
if exist_flag:
|
||||||
self.post_message(title=f"{self._current_media.title_year}"
|
self.post_message(
|
||||||
f"{self._current_meta.sea} 媒体库中已存在",
|
Notification(channel=channel,
|
||||||
userid=userid)
|
title=f"{self._current_media.title_year}"
|
||||||
|
f"{self._current_meta.sea} 媒体库中已存在",
|
||||||
|
userid=userid))
|
||||||
return
|
return
|
||||||
# 发送缺失的媒体信息
|
# 发送缺失的媒体信息
|
||||||
if no_exists:
|
if no_exists:
|
||||||
@ -100,19 +103,23 @@ class MessageChain(ChainBase):
|
|||||||
messages = [
|
messages = [
|
||||||
f"第 {sea} 季缺失 {StringUtils.str_series(no_exist.episodes) if no_exist.episodes else no_exist.total_episodes} 集"
|
f"第 {sea} 季缺失 {StringUtils.str_series(no_exist.episodes) if no_exist.episodes else no_exist.total_episodes} 集"
|
||||||
for sea, no_exist in no_exists.get(mediainfo.tmdb_id).items()]
|
for sea, no_exist in no_exists.get(mediainfo.tmdb_id).items()]
|
||||||
self.post_message(title=f"{mediainfo.title_year}:\n" + "\n".join(messages))
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"{mediainfo.title_year}:\n" + "\n".join(messages)))
|
||||||
# 搜索种子,过滤掉不需要的剧集,以便选择
|
# 搜索种子,过滤掉不需要的剧集,以便选择
|
||||||
logger.info(f"{mediainfo.title_year} 媒体库中不存在,开始搜索 ...")
|
logger.info(f"{mediainfo.title_year} 媒体库中不存在,开始搜索 ...")
|
||||||
self.post_message(
|
self.post_message(
|
||||||
title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...", userid=userid)
|
Notification(channel=channel,
|
||||||
|
title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...",
|
||||||
|
userid=userid))
|
||||||
# 开始搜索
|
# 开始搜索
|
||||||
contexts = self.searchchain.process(mediainfo=mediainfo,
|
contexts = self.searchchain.process(mediainfo=mediainfo,
|
||||||
no_exists=no_exists)
|
no_exists=no_exists)
|
||||||
if not contexts:
|
if not contexts:
|
||||||
# 没有数据
|
# 没有数据
|
||||||
self.post_message(title=f"{mediainfo.title}"
|
self.post_message(Notification(
|
||||||
f"{self._current_meta.sea} 未搜索到需要的资源!",
|
channel=channel, title=f"{mediainfo.title}"
|
||||||
userid=userid)
|
f"{self._current_meta.sea} 未搜索到需要的资源!",
|
||||||
|
userid=userid))
|
||||||
return
|
return
|
||||||
# 搜索结果排序
|
# 搜索结果排序
|
||||||
contexts = self.torrenthelper.sort_torrents(contexts)
|
contexts = self.torrenthelper.sort_torrents(contexts)
|
||||||
@ -124,9 +131,9 @@ class MessageChain(ChainBase):
|
|||||||
self._current_page = 0
|
self._current_page = 0
|
||||||
# 发送种子数据
|
# 发送种子数据
|
||||||
logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...")
|
logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...")
|
||||||
self.__post_torrents_message(title=mediainfo.title,
|
self.__post_torrents_message(channel=channel,
|
||||||
|
title=mediainfo.title,
|
||||||
items=contexts[:self._page_size],
|
items=contexts[:self._page_size],
|
||||||
mediainfo=mediainfo,
|
|
||||||
userid=userid,
|
userid=userid,
|
||||||
total=len(contexts))
|
total=len(contexts))
|
||||||
|
|
||||||
@ -137,15 +144,18 @@ class MessageChain(ChainBase):
|
|||||||
exist_flag, _ = self.downloadchain.get_no_exists_info(meta=self._current_meta,
|
exist_flag, _ = self.downloadchain.get_no_exists_info(meta=self._current_meta,
|
||||||
mediainfo=mediainfo)
|
mediainfo=mediainfo)
|
||||||
if exist_flag:
|
if exist_flag:
|
||||||
self.post_message(title=f"{mediainfo.title_year}"
|
self.post_message(Notification(
|
||||||
f"{self._current_meta.sea} 媒体库中已存在",
|
channel=channel,
|
||||||
userid=userid)
|
title=f"{mediainfo.title_year}"
|
||||||
|
f"{self._current_meta.sea} 媒体库中已存在",
|
||||||
|
userid=userid))
|
||||||
return
|
return
|
||||||
self.subscribechain.add(title=mediainfo.title,
|
self.subscribechain.add(title=mediainfo.title,
|
||||||
year=mediainfo.year,
|
year=mediainfo.year,
|
||||||
mtype=mediainfo.type,
|
mtype=mediainfo.type,
|
||||||
tmdbid=mediainfo.tmdb_id,
|
tmdbid=mediainfo.tmdb_id,
|
||||||
season=self._current_meta.begin_season,
|
season=self._current_meta.begin_season,
|
||||||
|
channel=channel,
|
||||||
userid=userid,
|
userid=userid,
|
||||||
username=username)
|
username=username)
|
||||||
elif cache_type == "Torrent":
|
elif cache_type == "Torrent":
|
||||||
@ -155,9 +165,11 @@ class MessageChain(ChainBase):
|
|||||||
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=self._current_meta,
|
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=self._current_meta,
|
||||||
mediainfo=self._current_media)
|
mediainfo=self._current_media)
|
||||||
if exist_flag:
|
if exist_flag:
|
||||||
self.post_message(title=f"{self._current_media.title_year}"
|
self.post_message(Notification(
|
||||||
f"{self._current_meta.sea} 媒体库中已存在",
|
channel=channel,
|
||||||
userid=userid)
|
title=f"{self._current_media.title_year}"
|
||||||
|
f"{self._current_meta.sea} 媒体库中已存在",
|
||||||
|
userid=userid))
|
||||||
return
|
return
|
||||||
# 批量下载
|
# 批量下载
|
||||||
downloads, lefts = self.downloadchain.batch_download(contexts=cache_list,
|
downloads, lefts = self.downloadchain.batch_download(contexts=cache_list,
|
||||||
@ -175,6 +187,7 @@ class MessageChain(ChainBase):
|
|||||||
mtype=self._current_media.type,
|
mtype=self._current_media.type,
|
||||||
tmdbid=self._current_media.tmdb_id,
|
tmdbid=self._current_media.tmdb_id,
|
||||||
season=self._current_meta.begin_season,
|
season=self._current_meta.begin_season,
|
||||||
|
channel=channel,
|
||||||
userid=userid,
|
userid=userid,
|
||||||
username=username)
|
username=username)
|
||||||
else:
|
else:
|
||||||
@ -188,12 +201,14 @@ class MessageChain(ChainBase):
|
|||||||
cache_data: dict = self._user_cache.get(userid)
|
cache_data: dict = self._user_cache.get(userid)
|
||||||
if not cache_data:
|
if not cache_data:
|
||||||
# 没有缓存
|
# 没有缓存
|
||||||
self.post_message(title="输入有误!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel, title="输入有误!", userid=userid))
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._current_page == 0:
|
if self._current_page == 0:
|
||||||
# 第一页
|
# 第一页
|
||||||
self.post_message(title="已经是第一页了!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel, title="已经是第一页了!", userid=userid))
|
||||||
return
|
return
|
||||||
cache_type: str = cache_data.get('type')
|
cache_type: str = cache_data.get('type')
|
||||||
cache_list: list = cache_data.get('items')
|
cache_list: list = cache_data.get('items')
|
||||||
@ -207,14 +222,15 @@ class MessageChain(ChainBase):
|
|||||||
end = start + self._page_size
|
end = start + self._page_size
|
||||||
if cache_type == "Torrent":
|
if cache_type == "Torrent":
|
||||||
# 发送种子数据
|
# 发送种子数据
|
||||||
self.__post_torrents_message(title=self._current_media.title,
|
self.__post_torrents_message(channel=channel,
|
||||||
|
title=self._current_media.title,
|
||||||
items=cache_list[start:end],
|
items=cache_list[start:end],
|
||||||
mediainfo=self._current_media,
|
|
||||||
userid=userid,
|
userid=userid,
|
||||||
total=len(cache_list))
|
total=len(cache_list))
|
||||||
else:
|
else:
|
||||||
# 发送媒体数据
|
# 发送媒体数据
|
||||||
self.__post_medias_message(title=self._current_media.title,
|
self.__post_medias_message(channel=channel,
|
||||||
|
title=self._current_media.title,
|
||||||
items=cache_list[start:end],
|
items=cache_list[start:end],
|
||||||
userid=userid,
|
userid=userid,
|
||||||
total=len(cache_list))
|
total=len(cache_list))
|
||||||
@ -224,7 +240,8 @@ class MessageChain(ChainBase):
|
|||||||
cache_data: dict = self._user_cache.get(userid)
|
cache_data: dict = self._user_cache.get(userid)
|
||||||
if not cache_data:
|
if not cache_data:
|
||||||
# 没有缓存
|
# 没有缓存
|
||||||
self.post_message(title="输入有误!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel, title="输入有误!", userid=userid))
|
||||||
return
|
return
|
||||||
cache_type: str = cache_data.get('type')
|
cache_type: str = cache_data.get('type')
|
||||||
cache_list: list = cache_data.get('items')
|
cache_list: list = cache_data.get('items')
|
||||||
@ -234,17 +251,19 @@ class MessageChain(ChainBase):
|
|||||||
cache_list = cache_list[self._current_page * self._page_size:(self._current_page + 1) * self._page_size]
|
cache_list = cache_list[self._current_page * self._page_size:(self._current_page + 1) * self._page_size]
|
||||||
if not cache_list:
|
if not cache_list:
|
||||||
# 没有数据
|
# 没有数据
|
||||||
self.post_message(title="已经是最后一页了!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel, title="已经是最后一页了!", userid=userid))
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if cache_type == "Torrent":
|
if cache_type == "Torrent":
|
||||||
# 发送种子数据
|
# 发送种子数据
|
||||||
self.__post_torrents_message(title=self._current_media.title,
|
self.__post_torrents_message(channel=channel,
|
||||||
mediainfo=self._current_media,
|
title=self._current_media.title,
|
||||||
items=cache_list, userid=userid, total=total)
|
items=cache_list, userid=userid, total=total)
|
||||||
else:
|
else:
|
||||||
# 发送媒体数据
|
# 发送媒体数据
|
||||||
self.__post_medias_message(title=self._current_media.title,
|
self.__post_medias_message(channel=channel,
|
||||||
|
title=self._current_media.title,
|
||||||
items=cache_list, userid=userid, total=total)
|
items=cache_list, userid=userid, total=total)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -261,11 +280,13 @@ class MessageChain(ChainBase):
|
|||||||
meta, medias = self.medtachain.search(content)
|
meta, medias = self.medtachain.search(content)
|
||||||
# 识别
|
# 识别
|
||||||
if not meta.name:
|
if not meta.name:
|
||||||
self.post_message(title="无法识别输入内容!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel, title="无法识别输入内容!", userid=userid))
|
||||||
return
|
return
|
||||||
# 开始搜索
|
# 开始搜索
|
||||||
if not medias:
|
if not medias:
|
||||||
self.post_message(title=f"{meta.name} 没有找到对应的媒体信息!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel, title=f"{meta.name} 没有找到对应的媒体信息!", userid=userid))
|
||||||
return
|
return
|
||||||
logger.info(f"搜索到 {len(medias)} 条相关媒体信息")
|
logger.info(f"搜索到 {len(medias)} 条相关媒体信息")
|
||||||
# 记录当前状态
|
# 记录当前状态
|
||||||
@ -277,28 +298,30 @@ class MessageChain(ChainBase):
|
|||||||
self._current_page = 0
|
self._current_page = 0
|
||||||
self._current_media = None
|
self._current_media = None
|
||||||
# 发送媒体列表
|
# 发送媒体列表
|
||||||
self.__post_medias_message(title=meta.name,
|
self.__post_medias_message(channel=channel,
|
||||||
|
title=meta.name,
|
||||||
items=medias[:self._page_size],
|
items=medias[:self._page_size],
|
||||||
userid=userid, total=len(medias))
|
userid=userid, total=len(medias))
|
||||||
|
|
||||||
def __post_medias_message(self, title: str, items: list, userid: str, total: int):
|
def __post_medias_message(self, channel: MessageChannel,
|
||||||
|
title: str, items: list, userid: str, total: int):
|
||||||
"""
|
"""
|
||||||
发送媒体列表消息
|
发送媒体列表消息
|
||||||
"""
|
"""
|
||||||
self.post_medias_message(
|
self.post_medias_message(Notification(
|
||||||
|
channel=channel,
|
||||||
title=f"【{title}】共找到{total}条相关信息,请回复对应数字选择(p: 上一页 n: 下一页)",
|
title=f"【{title}】共找到{total}条相关信息,请回复对应数字选择(p: 上一页 n: 下一页)",
|
||||||
items=items,
|
|
||||||
userid=userid
|
userid=userid
|
||||||
)
|
), medias=items)
|
||||||
|
|
||||||
def __post_torrents_message(self, title: str, items: list,
|
def __post_torrents_message(self, channel: MessageChannel, title: str, items: list,
|
||||||
mediainfo: MediaInfo, userid: str, total: int):
|
userid: str, total: int):
|
||||||
"""
|
"""
|
||||||
发送种子列表消息
|
发送种子列表消息
|
||||||
"""
|
"""
|
||||||
self.post_torrents_message(
|
self.post_torrents_message(Notification(
|
||||||
|
channel=channel,
|
||||||
title=f"【{title}】共找到{total}条相关资源,请回复对应数字下载(0: 自动选择 p: 上一页 n: 下一页)",
|
title=f"【{title}】共找到{total}条相关资源,请回复对应数字下载(0: 自动选择 p: 上一页 n: 下一页)",
|
||||||
items=items,
|
items=items,
|
||||||
mediainfo=mediainfo,
|
|
||||||
userid=userid
|
userid=userid
|
||||||
)
|
), torrents=items)
|
||||||
|
@ -16,7 +16,6 @@ from app.helper.torrent import TorrentHelper
|
|||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import NotExistMediaInfo
|
from app.schemas import NotExistMediaInfo
|
||||||
from app.schemas.types import MediaType, ProgressKey, SystemConfigKey
|
from app.schemas.types import MediaType, ProgressKey, SystemConfigKey
|
||||||
from app.utils.object import ObjectUtils
|
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ from app.helper.cloudflare import under_challenge
|
|||||||
from app.helper.cookie import CookieHelper
|
from app.helper.cookie import CookieHelper
|
||||||
from app.helper.message import MessageHelper
|
from app.helper.message import MessageHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
|
from app.schemas import MessageChannel, Notification
|
||||||
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
|
||||||
@ -80,13 +81,15 @@ class SiteChain(ChainBase):
|
|||||||
return False, f"{str(e)}!"
|
return False, f"{str(e)}!"
|
||||||
return True, "连接成功"
|
return True, "连接成功"
|
||||||
|
|
||||||
def remote_list(self, userid: Union[str, int] = None):
|
def remote_list(self, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
查询所有站点,发送消息
|
查询所有站点,发送消息
|
||||||
"""
|
"""
|
||||||
site_list = self.siteoper.list()
|
site_list = self.siteoper.list()
|
||||||
if not site_list:
|
if not site_list:
|
||||||
self.post_message(title="没有维护任何站点信息!")
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title="没有维护任何站点信息!"))
|
||||||
title = f"共有 {len(site_list)} 个站点,回复对应指令操作:" \
|
title = f"共有 {len(site_list)} 个站点,回复对应指令操作:" \
|
||||||
f"\n- 禁用站点:/site_disable [id]" \
|
f"\n- 禁用站点:/site_disable [id]" \
|
||||||
f"\n- 启用站点:/site_enable [id]" \
|
f"\n- 启用站点:/site_enable [id]" \
|
||||||
@ -102,9 +105,11 @@ class SiteChain(ChainBase):
|
|||||||
else:
|
else:
|
||||||
messages.append(f"{site.id}. {site.name}")
|
messages.append(f"{site.id}. {site.name}")
|
||||||
# 发送列表
|
# 发送列表
|
||||||
self.post_message(title=title, text="\n".join(messages), userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=title, text="\n".join(messages), userid=userid))
|
||||||
|
|
||||||
def remote_disable(self, arg_str, userid: Union[str, int] = None):
|
def remote_disable(self, arg_str, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
禁用站点
|
禁用站点
|
||||||
"""
|
"""
|
||||||
@ -116,16 +121,18 @@ class SiteChain(ChainBase):
|
|||||||
site_id = int(arg_str)
|
site_id = int(arg_str)
|
||||||
site = self.siteoper.get(site_id)
|
site = self.siteoper.get(site_id)
|
||||||
if not site:
|
if not site:
|
||||||
self.post_message(title=f"站点编号 {site_id} 不存在!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=f"站点编号 {site_id} 不存在!", userid=userid))
|
||||||
return
|
return
|
||||||
# 禁用站点
|
# 禁用站点
|
||||||
self.siteoper.update(site_id, {
|
self.siteoper.update(site_id, {
|
||||||
"is_active": False
|
"is_active": False
|
||||||
})
|
})
|
||||||
# 重新发送消息
|
# 重新发送消息
|
||||||
self.remote_list()
|
self.remote_list(channel, userid)
|
||||||
|
|
||||||
def remote_enable(self, arg_str, userid: Union[str, int] = None):
|
def remote_enable(self, arg_str, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
启用站点
|
启用站点
|
||||||
"""
|
"""
|
||||||
@ -139,14 +146,16 @@ class SiteChain(ChainBase):
|
|||||||
site_id = int(arg_str)
|
site_id = int(arg_str)
|
||||||
site = self.siteoper.get(site_id)
|
site = self.siteoper.get(site_id)
|
||||||
if not site:
|
if not site:
|
||||||
self.post_message(title=f"站点编号 {site_id} 不存在!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=f"站点编号 {site_id} 不存在!", userid=userid))
|
||||||
return
|
return
|
||||||
# 禁用站点
|
# 禁用站点
|
||||||
self.siteoper.update(site_id, {
|
self.siteoper.update(site_id, {
|
||||||
"is_active": True
|
"is_active": True
|
||||||
})
|
})
|
||||||
# 重新发送消息
|
# 重新发送消息
|
||||||
self.remote_list()
|
self.remote_list(channel, userid)
|
||||||
|
|
||||||
def update_cookie(self, site_info: Site,
|
def update_cookie(self, site_info: Site,
|
||||||
username: str, password: str) -> Tuple[bool, str]:
|
username: str, password: str) -> Tuple[bool, str]:
|
||||||
@ -175,32 +184,42 @@ class SiteChain(ChainBase):
|
|||||||
return True, msg
|
return True, msg
|
||||||
return False, "未知错误"
|
return False, "未知错误"
|
||||||
|
|
||||||
def remote_cookie(self, arg_str: str, userid: Union[str, int] = None):
|
def remote_cookie(self, arg_str: str, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
使用用户名密码更新站点Cookie
|
使用用户名密码更新站点Cookie
|
||||||
"""
|
"""
|
||||||
err_title = "请输入正确的命令格式:/site_cookie [id] [username] [password]," \
|
err_title = "请输入正确的命令格式:/site_cookie [id] [username] [password]," \
|
||||||
"[id]为站点编号,[uername]为站点用户名,[password]为站点密码"
|
"[id]为站点编号,[uername]为站点用户名,[password]为站点密码"
|
||||||
if not arg_str:
|
if not arg_str:
|
||||||
self.post_message(title=err_title, userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=err_title, userid=userid))
|
||||||
return
|
return
|
||||||
arg_str = str(arg_str).strip()
|
arg_str = str(arg_str).strip()
|
||||||
args = arg_str.split()
|
args = arg_str.split()
|
||||||
if len(args) != 3:
|
if len(args) != 3:
|
||||||
self.post_message(title=err_title, userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=err_title, userid=userid))
|
||||||
return
|
return
|
||||||
site_id = args[0]
|
site_id = args[0]
|
||||||
if not site_id.isdigit():
|
if not site_id.isdigit():
|
||||||
self.post_message(title=err_title, userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=err_title, userid=userid))
|
||||||
return
|
return
|
||||||
# 站点ID
|
# 站点ID
|
||||||
site_id = int(site_id)
|
site_id = int(site_id)
|
||||||
# 站点信息
|
# 站点信息
|
||||||
site_info = self.siteoper.get(site_id)
|
site_info = self.siteoper.get(site_id)
|
||||||
if not site_info:
|
if not site_info:
|
||||||
self.post_message(title=f"站点编号 {site_id} 不存在!", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=f"站点编号 {site_id} 不存在!", userid=userid))
|
||||||
return
|
return
|
||||||
self.post_message(title=f"开始更新【{site_info.name}】Cookie&UA ...", userid=userid)
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
|
title=f"开始更新【{site_info.name}】Cookie&UA ...", userid=userid))
|
||||||
# 用户名
|
# 用户名
|
||||||
username = args[1]
|
username = args[1]
|
||||||
# 密码
|
# 密码
|
||||||
@ -211,9 +230,13 @@ class SiteChain(ChainBase):
|
|||||||
password=password)
|
password=password)
|
||||||
if not status:
|
if not status:
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
self.post_message(title=f"【{site_info.name}】 Cookie&UA更新失败!",
|
self.post_message(Notification(
|
||||||
text=f"错误原因:{msg}",
|
channel=channel,
|
||||||
userid=userid)
|
title=f"【{site_info.name}】 Cookie&UA更新失败!",
|
||||||
|
text=f"错误原因:{msg}",
|
||||||
|
userid=userid))
|
||||||
else:
|
else:
|
||||||
self.post_message(title=f"【{site_info.name}】 Cookie&UA更新成功",
|
self.post_message(Notification(
|
||||||
userid=userid)
|
channel=channel,
|
||||||
|
title=f"【{site_info.name}】 Cookie&UA更新成功",
|
||||||
|
userid=userid))
|
||||||
|
@ -6,18 +6,17 @@ from typing import Dict, List, Optional, Union, Tuple
|
|||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.chain.download import DownloadChain
|
from app.chain.download import DownloadChain
|
||||||
from app.chain.search import SearchChain
|
from app.chain.search import SearchChain
|
||||||
from app.core.metainfo import MetaInfo
|
|
||||||
from app.core.context import TorrentInfo, Context, MediaInfo
|
from app.core.context import TorrentInfo, Context, MediaInfo
|
||||||
from app.core.config import settings
|
from app.core.metainfo import MetaInfo
|
||||||
from app.db.models.subscribe import Subscribe
|
from app.db.models.subscribe import Subscribe
|
||||||
from app.db.subscribe_oper import SubscribeOper
|
from app.db.subscribe_oper import SubscribeOper
|
||||||
from app.db.systemconfig_oper import SystemConfigOper
|
from app.db.systemconfig_oper import SystemConfigOper
|
||||||
from app.helper.message import MessageHelper
|
from app.helper.message import MessageHelper
|
||||||
from app.helper.sites import SitesHelper
|
from app.helper.sites import SitesHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import NotExistMediaInfo
|
from app.schemas import NotExistMediaInfo, Notification
|
||||||
|
from app.schemas.types import MediaType, SystemConfigKey, MessageChannel, NotificationType
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils
|
||||||
from app.schemas.types import MediaType, SystemConfigKey
|
|
||||||
|
|
||||||
|
|
||||||
class SubscribeChain(ChainBase):
|
class SubscribeChain(ChainBase):
|
||||||
@ -42,6 +41,7 @@ class SubscribeChain(ChainBase):
|
|||||||
tmdbid: int = None,
|
tmdbid: int = None,
|
||||||
doubanid: str = None,
|
doubanid: str = None,
|
||||||
season: int = None,
|
season: int = None,
|
||||||
|
channel: MessageChannel = None,
|
||||||
userid: str = None,
|
userid: str = None,
|
||||||
username: str = None,
|
username: str = None,
|
||||||
message: bool = True,
|
message: bool = True,
|
||||||
@ -106,11 +106,13 @@ class SubscribeChain(ChainBase):
|
|||||||
logger.error(f'{mediainfo.title_year} {err_msg}')
|
logger.error(f'{mediainfo.title_year} {err_msg}')
|
||||||
if not exist_ok and message:
|
if not exist_ok and message:
|
||||||
# 发回原用户
|
# 发回原用户
|
||||||
self.post_message(title=f"{mediainfo.title_year}{metainfo.season} "
|
self.post_message(Notification(channel=channel,
|
||||||
f"添加订阅失败!",
|
mtype=NotificationType.Subscribe,
|
||||||
text=f"{err_msg}",
|
title=f"{mediainfo.title_year}{metainfo.season} "
|
||||||
image=mediainfo.get_message_image(),
|
f"添加订阅失败!",
|
||||||
userid=userid)
|
text=f"{err_msg}",
|
||||||
|
image=mediainfo.get_message_image(),
|
||||||
|
userid=userid))
|
||||||
elif message:
|
elif message:
|
||||||
logger.info(f'{mediainfo.title_year}{metainfo.season} 添加订阅成功')
|
logger.info(f'{mediainfo.title_year}{metainfo.season} 添加订阅成功')
|
||||||
if username or userid:
|
if username or userid:
|
||||||
@ -118,42 +120,52 @@ class SubscribeChain(ChainBase):
|
|||||||
else:
|
else:
|
||||||
text = f"评分:{mediainfo.vote_average}"
|
text = f"评分:{mediainfo.vote_average}"
|
||||||
# 广而告之
|
# 广而告之
|
||||||
self.post_message(title=f"{mediainfo.title_year}{metainfo.season} 已添加订阅",
|
self.post_message(Notification(channel=channel,
|
||||||
text=text,
|
mtype=NotificationType.Subscribe,
|
||||||
image=mediainfo.get_message_image())
|
title=f"{mediainfo.title_year}{metainfo.season} 已添加订阅",
|
||||||
|
text=text,
|
||||||
|
image=mediainfo.get_message_image()))
|
||||||
# 返回结果
|
# 返回结果
|
||||||
return sid, ""
|
return sid, ""
|
||||||
|
|
||||||
def remote_refresh(self, userid: Union[str, int] = None):
|
def remote_refresh(self, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
远程刷新订阅,发送消息
|
远程刷新订阅,发送消息
|
||||||
"""
|
"""
|
||||||
self.post_message(title=f"开始刷新订阅 ...", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"开始刷新订阅 ...", userid=userid))
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self.post_message(title=f"订阅刷新完成!", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"订阅刷新完成!", userid=userid))
|
||||||
|
|
||||||
def remote_search(self, arg_str: str, userid: Union[str, int] = None):
|
def remote_search(self, arg_str: str, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
远程搜索订阅,发送消息
|
远程搜索订阅,发送消息
|
||||||
"""
|
"""
|
||||||
if arg_str and not str(arg_str).isdigit():
|
if arg_str and not str(arg_str).isdigit():
|
||||||
self.post_message(title="请输入正确的命令格式:/subscribe_search [id],"
|
self.post_message(Notification(channel=channel,
|
||||||
"[id]为订阅编号,不输入订阅编号时搜索所有订阅", userid=userid)
|
title="请输入正确的命令格式:/subscribe_search [id],"
|
||||||
|
"[id]为订阅编号,不输入订阅编号时搜索所有订阅", userid=userid))
|
||||||
return
|
return
|
||||||
if arg_str:
|
if arg_str:
|
||||||
sid = int(arg_str)
|
sid = int(arg_str)
|
||||||
subscribe = self.subscribehelper.get(sid)
|
subscribe = self.subscribehelper.get(sid)
|
||||||
if not subscribe:
|
if not subscribe:
|
||||||
self.post_message(title=f"订阅编号 {sid} 不存在!", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"订阅编号 {sid} 不存在!", userid=userid))
|
||||||
return
|
return
|
||||||
self.post_message(title=f"开始搜索 {subscribe.name} ...", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"开始搜索 {subscribe.name} ...", userid=userid))
|
||||||
# 搜索订阅
|
# 搜索订阅
|
||||||
self.search(sid=int(arg_str))
|
self.search(sid=int(arg_str))
|
||||||
self.post_message(title=f"{subscribe.name} 搜索完成!", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"{subscribe.name} 搜索完成!", userid=userid))
|
||||||
else:
|
else:
|
||||||
self.post_message(title=f"开始搜索所有订阅 ...", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"开始搜索所有订阅 ...", userid=userid))
|
||||||
self.search(state='R')
|
self.search(state='R')
|
||||||
self.post_message(title=f"订阅搜索完成!", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"订阅搜索完成!", userid=userid))
|
||||||
|
|
||||||
def search(self, sid: int = None, state: str = 'N', manual: bool = False):
|
def search(self, sid: int = None, state: str = 'N', manual: bool = False):
|
||||||
"""
|
"""
|
||||||
@ -189,8 +201,9 @@ class SubscribeChain(ChainBase):
|
|||||||
logger.info(f'{mediainfo.title_year} 媒体库中已存在,完成订阅')
|
logger.info(f'{mediainfo.title_year} 媒体库中已存在,完成订阅')
|
||||||
self.subscribehelper.delete(subscribe.id)
|
self.subscribehelper.delete(subscribe.id)
|
||||||
# 发送通知
|
# 发送通知
|
||||||
self.post_message(title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
self.post_message(Notification(mtype=NotificationType.Subscribe,
|
||||||
image=mediainfo.get_message_image())
|
title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
||||||
|
image=mediainfo.get_message_image()))
|
||||||
continue
|
continue
|
||||||
# 使用订阅的总集数和开始集数替换no_exists
|
# 使用订阅的总集数和开始集数替换no_exists
|
||||||
no_exists = self.__get_subscribe_no_exits(
|
no_exists = self.__get_subscribe_no_exits(
|
||||||
@ -255,8 +268,9 @@ class SubscribeChain(ChainBase):
|
|||||||
logger.info(f'{mediainfo.title_year} 下载完成,完成订阅')
|
logger.info(f'{mediainfo.title_year} 下载完成,完成订阅')
|
||||||
self.subscribehelper.delete(subscribe.id)
|
self.subscribehelper.delete(subscribe.id)
|
||||||
# 发送通知
|
# 发送通知
|
||||||
self.post_message(title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
self.post_message(Notification(mtype=NotificationType.Subscribe,
|
||||||
image=mediainfo.get_message_image())
|
title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
||||||
|
image=mediainfo.get_message_image()))
|
||||||
else:
|
else:
|
||||||
# 未完成下载
|
# 未完成下载
|
||||||
logger.info(f'{mediainfo.title_year} 未下载未完整,继续订阅 ...')
|
logger.info(f'{mediainfo.title_year} 未下载未完整,继续订阅 ...')
|
||||||
@ -343,8 +357,9 @@ class SubscribeChain(ChainBase):
|
|||||||
logger.info(f'{mediainfo.title_year} 媒体库中已存在,完成订阅')
|
logger.info(f'{mediainfo.title_year} 媒体库中已存在,完成订阅')
|
||||||
self.subscribehelper.delete(subscribe.id)
|
self.subscribehelper.delete(subscribe.id)
|
||||||
# 发送通知
|
# 发送通知
|
||||||
self.post_message(title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
self.post_message(Notification(mtype=NotificationType.Subscribe,
|
||||||
image=mediainfo.get_message_image())
|
title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
||||||
|
image=mediainfo.get_message_image()))
|
||||||
continue
|
continue
|
||||||
# 使用订阅的总集数和开始集数替换no_exists
|
# 使用订阅的总集数和开始集数替换no_exists
|
||||||
no_exists = self.__get_subscribe_no_exits(
|
no_exists = self.__get_subscribe_no_exits(
|
||||||
@ -404,8 +419,9 @@ class SubscribeChain(ChainBase):
|
|||||||
logger.info(f'{mediainfo.title_year} 下载完成,完成订阅')
|
logger.info(f'{mediainfo.title_year} 下载完成,完成订阅')
|
||||||
self.subscribehelper.delete(subscribe.id)
|
self.subscribehelper.delete(subscribe.id)
|
||||||
# 发送通知
|
# 发送通知
|
||||||
self.post_message(title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
self.post_message(Notification(mtype=NotificationType.Subscribe,
|
||||||
image=mediainfo.get_message_image())
|
title=f'{mediainfo.title_year}{meta.season} 已完成订阅',
|
||||||
|
image=mediainfo.get_message_image()))
|
||||||
else:
|
else:
|
||||||
update_date = True if downloads else False
|
update_date = True if downloads else False
|
||||||
# 未完成下载,计算剩余集数
|
# 未完成下载,计算剩余集数
|
||||||
@ -481,13 +497,14 @@ class SubscribeChain(ChainBase):
|
|||||||
"lack_episode": len(left_episodes)
|
"lack_episode": len(left_episodes)
|
||||||
})
|
})
|
||||||
|
|
||||||
def remote_list(self, userid: Union[str, int] = None):
|
def remote_list(self, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
查询订阅并发送消息
|
查询订阅并发送消息
|
||||||
"""
|
"""
|
||||||
subscribes = self.subscribehelper.list()
|
subscribes = self.subscribehelper.list()
|
||||||
if not subscribes:
|
if not subscribes:
|
||||||
self.post_message(title='没有任何订阅!', userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title='没有任何订阅!', userid=userid))
|
||||||
return
|
return
|
||||||
title = f"共有 {len(subscribes)} 个订阅,回复对应指令操作: " \
|
title = f"共有 {len(subscribes)} 个订阅,回复对应指令操作: " \
|
||||||
f"\n- 删除订阅:/subscribe_delete [id]" \
|
f"\n- 删除订阅:/subscribe_delete [id]" \
|
||||||
@ -505,15 +522,17 @@ class SubscribeChain(ChainBase):
|
|||||||
f"_{subscribe.total_episode - (subscribe.lack_episode or subscribe.total_episode)}"
|
f"_{subscribe.total_episode - (subscribe.lack_episode or subscribe.total_episode)}"
|
||||||
f"/{subscribe.total_episode}_")
|
f"/{subscribe.total_episode}_")
|
||||||
# 发送列表
|
# 发送列表
|
||||||
self.post_message(title=title, text='\n'.join(messages), userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=title, text='\n'.join(messages), userid=userid))
|
||||||
|
|
||||||
def remote_delete(self, arg_str: str, userid: Union[str, int] = None):
|
def remote_delete(self, arg_str: str, channel: MessageChannel, userid: Union[str, int] = None):
|
||||||
"""
|
"""
|
||||||
删除订阅
|
删除订阅
|
||||||
"""
|
"""
|
||||||
if not arg_str:
|
if not arg_str:
|
||||||
self.post_message(title="请输入正确的命令格式:/subscribe_delete [id],"
|
self.post_message(Notification(channel=channel,
|
||||||
"[id]为订阅编号", userid=userid)
|
title="请输入正确的命令格式:/subscribe_delete [id],"
|
||||||
|
"[id]为订阅编号", userid=userid))
|
||||||
return
|
return
|
||||||
arg_strs = str(arg_str).split()
|
arg_strs = str(arg_str).split()
|
||||||
for arg_str in arg_strs:
|
for arg_str in arg_strs:
|
||||||
@ -523,12 +542,13 @@ class SubscribeChain(ChainBase):
|
|||||||
subscribe_id = int(arg_str)
|
subscribe_id = int(arg_str)
|
||||||
subscribe = self.subscribehelper.get(subscribe_id)
|
subscribe = self.subscribehelper.get(subscribe_id)
|
||||||
if not subscribe:
|
if not subscribe:
|
||||||
self.post_message(title=f"订阅编号 {subscribe_id} 不存在!", userid=userid)
|
self.post_message(Notification(channel=channel,
|
||||||
|
title=f"订阅编号 {subscribe_id} 不存在!", userid=userid))
|
||||||
return
|
return
|
||||||
# 删除订阅
|
# 删除订阅
|
||||||
self.subscribehelper.delete(subscribe_id)
|
self.subscribehelper.delete(subscribe_id)
|
||||||
# 重新发送消息
|
# 重新发送消息
|
||||||
self.remote_list()
|
self.remote_list(channel, userid)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __get_subscribe_no_exits(no_exists: Dict[int, Dict[int, NotExistMediaInfo]],
|
def __get_subscribe_no_exits(no_exists: Dict[int, Dict[int, NotExistMediaInfo]],
|
||||||
|
@ -13,8 +13,8 @@ from app.db.models.downloadhistory import DownloadHistory
|
|||||||
from app.db.transferhistory_oper import TransferHistoryOper
|
from app.db.transferhistory_oper import TransferHistoryOper
|
||||||
from app.helper.progress import ProgressHelper
|
from app.helper.progress import ProgressHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import TransferInfo, TransferTorrent
|
from app.schemas import TransferInfo, TransferTorrent, Notification
|
||||||
from app.schemas.types import TorrentStatus, EventType, MediaType, ProgressKey
|
from app.schemas.types import TorrentStatus, EventType, MediaType, ProgressKey, MessageChannel, NotificationType
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils
|
||||||
from app.utils.system import SystemUtils
|
from app.utils.system import SystemUtils
|
||||||
|
|
||||||
@ -30,10 +30,11 @@ class TransferChain(ChainBase):
|
|||||||
self.transferhis = TransferHistoryOper()
|
self.transferhis = TransferHistoryOper()
|
||||||
self.progress = ProgressHelper()
|
self.progress = ProgressHelper()
|
||||||
|
|
||||||
def process(self, arg_str: str = None, userid: Union[str, int] = None) -> bool:
|
def process(self, arg_str: str = None, channel: MessageChannel = None, userid: Union[str, int] = None) -> bool:
|
||||||
"""
|
"""
|
||||||
获取下载器中的种子列表,并执行转移
|
获取下载器中的种子列表,并执行转移
|
||||||
:param arg_str: 传入的参数 (种子hash和TMDB ID)
|
:param arg_str: 传入的参数 (种子hash和TMDB ID)
|
||||||
|
:param channel: 消息通道
|
||||||
:param userid: 用户ID
|
:param userid: 用户ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -110,9 +111,12 @@ class TransferChain(ChainBase):
|
|||||||
mediainfo: MediaInfo = self.recognize_media(meta=meta)
|
mediainfo: MediaInfo = self.recognize_media(meta=meta)
|
||||||
if not mediainfo:
|
if not mediainfo:
|
||||||
logger.warn(f'未识别到媒体信息,标题:{torrent.title}')
|
logger.warn(f'未识别到媒体信息,标题:{torrent.title}')
|
||||||
self.post_message(title=f"{torrent.title} 未识别到媒体信息,无法入库!\n"
|
self.post_message(Notification(
|
||||||
f"回复:```\n/transfer {torrent.hash} [tmdbid]\n``` 手动识别转移。",
|
channel=channel,
|
||||||
userid=userid)
|
mtype=NotificationType.Organize,
|
||||||
|
title=f"{torrent.title} 未识别到媒体信息,无法入库!\n"
|
||||||
|
f"回复:```\n/transfer {torrent.hash} [tmdbid]\n``` 手动识别转移。",
|
||||||
|
userid=userid))
|
||||||
# 新增转移失败历史记录
|
# 新增转移失败历史记录
|
||||||
self.transferhis.add(
|
self.transferhis.add(
|
||||||
src=str(torrent.path),
|
src=str(torrent.path),
|
||||||
@ -134,12 +138,13 @@ class TransferChain(ChainBase):
|
|||||||
if not transferinfo or not transferinfo.target_path:
|
if not transferinfo or not transferinfo.target_path:
|
||||||
# 转移失败
|
# 转移失败
|
||||||
logger.warn(f"{torrent.title} 入库失败")
|
logger.warn(f"{torrent.title} 入库失败")
|
||||||
self.post_message(
|
self.post_message(Notification(
|
||||||
|
channel=channel,
|
||||||
title=f"{mediainfo.title_year}{meta.season_episode} 入库失败!",
|
title=f"{mediainfo.title_year}{meta.season_episode} 入库失败!",
|
||||||
text=f"原因:{transferinfo.message if transferinfo else '未知'}",
|
text=f"原因:{transferinfo.message if transferinfo else '未知'}",
|
||||||
image=mediainfo.get_message_image(),
|
image=mediainfo.get_message_image(),
|
||||||
userid=userid
|
userid=userid
|
||||||
)
|
))
|
||||||
# 新增转移失败历史记录
|
# 新增转移失败历史记录
|
||||||
self.transferhis.add(
|
self.transferhis.add(
|
||||||
src=str(torrent.path),
|
src=str(torrent.path),
|
||||||
@ -223,7 +228,9 @@ class TransferChain(ChainBase):
|
|||||||
if transferinfo.message:
|
if transferinfo.message:
|
||||||
msg_str = f"{msg_str},以下文件处理失败:\n{transferinfo.message}"
|
msg_str = f"{msg_str},以下文件处理失败:\n{transferinfo.message}"
|
||||||
# 发送
|
# 发送
|
||||||
self.post_message(title=msg_title, text=msg_str, image=mediainfo.get_message_image())
|
self.post_message(Notification(
|
||||||
|
mtype=NotificationType.Organize,
|
||||||
|
title=msg_title, text=msg_str, image=mediainfo.get_message_image()))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_files(path: Path):
|
def delete_files(path: Path):
|
||||||
|
@ -2,8 +2,9 @@ import time
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
|
from app.schemas import Notification
|
||||||
from app.utils.http import WebUtils
|
from app.utils.http import WebUtils
|
||||||
from app.schemas.types import EventType, MediaImageType, MediaType
|
from app.schemas.types import EventType, MediaImageType, MediaType, NotificationType
|
||||||
|
|
||||||
|
|
||||||
class WebhookChain(ChainBase):
|
class WebhookChain(ChainBase):
|
||||||
@ -92,4 +93,5 @@ class WebhookChain(ChainBase):
|
|||||||
image_url = _webhook_images.get(event_info.get("channel"))
|
image_url = _webhook_images.get(event_info.get("channel"))
|
||||||
|
|
||||||
# 发送消息
|
# 发送消息
|
||||||
self.post_message(title=message_title, text=message_content, image=image_url)
|
self.post_message(Notification(mtype=NotificationType.MediaServer,
|
||||||
|
title=message_title, text=message_content, image=image_url))
|
||||||
|
@ -15,7 +15,7 @@ from app.core.event import Event as ManagerEvent
|
|||||||
from app.log import logger
|
from app.log import logger
|
||||||
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
|
from app.schemas.types import EventType, MessageChannel
|
||||||
|
|
||||||
|
|
||||||
class CommandChian(ChainBase):
|
class CommandChian(ChainBase):
|
||||||
@ -173,7 +173,8 @@ class Command(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
return self._commands.get(cmd, {})
|
return self._commands.get(cmd, {})
|
||||||
|
|
||||||
def execute(self, cmd: str, data_str: str = "", userid: Union[str, int] = None) -> None:
|
def execute(self, cmd: str, data_str: str = "",
|
||||||
|
channel: MessageChannel = None, userid: Union[str, int] = None) -> None:
|
||||||
"""
|
"""
|
||||||
执行命令
|
执行命令
|
||||||
"""
|
"""
|
||||||
@ -187,12 +188,12 @@ class Command(metaclass=Singleton):
|
|||||||
if cmd_data:
|
if cmd_data:
|
||||||
# 有内置参数直接使用内置参数
|
# 有内置参数直接使用内置参数
|
||||||
command['func'](**cmd_data)
|
command['func'](**cmd_data)
|
||||||
elif args_num == 1:
|
elif args_num == 2:
|
||||||
# 没有用户输入参数
|
# 没有输入参数,只输入渠道和用户ID
|
||||||
command['func'](userid)
|
command['func'](channel, userid)
|
||||||
else:
|
else:
|
||||||
# 多个输入参数:用户输入、用户ID
|
# 多个输入参数:用户输入、用户ID
|
||||||
command['func'](data_str, userid)
|
command['func'](data_str, channel, userid)
|
||||||
else:
|
else:
|
||||||
# 没有参数
|
# 没有参数
|
||||||
command['func']()
|
command['func']()
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
from abc import abstractmethod, ABCMeta
|
from abc import abstractmethod, ABCMeta
|
||||||
from typing import Tuple, Union
|
from typing import Tuple, Union
|
||||||
|
|
||||||
|
from app.db.systemconfig_oper import SystemConfigOper
|
||||||
|
from app.schemas import Notification
|
||||||
|
from app.schemas.types import SystemConfigKey, MessageChannel
|
||||||
|
|
||||||
|
|
||||||
class _ModuleBase(metaclass=ABCMeta):
|
class _ModuleBase(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
@ -30,3 +34,32 @@ class _ModuleBase(metaclass=ABCMeta):
|
|||||||
:return: None,该方法可被多个模块同时处理
|
:return: None,该方法可被多个模块同时处理
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def checkMessage(channel_type: MessageChannel):
|
||||||
|
"""
|
||||||
|
检查消息渠道及消息类型,如不符合则不处理
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
def wrapper(self, message: Notification, *args, **kwargs):
|
||||||
|
# 检查消息渠道
|
||||||
|
if message.channel and message.channel != channel_type:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# 检查消息类型开关
|
||||||
|
if message.mtype:
|
||||||
|
switchs = SystemConfigOper().get(SystemConfigKey.NotificationChannels)
|
||||||
|
for switch in switchs:
|
||||||
|
if switch.get("mtype") == message.mtype.value:
|
||||||
|
if channel_type == MessageChannel.Wechat and not switch.get("wechat"):
|
||||||
|
return None
|
||||||
|
if channel_type == MessageChannel.Telegram and not switch.get("telegram"):
|
||||||
|
return None
|
||||||
|
if channel_type == MessageChannel.Slack and not switch.get("slack"):
|
||||||
|
return None
|
||||||
|
return func(self, message, *args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
@ -5,9 +5,9 @@ from typing import Optional, Union, List, Tuple, Any
|
|||||||
from app.core.context import MediaInfo, Context
|
from app.core.context import MediaInfo, Context
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.modules import _ModuleBase
|
from app.modules import _ModuleBase, checkMessage
|
||||||
from app.modules.slack.slack import Slack
|
from app.modules.slack.slack import Slack
|
||||||
from app.schemas import MessageChannel, CommingMessage
|
from app.schemas import MessageChannel, CommingMessage, Notification
|
||||||
|
|
||||||
|
|
||||||
class SlackModule(_ModuleBase):
|
class SlackModule(_ModuleBase):
|
||||||
@ -181,40 +181,33 @@ class SlackModule(_ModuleBase):
|
|||||||
userid=userid, username=username, text=text)
|
userid=userid, username=username, text=text)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def post_message(self, title: str,
|
@checkMessage(MessageChannel.Slack)
|
||||||
text: str = None, image: str = None,
|
def post_message(self, message: Notification) -> Optional[bool]:
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
|
||||||
"""
|
"""
|
||||||
发送消息
|
发送消息
|
||||||
:param title: 标题
|
:param message: 消息
|
||||||
:param text: 内容
|
|
||||||
:param image: 图片
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.slack.send_msg(title=title, text=text, image=image, userid=userid)
|
return self.slack.send_msg(title=message.title, text=message.text,
|
||||||
|
image=message.image, userid=message.userid)
|
||||||
|
|
||||||
def post_medias_message(self, title: str, items: List[MediaInfo],
|
@checkMessage(MessageChannel.Slack)
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
def post_medias_message(self, message: Notification, medias: List[MediaInfo]) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
发送媒体信息选择列表
|
发送媒体信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param items: 消息列表
|
:param medias: 媒体信息
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.slack.send_meidas_msg(title=title, medias=items, userid=userid)
|
return self.slack.send_meidas_msg(title=message.title, medias=medias, userid=message.userid)
|
||||||
|
|
||||||
def post_torrents_message(self, title: str, items: List[Context],
|
@checkMessage(MessageChannel.Slack)
|
||||||
mediainfo: MediaInfo = None,
|
def post_torrents_message(self, message: Notification, torrents: List[Context]) -> Optional[bool]:
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
|
||||||
"""
|
"""
|
||||||
发送种子信息选择列表
|
发送种子信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param items: 消息列表
|
:param torrents: 种子信息
|
||||||
:param mediainfo: 媒体信息
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.slack.send_torrents_msg(title=title, torrents=items,
|
return self.slack.send_torrents_msg(title=message.title, torrents=torrents,
|
||||||
userid=userid)
|
userid=message.userid)
|
||||||
|
@ -4,9 +4,9 @@ from typing import Optional, Union, List, Tuple, Any
|
|||||||
from app.core.context import MediaInfo, Context
|
from app.core.context import MediaInfo, Context
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.modules import _ModuleBase
|
from app.modules import _ModuleBase, checkMessage
|
||||||
from app.modules.telegram.telegram import Telegram
|
from app.modules.telegram.telegram import Telegram
|
||||||
from app.schemas import MessageChannel, CommingMessage
|
from app.schemas import MessageChannel, CommingMessage, Notification
|
||||||
|
|
||||||
|
|
||||||
class TelegramModule(_ModuleBase):
|
class TelegramModule(_ModuleBase):
|
||||||
@ -91,42 +91,36 @@ class TelegramModule(_ModuleBase):
|
|||||||
userid=user_id, username=user_id, text=text)
|
userid=user_id, username=user_id, text=text)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def post_message(self, title: str,
|
@checkMessage(MessageChannel.Telegram)
|
||||||
text: str = None, image: str = None, userid: Union[str, int] = None) -> Optional[bool]:
|
def post_message(self, message: Notification) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
发送消息
|
发送消息
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param text: 内容
|
|
||||||
:param image: 图片
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.telegram.send_msg(title=title, text=text, image=image, userid=userid)
|
return self.telegram.send_msg(title=message.title, text=message.text,
|
||||||
|
image=message.image, userid=message.userid)
|
||||||
|
|
||||||
def post_medias_message(self, title: str, items: List[MediaInfo],
|
@checkMessage(MessageChannel.Telegram)
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
def post_medias_message(self, message: Notification, medias: List[MediaInfo]) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
发送媒体信息选择列表
|
发送媒体信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param items: 消息列表
|
:param medias: 媒体列表
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.telegram.send_meidas_msg(title=title, medias=items, userid=userid)
|
return self.telegram.send_meidas_msg(title=message.title, medias=medias,
|
||||||
|
userid=message.userid)
|
||||||
|
|
||||||
def post_torrents_message(self, title: str, items: List[Context],
|
@checkMessage(MessageChannel.Telegram)
|
||||||
mediainfo: MediaInfo = None,
|
def post_torrents_message(self, message: Notification, torrents: List[Context]) -> Optional[bool]:
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
|
||||||
"""
|
"""
|
||||||
发送种子信息选择列表
|
发送种子信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息体
|
||||||
:param items: 消息列表
|
:param torrents: 种子列表
|
||||||
:param mediainfo: 媒体信息
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.telegram.send_torrents_msg(title=title, torrents=items,
|
return self.telegram.send_torrents_msg(title=message.title, torrents=torrents, userid=message.userid)
|
||||||
mediainfo=mediainfo, userid=userid)
|
|
||||||
|
|
||||||
def register_commands(self, commands: dict):
|
def register_commands(self, commands: dict):
|
||||||
"""
|
"""
|
||||||
|
@ -133,7 +133,6 @@ class Telegram(metaclass=Singleton):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def send_torrents_msg(self, torrents: List[Context],
|
def send_torrents_msg(self, torrents: List[Context],
|
||||||
mediainfo: MediaInfo = None,
|
|
||||||
userid: str = "", title: str = "") -> Optional[bool]:
|
userid: str = "", title: str = "") -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
发送列表消息
|
发送列表消息
|
||||||
@ -141,8 +140,12 @@ class Telegram(metaclass=Singleton):
|
|||||||
if not self._telegram_token or not self._telegram_chat_id:
|
if not self._telegram_token or not self._telegram_chat_id:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if not torrents:
|
||||||
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
index, caption = 1, "*%s*" % title
|
index, caption = 1, "*%s*" % title
|
||||||
|
mediainfo = torrents[0].media_info
|
||||||
for context in torrents:
|
for context in torrents:
|
||||||
torrent = context.torrent_info
|
torrent = context.torrent_info
|
||||||
site_name = torrent.site_name
|
site_name = torrent.site_name
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
from typing import Optional, Union, List, Tuple, Any
|
from typing import Optional, Union, List, Tuple, Any
|
||||||
|
|
||||||
from app.core.context import MediaInfo, Context
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.core.context import Context, MediaInfo
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.modules import _ModuleBase
|
from app.modules import _ModuleBase, checkMessage
|
||||||
from app.modules.wechat.WXBizMsgCrypt3 import WXBizMsgCrypt
|
from app.modules.wechat.WXBizMsgCrypt3 import WXBizMsgCrypt
|
||||||
from app.modules.wechat.wechat import WeChat
|
from app.modules.wechat.wechat import WeChat
|
||||||
from app.schemas import MessageChannel, CommingMessage
|
from app.schemas import MessageChannel, CommingMessage, Notification
|
||||||
from app.utils.dom import DomUtils
|
from app.utils.dom import DomUtils
|
||||||
|
|
||||||
|
|
||||||
@ -114,41 +114,35 @@ class WechatModule(_ModuleBase):
|
|||||||
logger.error(f"微信消息处理发生错误:{err}")
|
logger.error(f"微信消息处理发生错误:{err}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def post_message(self, title: str,
|
@checkMessage(MessageChannel.Wechat)
|
||||||
text: str = None, image: str = None, userid: Union[str, int] = None) -> Optional[bool]:
|
def post_message(self, message: Notification) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
发送消息
|
发送消息
|
||||||
:param title: 标题
|
:param message: 消息内容
|
||||||
:param text: 内容
|
|
||||||
:param image: 图片
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.wechat.send_msg(title=title, text=text, image=image, userid=userid)
|
return self.wechat.send_msg(title=message.title, text=message.text,
|
||||||
|
image=message.image, userid=message.userid)
|
||||||
|
|
||||||
def post_medias_message(self, title: str, items: List[MediaInfo],
|
@checkMessage(MessageChannel.Wechat)
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
def post_medias_message(self, message: Notification, medias: List[MediaInfo]) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
发送媒体信息选择列表
|
发送媒体信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息内容
|
||||||
:param items: 消息列表
|
:param medias: 媒体列表
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
# 先发送标题
|
# 先发送标题
|
||||||
self.wechat.send_msg(title=title)
|
self.wechat.send_msg(title=message.title)
|
||||||
# 再发送内容
|
# 再发送内容
|
||||||
return self.wechat.send_medias_msg(medias=items, userid=userid)
|
return self.wechat.send_medias_msg(medias=medias, userid=message.userid)
|
||||||
|
|
||||||
def post_torrents_message(self, title: str, items: List[Context],
|
@checkMessage(MessageChannel.Wechat)
|
||||||
mediainfo: MediaInfo,
|
def post_torrents_message(self, message: Notification, torrents: List[Context]) -> Optional[bool]:
|
||||||
userid: Union[str, int] = None) -> Optional[bool]:
|
|
||||||
"""
|
"""
|
||||||
发送种子信息选择列表
|
发送种子信息选择列表
|
||||||
:param title: 标题
|
:param message: 消息内容
|
||||||
:param items: 消息列表
|
:param torrents: 种子列表
|
||||||
:param mediainfo: 媒体信息
|
|
||||||
:param userid: 用户ID
|
|
||||||
:return: 成功或失败
|
:return: 成功或失败
|
||||||
"""
|
"""
|
||||||
return self.wechat.send_torrents_msg(title=title, torrents=items, mediainfo=mediainfo, userid=userid)
|
return self.wechat.send_torrents_msg(title=message.title, torrents=torrents, userid=message.userid)
|
||||||
|
@ -191,7 +191,7 @@ class WeChat(metaclass=Singleton):
|
|||||||
}
|
}
|
||||||
return self.__post_request(message_url, req_json)
|
return self.__post_request(message_url, req_json)
|
||||||
|
|
||||||
def send_torrents_msg(self, torrents: List[Context], mediainfo: MediaInfo,
|
def send_torrents_msg(self, torrents: List[Context],
|
||||||
userid: str = "", title: str = "") -> Optional[bool]:
|
userid: str = "", title: str = "") -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
发送列表消息
|
发送列表消息
|
||||||
@ -213,6 +213,7 @@ class WeChat(metaclass=Singleton):
|
|||||||
for context in torrents:
|
for context in torrents:
|
||||||
torrent = context.torrent_info
|
torrent = context.torrent_info
|
||||||
meta = MetaInfo(title=torrent.title, subtitle=torrent.description)
|
meta = MetaInfo(title=torrent.title, subtitle=torrent.description)
|
||||||
|
mediainfo = context.media_info
|
||||||
torrent_title = f"{index}.【{torrent.site_name}】" \
|
torrent_title = f"{index}.【{torrent.site_name}】" \
|
||||||
f"{meta.season_episode} " \
|
f"{meta.season_episode} " \
|
||||||
f"{meta.resource_term} " \
|
f"{meta.resource_term} " \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Dict, List
|
from typing import Optional, Dict, List, Union
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@ -321,14 +321,12 @@ class Notification(BaseModel):
|
|||||||
title: Optional[str] = None
|
title: Optional[str] = None
|
||||||
# 文本内容
|
# 文本内容
|
||||||
text: Optional[str] = None
|
text: Optional[str] = None
|
||||||
# 列表内容
|
|
||||||
items: Optional[list] = []
|
|
||||||
# 图片
|
# 图片
|
||||||
image: Optional[str] = None
|
image: Optional[str] = None
|
||||||
# 链接
|
# 链接
|
||||||
link: Optional[str] = None
|
link: Optional[str] = None
|
||||||
# 用户ID
|
# 用户ID
|
||||||
user_id: Optional[str] = None
|
userid: Optional[Union[str, int]] = None
|
||||||
|
|
||||||
|
|
||||||
class CommingMessage(BaseModel):
|
class CommingMessage(BaseModel):
|
||||||
@ -336,7 +334,7 @@ class CommingMessage(BaseModel):
|
|||||||
外来消息
|
外来消息
|
||||||
"""
|
"""
|
||||||
# 用户ID
|
# 用户ID
|
||||||
userid: Optional[str] = None
|
userid: Optional[Union[str, int]] = None
|
||||||
# 用户名称
|
# 用户名称
|
||||||
username: Optional[str] = None
|
username: Optional[str] = None
|
||||||
# 消息渠道
|
# 消息渠道
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import random
|
import random
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class TimerUtils:
|
class TimerUtils:
|
||||||
@ -38,8 +39,6 @@ class TimerUtils:
|
|||||||
|
|
||||||
return trigger
|
return trigger
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def time_difference(input_datetime: datetime) -> str:
|
def time_difference(input_datetime: datetime) -> str:
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user