diff --git a/app/api/endpoints/download.py b/app/api/endpoints/download.py index ca1ed633..e3daf6ea 100644 --- a/app/api/endpoints/download.py +++ b/app/api/endpoints/download.py @@ -5,15 +5,13 @@ from fastapi import APIRouter, Depends, Body from app import schemas from app.chain.download import DownloadChain from app.chain.media import MediaChain -from app.core.config import settings from app.core.context import MediaInfo, Context, TorrentInfo -from app.core.event import eventmanager from app.core.metainfo import MetaInfo from app.core.security import verify_token from app.db.models.user import User from app.db.systemconfig_oper import SystemConfigOper from app.db.user_oper import get_current_active_user -from app.schemas.types import ChainEventType, SystemConfigKey +from app.schemas.types import SystemConfigKey router = APIRouter() diff --git a/app/api/endpoints/user.py b/app/api/endpoints/user.py index 56d756fc..39b3b7a2 100644 --- a/app/api/endpoints/user.py +++ b/app/api/endpoints/user.py @@ -12,7 +12,6 @@ from app.db.models.user import User from app.db.user_oper import get_current_active_superuser_async, \ get_current_active_user_async, get_current_active_user from app.db.userconfig_oper import UserConfigOper -from app.utils.otp import OtpUtils router = APIRouter() diff --git a/app/chain/media.py b/app/chain/media.py index 469e3493..293ecb4e 100644 --- a/app/chain/media.py +++ b/app/chain/media.py @@ -253,7 +253,6 @@ class MediaChain(ChainBase, ConfigReloadMixin, metaclass=Singleton): """ 流式下载图片并保存到文件 - :param storagechain: StorageChain实例 :param fileitem: 关联的媒体文件项 :param path: 图片文件路径 :param url: 图片下载URL diff --git a/app/helper/passkey.py b/app/helper/passkey.py index cbac5d27..e72db869 100644 --- a/app/helper/passkey.py +++ b/app/helper/passkey.py @@ -22,7 +22,6 @@ from webauthn.helpers.structs import ( PublicKeyCredentialDescriptor, AuthenticatorTransport, UserVerificationRequirement, - AuthenticatorAttachment, ResidentKeyRequirement, AuthenticatorSelectionCriteria ) diff --git a/app/modules/emby/emby.py b/app/modules/emby/emby.py index c7310dcb..cbde1671 100644 --- a/app/modules/emby/emby.py +++ b/app/modules/emby/emby.py @@ -714,7 +714,7 @@ class Emby: logger.error(f"连接Users/Items出错:" + str(e)) return None - def get_webhook_message(self, form: any, args: dict) -> Optional[schemas.WebhookEventInfo]: + def get_webhook_message(self, form: Any, args: dict) -> Optional[schemas.WebhookEventInfo]: """ 解析Emby Webhook报文 电影: diff --git a/app/modules/indexer/parser/bitpt.py b/app/modules/indexer/parser/bitpt.py index b5d0102c..601f17ee 100644 --- a/app/modules/indexer/parser/bitpt.py +++ b/app/modules/indexer/parser/bitpt.py @@ -111,7 +111,7 @@ class BitptSiteUserInfo(SiteParserBase): def _parse_message_content(self, html_text) -> Tuple[Optional[str], Optional[str], Optional[str]]: pass - def _parse_user_torrent_seeding_info(self, html_text: str): + def _parse_user_torrent_seeding_info(self, html_text: str, **kwargs): pass def parse(self): diff --git a/app/modules/indexer/parser/zhixing.py b/app/modules/indexer/parser/zhixing.py index d92a85cc..ce610bf1 100644 --- a/app/modules/indexer/parser/zhixing.py +++ b/app/modules/indexer/parser/zhixing.py @@ -117,7 +117,7 @@ class ZhixingSiteUserInfo(SiteParserBase): def _parse_message_content(self, html_text) -> Tuple[Optional[str], Optional[str], Optional[str]]: pass - def _parse_user_torrent_seeding_info(self, html_text: str): + def _parse_user_torrent_seeding_info(self, html_text: str, multi_page: bool = False): """ 占位,避免抽象类报错 """ diff --git a/app/modules/jellyfin/jellyfin.py b/app/modules/jellyfin/jellyfin.py index a0982427..ca8db3ab 100644 --- a/app/modules/jellyfin/jellyfin.py +++ b/app/modules/jellyfin/jellyfin.py @@ -569,7 +569,7 @@ class Jellyfin: logger.error(f"连接Library/Refresh出错:" + str(e)) return False - def get_webhook_message(self, body: any) -> Optional[schemas.WebhookEventInfo]: + def get_webhook_message(self, body: Any) -> Optional[schemas.WebhookEventInfo]: """ 解析Jellyfin报文 { diff --git a/app/modules/plex/plex.py b/app/modules/plex/plex.py index 7ac7d60a..11a870cc 100644 --- a/app/modules/plex/plex.py +++ b/app/modules/plex/plex.py @@ -549,7 +549,7 @@ class Plex: logger.error(f"获取媒体库列表出错:{str(err)}") return None - def get_webhook_message(self, form: any) -> Optional[schemas.WebhookEventInfo]: + def get_webhook_message(self, form: Any) -> Optional[schemas.WebhookEventInfo]: """ 解析Plex报文 eventItem 字段的含义 diff --git a/app/modules/trimemedia/trimemedia.py b/app/modules/trimemedia/trimemedia.py index b5d6f074..1249958f 100644 --- a/app/modules/trimemedia/trimemedia.py +++ b/app/modules/trimemedia/trimemedia.py @@ -409,7 +409,7 @@ class TrimeMedia: return lib return None - def get_webhook_message(self, body: any) -> Optional[schemas.WebhookEventInfo]: + def get_webhook_message(self, body: Any) -> Optional[schemas.WebhookEventInfo]: pass def get_iteminfo(self, itemid: str) -> Optional[schemas.MediaServerItem]: diff --git a/app/utils/mixins.py b/app/utils/mixins.py index 117a05a1..cd838899 100644 --- a/app/utils/mixins.py +++ b/app/utils/mixins.py @@ -17,34 +17,44 @@ class ConfigReloadMixin: def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) - config_watch = getattr(cls, 'CONFIG_WATCH', None) + config_watch = getattr(cls, "CONFIG_WATCH", None) if not config_watch: return # 检查 on_config_changed 方法是否为异步 is_async = inspect.iscoroutinefunction(cls.on_config_changed) - method_name = 'handle_config_changed' + method_name = "handle_config_changed" # 创建事件处理函数 def create_handler(is_async): if is_async: + async def wrapper(self: ConfigReloadMixin, event: Event): if not event: return - changed_keys = getattr(event.event_data, "key", set()) & config_watch + changed_keys = ( + getattr(event.event_data, "key", set()) & config_watch + ) if not changed_keys: return - logger.info(f"配置 {', '.join(changed_keys)} 变更,重载 {self.get_reload_name()}...") - await self.on_config_changed() + logger.info( + f"配置 {', '.join(changed_keys)} 变更,重载 {self.get_reload_name()}..." + ) + self.on_config_changed() else: + def wrapper(self: ConfigReloadMixin, event: Event): if not event: return - changed_keys = getattr(event.event_data, "key", set()) & config_watch + changed_keys = ( + getattr(event.event_data, "key", set()) & config_watch + ) if not changed_keys: return - logger.info(f"配置 {', '.join(changed_keys)} 变更,重载 {self.get_reload_name()}...") + logger.info( + f"配置 {', '.join(changed_keys)} 变更,重载 {self.get_reload_name()}..." + ) self.on_config_changed() return wrapper @@ -52,7 +62,7 @@ class ConfigReloadMixin: # 创建并设置处理函数 handler = create_handler(is_async) handler.__module__ = cls.__module__ - handler.__qualname__ = f'{cls.__name__}.{method_name}' + handler.__qualname__ = f"{cls.__name__}.{method_name}" setattr(cls, method_name, handler) # 添加为事件处理器 eventmanager.add_event_listener(EventType.ConfigChanged, handler) diff --git a/app/utils/otp.py b/app/utils/otp.py index 60121659..6e57832f 100644 --- a/app/utils/otp.py +++ b/app/utils/otp.py @@ -1,9 +1,11 @@ +from typing import Tuple + import pyotp class OtpUtils: @staticmethod - def generate_secret_key(username: str) -> (str, str): + def generate_secret_key(username: str) -> Tuple[str, str]: try: secret = pyotp.random_base32() uri = pyotp.totp.TOTP(secret).provisioning_uri(name='MoviePilot', diff --git a/docker/Dockerfile b/docker/Dockerfile index 393a5080..92da6d68 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.8-slim-bookworm AS base +FROM python:3.12.13-slim-bookworm AS base # 准备软件包 @@ -68,7 +68,7 @@ WORKDIR /app COPY requirements.in requirements.in RUN python3 -m venv ${VENV_PATH} \ && pip install --upgrade "pip<25.0" \ - && pip install "Cython" "pip-tools<7.5" \ + && pip install "Cython~=3.1.2" "pip-tools<7.5" \ && pip-compile requirements.in \ && pip install -r requirements.txt diff --git a/requirements.in b/requirements.in index c8c6baa2..b8e99d32 100644 --- a/requirements.in +++ b/requirements.in @@ -10,6 +10,7 @@ python-multipart~=0.0.9 aiofiles~=24.1.0 aioshutil~=1.5 alembic~=1.16.2 +anyio~=4.10.0 bcrypt~=4.0.1 regex~=2024.11.6 cn2an~=0.5.19 @@ -22,6 +23,7 @@ urllib3~=2.5.0 lxml~=6.0.0 pyquery~=2.0.1 ruamel.yaml~=0.18.14 +PyYAML~=6.0.2 APScheduler~=3.11.0 cryptography~=45.0.4 pytz~=2025.2 @@ -31,10 +33,8 @@ plexapi~=4.17.0 transmission-rpc~=4.3.0 Jinja2~=3.1.6 pyparsing~=3.2.3 -func_timeout==4.3.5 -bs4~=0.0.2 beautifulsoup4~=4.13.4 -pillow~=11.2.1 +pillow~=12.1.1 pillow-avif-plugin~=1.5.2 pyTelegramBotAPI~=4.27.0 telegramify-markdown~=0.5.2 @@ -49,24 +49,18 @@ starlette~=0.46.2 PyVirtualDisplay~=3.0 psutil~=7.0.0 python-dotenv~=1.1.1 -python-hosts~=1.1.2 watchdog~=6.0.0 watchfiles~=1.1.0 -cacheout~=0.16.0 click~=8.2.1 -requests-cache~=1.2.1 parse~=1.20.2 docker~=7.1.0 pywin32==310; platform_system == "Windows" cachetools~=6.1.0 -fast-bencode~=1.1.7 pystray~=0.19.5 pyotp~=2.9.0 webauthn~=2.7.0 Pinyin2Hanzi~=0.1.1 pywebpush~=2.0.3 -aiopathlib~=0.6.0 -asynctempfile~=0.5.0 aiosqlite~=0.21.0 psycopg2-binary~=2.9.10 asyncpg~=0.30.0 @@ -88,8 +82,8 @@ langchain-community~=0.4.1 langchain-openai~=1.1.11 langchain-google-genai~=4.2.1 langchain-deepseek~=1.0.1 -langchain-experimental~=0.4.1 langgraph~=1.1.3 openai~=2.29.0 +google-genai~=1.68.0 ddgs~=9.10.0 websocket-client~=1.8.0