refactor(config): retire RuntimeSettingsCompat host usage

This commit is contained in:
jxxghp
2026-08-26 15:55:21 +08:00
parent cdab54254d
commit 9dbe424c3d
162 changed files with 1966 additions and 1745 deletions
+12 -12
View File
@@ -94,13 +94,13 @@ class TheMovieDbModule(MediaAuxiliaryProviderMixin, _ModuleBase):
"""
测试模块连接性
"""
ret = RequestUtils(ua=get_runtime_setting("NORMAL_USER_AGENT"), proxies=get_runtime_setting("PROXY")).get_res(
f"https://{get_runtime_setting("TMDB_API_DOMAIN")}/3/movie/550?api_key={get_runtime_setting("TMDB_API_KEY")}")
ret = RequestUtils(ua=get_runtime_setting('NORMAL_USER_AGENT'), proxies=get_runtime_setting('PROXY')).get_res(
f"https://{get_runtime_setting('TMDB_API_DOMAIN')}/3/movie/550?api_key={get_runtime_setting('TMDB_API_KEY')}")
if ret and ret.status_code == 200:
return True, ""
elif ret:
return False, f"无法连接 {get_runtime_setting("TMDB_API_DOMAIN")},错误码:{ret.status_code}"
return False, f"{get_runtime_setting("TMDB_API_DOMAIN")} 网络连接失败"
return False, f"无法连接 {get_runtime_setting('TMDB_API_DOMAIN')},错误码:{ret.status_code}"
return False, f"{get_runtime_setting('TMDB_API_DOMAIN')} 网络连接失败"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass
@@ -122,7 +122,7 @@ class TheMovieDbModule(MediaAuxiliaryProviderMixin, _ModuleBase):
if not tmdbid and not meta:
return False
selected_source = normalize_media_source(media_source or get_runtime_setting("RECOGNIZE_SOURCE"))
selected_source = normalize_media_source(media_source or get_runtime_setting('RECOGNIZE_SOURCE'))
if meta and not tmdbid and selected_source != MediaSource.TMDB:
return False
@@ -973,7 +973,7 @@ class TheMovieDbModule(MediaAuxiliaryProviderMixin, _ModuleBase):
:param season: 季号
:param episode: 集号
"""
if (mediainfo.scrape_source or get_runtime_setting("SCRAP_SOURCE")) != "themoviedb":
if (mediainfo.scrape_source or get_runtime_setting('SCRAP_SOURCE')) != "themoviedb":
return None
return self.scraper.get_metadata_nfo(meta=meta, mediainfo=mediainfo, season=season, episode=episode)
@@ -985,7 +985,7 @@ class TheMovieDbModule(MediaAuxiliaryProviderMixin, _ModuleBase):
:param season: 季号
:param episode: 集号
"""
if (mediainfo.scrape_source or get_runtime_setting("SCRAP_SOURCE")) != "themoviedb":
if (mediainfo.scrape_source or get_runtime_setting('SCRAP_SOURCE')) != "themoviedb":
return None
return self.scraper.get_metadata_img(mediainfo=mediainfo, season=season, episode=episode)
@@ -1106,7 +1106,7 @@ class TheMovieDbModule(MediaAuxiliaryProviderMixin, _ModuleBase):
:param mediainfo: 媒体信息
:return: None 表示不处理,MediaInfo 表示继续处理
"""
if mediainfo.media_source != "themoviedb" and get_runtime_setting("RECOGNIZE_SOURCE") != "themoviedb":
if mediainfo.media_source != "themoviedb" and get_runtime_setting('RECOGNIZE_SOURCE') != "themoviedb":
return None
if not mediainfo.tmdb_id:
return mediainfo
@@ -1147,15 +1147,15 @@ class TheMovieDbModule(MediaAuxiliaryProviderMixin, _ModuleBase):
# 背景图
if not mediainfo.backdrop_path:
if image_path := cls._pick_best_tmdb_image(images.get("backdrops")):
mediainfo.backdrop_path = get_runtime_setting("TMDB_IMAGE_URL")(image_path)
mediainfo.backdrop_path = get_runtime_setting('TMDB_IMAGE_URL')(image_path)
# 标志
if not mediainfo.logo_path:
if image_path := cls._pick_best_tmdb_image(images.get("logos")):
mediainfo.logo_path = get_runtime_setting("TMDB_IMAGE_URL")(image_path)
mediainfo.logo_path = get_runtime_setting('TMDB_IMAGE_URL')(image_path)
# 海报
if not mediainfo.poster_path:
if image_path := cls._pick_best_tmdb_image(images.get("posters")):
mediainfo.poster_path = get_runtime_setting("TMDB_IMAGE_URL")(image_path)
mediainfo.poster_path = get_runtime_setting('TMDB_IMAGE_URL')(image_path)
return mediainfo
def obtain_images(self, mediainfo: MediaInfo) -> Optional[MediaInfo]:
@@ -1245,7 +1245,7 @@ class TheMovieDbModule(MediaAuxiliaryProviderMixin, _ModuleBase):
image_path = seasoninfo.get(image_type.value)
if image_path:
return get_runtime_setting("TMDB_IMAGE_URL")(image_path, image_prefix)
return get_runtime_setting('TMDB_IMAGE_URL')(image_path, image_prefix)
return None
def tmdb_movie_similar(self, tmdbid: int) -> List[MediaInfo]:
+3 -4
View File
@@ -5,9 +5,8 @@ from typing import Union
import ruamel.yaml
from ruamel.yaml import CommentedMap
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
settings = RuntimeSettingsCompat()
from app.runtime.log import logger
from app.schemas.category import CategoryConfig
from app.foundation.singleton import WeakSingleton
@@ -33,7 +32,7 @@ class CategoryHelper(metaclass=WeakSingleton):
"""
def __init__(self):
self._category_path: Path = settings.CONFIG_PATH / "category.yaml"
self._category_path: Path = get_runtime_setting('CONFIG_PATH') / "category.yaml"
self._categorys = {}
self._movie_categorys = {}
self._tv_categorys = {}
@@ -45,7 +44,7 @@ class CategoryHelper(metaclass=WeakSingleton):
"""
try:
if not self._category_path.exists():
shutil.copy(settings.INNER_CONFIG_PATH / "category.yaml", self._category_path)
shutil.copy(get_runtime_setting('INNER_CONFIG_PATH') / "category.yaml", self._category_path)
with open(self._category_path, mode='r', encoding='utf-8', errors='replace') as f:
try:
yaml_loader = ruamel.yaml.YAML()
+11 -12
View File
@@ -2,9 +2,8 @@ from pathlib import Path
from typing import Optional, Tuple
from xml.dom import minidom
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
settings = RuntimeSettingsCompat()
from app.domain.context import MediaInfo
from app.domain.meta.metabase import MetaBase
from app.schemas.types import MediaType
@@ -22,14 +21,14 @@ class TmdbScraper:
获取元数据TMDB Api
"""
if not self._meta_tmdb:
self._meta_tmdb = TmdbApi(language=settings.TMDB_LOCALE)
self._meta_tmdb = TmdbApi(language=get_runtime_setting('TMDB_LOCALE'))
return self._meta_tmdb
def original_tmdb(self, mediainfo: Optional[MediaInfo] = None):
"""
获取图片TMDB Api
"""
if settings.TMDB_SCRAP_ORIGINAL_IMAGE and mediainfo:
if get_runtime_setting('TMDB_SCRAP_ORIGINAL_IMAGE') and mediainfo:
return TmdbApi(language=mediainfo.original_language)
return self.default_tmdb
@@ -116,7 +115,7 @@ class TmdbScraper:
# TMDB集still图片
ext = Path(still_path).suffix
still_name = f"episode-thumb{ext}"
still_url = settings.TMDB_IMAGE_URL(still_path)
still_url = get_runtime_setting('TMDB_IMAGE_URL')(still_path)
images[still_name] = still_url
else:
# 季的图片
@@ -144,14 +143,14 @@ class TmdbScraper:
images[image_name] = attr_value
# 替换原语言Poster
if settings.TMDB_SCRAP_ORIGINAL_IMAGE:
if get_runtime_setting('TMDB_SCRAP_ORIGINAL_IMAGE'):
_mediainfo = self.original_tmdb(mediainfo).get_info(
mediainfo.type, mediainfo.tmdb_id
)
if _mediainfo:
for attr_name, attr_value in _mediainfo.items():
if attr_name.endswith("_path") and attr_value is not None:
image_url = settings.TMDB_IMAGE_URL(attr_value)
image_url = get_runtime_setting('TMDB_IMAGE_URL')(attr_value)
image_name = (
attr_name.replace("_path", "") + Path(image_url).suffix
)
@@ -181,11 +180,11 @@ class TmdbScraper:
if not mediainfo.poster_path:
poster_path = self.__pick_best_image_path(image_info.get("posters"))
if poster_path:
mediainfo.poster_path = settings.TMDB_IMAGE_URL(poster_path)
mediainfo.poster_path = get_runtime_setting('TMDB_IMAGE_URL')(poster_path)
if not mediainfo.backdrop_path:
backdrop_path = self.__pick_best_image_path(image_info.get("backdrops"))
if backdrop_path:
mediainfo.backdrop_path = settings.TMDB_IMAGE_URL(backdrop_path)
mediainfo.backdrop_path = get_runtime_setting('TMDB_IMAGE_URL')(backdrop_path)
@staticmethod
def __pick_best_image_path(images: list) -> Optional[str]:
@@ -215,7 +214,7 @@ class TmdbScraper:
# 后缀
ext = Path(poster_path).suffix
# URL
url = settings.TMDB_IMAGE_URL(poster_path)
url = get_runtime_setting('TMDB_IMAGE_URL')(poster_path)
# S0海报格式不同
if season == 0:
image_name = f"season-specials-poster{ext}"
@@ -286,7 +285,7 @@ class TmdbScraper:
DomUtils.add_node(doc, xactor, "tmdbid", actor.get("id") or "")
if profile_path := actor.get("profile_path"):
DomUtils.add_node(
doc, xactor, "thumb", settings.TMDB_IMAGE_URL(profile_path)
doc, xactor, "thumb", get_runtime_setting('TMDB_IMAGE_URL')(profile_path)
)
DomUtils.add_node(
doc,
@@ -453,7 +452,7 @@ class TmdbScraper:
DomUtils.add_node(doc, xactor, "tmdbid", actor.get("id") or "")
if profile_path := actor.get("profile_path"):
DomUtils.add_node(
doc, xactor, "thumb", settings.TMDB_IMAGE_URL(profile_path)
doc, xactor, "thumb", get_runtime_setting('TMDB_IMAGE_URL')(profile_path)
)
DomUtils.add_node(
doc,
+9 -10
View File
@@ -6,9 +6,8 @@ from time import time
from typing import Any, Optional
from app.runtime.cache import FileCache, TTLCache
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
settings = RuntimeSettingsCompat()
from app.domain.meta.metabase import MetaBase
from app.runtime.log import logger
from app.schemas.types import MediaSource, MediaType
@@ -32,8 +31,8 @@ class TmdbCache(metaclass=WeakSingleton):
"""
def __init__(self):
"""初始化 TMDB 识别缓存并恢复未过期的持久化数据。"""
self.maxsize = settings.CONF.tmdb
self.ttl = settings.CONF.meta
self.maxsize = get_runtime_setting('CONF').tmdb
self.ttl = get_runtime_setting('CONF').meta
self.region = "__tmdb_cache__"
self._cache = TTLCache(region=self.region, maxsize=self.maxsize, ttl=self.ttl)
self._expires_at: dict[str, float] = {}
@@ -42,8 +41,8 @@ class TmdbCache(metaclass=WeakSingleton):
self._legacy_file_cache = None
self._legacy_cache_found = False
if not self._cache.is_redis():
self._file_cache = FileCache(base=settings.CACHE_PATH, ttl=self.ttl)
self._legacy_file_cache = FileCache(base=settings.TEMP_PATH.parent, ttl=self.ttl)
self._file_cache = FileCache(base=get_runtime_setting('CACHE_PATH'), ttl=self.ttl)
self._legacy_file_cache = FileCache(base=get_runtime_setting('TEMP_PATH').parent, ttl=self.ttl)
self._restore()
def _restore(self) -> None:
@@ -53,7 +52,7 @@ class TmdbCache(metaclass=WeakSingleton):
if not content:
content = self._legacy_file_cache.get(
self.region,
region=settings.TEMP_PATH.name,
region=get_runtime_setting('TEMP_PATH').name,
)
if content:
self._legacy_cache_found = True
@@ -146,7 +145,7 @@ class TmdbCache(metaclass=WeakSingleton):
获取缓存KEY
"""
media_id = meta.media_id if meta.media_source == MediaSource.TMDB else None
return f"[{meta.type.value if meta.type else '未知'}][{settings.TMDB_LOCALE}]{media_id or meta.name}-{meta.year}-{meta.begin_season}"
return f"[{meta.type.value if meta.type else '未知'}][{get_runtime_setting('TMDB_LOCALE')}]{media_id or meta.name}-{meta.year}-{meta.begin_season}"
@staticmethod
def __is_type_conflicted(meta: MetaBase, media_type: Any, tmdb_id: Any) -> bool:
@@ -263,7 +262,7 @@ class TmdbCache(metaclass=WeakSingleton):
# 负识别缓存使用独立的短 TTL:故障期间「合法 JSON 但结果为空」会被
# 记为未识别,若按完整有效期固化,故障自愈后同名仍会被判无法识别;
# 短过期让恢复后可重新识别,真不存在的条目过期后重新确认一次即可
self._set(key, {"id": 0}, ttl=settings.EMPTY_RESULT_CACHE_TTL)
self._set(key, {"id": 0}, ttl=get_runtime_setting('EMPTY_RESULT_CACHE_TTL'))
def save(self, force: bool = False) -> None:
"""
@@ -314,7 +313,7 @@ class TmdbCache(metaclass=WeakSingleton):
if self._legacy_cache_found:
self._legacy_file_cache.delete(
self.region,
region=settings.TEMP_PATH.name,
region=get_runtime_setting('TEMP_PATH').name,
)
self._legacy_cache_found = False
self._dirty = False
+2 -3
View File
@@ -2,9 +2,8 @@ import re
import traceback
from typing import Optional, List
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
settings = RuntimeSettingsCompat()
from app.runtime.log import logger
from app.schemas.types import MediaType
from app.foundation import text as text_tools
@@ -1279,7 +1278,7 @@ class TmdbApi:
"""
languages = []
for language in (
settings.TMDB_LOCALE,
get_runtime_setting('TMDB_LOCALE'),
"en",
None,
original_language,
@@ -1,7 +1,6 @@
from app.runtime.cache import cached
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
settings = RuntimeSettingsCompat()
from ..tmdb import TMDb
try:
@@ -16,7 +15,7 @@ class Discover(TMDb):
"tv": "/discover/tv"
}
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=get_runtime_setting('EMPTY_RESULT_CACHE_TTL'))
def discover_movies(self, params_tuple):
"""
Discover movies by different types of data like average rating, number of votes, genres and certifications.
@@ -26,7 +25,7 @@ class Discover(TMDb):
params = dict(params_tuple)
return self._request_obj(self._urls["movies"], urlencode(params), key="results", call_cached=False)
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=get_runtime_setting('EMPTY_RESULT_CACHE_TTL'))
def discover_tv_shows(self, params_tuple):
"""
Discover TV shows by different types of data like average rating, number of votes, genres,
@@ -36,7 +35,7 @@ class Discover(TMDb):
"""
return self._request_obj(self._urls["tv"], urlencode(params_tuple), key="results", call_cached=False)
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=get_runtime_setting('EMPTY_RESULT_CACHE_TTL'))
async def async_discover_movies(self, params_tuple):
"""
Discover movies by different types of data like average rating, number of votes, genres and certifications.(异步版本)
@@ -46,7 +45,7 @@ class Discover(TMDb):
params = dict(params_tuple)
return await self._async_request_obj(self._urls["movies"], urlencode(params), key="results", call_cached=False)
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=get_runtime_setting('EMPTY_RESULT_CACHE_TTL'))
async def async_discover_tv_shows(self, params_tuple):
"""
Discover TV shows by different types of data like average rating, number of votes, genres,
+12 -13
View File
@@ -10,9 +10,8 @@ import requests
import requests.exceptions
from app.runtime.cache import cached, fresh, async_fresh
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
settings = RuntimeSettingsCompat()
from app.adapters.network.http import RequestUtils, AsyncRequestUtils
from .exceptions import TMDbException, TMDbConnectionError
@@ -44,7 +43,7 @@ def _is_empty_result_snapshot(snapshot) -> bool:
判断响应快照是否为空结果(列表/搜索类接口的 results 为空列表)。
这类快照结构合法但无业务内容,常由代理瞬时故障产生;不能靠 skip_none/skip_empty
识别(快照本身是非空字典),需单独谓词判定后按 settings.EMPTY_RESULT_CACHE_TTL
识别(快照本身是非空字典),需单独谓词判定后按 get_runtime_setting('EMPTY_RESULT_CACHE_TTL')
短 TTL 缓存。详情类接口无 results 字段,不属于空结果。
"""
if not isinstance(snapshot, dict):
@@ -60,13 +59,13 @@ class TMDb(object):
_RESPONSE_SNAPSHOT_MARKER = "__mp_tmdb_response_snapshot__"
def __init__(self, session=None, language=None):
self._api_key = settings.TMDB_API_KEY
self._language = language or settings.TMDB_LOCALE or "en-US"
self._api_key = get_runtime_setting('TMDB_API_KEY')
self._language = language or get_runtime_setting('TMDB_LOCALE') or "en-US"
self._session_id = None
self._session = session
self._wait_on_rate_limit = True
self._proxies = settings.PROXY
self._domain = settings.TMDB_API_DOMAIN
self._proxies = get_runtime_setting('PROXY')
self._domain = get_runtime_setting('TMDB_API_DOMAIN')
self._page = None
self._total_results = None
self._total_pages = None
@@ -76,7 +75,7 @@ class TMDb(object):
# TMDB 在部分代理和运营商链路下的 HTTP/2 长连接偶发卡死,识别路径优先保证稳定性。
self._async_req = AsyncRequestUtils(
ua=settings.NORMAL_USER_AGENT,
ua=get_runtime_setting('NORMAL_USER_AGENT'),
proxies=self.proxies,
http2=False,
)
@@ -91,7 +90,7 @@ class TMDb(object):
"""
self._session = session or requests.Session()
self._req = RequestUtils(
ua=settings.NORMAL_USER_AGENT,
ua=get_runtime_setting('NORMAL_USER_AGENT'),
session=self._session,
proxies=self.proxies,
)
@@ -175,9 +174,9 @@ class TMDb(object):
def wait_on_rate_limit(self, wait_on_rate_limit):
self._wait_on_rate_limit = bool(wait_on_rate_limit)
@cached(maxsize=settings.CONF.tmdb, ttl=settings.CONF.meta, skip_none=True,
@cached(maxsize=get_runtime_setting('CONF').tmdb, ttl=get_runtime_setting('CONF').meta, skip_none=True,
skip_if=_is_business_failure_snapshot,
empty_ttl=settings.EMPTY_RESULT_CACHE_TTL, empty_if=_is_empty_result_snapshot)
empty_ttl=get_runtime_setting('EMPTY_RESULT_CACHE_TTL'), empty_if=_is_empty_result_snapshot)
def request(self, method, url, data, json, **kwargs):
req = self._request_once(method, url, data, json)
if req is None and method == "GET" and self._owns_session:
@@ -201,9 +200,9 @@ class TMDb(object):
return self._req.get_res(url, params=data, json=json)
return self._req.post_res(url, data=data, json=json)
@cached(maxsize=settings.CONF.tmdb, ttl=settings.CONF.meta, skip_none=True,
@cached(maxsize=get_runtime_setting('CONF').tmdb, ttl=get_runtime_setting('CONF').meta, skip_none=True,
skip_if=_is_business_failure_snapshot,
empty_ttl=settings.EMPTY_RESULT_CACHE_TTL, empty_if=_is_empty_result_snapshot)
empty_ttl=get_runtime_setting('EMPTY_RESULT_CACHE_TTL'), empty_if=_is_empty_result_snapshot)
async def async_request(self, method, url, data, json, **kwargs):
req = await self._async_request_once(method, url, data, json)
if req is None: