mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-02 13:28:32 +08:00
Merge pull request #6619 from ranzhigg/fix/refresh-architecture-baseline
This commit is contained in:
31
app/adapters/external/plugin/client.py
vendored
31
app/adapters/external/plugin/client.py
vendored
@@ -26,10 +26,14 @@ from app.domain.plugin import (
|
||||
is_local_plugin_source,
|
||||
is_physical_plugin_id,
|
||||
is_plugin_generation_compatible,
|
||||
normalize_plugin_market_repo_url as _normalize_plugin_market_repo_url,
|
||||
parse_local_plugin_generation,
|
||||
parse_local_plugin_path,
|
||||
parse_local_plugin_reference,
|
||||
)
|
||||
from app.domain.plugin import (
|
||||
normalize_plugin_market_repo_url as _normalize_plugin_market_repo_url,
|
||||
)
|
||||
from app.domain.plugin import (
|
||||
split_plugin_market_repo_urls as _split_plugin_market_repo_urls,
|
||||
)
|
||||
from app.foundation.environment import is_free_threaded_runtime
|
||||
@@ -1157,7 +1161,7 @@ class PluginMarketTransport(metaclass=WeakSingleton):
|
||||
def _remove_index_task(
|
||||
cls,
|
||||
key: tuple[asyncio.AbstractEventLoop, str, str],
|
||||
task: asyncio.Task[Optional[PluginIndex]],
|
||||
task: asyncio.Future[Optional[PluginIndex]],
|
||||
) -> None:
|
||||
"""异步索引请求结束后释放事件循环和仓库引用。"""
|
||||
with cls._index_task_lock:
|
||||
@@ -1219,10 +1223,14 @@ class PluginMarketTransport(metaclass=WeakSingleton):
|
||||
key = self._plugin_index_key(repo_url, package_version)
|
||||
with self._index_future_lock:
|
||||
future = self._index_futures.get(key)
|
||||
owner = future is None
|
||||
if owner:
|
||||
future = Future()
|
||||
if future is None:
|
||||
future = Future[Optional[PluginIndex]]()
|
||||
self._index_futures[key] = future
|
||||
owner = True
|
||||
else:
|
||||
owner = False
|
||||
|
||||
assert future is not None
|
||||
|
||||
if not owner:
|
||||
return future.result()
|
||||
@@ -1588,12 +1596,13 @@ class PluginMarketTransport(metaclass=WeakSingleton):
|
||||
),
|
||||
)
|
||||
self._index_tasks[task_key] = task
|
||||
task.add_done_callback(
|
||||
lambda completed_task, key=task_key: self._remove_index_task(
|
||||
key,
|
||||
completed_task,
|
||||
)
|
||||
)
|
||||
|
||||
def on_index_task_done(
|
||||
completed_task: asyncio.Future[Optional[PluginIndex]],
|
||||
) -> None:
|
||||
self._remove_index_task(task_key, completed_task)
|
||||
|
||||
task.add_done_callback(on_index_task_done)
|
||||
|
||||
# 单个调用方取消等待时不能连带取消共享请求。
|
||||
return await asyncio.shield(task)
|
||||
|
||||
@@ -470,16 +470,6 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
||||
return False, "Cookie已过期"
|
||||
return False, f"错误:{res.status_code} {res.reason}"
|
||||
|
||||
@staticmethod
|
||||
def __resolve_site_page_url(site_url: str, page_path: Optional[str]) -> str:
|
||||
"""将站点资源声明的相对页面路径解析为绝对地址。"""
|
||||
page_path = str(page_path or "").strip()
|
||||
if not page_path:
|
||||
return site_url
|
||||
if page_path.startswith(("http://", "https://")):
|
||||
return page_path
|
||||
return urljoin(f"{str(site_url).rstrip('/')}/", page_path.lstrip("/"))
|
||||
|
||||
def __hddolby_test(self, site: SiteSnapshot) -> Tuple[bool, str]:
|
||||
"""
|
||||
判断站点是否已经登陆:hddolby
|
||||
@@ -693,7 +683,7 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
||||
logger.warning(f"站点 {domain} 已在黑名单中,不添加站点")
|
||||
return 0, 0, 0, False
|
||||
domain_url = self._cookiecloud_indexer_domain(indexer, domain)
|
||||
login_url = self.__resolve_site_page_url(domain_url, indexer.get("login_path"))
|
||||
login_url = site_rules.resolve_page_url(domain_url, indexer.get("login_path"))
|
||||
proxy, response = self._cookiecloud_connect(login_url, cookie, indexer)
|
||||
if response is None:
|
||||
return 0, 0, 1, False
|
||||
@@ -886,16 +876,14 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
||||
state, message = special_test(site_info)
|
||||
else:
|
||||
indexer = SitesHelper().get_indexer(domain) or {}
|
||||
login_path = indexer.get("login_path")
|
||||
if login_path:
|
||||
state, message = self.__test(
|
||||
replace(
|
||||
site_info,
|
||||
url=self.__resolve_site_page_url(site_info.url, login_path),
|
||||
)
|
||||
state, message = self.__test(
|
||||
replace(
|
||||
site_info,
|
||||
url=site_rules.resolve_page_url(
|
||||
site_info.url, indexer.get("login_path")
|
||||
),
|
||||
)
|
||||
else:
|
||||
state, message = self.__test(site_info)
|
||||
)
|
||||
# 统计
|
||||
seconds = (datetime.now() - start_time).seconds
|
||||
if state:
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from typing import Optional
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from app.foundation.dom import DomUtils
|
||||
from app.foundation.url import split_netloc
|
||||
|
||||
|
||||
_SPECIAL_SITE_DOMAINS = (
|
||||
"u2.dmhy.org",
|
||||
"pt.ecust.pp.ua",
|
||||
@@ -39,6 +41,16 @@ def extract_domain(url: str) -> str:
|
||||
return ".".join(labels[-2:])
|
||||
|
||||
|
||||
def resolve_page_url(site_url: str, page_path: Optional[str]) -> str:
|
||||
"""将站点资源声明的页面路径解析为绝对地址。"""
|
||||
page_path = str(page_path or "").strip()
|
||||
if not page_path:
|
||||
return site_url
|
||||
if page_path.startswith(("http://", "https://")):
|
||||
return page_path
|
||||
return urljoin(f"{str(site_url).rstrip('/')}/", page_path.lstrip("/"))
|
||||
|
||||
|
||||
class SiteUtils:
|
||||
"""提供站点域名、Cookie 和访问参数处理能力。"""
|
||||
|
||||
|
||||
@@ -755,7 +755,7 @@ flowchart LR
|
||||
| 指标 | 当前值 |
|
||||
|---|---:|
|
||||
| Python 模块 | 985 |
|
||||
| 内部导入边 | 8,358 |
|
||||
| 内部导入边 | 8,359 |
|
||||
| 非平凡 SCC | 1(精确 containment 的 TMDB 移植包环) |
|
||||
| Application / Chain 具体 Adapter 直连 | 0 / 0 |
|
||||
| Direct egress | 53(债务已清零,53 条精确 containment) |
|
||||
|
||||
@@ -94,7 +94,7 @@ ARCH-201 至 ARCH-204 均达到实现、验证、提交、推送和远端门禁
|
||||
|
||||
| 指标 | 当前值 | 解释 |
|
||||
|---|---:|---|
|
||||
| 宿主 Python 模块 / 内部依赖边 | 985 / 8,358 | `dependency-baseline.json` 当前快照;分类、下载资源归类、订阅搜索与整理任务恢复模块的受控依赖 |
|
||||
| 宿主 Python 模块 / 内部依赖边 | 985 / 8,359 | `dependency-baseline.json` 当前快照;分类、下载资源归类、订阅搜索与整理任务恢复模块的受控依赖 |
|
||||
| 非平凡 SCC | 1 | 仅保留精确 containment 的 29 模块 TMDB 移植包环 |
|
||||
| 跨层 DB 边界债务 | 0 | Application、Chain、API、Agent、Runtime、Workflow 到 DB 的受控债务均为零 |
|
||||
| Model/Oper 事务债务 | 0 | 自建 Session、自动事务装饰器、直接 commit/rollback 等基线均为零 |
|
||||
@@ -103,7 +103,7 @@ ARCH-201 至 ARCH-204 均达到实现、验证、提交、推送和远端门禁
|
||||
| Python 源码量 | 305,884 行 | 排除 `app/plugins/**`;61 个文件超过 1,000 行,11 个超过 2,000 行 |
|
||||
| 长方法 | 290 个超过 80 行 | AST 统计排除 `app/plugins/**`;65 个超过 150 行,21 个超过 250 行 |
|
||||
| 全量 mypy 历史债务 | 9,440 / 513 文件 | Agent API 重构后的现状基线;canonical Facade 与 endpoint 类型边界已补齐,低水位只允许继续下降 |
|
||||
| Ruff 历史诊断 | 537 | 低水位门禁通过,但规则集只覆盖 `E4/E7/E9/F/I` |
|
||||
| Ruff 历史诊断 | 536 | 低水位门禁通过,但规则集只覆盖 `E4/E7/E9/F/I` |
|
||||
| 覆盖率固定基线 | Application 80.00%,Domain 80.00% | Chain、Runtime、Agent、Adapter、Startup 未进入包级覆盖率门禁 |
|
||||
|
||||
### 3.3 热点文件
|
||||
|
||||
@@ -1074,8 +1074,8 @@
|
||||
"runtime_only": true
|
||||
}
|
||||
},
|
||||
"edge_count": 8358,
|
||||
"edge_sha256": "c0785c61259ea746f28fa0e13d65fb72c3d0d438d52bc624177f0787f98f8728",
|
||||
"edge_count": 8359,
|
||||
"edge_sha256": "68e8ba94394d9c5b6e77890dde09b5f8916776c39992958460e198f854a1ee19",
|
||||
"edges": [
|
||||
"app -> app.foundation",
|
||||
"app -> app.foundation.environment",
|
||||
@@ -6617,6 +6617,7 @@
|
||||
"app.modules.indexer -> app.modules.indexer.spider.yema",
|
||||
"app.modules.indexer -> app.runtime",
|
||||
"app.modules.indexer -> app.runtime.log",
|
||||
"app.modules.indexer -> app.runtime.settings",
|
||||
"app.modules.indexer -> app.schemas",
|
||||
"app.modules.indexer -> app.schemas.media",
|
||||
"app.modules.indexer -> app.schemas.site",
|
||||
|
||||
@@ -167,9 +167,6 @@
|
||||
"app/domain/scraper.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/domain/site.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/domain/title.py": {
|
||||
"I001": 1
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user