fix actions

This commit is contained in:
jxxghp
2025-02-19 17:44:14 +08:00
parent 1317d9c4f0
commit b41de1a982
11 changed files with 179 additions and 72 deletions
+9
View File
@@ -2,9 +2,14 @@ from abc import ABC, abstractmethod
from pydantic.main import BaseModel from pydantic.main import BaseModel
from app.chain import ChainBase
from app.schemas import ActionContext, ActionParams from app.schemas import ActionContext, ActionParams
class ActionChain(ChainBase):
pass
class BaseAction(BaseModel, ABC): class BaseAction(BaseModel, ABC):
""" """
工作流动作基类 工作流动作基类
@@ -13,6 +18,10 @@ class BaseAction(BaseModel, ABC):
# 完成标志 # 完成标志
_done_flag = False _done_flag = False
def __init__(self):
super().__init__()
self.chain = ActionChain()
@property @property
@abstractmethod @abstractmethod
def name(self) -> str: def name(self) -> str:
+1 -6
View File
@@ -1,5 +1,4 @@
from app.actions import BaseAction from app.actions import BaseAction
from app.chain.download import DownloadChain
from app.schemas import ActionParams, ActionContext from app.schemas import ActionParams, ActionContext
@@ -17,10 +16,6 @@ class FetchDownloadsAction(BaseAction):
_downloads = [] _downloads = []
def __init__(self):
super().__init__()
self.downloadchain = DownloadChain()
@property @property
def name(self) -> str: def name(self) -> str:
return "获取下载任务" return "获取下载任务"
@@ -41,7 +36,7 @@ class FetchDownloadsAction(BaseAction):
""" """
self._downloads = context.downloads self._downloads = context.downloads
for download in self._downloads: for download in self._downloads:
torrents = self.downloadchain.list_torrents(hashs=[download.download_id]) torrents = self.chain.list_torrents(hashs=[download.download_id])
if not torrents: if not torrents:
download.completed = True download.completed = True
continue continue
+5 -10
View File
@@ -3,7 +3,6 @@ from typing import Optional
from pydantic import Field from pydantic import Field
from app.actions import BaseAction from app.actions import BaseAction
from app.chain.media import MediaChain
from app.core.config import settings from app.core.config import settings
from app.core.context import Context from app.core.context import Context
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo
@@ -22,7 +21,6 @@ class FetchRssParams(ActionParams):
content_type: Optional[str] = Field(None, description="Content-Type") content_type: Optional[str] = Field(None, description="Content-Type")
referer: Optional[str] = Field(None, description="Referer") referer: Optional[str] = Field(None, description="Referer")
ua: Optional[str] = Field(None, description="User-Agent") ua: Optional[str] = Field(None, description="User-Agent")
recognize: Optional[bool] = Field(False, description="是否识别")
class FetchRssAction(BaseAction): class FetchRssAction(BaseAction):
@@ -35,7 +33,6 @@ class FetchRssAction(BaseAction):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.rsshelper = RssHelper() self.rsshelper = RssHelper()
self.mediachain = MediaChain()
@property @property
def name(self) -> str: def name(self) -> str:
@@ -83,13 +80,11 @@ class FetchRssAction(BaseAction):
size=item.get("size"), size=item.get("size"),
pubdate=item["pubdate"].strftime("%Y-%m-%d %H:%M:%S") if item.get("pubdate") else None, pubdate=item["pubdate"].strftime("%Y-%m-%d %H:%M:%S") if item.get("pubdate") else None,
) )
meta, mediainfo = None, None meta = MetaInfo(title=torrentinfo.title, subtitle=torrentinfo.description)
if params.recognize: mediainfo = self.chain.recognize_media(meta)
meta = MetaInfo(title=torrentinfo.title, subtitle=torrentinfo.description) if not mediainfo:
mediainfo = self.mediachain.recognize_media(meta) logger.warning(f"{torrentinfo.title} 未识别到媒体信息")
if not mediainfo: continue
logger.warning(f"{torrentinfo.title} 未识别到媒体信息")
continue
self._rss_torrents.append(Context(meta_info=meta, media_info=mediainfo, torrent_info=torrentinfo)) self._rss_torrents.append(Context(meta_info=meta, media_info=mediainfo, torrent_info=torrentinfo))
if self._rss_torrents: if self._rss_torrents:
+69
View File
@@ -0,0 +1,69 @@
from typing import Optional, List
from pydantic import Field
from app.actions import BaseAction
from app.chain.search import SearchChain
from app.log import logger
from app.schemas import ActionParams, ActionContext, MediaType
class FetchTorrentsParams(ActionParams):
"""
获取站点资源参数
"""
name: str = Field(None, description="资源名称")
year: Optional[int] = Field(None, description="年份")
type: Optional[str] = Field(None, description="资源类型 (电影/电视剧)")
season: Optional[int] = Field(None, description="季度")
sites: Optional[List[int]] = Field([], description="站点列表")
class FetchTorrentsAction(BaseAction):
"""
搜索站点资源
"""
_torrents = []
def __init__(self):
super().__init__()
self.searchchain = SearchChain()
@property
def name(self) -> str:
return "获取站点资源"
@property
def description(self) -> str:
return "根据关键字搜索站点种子资源"
@property
def success(self) -> bool:
return True if self._torrents else False
async def execute(self, params: FetchTorrentsParams, context: ActionContext) -> ActionContext:
"""
搜索站点,获取资源列表
"""
torrents = self.searchchain.search_by_title(title=params.name, sites=params.sites)
for torrent in torrents:
if params.year and torrent.meta_info.year != params.year:
continue
if params.type and torrent.media_info and torrent.media_info.type != MediaType(params.type):
continue
if params.season and torrent.meta_info.begin_season != params.season:
continue
# 识别媒体信息
torrent.media_info = self.chain.recognize_media(torrent.meta_info)
if not torrent.media_info:
logger.warning(f"{torrent.torrent_info.title} 未识别到媒体信息")
continue
self._torrents.append(torrent)
if self._torrents:
context.torrents.extend(self._torrents)
logger.info(f"搜索到 {len(self._torrents)} 条资源")
self.job_done()
return context
+39 -3
View File
@@ -1,4 +1,9 @@
from typing import Optional, List
from pydantic import Field
from app.actions import BaseAction from app.actions import BaseAction
from app.helper.torrent import TorrentHelper
from app.schemas import ActionParams, ActionContext from app.schemas import ActionParams, ActionContext
@@ -6,7 +11,10 @@ class FilterTorrentsParams(ActionParams):
""" """
过滤资源数据参数 过滤资源数据参数
""" """
pass rule_groups: Optional[List[str]] = Field([], description="规则组")
include: Optional[str] = Field(None, description="包含规则")
exclude: Optional[str] = Field(None, description="排除规则")
size: Optional[str] = Field(None, description="资源大小范围(MB")
class FilterTorrentsAction(BaseAction): class FilterTorrentsAction(BaseAction):
@@ -14,6 +22,12 @@ class FilterTorrentsAction(BaseAction):
过滤资源数据 过滤资源数据
""" """
_torrents = []
def __init__(self):
super().__init__()
self.torrenthelper = TorrentHelper()
@property @property
def name(self) -> str: def name(self) -> str:
return "过滤资源数据" return "过滤资源数据"
@@ -24,7 +38,29 @@ class FilterTorrentsAction(BaseAction):
@property @property
def success(self) -> bool: def success(self) -> bool:
return True return self.done
async def execute(self, params: FilterTorrentsParams, context: ActionContext) -> ActionContext: async def execute(self, params: FilterTorrentsParams, context: ActionContext) -> ActionContext:
pass """
过滤torrents中的资源
"""
for torrent in context.torrents:
if self.torrenthelper.filter_torrent(
torrent_info=torrent.torrent_info,
filter_params={
"include": params.include,
"exclude": params.exclude,
"size": params.size
}
):
if self.chain.filter_torrents(
rule_groups=params.rule_groups,
torrent_list=[torrent.torrent_info],
mediainfo=torrent.media_info
):
self._torrents.append(torrent)
context.torrents = self._torrents
self.job_done()
return context
-38
View File
@@ -1,38 +0,0 @@
from typing import Optional
from pydantic import Field
from app.actions import BaseAction
from app.schemas import ActionParams, ActionContext
class SearchTorrentsParams(ActionParams):
"""
搜索站点资源参数
"""
name: str = Field(None, description="资源名称")
year: Optional[int] = Field(None, description="年份")
type: Optional[str] = Field(None, description="资源类型 (电影/电视剧)")
season: Optional[int] = Field(None, description="季度")
recognize: Optional[bool] = Field(False, description="是否识别")
class SearchTorrentsAction(BaseAction):
"""
搜索站点资源
"""
@property
def name(self) -> str:
return "搜索站点资源"
@property
def description(self) -> str:
return "根据关键字搜索站点种子资源"
@property
def success(self) -> bool:
return True
async def execute(self, params: SearchTorrentsParams, context: ActionContext) -> ActionContext:
pass
+22 -4
View File
@@ -1,12 +1,17 @@
from typing import List, Optional, Union
from pydantic import Field
from app.actions import BaseAction from app.actions import BaseAction
from app.schemas import ActionParams, ActionContext from app.schemas import ActionParams, ActionContext, MessageChannel
class SendMessageParams(ActionParams): class SendMessageParams(ActionParams):
""" """
发送消息参数 发送消息参数
""" """
pass channel: Optional[List[str]] = Field([], description="消息渠道")
userid: Optional[Union[str, int]] = Field(None, description="用户ID")
class SendMessageAction(BaseAction): class SendMessageAction(BaseAction):
@@ -24,7 +29,20 @@ class SendMessageAction(BaseAction):
@property @property
def success(self) -> bool: def success(self) -> bool:
return True return self.done
async def execute(self, params: SendMessageParams, context: ActionContext) -> ActionContext: async def execute(self, params: SendMessageParams, context: ActionContext) -> ActionContext:
pass """
发送messages中的消息
"""
for message in context.messages:
if params.channel:
message.channel = MessageChannel(params.channel)
if params.userid:
message.userid = params.userid
self.chain.post_message(message)
context.messages = []
self.job_done()
return context
+2 -2
View File
@@ -133,12 +133,12 @@ def search_by_id(mediaid: str,
@router.get("/title", summary="模糊搜索资源", response_model=schemas.Response) @router.get("/title", summary="模糊搜索资源", response_model=schemas.Response)
def search_by_title(keyword: str = None, def search_by_title(keyword: str = None,
page: int = 0, page: int = 0,
site: int = None, sites: List[int] = None,
_: schemas.TokenPayload = Depends(verify_token)) -> Any: _: schemas.TokenPayload = Depends(verify_token)) -> Any:
""" """
根据名称模糊搜索站点资源,支持分页,关键词为空是返回首页资源 根据名称模糊搜索站点资源,支持分页,关键词为空是返回首页资源
""" """
torrents = SearchChain().search_by_title(title=keyword, page=page, site=site) torrents = SearchChain().search_by_title(title=keyword, page=page, sites=sites)
if not torrents: if not torrents:
return schemas.Response(success=False, message="未搜索到任何资源") return schemas.Response(success=False, message="未搜索到任何资源")
return schemas.Response(success=True, data=[torrent.to_dict() for torrent in torrents]) return schemas.Response(success=True, data=[torrent.to_dict() for torrent in torrents])
+9 -6
View File
@@ -61,19 +61,21 @@ class SearchChain(ChainBase):
self.save_cache(bytes_results, self.__result_temp_file) self.save_cache(bytes_results, self.__result_temp_file)
return results return results
def search_by_title(self, title: str, page: int = 0, site: int = None) -> List[Context]: def search_by_title(self, title: str, page: int = 0,
sites: List[int] = None, cache_local: bool = True) -> List[Context]:
""" """
根据标题搜索资源,不识别不过滤,直接返回站点内容 根据标题搜索资源,不识别不过滤,直接返回站点内容
:param title: 标题,为空时返回所有站点首页内容 :param title: 标题,为空时返回所有站点首页内容
:param page: 页码 :param page: 页码
:param site: 站点ID :param sites: 站点ID列表
:param cache_local: 是否缓存到本地
""" """
if title: if title:
logger.info(f'开始搜索资源,关键词:{title} ...') logger.info(f'开始搜索资源,关键词:{title} ...')
else: else:
logger.info(f'开始浏览资源,站点:{site} ...') logger.info(f'开始浏览资源,站点:{sites} ...')
# 搜索 # 搜索
torrents = self.__search_all_sites(keywords=[title], sites=[site] if site else None, page=page) or [] torrents = self.__search_all_sites(keywords=[title], sites=sites if sites else None, page=page) or []
if not torrents: if not torrents:
logger.warn(f'{title} 未搜索到资源') logger.warn(f'{title} 未搜索到资源')
return [] return []
@@ -81,8 +83,9 @@ class SearchChain(ChainBase):
contexts = [Context(meta_info=MetaInfo(title=torrent.title, subtitle=torrent.description), contexts = [Context(meta_info=MetaInfo(title=torrent.title, subtitle=torrent.description),
torrent_info=torrent) for torrent in torrents] torrent_info=torrent) for torrent in torrents]
# 保存到本地文件 # 保存到本地文件
bytes_results = pickle.dumps(contexts) if cache_local:
self.save_cache(bytes_results, self.__result_temp_file) bytes_results = pickle.dumps(contexts)
self.save_cache(bytes_results, self.__result_temp_file)
return contexts return contexts
def last_search_results(self) -> List[Context]: def last_search_results(self) -> List[Context]:
+3 -3
View File
@@ -33,7 +33,7 @@ class RuleHelper:
return group return group
return None return None
def get_rule_group_by_media(self, media: MediaInfo, group_names: list = None) -> List[FilterRuleGroup]: def get_rule_group_by_media(self, media: MediaInfo = None, group_names: list = None) -> List[FilterRuleGroup]:
""" """
根据媒体信息获取规则组 根据媒体信息获取规则组
""" """
@@ -44,9 +44,9 @@ class RuleHelper:
for group in rule_groups: for group in rule_groups:
if not group.media_type: if not group.media_type:
ret_groups.append(group) ret_groups.append(group)
elif not group.category and group.media_type == media.type.value: elif media and not group.category and group.media_type == media.type.value:
ret_groups.append(group) ret_groups.append(group)
elif group.category == media.category: elif media and group.category == media.category:
ret_groups.append(group) ret_groups.append(group)
return ret_groups return ret_groups
+20
View File
@@ -445,6 +445,26 @@ class TorrentHelper(metaclass=Singleton):
logger.info(f"{torrent_info.title} 不匹配特效规则 {effect}") logger.info(f"{torrent_info.title} 不匹配特效规则 {effect}")
return False return False
# 大小
size_range = filter_params.get("size")
if size_range.find("-") != -1:
# 区间
size_min, size_max = size_range.split("-")
size_min = float(size_min.strip()) * 1024 * 1024
size_max = float(size_max.strip()) * 1024 * 1024
if torrent_info.size < size_min or torrent_info.size > size_max:
return False
elif size_range.startswith(">"):
# 大于
size_min = float(size_range[1:].strip()) * 1024 * 1024
if torrent_info.size < size_min:
return False
elif size_range.startswith("<"):
# 小于
size_max = float(size_range[1:].strip()) * 1024 * 1024
if torrent_info.size > size_max:
return False
return True return True
@staticmethod @staticmethod