diff --git a/api/main.py b/api/main.py index 157266d..230f3f6 100644 --- a/api/main.py +++ b/api/main.py @@ -58,32 +58,31 @@ async def lifespan(fastapi_app: FastAPI): # Startup logic await database.init() await torrent.init_best_trackers() + scheduler = None + scheduler_lock = None if not settings.disable_all_scheduler: - acquired, lock = await acquire_scheduler_lock() + acquired, scheduler_lock = await acquire_scheduler_lock() if acquired: try: scheduler = AsyncIOScheduler() setup_scheduler(scheduler) scheduler.start() - fastapi_app.state.scheduler = scheduler - fastapi_app.state.scheduler_lock = lock await asyncio.create_task(maintain_heartbeat()) except Exception as e: - await release_scheduler_lock(lock) + await release_scheduler_lock(scheduler_lock) raise e yield # Shutdown logic - if hasattr(fastapi_app.state, "scheduler"): - fastapi_app.state.scheduler.shutdown(wait=False) - - if ( - hasattr(fastapi_app.state, "scheduler_lock") - and fastapi_app.state.scheduler_lock - ): - await release_scheduler_lock(fastapi_app.state.scheduler_lock) + if scheduler: + try: + scheduler.shutdown(wait=False) + except Exception as e: + logging.exception("Error shutting down scheduler") + finally: + await release_scheduler_lock(scheduler_lock) await REDIS_ASYNC_CLIENT.aclose() diff --git a/api/middleware.py b/api/middleware.py index f5d5da8..6acb75b 100644 --- a/api/middleware.py +++ b/api/middleware.py @@ -42,12 +42,13 @@ class SecureLoggingMiddleware(BaseHTTPMiddleware): async def custom_log(request: Request, response: Response): ip = get_client_ip(request) url_path = str(request.url) + process_time = response.headers.get("X-Process-Time", "") if request.path_params.get("secret_str"): url_path = url_path.replace( - request.path_params.get("secret_str"), "***MASKED***" + request.path_params.get("secret_str"), "*MASKED*" ) logging.info( - f'{ip} - "{request.method} {url_path} HTTP/1.1" {response.status_code}' + f'{ip} - "{request.method} {url_path} HTTP/1.1" {response.status_code} {process_time}' ) diff --git a/db/crud.py b/db/crud.py index d2129ac..7747d0a 100644 --- a/db/crud.py +++ b/db/crud.py @@ -30,6 +30,7 @@ from db.schemas import Stream, TorrentStreamsList from scrapers.utils import run_scrapers from scrapers.imdb_data import get_imdb_movie_data, search_imdb from utils import crypto +from utils.lock import acquire_redis_lock, release_redis_lock from utils.parser import ( fetch_downloaded_info_hashes, parse_stream_data, @@ -319,6 +320,13 @@ async def get_movie_streams( return [] cache_key = f"torrent_streams:{video_id}" + lock_key = f"{cache_key}_lock" if video_id.startswith("tt") else None + redis_lock = None + + # Acquire the lock to prevent multiple scrapers from running at the same time + if lock_key: + _, redis_lock = await acquire_redis_lock(lock_key, timeout=60, block=True) + cached_streams = await get_cached_torrent_streams(cache_key, video_id) if video_id.startswith("tt"): @@ -331,7 +339,9 @@ async def get_movie_streams( if new_streams: # reset the cache await REDIS_ASYNC_CLIENT.delete(cache_key) - background_tasks.add_task(store_new_torrent_streams, new_streams) + background_tasks.add_task( + store_new_torrent_streams, new_streams, redis_lock=redis_lock + ) else: all_streams = cached_streams @@ -354,6 +364,13 @@ async def get_series_streams( return [] cache_key = f"torrent_streams:{video_id}:{season}:{episode}" + lock_key = f"{cache_key}_lock" if video_id.startswith("tt") else None + redis_lock = None + + # Acquire the lock to prevent multiple scrapers from running at the same time + if lock_key: + _, redis_lock = await acquire_redis_lock(lock_key, timeout=60, block=True) + cached_streams = await get_cached_torrent_streams( cache_key, video_id, season, episode ) @@ -370,7 +387,9 @@ async def get_series_streams( if new_streams: # reset the cache await REDIS_ASYNC_CLIENT.delete(cache_key) - background_tasks.add_task(store_new_torrent_streams, new_streams) + background_tasks.add_task( + store_new_torrent_streams, new_streams, redis_lock + ) else: all_streams = cached_streams @@ -386,7 +405,7 @@ async def get_series_streams( async def store_new_torrent_streams( - streams: list[TorrentStreams] | set[TorrentStreams], + streams: list[TorrentStreams] | set[TorrentStreams], redis_lock=None ): if not streams: return @@ -439,6 +458,8 @@ async def store_new_torrent_streams( ) await bulk_writer.commit() + if redis_lock: + await release_redis_lock(redis_lock) async def get_tv_streams(video_id: str, namespace: str, user_data) -> list[Stream]: diff --git a/db/schemas.py b/db/schemas.py index 4117b07..bbbc1d9 100644 --- a/db/schemas.py +++ b/db/schemas.py @@ -144,6 +144,7 @@ class StreamingProvider(BaseModel): enable_watchlist_catalogs: bool = Field(default=True, alias="ewc") qbittorrent_config: QBittorrentConfig | None = Field(default=None, alias="qbc") download_via_browser: bool = Field(default=False, alias="dvb") + only_show_cached_streams: bool = Field(default=False, alias="oscs") @model_validator(mode="after") def validate_token_or_username_password(self) -> "StreamingProvider": @@ -167,7 +168,13 @@ class StreamingProvider(BaseModel): class UserData(BaseModel): streaming_provider: StreamingProvider | None = Field(default=None, alias="sp") selected_catalogs: list[str] = Field( - default=["prowlarr_streams", "torrentio_streams", "zilean_dmm_streams"], + default=[ + "prowlarr_streams", + "torrentio_streams", + "zilean_dmm_streams", + "english_hdrip", + "english_series", + ], alias="sc", ) selected_resolutions: list[str | None] = Field( @@ -176,7 +183,7 @@ class UserData(BaseModel): enable_catalogs: bool = Field(default=True, alias="ec") enable_imdb_metadata: bool = Field(default=True, alias="eim") max_size: int | str | float = Field(default=math.inf, alias="ms") - max_streams_per_resolution: int = Field(default=3, alias="mspr") + max_streams_per_resolution: int = Field(default=10, alias="mspr") show_full_torrent_name: bool = Field(default=True, alias="sftn") torrent_sorting_priority: list[str] = Field( default=const.TORRENT_SORTING_PRIORITY, alias="tsp" diff --git a/resources/html/configure.html b/resources/html/configure.html index 64627ee..2dbe9a1 100644 --- a/resources/html/configure.html +++ b/resources/html/configure.html @@ -227,6 +227,13 @@ {% endif %} +