mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 07:56:52 +08:00
refactor(string): split utilities by responsibility
This commit is contained in:
+10
-8
@@ -39,7 +39,9 @@ from app.schemas.types import MUSIC_ENTITY_ALBUM, MediaSource, MediaType, Torren
|
||||
ChainEventType
|
||||
from app.adapters.network.http import RequestUtils
|
||||
from app.schemas.media import build_media_key, resolve_media_identity
|
||||
from app.domain.string import StringUtils
|
||||
from app.domain import episode as episode_rules
|
||||
from app.foundation import size as size_tools
|
||||
from app.foundation import text as text_tools
|
||||
from app.adapters.system.host import SystemUtils
|
||||
|
||||
|
||||
@@ -138,7 +140,7 @@ class DownloadChain(ChainBase):
|
||||
).apply_path_context(file_path)
|
||||
track_identity: Union[int, str, None] = file_meta.track_number
|
||||
if track_identity is None:
|
||||
track_identity = StringUtils.clear_upper(file_meta.title or file_path.stem)
|
||||
track_identity = text_tools.normalize_upper(file_meta.title or file_path.stem)
|
||||
if track_identity in (None, ""):
|
||||
return None
|
||||
return file_meta.disc_number or 1, track_identity
|
||||
@@ -554,7 +556,7 @@ class DownloadChain(ChainBase):
|
||||
return meta.episode
|
||||
episode_list = getattr(meta, "episode_list", None)
|
||||
if episode_list:
|
||||
return StringUtils.format_ep(list(episode_list))
|
||||
return episode_rules.format_ranges(list(episode_list))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@@ -669,7 +671,7 @@ class DownloadChain(ChainBase):
|
||||
media_source=media_source,
|
||||
media_id=media_id,
|
||||
seasons=getattr(meta, "season", None),
|
||||
episodes=StringUtils.format_ep(list(episodes)) if episodes else self._format_failure_episodes(meta),
|
||||
episodes=episode_rules.format_ranges(list(episodes)) if episodes else self._format_failure_episodes(meta),
|
||||
site=site if isinstance(site, int) else None,
|
||||
site_name=getattr(torrent, "site_name", None),
|
||||
torrent_id=self._torrent_resource_key(torrent),
|
||||
@@ -916,7 +918,7 @@ class DownloadChain(ChainBase):
|
||||
return (None, str(err)) if return_detail else None
|
||||
|
||||
# 实际下载的集数
|
||||
download_episodes = StringUtils.format_ep(list(episodes)) if episodes else None
|
||||
download_episodes = episode_rules.format_ranges(list(episodes)) if episodes else None
|
||||
if episodes is not None:
|
||||
context.selected_episodes = sorted(set(episodes))
|
||||
elif _meta and _meta.episode_list:
|
||||
@@ -1427,12 +1429,12 @@ class DownloadChain(ChainBase):
|
||||
if complete_coverage_matched:
|
||||
logger.info(
|
||||
f"{meta.org_string} 解析文件集数已完整覆盖目标范围:"
|
||||
f"{StringUtils.format_ep(sorted(required_episodes))}")
|
||||
f"{episode_rules.format_ranges(sorted(required_episodes))}")
|
||||
if required_episodes and not complete_coverage_matched:
|
||||
missing_episodes = sorted(required_episodes.difference(torrent_episodes_set))
|
||||
logger.info(
|
||||
f"{meta.org_string} 解析文件集数未覆盖目标范围,"
|
||||
f"缺少 {StringUtils.format_ep(missing_episodes)},先放弃这个种子")
|
||||
f"缺少 {episode_rules.format_ranges(missing_episodes)},先放弃这个种子")
|
||||
continue
|
||||
if not required_episodes and need_total and len(torrent_episodes) < need_total:
|
||||
logger.info(
|
||||
@@ -1858,7 +1860,7 @@ class DownloadChain(ChainBase):
|
||||
index = 1
|
||||
for torrent in torrents:
|
||||
messages.append(f"{index}. {torrent.title} "
|
||||
f"{StringUtils.str_filesize(torrent.size)} "
|
||||
f"{size_tools.format_compact_size(torrent.size)} "
|
||||
f"{round(torrent.progress, 1)}%")
|
||||
index += 1
|
||||
self.post_message(Notification(
|
||||
|
||||
+3
-3
@@ -41,7 +41,7 @@ from app.domain.media import is_music_media_source
|
||||
from app.schemas.media import normalize_media_source, resolve_media_identity
|
||||
from app.foundation.singleton import Singleton
|
||||
from app.foundation.text import convert as zhconv_convert
|
||||
from app.domain.string import StringUtils
|
||||
from app.domain import title as title_rules
|
||||
|
||||
recognize_lock = Lock()
|
||||
|
||||
@@ -1412,7 +1412,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
||||
"""
|
||||
# 提取要素
|
||||
mtype, key_word, season_num, episode_num, year, content = (
|
||||
StringUtils.get_keyword(title)
|
||||
title_rules.parse_search_keyword(title)
|
||||
)
|
||||
# 识别
|
||||
meta = MetaInfo(content)
|
||||
@@ -1889,7 +1889,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
||||
"""
|
||||
# 提取要素
|
||||
mtype, key_word, season_num, episode_num, year, content = (
|
||||
StringUtils.get_keyword(title)
|
||||
title_rules.parse_search_keyword(title)
|
||||
)
|
||||
# 识别
|
||||
meta = MetaInfo(content)
|
||||
|
||||
@@ -43,7 +43,9 @@ from app.schemas.system import TransferDirectoryConf
|
||||
from app.schemas.types import EventType, MessageChannel, MediaType
|
||||
from app.adapters.network.http import RequestUtils
|
||||
from app.schemas.media import build_media_key, resolve_media_identity
|
||||
from app.domain.string import StringUtils
|
||||
from app.domain import episode as episode_rules
|
||||
from app.domain import title as title_rules
|
||||
from app.foundation import url as url_tools
|
||||
|
||||
|
||||
class MessageChain(ChainBase):
|
||||
@@ -2562,9 +2564,9 @@ class MediaInteractionChain(ChainBase):
|
||||
return "ReSubscribe", re.sub(r"洗版[::\s]*", "", text)
|
||||
if text.startswith("搜索") or text.startswith("下载"):
|
||||
return "ReSearch", re.sub(r"(搜索|下载)[::\s]*", "", text)
|
||||
if StringUtils.is_link(text):
|
||||
if url_tools.is_link(text):
|
||||
return None, text
|
||||
if not StringUtils.is_media_title_like(text):
|
||||
if not title_rules.is_media_title_like(text):
|
||||
return None, text
|
||||
return "Search", text
|
||||
|
||||
@@ -3683,7 +3685,7 @@ class MediaInteractionChain(ChainBase):
|
||||
season_map = no_exists.get(mediakey) or {}
|
||||
if show_missing_only:
|
||||
return [
|
||||
f"第 {sea} 季缺失 {StringUtils.str_series(no_exist.episodes) if no_exist.episodes else no_exist.total_episode} 集"
|
||||
f"第 {sea} 季缺失 {episode_rules.compact_numbers(no_exist.episodes) if no_exist.episodes else no_exist.total_episode} 集"
|
||||
for sea, no_exist in season_map.items()
|
||||
]
|
||||
return [
|
||||
|
||||
@@ -47,7 +47,7 @@ from app.domain.media import is_music_media_source
|
||||
from app.schemas.media import normalize_media_source, resolve_media_identity
|
||||
from app.runtime.reload import ConfigReloadMixin
|
||||
from app.foundation.singleton import Singleton
|
||||
from app.domain.string import StringUtils
|
||||
|
||||
|
||||
|
||||
from app.chain.media import MediaChain
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ from app.schemas.types import (
|
||||
SystemConfigKey,
|
||||
)
|
||||
from app.schemas.media import build_media_key, parse_media_key, resolve_media_identity
|
||||
from app.domain.string import StringUtils
|
||||
from app.foundation import size as size_tools
|
||||
from app.foundation.text import convert as zhconv_convert
|
||||
|
||||
|
||||
@@ -466,7 +466,7 @@ class SearchChain(ChainBase):
|
||||
"index": index,
|
||||
"title": torrent.torrent_info.title or "未知",
|
||||
"size": (
|
||||
StringUtils.format_size(torrent.torrent_info.size)
|
||||
size_tools.format_size(torrent.torrent_info.size)
|
||||
if torrent.torrent_info.size
|
||||
else "0 B"
|
||||
),
|
||||
|
||||
+21
-18
@@ -32,7 +32,10 @@ from app.schemas import MessageChannel, Notification, SiteUserData
|
||||
from app.schemas.types import EventType, NotificationType
|
||||
from app.adapters.network.http import RequestUtils
|
||||
from app.domain.site import SiteUtils
|
||||
from app.domain.string import StringUtils
|
||||
from app.domain import site as site_rules
|
||||
from app.foundation import size as size_tools
|
||||
from app.foundation import url as url_tools
|
||||
from app.foundation.dom import DomUtils
|
||||
|
||||
site_interaction_manager = SlashInteractionManager()
|
||||
|
||||
@@ -71,7 +74,7 @@ class SiteChain(ChainBase):
|
||||
"""
|
||||
userdata: SiteUserData = self.run_module("refresh_userdata", site=site)
|
||||
if userdata:
|
||||
SiteOper().update_userdata(domain=StringUtils.get_url_domain(site.get("domain")),
|
||||
SiteOper().update_userdata(domain=site_rules.extract_domain(site.get("domain")),
|
||||
name=site.get("name"),
|
||||
payload=userdata.model_dump())
|
||||
# 发送事件
|
||||
@@ -229,7 +232,7 @@ class SiteChain(ChainBase):
|
||||
判断站点是否已经登陆:m-team
|
||||
"""
|
||||
user_agent = site.ua or settings.USER_AGENT
|
||||
domain = StringUtils.get_url_domain(site.url)
|
||||
domain = site_rules.extract_domain(site.url)
|
||||
url = f"https://api.{domain}/api/member/profile"
|
||||
headers = {
|
||||
"User-Agent": user_agent,
|
||||
@@ -352,7 +355,7 @@ class SiteChain(ChainBase):
|
||||
"""
|
||||
判断站点是否已经登陆:rousi
|
||||
"""
|
||||
url = f"https://{StringUtils.get_url_domain(site.url)}/api/v1/profile"
|
||||
url = f"https://{site_rules.extract_domain(site.url)}/api/v1/profile"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
@@ -391,7 +394,7 @@ class SiteChain(ChainBase):
|
||||
return favicon_url, None
|
||||
html = etree.HTML(html_text)
|
||||
try:
|
||||
if StringUtils.is_valid_html_element(html):
|
||||
if DomUtils.has_child_elements(html):
|
||||
fav_link = html.xpath('//head/link[contains(@rel, "icon")]/@href')
|
||||
if fav_link:
|
||||
favicon_url = urljoin(url, fav_link[0])
|
||||
@@ -422,10 +425,10 @@ class SiteChain(ChainBase):
|
||||
"""
|
||||
根据主域名获取索引器地址
|
||||
"""
|
||||
if StringUtils.get_url_domain(inx.get("domain")) == sub_domain:
|
||||
if site_rules.extract_domain(inx.get("domain")) == sub_domain:
|
||||
return inx.get("domain")
|
||||
for ext_d in inx.get("ext_domains", []):
|
||||
if StringUtils.get_url_domain(ext_d) == sub_domain:
|
||||
if site_rules.extract_domain(ext_d) == sub_domain:
|
||||
return ext_d
|
||||
return sub_domain
|
||||
|
||||
@@ -496,7 +499,7 @@ class SiteChain(ChainBase):
|
||||
_update_count += 1
|
||||
elif indexer:
|
||||
if settings.COOKIECLOUD_BLACKLIST and any(
|
||||
StringUtils.get_url_domain(domain) == StringUtils.get_url_domain(black_domain) for black_domain
|
||||
site_rules.extract_domain(domain) == site_rules.extract_domain(black_domain) for black_domain
|
||||
in str(settings.COOKIECLOUD_BLACKLIST).split(",")):
|
||||
logger.warn(f"站点 {domain} 已在黑名单中,不添加站点")
|
||||
continue
|
||||
@@ -600,7 +603,7 @@ class SiteChain(ChainBase):
|
||||
if not domain:
|
||||
return
|
||||
if str(domain).startswith("http"):
|
||||
domain = StringUtils.get_url_domain(domain)
|
||||
domain = site_rules.extract_domain(domain)
|
||||
# 站点信息
|
||||
siteoper = SiteOper()
|
||||
siteshelper = SitesHelper()
|
||||
@@ -642,7 +645,7 @@ class SiteChain(ChainBase):
|
||||
if not domain:
|
||||
return
|
||||
# 获取主域名中间那段
|
||||
domain_host = StringUtils.get_url_host(domain)
|
||||
domain_host = url_tools.host_label(domain)
|
||||
# 查询以"site.domain_host"开头的配置项,并清除
|
||||
systemconfig = SystemConfigOper()
|
||||
site_keys = systemconfig.all().keys()
|
||||
@@ -664,7 +667,7 @@ class SiteChain(ChainBase):
|
||||
if not domain:
|
||||
return
|
||||
if str(domain).startswith("http"):
|
||||
domain = StringUtils.get_url_domain(domain)
|
||||
domain = site_rules.extract_domain(domain)
|
||||
indexer = SitesHelper().get_indexer(domain)
|
||||
if not indexer:
|
||||
return
|
||||
@@ -678,7 +681,7 @@ class SiteChain(ChainBase):
|
||||
:return: (是否可用, 错误信息)
|
||||
"""
|
||||
# 检查域名是否可用
|
||||
domain = StringUtils.get_url_domain(url)
|
||||
domain = site_rules.extract_domain(url)
|
||||
siteoper = SiteOper()
|
||||
site_info = siteoper.get_by_domain(domain)
|
||||
if not site_info:
|
||||
@@ -1188,7 +1191,7 @@ class SiteChain(ChainBase):
|
||||
"启用" if site.is_active else "禁用",
|
||||
"已配置" if site.cookie else "未配置",
|
||||
"是" if site.render else "否",
|
||||
site.domain or StringUtils.get_url_domain(site.url or ""),
|
||||
site.domain or site_rules.extract_domain(site.url or ""),
|
||||
]
|
||||
for site in site_list
|
||||
]
|
||||
@@ -1203,7 +1206,7 @@ class SiteChain(ChainBase):
|
||||
f"{site.id}. {site.name} | 状态:{'启用' if site.is_active else '禁用'}"
|
||||
f" | Cookie:{'已配置' if site.cookie else '未配置'}"
|
||||
f" | 渲染:{'是' if site.render else '否'}"
|
||||
f" | 域名:{site.domain or StringUtils.get_url_domain(site.url or '')}"
|
||||
f" | 域名:{site.domain or site_rules.extract_domain(site.url or '')}"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
@@ -1506,15 +1509,15 @@ class SiteChain(ChainBase):
|
||||
incDownloads += download
|
||||
messages[upload + (rand / 1000)] = (
|
||||
f"【{site}】{updated_date}\n"
|
||||
+ f"上传量:{StringUtils.str_filesize(upload)}\n"
|
||||
+ f"下载量:{StringUtils.str_filesize(download)}\n"
|
||||
+ f"上传量:{size_tools.format_compact_size(upload)}\n"
|
||||
+ f"下载量:{size_tools.format_compact_size(download)}\n"
|
||||
+ "————————————"
|
||||
)
|
||||
if incDownloads or incUploads:
|
||||
sorted_messages = [messages[key] for key in sorted(messages.keys(), reverse=True)]
|
||||
sorted_messages.insert(0, f"【汇总】\n"
|
||||
f"总上传:{StringUtils.str_filesize(incUploads)}\n"
|
||||
f"总下载:{StringUtils.str_filesize(incDownloads)}\n"
|
||||
f"总上传:{size_tools.format_compact_size(incUploads)}\n"
|
||||
f"总下载:{size_tools.format_compact_size(incDownloads)}\n"
|
||||
f"————————————")
|
||||
self.post_message(Notification(
|
||||
channel=channel,
|
||||
|
||||
@@ -20,7 +20,8 @@ from app.runtime.log import logger
|
||||
from app.schemas import Notification
|
||||
from app.schemas.types import SystemConfigKey, MessageChannel, NotificationType, MediaType
|
||||
from app.schemas.media import resolve_media_identity
|
||||
from app.domain.string import StringUtils
|
||||
from app.domain import site as site_rules
|
||||
from app.foundation import text as text_tools
|
||||
|
||||
|
||||
class TorrentsChain(ChainBase):
|
||||
@@ -355,7 +356,7 @@ class TorrentsChain(ChainBase):
|
||||
"""
|
||||
归一标题用于低置信标题兜底匹配。
|
||||
"""
|
||||
return (StringUtils.clear_upper(value or "") or "").strip()
|
||||
return (text_tools.normalize_upper(value or "") or "").strip()
|
||||
|
||||
def clear_torrents(self):
|
||||
"""
|
||||
@@ -603,7 +604,7 @@ class TorrentsChain(ChainBase):
|
||||
"current": indexer.get("id"),
|
||||
},
|
||||
)
|
||||
domain = StringUtils.get_url_domain(indexer.get("domain"))
|
||||
domain = site_rules.extract_domain(indexer.get("domain"))
|
||||
domains.append(domain)
|
||||
if stype == "spider":
|
||||
# 刷新首页种子
|
||||
|
||||
+10
-9
@@ -68,7 +68,8 @@ from app.application.transfer import TransferQueue, TransferTask
|
||||
from app.domain.media import normalize_music_type
|
||||
from app.schemas.media import normalize_media_source, resolve_media_identity
|
||||
from app.foundation.singleton import Singleton
|
||||
from app.domain.string import StringUtils
|
||||
from app.domain import episode as episode_rules
|
||||
from app.foundation import text as text_tools
|
||||
from app.adapters.system.host import SystemUtils
|
||||
|
||||
# 下载器锁
|
||||
@@ -169,16 +170,16 @@ class JobManager:
|
||||
return "music", source, media_id, music_type
|
||||
|
||||
artists = tuple(
|
||||
StringUtils.clear_upper(artist)
|
||||
text_tools.normalize_upper(artist)
|
||||
for artist in (getattr(media, "artists", None) or [])
|
||||
if StringUtils.clear_upper(artist)
|
||||
if text_tools.normalize_upper(artist)
|
||||
)
|
||||
if music_type == MUSIC_ENTITY_ALBUM:
|
||||
album_artist = StringUtils.clear_upper(
|
||||
album_artist = text_tools.normalize_upper(
|
||||
getattr(media, "album_artist", None)
|
||||
or (artists[0] if artists else "")
|
||||
)
|
||||
album = StringUtils.clear_upper(
|
||||
album = text_tools.normalize_upper(
|
||||
getattr(media, "album", None) or getattr(media, "title", None) or ""
|
||||
)
|
||||
return "music", "local", music_type, album_artist, album, getattr(media, "year", None)
|
||||
@@ -188,8 +189,8 @@ class JobManager:
|
||||
"local",
|
||||
music_type,
|
||||
artists,
|
||||
StringUtils.clear_upper(getattr(media, "title", None) or ""),
|
||||
StringUtils.clear_upper(getattr(media, "album", None) or ""),
|
||||
text_tools.normalize_upper(getattr(media, "title", None) or ""),
|
||||
text_tools.normalize_upper(getattr(media, "album", None) or ""),
|
||||
getattr(media, "disc_number", None),
|
||||
getattr(media, "track_number", None),
|
||||
)
|
||||
@@ -1420,7 +1421,7 @@ class TransferChain(ChainBase, ConfigReloadMixin, metaclass=Singleton):
|
||||
task.mediainfo, task.meta.begin_season
|
||||
)
|
||||
if season_episodes:
|
||||
se_str = f"{task.meta.season} {StringUtils.format_ep(season_episodes)}"
|
||||
se_str = f"{task.meta.season} {episode_rules.format_ranges(season_episodes)}"
|
||||
else:
|
||||
se_str = f"{task.meta.season}"
|
||||
# 发送入库成功消息
|
||||
@@ -3242,7 +3243,7 @@ class TransferChain(ChainBase, ConfigReloadMixin, metaclass=Singleton):
|
||||
return False
|
||||
if source_meta.type != target_meta.type:
|
||||
return False
|
||||
if StringUtils.clear_upper(source_meta.name) != StringUtils.clear_upper(
|
||||
if text_tools.normalize_upper(source_meta.name) != text_tools.normalize_upper(
|
||||
target_meta.name
|
||||
):
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user