mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 16:36:53 +08:00
refactor: 收口 V3 分层架构与插件兼容边界
This commit is contained in:
+80
-93
@@ -1,8 +1,6 @@
|
||||
from typing import List, Any, Dict, Optional
|
||||
|
||||
from fastapi import Depends, HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.background import BackgroundTasks
|
||||
|
||||
from app.schemas.common import JsonObject as _SchemaJsonObject
|
||||
@@ -19,32 +17,28 @@ from app.schemas.token import TokenPayload as _SchemaTokenPayload
|
||||
from app.schemas.workflow import Site as _SchemaSite
|
||||
from app.api.response import ResponseAPIRouter
|
||||
from app.application.site.mutation import SiteMutationCommand
|
||||
from app.application.site.query import SiteQueryService
|
||||
from app.api.endpoints.plugin import register_plugin_api
|
||||
from app.chain.site import SiteChain
|
||||
from app.chain.torrents import TorrentsChain
|
||||
from app.command import Command
|
||||
from app.runtime.events import eventmanager
|
||||
from app.runtime.extensions.plugin_manager import PluginManager
|
||||
from app.application.security.access import verify_token
|
||||
from app.db import get_db, get_async_db
|
||||
from app.db.models import User
|
||||
from app.db.models.site import Site
|
||||
from app.db.models.siteicon import SiteIcon
|
||||
from app.db.models.sitestatistic import SiteStatistic
|
||||
from app.db.models.siteuserdata import SiteUserData
|
||||
from app.db.oper.site import SiteOper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.plugin.runtime import get_plugin_manager as PluginManager
|
||||
from app.adapters.web.security.access import verify_token
|
||||
from app.api.principal import ApiPrincipal
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.api.deps import (
|
||||
get_current_active_manage_user,
|
||||
get_current_active_manage_user_async,
|
||||
get_current_active_superuser,
|
||||
get_current_active_superuser_async,
|
||||
get_site_mutation_command,
|
||||
get_site_query_service,
|
||||
get_site_sync_query_service,
|
||||
)
|
||||
from app.application.site.sites import SitesHelper # pylint: disable=no-name-in-module
|
||||
from app.runtime.log import logger
|
||||
from app.scheduler import Scheduler
|
||||
from app.schemas.types import SystemConfigKey, EventType, MediaType
|
||||
from app.application.scheduling import Scheduler
|
||||
from app.schemas.types import SystemConfigKey, MediaType
|
||||
from app.domain import site as site_rules
|
||||
|
||||
router = ResponseAPIRouter()
|
||||
@@ -88,13 +82,13 @@ def _indexer_supports_media_type(indexer: dict, media_type: MediaType) -> bool:
|
||||
|
||||
@router.get("/", summary="所有站点", response_model=List[_SchemaSite])
|
||||
async def read_sites(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> List[dict]:
|
||||
"""
|
||||
获取站点列表
|
||||
"""
|
||||
return await Site.async_list_order_by_pri(db)
|
||||
return await query.list_ordered()
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -104,14 +98,14 @@ async def read_sites(
|
||||
)
|
||||
async def read_sites_by_media_type(
|
||||
media_type: str,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
) -> List[Site]:
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> List[_SchemaSite]:
|
||||
"""
|
||||
获取支持指定媒体类型的已配置启用站点。
|
||||
|
||||
:param media_type: Agent 媒体类型名称或中文媒体类型
|
||||
:param db: 异步数据库会话
|
||||
:param query: 站点查询服务
|
||||
:return: 按优先级排序的可搜索站点
|
||||
"""
|
||||
target_media_type = MediaType.from_agent(media_type)
|
||||
@@ -134,7 +128,7 @@ async def read_sites_by_media_type(
|
||||
if domain:
|
||||
supported_domains.add(domain)
|
||||
|
||||
sites = await Site.async_list_order_by_pri(db)
|
||||
sites = await query.list_ordered()
|
||||
return [
|
||||
site
|
||||
for site in sites
|
||||
@@ -148,7 +142,7 @@ async def add_site(
|
||||
*,
|
||||
site_in: _SchemaSite,
|
||||
command: SiteMutationCommand = Depends(get_site_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
新增站点
|
||||
@@ -162,7 +156,7 @@ async def update_site(
|
||||
*,
|
||||
site_in: _SchemaSite,
|
||||
command: SiteMutationCommand = Depends(get_site_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
更新站点信息
|
||||
@@ -174,7 +168,7 @@ async def update_site(
|
||||
@router.get("/cookiecloud", summary="CookieCloud同步", response_model=_SchemaResponse[None])
|
||||
async def cookie_cloud_sync(
|
||||
background_tasks: BackgroundTasks,
|
||||
_: User = Depends(get_current_active_superuser_async),
|
||||
_: ApiPrincipal = Depends(get_current_active_superuser_async),
|
||||
) -> Any:
|
||||
"""
|
||||
运行CookieCloud同步站点信息
|
||||
@@ -184,20 +178,20 @@ async def cookie_cloud_sync(
|
||||
|
||||
|
||||
@router.get("/reset", summary="重置站点", response_model=_SchemaResponse[None])
|
||||
def reset(
|
||||
db: AsyncSession = Depends(get_db), _: User = Depends(get_current_active_superuser)
|
||||
async def reset(
|
||||
command: SiteMutationCommand = Depends(get_site_mutation_command),
|
||||
_: ApiPrincipal = Depends(get_current_active_superuser_async),
|
||||
) -> Any:
|
||||
"""
|
||||
清空所有站点数据并重新同步CookieCloud站点信息
|
||||
"""
|
||||
Site.reset(db)
|
||||
SystemConfigOper().set(SystemConfigKey.IndexerSites, [])
|
||||
SystemConfigOper().set(SystemConfigKey.RssSites, [])
|
||||
result = await command.reset()
|
||||
get_configured_system_config().set(SystemConfigKey.IndexerSites, [])
|
||||
get_configured_system_config().set(SystemConfigKey.RssSites, [])
|
||||
# 启动定时服务
|
||||
Scheduler().start("cookiecloud", manual=True)
|
||||
# 插件站点删除
|
||||
eventmanager.send_event(EventType.SiteDeleted, {"site_id": "*"})
|
||||
return _SchemaResponse(success=True, message="站点已重置!")
|
||||
return _SchemaResponse(success=result.success, message="站点已重置!")
|
||||
|
||||
|
||||
@router.post(
|
||||
@@ -206,7 +200,7 @@ def reset(
|
||||
async def update_sites_priority(
|
||||
priorities: List[dict],
|
||||
command: SiteMutationCommand = Depends(get_site_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
批量更新站点优先级
|
||||
@@ -220,7 +214,7 @@ def _update_site_cookie(
|
||||
username: str,
|
||||
password: str,
|
||||
code: Optional[str],
|
||||
db: Session,
|
||||
query: SiteQueryService,
|
||||
) -> _SchemaResponse:
|
||||
"""
|
||||
执行站点 Cookie 与 UA 更新。
|
||||
@@ -229,10 +223,10 @@ def _update_site_cookie(
|
||||
:param username: 站点登录用户名
|
||||
:param password: 站点登录密码
|
||||
:param code: 二步验证码或密钥
|
||||
:param db: 数据库会话
|
||||
:param query: 站点查询服务
|
||||
:return: 更新结果
|
||||
"""
|
||||
site_info = Site.get(db, site_id)
|
||||
site_info = query.get_sync(site_id)
|
||||
if not site_info:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
@@ -255,8 +249,8 @@ def _update_site_cookie(
|
||||
def update_cookie_by_body(
|
||||
site_id: int,
|
||||
site_cookie_update: _SchemaSiteCookieUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(get_current_active_manage_user),
|
||||
query: SiteQueryService = Depends(get_site_sync_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user),
|
||||
) -> Any:
|
||||
"""
|
||||
使用请求体中的用户密码更新站点Cookie
|
||||
@@ -266,7 +260,7 @@ def update_cookie_by_body(
|
||||
username=site_cookie_update.username,
|
||||
password=site_cookie_update.password,
|
||||
code=site_cookie_update.code,
|
||||
db=db,
|
||||
query=query,
|
||||
)
|
||||
|
||||
|
||||
@@ -278,8 +272,8 @@ def update_cookie(
|
||||
username: str,
|
||||
password: str,
|
||||
code: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(get_current_active_manage_user),
|
||||
query: SiteQueryService = Depends(get_site_sync_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user),
|
||||
) -> Any:
|
||||
"""
|
||||
使用用户密码更新站点Cookie
|
||||
@@ -289,7 +283,7 @@ def update_cookie(
|
||||
username=username,
|
||||
password=password,
|
||||
code=code,
|
||||
db=db,
|
||||
query=query,
|
||||
)
|
||||
|
||||
|
||||
@@ -300,13 +294,13 @@ def update_cookie(
|
||||
)
|
||||
def refresh_userdata(
|
||||
site_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(get_current_active_manage_user),
|
||||
query: SiteQueryService = Depends(get_site_sync_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user),
|
||||
) -> Any:
|
||||
"""
|
||||
刷新站点用户数据
|
||||
"""
|
||||
site = Site.get(db, site_id)
|
||||
site = query.get_sync(site_id)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
@@ -327,16 +321,13 @@ def refresh_userdata(
|
||||
response_model=List[_SchemaSiteUserData],
|
||||
)
|
||||
async def read_userdata_latest(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
查询所有站点最新用户数据
|
||||
"""
|
||||
user_datas = await SiteUserData.async_get_latest(db)
|
||||
if not user_datas:
|
||||
return []
|
||||
return [user_data.to_dict() for user_data in user_datas]
|
||||
return await query.userdata_latest()
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -347,36 +338,34 @@ async def read_userdata_latest(
|
||||
async def read_userdata(
|
||||
site_id: int,
|
||||
workdate: Optional[str] = None,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
查询站点用户数据
|
||||
"""
|
||||
site = await Site.async_get(db, site_id)
|
||||
site = await query.get(site_id)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"站点 {site_id} 不存在",
|
||||
)
|
||||
user_datas = await SiteUserData.async_get_by_domain(
|
||||
db, domain=site.domain, workdate=workdate
|
||||
)
|
||||
user_datas = await query.userdata(site.domain, workdate)
|
||||
if not user_datas:
|
||||
return _SchemaResponse(success=False, data=[])
|
||||
return _SchemaResponse(success=True, data=[data.to_dict() for data in user_datas])
|
||||
return _SchemaResponse(success=True, data=user_datas)
|
||||
|
||||
|
||||
@router.get("/test/{site_id}", summary="连接测试", response_model=_SchemaResponse[None])
|
||||
def test_site(
|
||||
site_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
query: SiteQueryService = Depends(get_site_sync_query_service),
|
||||
_: _SchemaTokenPayload = Depends(verify_token),
|
||||
) -> Any:
|
||||
"""
|
||||
测试站点是否可用
|
||||
"""
|
||||
site = Site.get(db, site_id)
|
||||
site = query.get_sync(site_id)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
@@ -393,24 +382,22 @@ def test_site(
|
||||
)
|
||||
async def site_icon(
|
||||
site_id: int,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: _SchemaTokenPayload = Depends(verify_token),
|
||||
) -> Any:
|
||||
"""
|
||||
获取站点图标:base64或者url
|
||||
"""
|
||||
site = await Site.async_get(db, site_id)
|
||||
site = await query.get(site_id)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"站点 {site_id} 不存在",
|
||||
)
|
||||
icon = await SiteIcon.async_get_by_domain(db, site.domain)
|
||||
icon = await query.icon(site.domain)
|
||||
if not icon:
|
||||
return _SchemaResponse(success=False, message="站点图标不存在!")
|
||||
return _SchemaResponse(
|
||||
success=True, data={"icon": icon.base64 if icon.base64 else icon.url}
|
||||
)
|
||||
return _SchemaResponse(success=True, data=icon.model_dump())
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -418,13 +405,13 @@ async def site_icon(
|
||||
)
|
||||
async def site_category(
|
||||
site_id: int,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: _SchemaTokenPayload = Depends(verify_token),
|
||||
) -> Any:
|
||||
"""
|
||||
获取站点分类
|
||||
"""
|
||||
site = await Site.async_get(db, site_id)
|
||||
site = await query.get(site_id)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
@@ -456,13 +443,13 @@ async def site_resource(
|
||||
mtype: Optional[str] = None,
|
||||
cat: Optional[str] = None,
|
||||
page: Optional[int] = 0,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
浏览站点资源
|
||||
"""
|
||||
site = await Site.async_get(db, site_id)
|
||||
site = await query.get(site_id)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
@@ -483,14 +470,14 @@ async def site_resource(
|
||||
@router.get("/domain/{site_url}", summary="站点详情", response_model=_SchemaSite)
|
||||
async def read_site_by_domain(
|
||||
site_url: str,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: _SchemaTokenPayload = Depends(verify_token),
|
||||
) -> Any:
|
||||
"""
|
||||
通过域名获取站点信息
|
||||
"""
|
||||
domain = site_rules.extract_domain(site_url)
|
||||
site = await Site.async_get_by_domain(db, domain)
|
||||
site = await query.get_by_domain(domain)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
@@ -506,45 +493,42 @@ async def read_site_by_domain(
|
||||
)
|
||||
async def read_statistic_by_domain(
|
||||
site_url: str,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: _SchemaTokenPayload = Depends(verify_token),
|
||||
) -> Any:
|
||||
"""
|
||||
通过域名获取站点统计信息
|
||||
"""
|
||||
domain = site_rules.extract_domain(site_url)
|
||||
sitestatistic = await SiteStatistic.async_get_by_domain(db, domain)
|
||||
if sitestatistic:
|
||||
return sitestatistic
|
||||
return _SchemaSiteStatistic(domain=domain)
|
||||
return await query.statistic(domain)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/statistic", summary="所有站点统计信息", response_model=List[_SchemaSiteStatistic]
|
||||
)
|
||||
async def read_statistics(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: _SchemaTokenPayload = Depends(verify_token),
|
||||
) -> Any:
|
||||
"""
|
||||
获取所有站点统计信息
|
||||
"""
|
||||
return await SiteStatistic.async_list(db)
|
||||
return await query.statistics()
|
||||
|
||||
|
||||
@router.get("/rss", summary="所有订阅站点", response_model=List[_SchemaSite])
|
||||
async def read_rss_sites(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: _SchemaTokenPayload = Depends(verify_token),
|
||||
) -> List[dict]:
|
||||
"""
|
||||
获取站点列表
|
||||
"""
|
||||
# 选中的rss站点
|
||||
selected_sites = SystemConfigOper().get(SystemConfigKey.RssSites) or []
|
||||
selected_sites = get_configured_system_config().get(SystemConfigKey.RssSites) or []
|
||||
|
||||
# 所有站点
|
||||
all_site = await Site.async_list_order_by_pri(db)
|
||||
all_site = await query.list_ordered()
|
||||
if not selected_sites:
|
||||
return all_site
|
||||
|
||||
@@ -563,7 +547,7 @@ async def read_auth_sites(_: _SchemaTokenPayload = Depends(verify_token)) -> dic
|
||||
|
||||
@router.post("/auth", summary="用户站点认证", response_model=_SchemaResponse[None])
|
||||
def auth_site(
|
||||
auth_info: _SchemaSiteAuth, _: User = Depends(get_current_active_superuser)
|
||||
auth_info: _SchemaSiteAuth, _: ApiPrincipal = Depends(get_current_active_superuser)
|
||||
) -> Any:
|
||||
"""
|
||||
用户站点认证
|
||||
@@ -571,7 +555,7 @@ def auth_site(
|
||||
if not auth_info or not auth_info.site or not auth_info.params:
|
||||
return _SchemaResponse(success=False, message="请输入认证站点和认证参数")
|
||||
status, msg = SitesHelper().check_user(auth_info.site, auth_info.params)
|
||||
SystemConfigOper().set(SystemConfigKey.UserSiteAuthParams, auth_info.model_dump())
|
||||
get_configured_system_config().set(SystemConfigKey.UserSiteAuthParams, auth_info.model_dump())
|
||||
# 认证成功后,重新初始化插件
|
||||
PluginManager().init_config()
|
||||
Scheduler().init_plugin_jobs()
|
||||
@@ -585,12 +569,15 @@ def auth_site(
|
||||
summary="获取站点域名到名称的映射",
|
||||
response_model=_SchemaResponse[_SchemaSiteMappingData],
|
||||
)
|
||||
async def site_mapping(_: User = Depends(get_current_active_superuser_async)):
|
||||
async def site_mapping(
|
||||
query: SiteQueryService = Depends(get_site_sync_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_superuser_async),
|
||||
):
|
||||
"""
|
||||
获取站点域名到名称的映射关系
|
||||
"""
|
||||
try:
|
||||
sites = await SiteOper().async_list()
|
||||
sites = query.list_sync()
|
||||
mapping = {}
|
||||
for site in sites:
|
||||
mapping[site.domain] = site.name
|
||||
@@ -604,7 +591,7 @@ async def site_mapping(_: User = Depends(get_current_active_superuser_async)):
|
||||
summary="获取支持的站点列表",
|
||||
response_model=_SchemaJsonObject,
|
||||
)
|
||||
async def support_sites(_: User = Depends(get_current_active_superuser_async)):
|
||||
async def support_sites(_: ApiPrincipal = Depends(get_current_active_superuser_async)):
|
||||
"""
|
||||
获取支持的站点列表
|
||||
"""
|
||||
@@ -614,13 +601,13 @@ async def support_sites(_: User = Depends(get_current_active_superuser_async)):
|
||||
@router.get("/{site_id}", summary="站点详情", response_model=_SchemaSite)
|
||||
async def read_site(
|
||||
site_id: int,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
query: SiteQueryService = Depends(get_site_query_service),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
通过ID获取站点信息
|
||||
"""
|
||||
site = await Site.async_get(db, site_id)
|
||||
site = await query.get(site_id)
|
||||
if not site:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
@@ -633,7 +620,7 @@ async def read_site(
|
||||
async def delete_site(
|
||||
site_id: int,
|
||||
command: SiteMutationCommand = Depends(get_site_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
_: ApiPrincipal = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
删除站点
|
||||
|
||||
Reference in New Issue
Block a user