cleanup
This commit is contained in:
@@ -24,6 +24,7 @@ from .provider_config import (
|
||||
DEFAULT_PROVIDERS,
|
||||
INVALID_PATH_CHARS,
|
||||
LULUVDO_USER_AGENT,
|
||||
ProviderType,
|
||||
)
|
||||
|
||||
# Configure persistent loggers but don't add duplicate handlers when module
|
||||
@@ -54,7 +55,7 @@ if not noKeyFound_logger.handlers:
|
||||
|
||||
|
||||
class AniworldLoader(Loader):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self.SUPPORTED_PROVIDERS = DEFAULT_PROVIDERS
|
||||
# Copy default AniWorld headers so modifications remain local
|
||||
self.AniworldHeaders = dict(ANIWORLD_HEADERS)
|
||||
@@ -62,10 +63,10 @@ class AniworldLoader(Loader):
|
||||
self.RANDOM_USER_AGENT = UserAgent().random
|
||||
self.LULUVDO_USER_AGENT = LULUVDO_USER_AGENT
|
||||
self.PROVIDER_HEADERS = {
|
||||
"Vidmoly": ['Referer: "https://vidmoly.to"'],
|
||||
"Doodstream": ['Referer: "https://dood.li/"'],
|
||||
"VOE": [f"User-Agent: {self.RANDOM_USER_AGENT}"],
|
||||
"Luluvdo": [
|
||||
ProviderType.VIDMOLY.value: ['Referer: "https://vidmoly.to"'],
|
||||
ProviderType.DOODSTREAM.value: ['Referer: "https://dood.li/"'],
|
||||
ProviderType.VOE.value: [f"User-Agent: {self.RANDOM_USER_AGENT}"],
|
||||
ProviderType.LULUVDO.value: [
|
||||
f"User-Agent: {self.LULUVDO_USER_AGENT}",
|
||||
"Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
'Origin: "https://luluvdo.com"',
|
||||
|
||||
@@ -39,6 +39,7 @@ from .provider_config import (
|
||||
DEFAULT_PROVIDERS,
|
||||
INVALID_PATH_CHARS,
|
||||
LULUVDO_USER_AGENT,
|
||||
ProviderType,
|
||||
)
|
||||
|
||||
|
||||
@@ -48,7 +49,7 @@ class EnhancedAniWorldLoader(Loader):
|
||||
Also exposes metrics hooks for download statistics.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.SUPPORTED_PROVIDERS = DEFAULT_PROVIDERS
|
||||
@@ -59,10 +60,10 @@ class EnhancedAniWorldLoader(Loader):
|
||||
self.LULUVDO_USER_AGENT = LULUVDO_USER_AGENT
|
||||
|
||||
self.PROVIDER_HEADERS = {
|
||||
"Vidmoly": ['Referer: "https://vidmoly.to"'],
|
||||
"Doodstream": ['Referer: "https://dood.li/"'],
|
||||
"VOE": [f'User-Agent: {self.RANDOM_USER_AGENT}'],
|
||||
"Luluvdo": [
|
||||
ProviderType.VIDMOLY.value: ['Referer: "https://vidmoly.to"'],
|
||||
ProviderType.DOODSTREAM.value: ['Referer: "https://dood.li/"'],
|
||||
ProviderType.VOE.value: [f'User-Agent: {self.RANDOM_USER_AGENT}'],
|
||||
ProviderType.LULUVDO.value: [
|
||||
f'User-Agent: {self.LULUVDO_USER_AGENT}',
|
||||
"Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
'Origin: "https://luluvdo.com"',
|
||||
|
||||
@@ -3,16 +3,29 @@
|
||||
Centralizes user-agent strings, provider lists and common headers so
|
||||
multiple provider implementations can import a single source of truth.
|
||||
"""
|
||||
from enum import Enum
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
class ProviderType(str, Enum):
|
||||
"""Enumeration of supported video providers."""
|
||||
VOE = "VOE"
|
||||
DOODSTREAM = "Doodstream"
|
||||
VIDMOLY = "Vidmoly"
|
||||
VIDOZA = "Vidoza"
|
||||
SPEEDFILES = "SpeedFiles"
|
||||
STREAMTAPE = "Streamtape"
|
||||
LULUVDO = "Luluvdo"
|
||||
|
||||
|
||||
DEFAULT_PROVIDERS: List[str] = [
|
||||
"VOE",
|
||||
"Doodstream",
|
||||
"Vidmoly",
|
||||
"Vidoza",
|
||||
"SpeedFiles",
|
||||
"Streamtape",
|
||||
"Luluvdo",
|
||||
ProviderType.VOE.value,
|
||||
ProviderType.DOODSTREAM.value,
|
||||
ProviderType.VIDMOLY.value,
|
||||
ProviderType.VIDOZA.value,
|
||||
ProviderType.SPEEDFILES.value,
|
||||
ProviderType.STREAMTAPE.value,
|
||||
ProviderType.LULUVDO.value,
|
||||
]
|
||||
|
||||
ANIWORLD_HEADERS: Dict[str, str] = {
|
||||
|
||||
@@ -91,13 +91,19 @@ def get_series_app() -> Optional[SeriesApp]:
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
async def startup_event() -> None:
|
||||
"""Initialize application on startup."""
|
||||
try:
|
||||
# Initialize SeriesApp with configured directory and store it on
|
||||
# application state so it can be injected via dependencies.
|
||||
if settings.anime_directory:
|
||||
app.state.series_app = SeriesApp(settings.anime_directory)
|
||||
else:
|
||||
# Log warning when anime directory is not configured
|
||||
print(
|
||||
"WARNING: ANIME_DIRECTORY not configured. "
|
||||
"Some features may be unavailable."
|
||||
)
|
||||
|
||||
# Initialize progress service with websocket callback
|
||||
progress_service = get_progress_service()
|
||||
@@ -105,7 +111,7 @@ async def startup_event():
|
||||
|
||||
async def broadcast_callback(
|
||||
message_type: str, data: dict, room: str
|
||||
):
|
||||
) -> None:
|
||||
"""Broadcast progress updates via WebSocket."""
|
||||
message = {
|
||||
"type": message_type,
|
||||
@@ -118,6 +124,7 @@ async def startup_event():
|
||||
print("FastAPI application started successfully")
|
||||
except Exception as e:
|
||||
print(f"Error during startup: {e}")
|
||||
raise # Re-raise to prevent app from starting in broken state
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
|
||||
@@ -46,7 +46,11 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self, app: ASGIApp, *, rate_limit_per_minute: int = 5
|
||||
self,
|
||||
app: ASGIApp,
|
||||
*,
|
||||
rate_limit_per_minute: int = 5,
|
||||
window_seconds: int = 60
|
||||
) -> None:
|
||||
super().__init__(app)
|
||||
# in-memory rate limiter: ip -> {count, window_start}
|
||||
@@ -54,15 +58,16 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
||||
# origin-based rate limiter for CORS: origin -> {count, window_start}
|
||||
self._origin_rate: Dict[str, Dict[str, float]] = {}
|
||||
self.rate_limit_per_minute = rate_limit_per_minute
|
||||
self.window_seconds = 60
|
||||
self.window_seconds = window_seconds
|
||||
# Track last cleanup time to prevent memory leaks
|
||||
self._last_cleanup = time.time()
|
||||
self._cleanup_interval = 300 # Clean every 5 minutes
|
||||
|
||||
def _cleanup_old_entries(self) -> None:
|
||||
"""Remove rate limit entries older than cleanup interval.
|
||||
|
||||
This prevents memory leaks from accumulating old IP addresses and origins.
|
||||
|
||||
This prevents memory leaks from accumulating old IP addresses
|
||||
and origins.
|
||||
"""
|
||||
now = time.time()
|
||||
if now - self._last_cleanup < self._cleanup_interval:
|
||||
|
||||
@@ -64,6 +64,15 @@ class AuthService:
|
||||
return pwd_context.hash(password)
|
||||
|
||||
def _verify_password(self, plain: str, hashed: str) -> bool:
|
||||
"""Verify a password against a hash.
|
||||
|
||||
Args:
|
||||
plain: Plain text password
|
||||
hashed: Hashed password
|
||||
|
||||
Returns:
|
||||
bool: True if password matches, False otherwise
|
||||
"""
|
||||
try:
|
||||
return pwd_context.verify(plain, hashed)
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user