refactor(project): make pyright & ruff happy

This commit is contained in:
MingxuanGame
2025-08-22 08:21:52 +00:00
parent 3b1d7a2234
commit 598fcc8b38
157 changed files with 2382 additions and 4590 deletions

View File

@@ -1,7 +1,12 @@
from __future__ import annotations
import asyncio
from collections.abc import Awaitable, Callable, Sequence
from datetime import datetime
import functools
import inspect
from io import BytesIO
from typing import Any, ParamSpec, TypeVar
from fastapi import HTTPException
from PIL import Image
@@ -151,75 +156,117 @@ def check_image(content: bytes, size: int, width: int, height: int) -> None:
def simplify_user_agent(user_agent: str | None, max_length: int = 200) -> str | None:
"""
简化 User-Agent 字符串,只保留 osu! 和关键设备系统信息浏览器
Args:
user_agent: 原始 User-Agent 字符串
max_length: 最大长度限制
Returns:
简化后的 User-Agent 字符串,或 None
"""
import re
if not user_agent:
return None
# 如果长度在限制内,直接返回
if len(user_agent) <= max_length:
return user_agent
# 提取操作系统信息
os_info = ""
os_patterns = [
r'(Windows[^;)]*)',
r'(Mac OS[^;)]*)',
r'(Linux[^;)]*)',
r'(Android[^;)]*)',
r'(iOS[^;)]*)',
r'(iPhone[^;)]*)',
r'(iPad[^;)]*)'
r"(Windows[^;)]*)",
r"(Mac OS[^;)]*)",
r"(Linux[^;)]*)",
r"(Android[^;)]*)",
r"(iOS[^;)]*)",
r"(iPhone[^;)]*)",
r"(iPad[^;)]*)",
]
for pattern in os_patterns:
match = re.search(pattern, user_agent, re.IGNORECASE)
if match:
os_info = match.group(1).strip()
break
# 提取浏览器信息
browser_info = ""
browser_patterns = [
r'(osu![^)]*)', # osu! 客户端
r'(Chrome/[\d.]+)',
r'(Firefox/[\d.]+)',
r'(Safari/[\d.]+)',
r'(Edge/[\d.]+)',
r'(Opera/[\d.]+)'
r"(osu![^)]*)", # osu! 客户端
r"(Chrome/[\d.]+)",
r"(Firefox/[\d.]+)",
r"(Safari/[\d.]+)",
r"(Edge/[\d.]+)",
r"(Opera/[\d.]+)",
]
for pattern in browser_patterns:
match = re.search(pattern, user_agent, re.IGNORECASE)
if match:
browser_info = match.group(1).strip()
# 如果找到了 osu! 客户端,优先使用
if 'osu!' in browser_info.lower():
if "osu!" in browser_info.lower():
break
# 构建简化的 User-Agent
parts = []
if os_info:
parts.append(os_info)
if browser_info:
parts.append(browser_info)
if parts:
simplified = '; '.join(parts)
simplified = "; ".join(parts)
else:
# 如果没有识别到关键信息,截断原始字符串
simplified = user_agent[:max_length-3] + "..."
simplified = user_agent[: max_length - 3] + "..."
# 确保不超过最大长度
if len(simplified) > max_length:
simplified = simplified[:max_length-3] + "..."
simplified = simplified[: max_length - 3] + "..."
return simplified
# https://github.com/encode/starlette/blob/master/starlette/_utils.py
T = TypeVar("T")
AwaitableCallable = Callable[..., Awaitable[T]]
def is_async_callable(obj: Any) -> bool:
while isinstance(obj, functools.partial):
obj = obj.func
return inspect.iscoroutinefunction(obj)
P = ParamSpec("P")
async def run_in_threadpool(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
func = functools.partial(func, *args, **kwargs)
return await asyncio.get_event_loop().run_in_executor(None, func)
class BackgroundTasks:
def __init__(self, tasks: Sequence[asyncio.Task] | None = None):
self.tasks = set(tasks) if tasks else set()
def add_task(self, func: Callable[P, Any], *args: P.args, **kwargs: P.kwargs) -> None:
if is_async_callable(func):
coro = func(*args, **kwargs)
else:
coro = run_in_threadpool(func, *args, **kwargs)
task = asyncio.create_task(coro)
self.tasks.add(task)
task.add_done_callback(self.tasks.discard)
def stop(self) -> None:
for task in self.tasks:
task.cancel()
self.tasks.clear()
bg_tasks = BackgroundTasks()