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

View File

@@ -2,9 +2,14 @@ from abc import ABC, abstractmethod
from pydantic.main import BaseModel
from app.chain import ChainBase
from app.schemas import ActionContext, ActionParams
class ActionChain(ChainBase):
pass
class BaseAction(BaseModel, ABC):
"""
工作流动作基类
@@ -13,6 +18,10 @@ class BaseAction(BaseModel, ABC):
# 完成标志
_done_flag = False
def __init__(self):
super().__init__()
self.chain = ActionChain()
@property
@abstractmethod
def name(self) -> str:

View File

@@ -1,5 +1,4 @@
from app.actions import BaseAction
from app.chain.download import DownloadChain
from app.schemas import ActionParams, ActionContext
@@ -17,10 +16,6 @@ class FetchDownloadsAction(BaseAction):
_downloads = []
def __init__(self):
super().__init__()
self.downloadchain = DownloadChain()
@property
def name(self) -> str:
return "获取下载任务"
@@ -41,7 +36,7 @@ class FetchDownloadsAction(BaseAction):
"""
self._downloads = context.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:
download.completed = True
continue

View File

@@ -3,7 +3,6 @@ from typing import Optional
from pydantic import Field
from app.actions import BaseAction
from app.chain.media import MediaChain
from app.core.config import settings
from app.core.context import Context
from app.core.metainfo import MetaInfo
@@ -22,7 +21,6 @@ class FetchRssParams(ActionParams):
content_type: Optional[str] = Field(None, description="Content-Type")
referer: Optional[str] = Field(None, description="Referer")
ua: Optional[str] = Field(None, description="User-Agent")
recognize: Optional[bool] = Field(False, description="是否识别")
class FetchRssAction(BaseAction):
@@ -35,7 +33,6 @@ class FetchRssAction(BaseAction):
def __init__(self):
super().__init__()
self.rsshelper = RssHelper()
self.mediachain = MediaChain()
@property
def name(self) -> str:
@@ -83,13 +80,11 @@ class FetchRssAction(BaseAction):
size=item.get("size"),
pubdate=item["pubdate"].strftime("%Y-%m-%d %H:%M:%S") if item.get("pubdate") else None,
)
meta, mediainfo = None, None
if params.recognize:
meta = MetaInfo(title=torrentinfo.title, subtitle=torrentinfo.description)
mediainfo = self.mediachain.recognize_media(meta)
if not mediainfo:
logger.warning(f"{torrentinfo.title} 未识别到媒体信息")
continue
meta = MetaInfo(title=torrentinfo.title, subtitle=torrentinfo.description)
mediainfo = self.chain.recognize_media(meta)
if not mediainfo:
logger.warning(f"{torrentinfo.title} 未识别到媒体信息")
continue
self._rss_torrents.append(Context(meta_info=meta, media_info=mediainfo, torrent_info=torrentinfo))
if self._rss_torrents:

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

View File

@@ -1,4 +1,9 @@
from typing import Optional, List
from pydantic import Field
from app.actions import BaseAction
from app.helper.torrent import TorrentHelper
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):
@@ -14,6 +22,12 @@ class FilterTorrentsAction(BaseAction):
过滤资源数据
"""
_torrents = []
def __init__(self):
super().__init__()
self.torrenthelper = TorrentHelper()
@property
def name(self) -> str:
return "过滤资源数据"
@@ -24,7 +38,29 @@ class FilterTorrentsAction(BaseAction):
@property
def success(self) -> bool:
return True
return self.done
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

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

View File

@@ -1,12 +1,17 @@
from typing import List, Optional, Union
from pydantic import Field
from app.actions import BaseAction
from app.schemas import ActionParams, ActionContext
from app.schemas import ActionParams, ActionContext, MessageChannel
class SendMessageParams(ActionParams):
"""
发送消息参数
"""
pass
channel: Optional[List[str]] = Field([], description="消息渠道")
userid: Optional[Union[str, int]] = Field(None, description="用户ID")
class SendMessageAction(BaseAction):
@@ -24,7 +29,20 @@ class SendMessageAction(BaseAction):
@property
def success(self) -> bool:
return True
return self.done
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

View File

@@ -133,12 +133,12 @@ def search_by_id(mediaid: str,
@router.get("/title", summary="模糊搜索资源", response_model=schemas.Response)
def search_by_title(keyword: str = None,
page: int = 0,
site: int = None,
sites: List[int] = None,
_: 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:
return schemas.Response(success=False, message="未搜索到任何资源")
return schemas.Response(success=True, data=[torrent.to_dict() for torrent in torrents])

View File

@@ -61,19 +61,21 @@ class SearchChain(ChainBase):
self.save_cache(bytes_results, self.__result_temp_file)
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 page: 页码
:param site: 站点ID
:param sites: 站点ID列表
:param cache_local: 是否缓存到本地
"""
if title:
logger.info(f'开始搜索资源,关键词:{title} ...')
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:
logger.warn(f'{title} 未搜索到资源')
return []
@@ -81,8 +83,9 @@ class SearchChain(ChainBase):
contexts = [Context(meta_info=MetaInfo(title=torrent.title, subtitle=torrent.description),
torrent_info=torrent) for torrent in torrents]
# 保存到本地文件
bytes_results = pickle.dumps(contexts)
self.save_cache(bytes_results, self.__result_temp_file)
if cache_local:
bytes_results = pickle.dumps(contexts)
self.save_cache(bytes_results, self.__result_temp_file)
return contexts
def last_search_results(self) -> List[Context]:

View File

@@ -33,7 +33,7 @@ class RuleHelper:
return group
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:
if not group.media_type:
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)
elif group.category == media.category:
elif media and group.category == media.category:
ret_groups.append(group)
return ret_groups

View File

@@ -445,6 +445,26 @@ class TorrentHelper(metaclass=Singleton):
logger.info(f"{torrent_info.title} 不匹配特效规则 {effect}")
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
@staticmethod