mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
fix: clean typing issues and refresh runtime dependencies
Align endpoint/module type hints and config reload handling while updating base Python image and package pins to improve build/runtime compatibility. Made-with: Cursor
This commit is contained in:
@@ -5,15 +5,13 @@ from fastapi import APIRouter, Depends, Body
|
|||||||
from app import schemas
|
from app import schemas
|
||||||
from app.chain.download import DownloadChain
|
from app.chain.download import DownloadChain
|
||||||
from app.chain.media import MediaChain
|
from app.chain.media import MediaChain
|
||||||
from app.core.config import settings
|
|
||||||
from app.core.context import MediaInfo, Context, TorrentInfo
|
from app.core.context import MediaInfo, Context, TorrentInfo
|
||||||
from app.core.event import eventmanager
|
|
||||||
from app.core.metainfo import MetaInfo
|
from app.core.metainfo import MetaInfo
|
||||||
from app.core.security import verify_token
|
from app.core.security import verify_token
|
||||||
from app.db.models.user import User
|
from app.db.models.user import User
|
||||||
from app.db.systemconfig_oper import SystemConfigOper
|
from app.db.systemconfig_oper import SystemConfigOper
|
||||||
from app.db.user_oper import get_current_active_user
|
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()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ from app.db.models.user import User
|
|||||||
from app.db.user_oper import get_current_active_superuser_async, \
|
from app.db.user_oper import get_current_active_superuser_async, \
|
||||||
get_current_active_user_async, get_current_active_user
|
get_current_active_user_async, get_current_active_user
|
||||||
from app.db.userconfig_oper import UserConfigOper
|
from app.db.userconfig_oper import UserConfigOper
|
||||||
from app.utils.otp import OtpUtils
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,6 @@ class MediaChain(ChainBase, ConfigReloadMixin, metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
流式下载图片并保存到文件
|
流式下载图片并保存到文件
|
||||||
|
|
||||||
:param storagechain: StorageChain实例
|
|
||||||
:param fileitem: 关联的媒体文件项
|
:param fileitem: 关联的媒体文件项
|
||||||
:param path: 图片文件路径
|
:param path: 图片文件路径
|
||||||
:param url: 图片下载URL
|
:param url: 图片下载URL
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ from webauthn.helpers.structs import (
|
|||||||
PublicKeyCredentialDescriptor,
|
PublicKeyCredentialDescriptor,
|
||||||
AuthenticatorTransport,
|
AuthenticatorTransport,
|
||||||
UserVerificationRequirement,
|
UserVerificationRequirement,
|
||||||
AuthenticatorAttachment,
|
|
||||||
ResidentKeyRequirement,
|
ResidentKeyRequirement,
|
||||||
AuthenticatorSelectionCriteria
|
AuthenticatorSelectionCriteria
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -714,7 +714,7 @@ class Emby:
|
|||||||
logger.error(f"连接Users/Items出错:" + str(e))
|
logger.error(f"连接Users/Items出错:" + str(e))
|
||||||
return None
|
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报文
|
解析Emby Webhook报文
|
||||||
电影:
|
电影:
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class BitptSiteUserInfo(SiteParserBase):
|
|||||||
def _parse_message_content(self, html_text) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
def _parse_message_content(self, html_text) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _parse_user_torrent_seeding_info(self, html_text: str):
|
def _parse_user_torrent_seeding_info(self, html_text: str, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ class ZhixingSiteUserInfo(SiteParserBase):
|
|||||||
def _parse_message_content(self, html_text) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
def _parse_message_content(self, html_text) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||||
pass
|
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):
|
||||||
"""
|
"""
|
||||||
占位,避免抽象类报错
|
占位,避免抽象类报错
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ class Jellyfin:
|
|||||||
logger.error(f"连接Library/Refresh出错:" + str(e))
|
logger.error(f"连接Library/Refresh出错:" + str(e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_webhook_message(self, body: any) -> Optional[schemas.WebhookEventInfo]:
|
def get_webhook_message(self, body: Any) -> Optional[schemas.WebhookEventInfo]:
|
||||||
"""
|
"""
|
||||||
解析Jellyfin报文
|
解析Jellyfin报文
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -549,7 +549,7 @@ class Plex:
|
|||||||
logger.error(f"获取媒体库列表出错:{str(err)}")
|
logger.error(f"获取媒体库列表出错:{str(err)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_webhook_message(self, form: any) -> Optional[schemas.WebhookEventInfo]:
|
def get_webhook_message(self, form: Any) -> Optional[schemas.WebhookEventInfo]:
|
||||||
"""
|
"""
|
||||||
解析Plex报文
|
解析Plex报文
|
||||||
eventItem 字段的含义
|
eventItem 字段的含义
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ class TrimeMedia:
|
|||||||
return lib
|
return lib
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_webhook_message(self, body: any) -> Optional[schemas.WebhookEventInfo]:
|
def get_webhook_message(self, body: Any) -> Optional[schemas.WebhookEventInfo]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_iteminfo(self, itemid: str) -> Optional[schemas.MediaServerItem]:
|
def get_iteminfo(self, itemid: str) -> Optional[schemas.MediaServerItem]:
|
||||||
|
|||||||
+18
-8
@@ -17,34 +17,44 @@ class ConfigReloadMixin:
|
|||||||
def __init_subclass__(cls, **kwargs):
|
def __init_subclass__(cls, **kwargs):
|
||||||
super().__init_subclass__(**kwargs)
|
super().__init_subclass__(**kwargs)
|
||||||
|
|
||||||
config_watch = getattr(cls, 'CONFIG_WATCH', None)
|
config_watch = getattr(cls, "CONFIG_WATCH", None)
|
||||||
if not config_watch:
|
if not config_watch:
|
||||||
return
|
return
|
||||||
|
|
||||||
# 检查 on_config_changed 方法是否为异步
|
# 检查 on_config_changed 方法是否为异步
|
||||||
is_async = inspect.iscoroutinefunction(cls.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):
|
def create_handler(is_async):
|
||||||
if is_async:
|
if is_async:
|
||||||
|
|
||||||
async def wrapper(self: ConfigReloadMixin, event: Event):
|
async def wrapper(self: ConfigReloadMixin, event: Event):
|
||||||
if not event:
|
if not event:
|
||||||
return
|
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:
|
if not changed_keys:
|
||||||
return
|
return
|
||||||
logger.info(f"配置 {', '.join(changed_keys)} 变更,重载 {self.get_reload_name()}...")
|
logger.info(
|
||||||
await self.on_config_changed()
|
f"配置 {', '.join(changed_keys)} 变更,重载 {self.get_reload_name()}..."
|
||||||
|
)
|
||||||
|
self.on_config_changed()
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def wrapper(self: ConfigReloadMixin, event: Event):
|
def wrapper(self: ConfigReloadMixin, event: Event):
|
||||||
if not event:
|
if not event:
|
||||||
return
|
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:
|
if not changed_keys:
|
||||||
return
|
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()
|
self.on_config_changed()
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
@@ -52,7 +62,7 @@ class ConfigReloadMixin:
|
|||||||
# 创建并设置处理函数
|
# 创建并设置处理函数
|
||||||
handler = create_handler(is_async)
|
handler = create_handler(is_async)
|
||||||
handler.__module__ = cls.__module__
|
handler.__module__ = cls.__module__
|
||||||
handler.__qualname__ = f'{cls.__name__}.{method_name}'
|
handler.__qualname__ = f"{cls.__name__}.{method_name}"
|
||||||
setattr(cls, method_name, handler)
|
setattr(cls, method_name, handler)
|
||||||
# 添加为事件处理器
|
# 添加为事件处理器
|
||||||
eventmanager.add_event_listener(EventType.ConfigChanged, handler)
|
eventmanager.add_event_listener(EventType.ConfigChanged, handler)
|
||||||
|
|||||||
+3
-1
@@ -1,9 +1,11 @@
|
|||||||
|
from typing import Tuple
|
||||||
|
|
||||||
import pyotp
|
import pyotp
|
||||||
|
|
||||||
|
|
||||||
class OtpUtils:
|
class OtpUtils:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_secret_key(username: str) -> (str, str):
|
def generate_secret_key(username: str) -> Tuple[str, str]:
|
||||||
try:
|
try:
|
||||||
secret = pyotp.random_base32()
|
secret = pyotp.random_base32()
|
||||||
uri = pyotp.totp.TOTP(secret).provisioning_uri(name='MoviePilot',
|
uri = pyotp.totp.TOTP(secret).provisioning_uri(name='MoviePilot',
|
||||||
|
|||||||
+2
-2
@@ -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
|
COPY requirements.in requirements.in
|
||||||
RUN python3 -m venv ${VENV_PATH} \
|
RUN python3 -m venv ${VENV_PATH} \
|
||||||
&& pip install --upgrade "pip<25.0" \
|
&& 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-compile requirements.in \
|
||||||
&& pip install -r requirements.txt
|
&& pip install -r requirements.txt
|
||||||
|
|
||||||
|
|||||||
+4
-10
@@ -10,6 +10,7 @@ python-multipart~=0.0.9
|
|||||||
aiofiles~=24.1.0
|
aiofiles~=24.1.0
|
||||||
aioshutil~=1.5
|
aioshutil~=1.5
|
||||||
alembic~=1.16.2
|
alembic~=1.16.2
|
||||||
|
anyio~=4.10.0
|
||||||
bcrypt~=4.0.1
|
bcrypt~=4.0.1
|
||||||
regex~=2024.11.6
|
regex~=2024.11.6
|
||||||
cn2an~=0.5.19
|
cn2an~=0.5.19
|
||||||
@@ -22,6 +23,7 @@ urllib3~=2.5.0
|
|||||||
lxml~=6.0.0
|
lxml~=6.0.0
|
||||||
pyquery~=2.0.1
|
pyquery~=2.0.1
|
||||||
ruamel.yaml~=0.18.14
|
ruamel.yaml~=0.18.14
|
||||||
|
PyYAML~=6.0.2
|
||||||
APScheduler~=3.11.0
|
APScheduler~=3.11.0
|
||||||
cryptography~=45.0.4
|
cryptography~=45.0.4
|
||||||
pytz~=2025.2
|
pytz~=2025.2
|
||||||
@@ -31,10 +33,8 @@ plexapi~=4.17.0
|
|||||||
transmission-rpc~=4.3.0
|
transmission-rpc~=4.3.0
|
||||||
Jinja2~=3.1.6
|
Jinja2~=3.1.6
|
||||||
pyparsing~=3.2.3
|
pyparsing~=3.2.3
|
||||||
func_timeout==4.3.5
|
|
||||||
bs4~=0.0.2
|
|
||||||
beautifulsoup4~=4.13.4
|
beautifulsoup4~=4.13.4
|
||||||
pillow~=11.2.1
|
pillow~=12.1.1
|
||||||
pillow-avif-plugin~=1.5.2
|
pillow-avif-plugin~=1.5.2
|
||||||
pyTelegramBotAPI~=4.27.0
|
pyTelegramBotAPI~=4.27.0
|
||||||
telegramify-markdown~=0.5.2
|
telegramify-markdown~=0.5.2
|
||||||
@@ -49,24 +49,18 @@ starlette~=0.46.2
|
|||||||
PyVirtualDisplay~=3.0
|
PyVirtualDisplay~=3.0
|
||||||
psutil~=7.0.0
|
psutil~=7.0.0
|
||||||
python-dotenv~=1.1.1
|
python-dotenv~=1.1.1
|
||||||
python-hosts~=1.1.2
|
|
||||||
watchdog~=6.0.0
|
watchdog~=6.0.0
|
||||||
watchfiles~=1.1.0
|
watchfiles~=1.1.0
|
||||||
cacheout~=0.16.0
|
|
||||||
click~=8.2.1
|
click~=8.2.1
|
||||||
requests-cache~=1.2.1
|
|
||||||
parse~=1.20.2
|
parse~=1.20.2
|
||||||
docker~=7.1.0
|
docker~=7.1.0
|
||||||
pywin32==310; platform_system == "Windows"
|
pywin32==310; platform_system == "Windows"
|
||||||
cachetools~=6.1.0
|
cachetools~=6.1.0
|
||||||
fast-bencode~=1.1.7
|
|
||||||
pystray~=0.19.5
|
pystray~=0.19.5
|
||||||
pyotp~=2.9.0
|
pyotp~=2.9.0
|
||||||
webauthn~=2.7.0
|
webauthn~=2.7.0
|
||||||
Pinyin2Hanzi~=0.1.1
|
Pinyin2Hanzi~=0.1.1
|
||||||
pywebpush~=2.0.3
|
pywebpush~=2.0.3
|
||||||
aiopathlib~=0.6.0
|
|
||||||
asynctempfile~=0.5.0
|
|
||||||
aiosqlite~=0.21.0
|
aiosqlite~=0.21.0
|
||||||
psycopg2-binary~=2.9.10
|
psycopg2-binary~=2.9.10
|
||||||
asyncpg~=0.30.0
|
asyncpg~=0.30.0
|
||||||
@@ -88,8 +82,8 @@ langchain-community~=0.4.1
|
|||||||
langchain-openai~=1.1.11
|
langchain-openai~=1.1.11
|
||||||
langchain-google-genai~=4.2.1
|
langchain-google-genai~=4.2.1
|
||||||
langchain-deepseek~=1.0.1
|
langchain-deepseek~=1.0.1
|
||||||
langchain-experimental~=0.4.1
|
|
||||||
langgraph~=1.1.3
|
langgraph~=1.1.3
|
||||||
openai~=2.29.0
|
openai~=2.29.0
|
||||||
|
google-genai~=1.68.0
|
||||||
ddgs~=9.10.0
|
ddgs~=9.10.0
|
||||||
websocket-client~=1.8.0
|
websocket-client~=1.8.0
|
||||||
|
|||||||
Reference in New Issue
Block a user