From 23ab2f44b187f72048376bd3637395d781344276 Mon Sep 17 00:00:00 2001 From: g0ldyy <153996346+g0ldyy@users.noreply.github.com> Date: Sun, 11 Jan 2026 13:45:05 +0100 Subject: [PATCH] feat: enhance caching policies and improve manifest handling --- comet/api/endpoints/chilllink.py | 4 +- comet/api/endpoints/manifest.py | 9 +- comet/api/endpoints/stream.py | 106 +- comet/core/config_validation.py | 55 + comet/templates/admin_dashboard.html | 85 +- comet/templates/admin_login.html | 23 +- comet/templates/index.html | 1879 +++++++++++++++----------- comet/utils/cache.py | 14 + 8 files changed, 1280 insertions(+), 895 deletions(-) diff --git a/comet/api/endpoints/chilllink.py b/comet/api/endpoints/chilllink.py index bd0c852..b6b75a3 100644 --- a/comet/api/endpoints/chilllink.py +++ b/comet/api/endpoints/chilllink.py @@ -1,5 +1,3 @@ -import random -import string from typing import Optional from fastapi import APIRouter, BackgroundTasks, Query, Request @@ -28,7 +26,7 @@ async def chilllink_manifest(request: Request, b64config: str = None): config = config_check(b64config) manifest = { - "id": f"{settings.ADDON_ID}.{''.join(random.choice(string.ascii_letters) for _ in range(4))}", + "id": settings.ADDON_ID, "version": "2.0.0", "description": "Chillio's fastest debrid search add-on.", "supported_endpoints": {"feeds": None, "streams": "/streams"}, diff --git a/comet/api/endpoints/manifest.py b/comet/api/endpoints/manifest.py index 5a0e3b6..e53a8a0 100644 --- a/comet/api/endpoints/manifest.py +++ b/comet/api/endpoints/manifest.py @@ -1,6 +1,3 @@ -import random -import string - from fastapi import APIRouter, Request from comet.core.config_validation import config_check @@ -27,7 +24,7 @@ router = APIRouter() ) async def manifest(request: Request, b64config: str = None): base_manifest = { - "id": f"{settings.ADDON_ID}.{''.join(random.choice(string.ascii_letters) for _ in range(4))}", + "id": settings.ADDON_ID, "description": "Stremio's fastest torrent/debrid search add-on.", "version": "2.0.0", "catalogs": [], @@ -58,9 +55,7 @@ async def manifest(request: Request, b64config: str = None): ) if settings.HTTP_CACHE_ENABLED: - base_manifest_etag_data = base_manifest.copy() - base_manifest_etag_data.pop("id", None) - etag = generate_etag(base_manifest_etag_data) + etag = generate_etag(base_manifest) if check_etag_match(request, etag): return not_modified_response(etag) diff --git a/comet/api/endpoints/stream.py b/comet/api/endpoints/stream.py index eaef725..fd33f1f 100644 --- a/comet/api/endpoints/stream.py +++ b/comet/api/endpoints/stream.py @@ -5,7 +5,7 @@ from urllib.parse import quote import aiohttp from fastapi import APIRouter, BackgroundTasks, Request -from comet.core.config_validation import config_check +from comet.core.config_validation import config_check, is_default_config from comet.core.logger import logger from comet.core.models import database, settings, trackers from comet.debrid.exceptions import DebridAuthError @@ -31,6 +31,7 @@ def _build_stream_response( request: Request, content: dict, is_public: bool = False, + is_empty: bool = False, vary_headers: list = None, ): if not settings.HTTP_CACHE_ENABLED: @@ -41,7 +42,10 @@ def _build_stream_response( if check_etag_match(request, etag): return not_modified_response(etag) - if is_public: + if is_empty: + cache_policy = CachePolicies.empty_results() + vary = ["Accept", "Accept-Encoding"] + elif is_public: cache_policy = CachePolicies.public_torrents() vary = ["Accept", "Accept-Encoding"] else: @@ -177,12 +181,12 @@ async def stream( if media_type not in ["movie", "series"]: return _build_stream_response( - request, {"streams": []}, is_public=is_public_request + request, {"streams": []}, is_public=True, is_empty=True ) if "tmdb:" in media_id: return _build_stream_response( - request, {"streams": []}, is_public=is_public_request + request, {"streams": []}, is_public=True, is_empty=True ) media_id = media_id.replace("imdb_id:", "") @@ -198,7 +202,12 @@ async def stream( } ] } - return error_response + return _build_stream_response( + request, error_response, is_public=True, is_empty=True + ) + + if is_default_config(config): + is_public_request = True is_torrent = config["debridService"] == "torrent" if settings.DISABLE_TORRENT_STREAMS and is_torrent: @@ -238,7 +247,8 @@ async def stream( } ] }, - is_public=is_public_request, + is_public=True, + is_empty=True, ) # Check if metadata is already cached @@ -335,15 +345,20 @@ async def stream( if lock_acquired and scrape_lock: await scrape_lock.release() logger.log("SCRAPER", f"❌ Failed to fetch metadata for {media_id}") - return { - "streams": [ - { - "name": "[⚠️] Comet", - "description": "Unable to get metadata.", - "url": "https://comet.feels.legal", - } - ] - } + return _build_stream_response( + request, + { + "streams": [ + { + "name": "[⚠️] Comet", + "description": "Unable to get metadata.", + "url": "https://comet.feels.legal", + } + ] + }, + is_public=True, + is_empty=True, + ) title = metadata["title"] year = metadata["year"] @@ -449,15 +464,20 @@ async def stream( ) if len(torrent_manager.torrents) == 0: - return { - "streams": [ - { - "name": "[🔄] Comet", - "description": "Scraping in progress by another instance, please try again in a few seconds...", - "url": "https://comet.feels.legal", - } - ] - } + return _build_stream_response( + request, + { + "streams": [ + { + "name": "[🔄] Comet", + "description": "Scraping in progress by another instance, please try again in a few seconds...", + "url": "https://comet.feels.legal", + } + ] + }, + is_public=True, + is_empty=True, + ) elif is_first or cache_is_stale: # Background scrape if first search OR if cache is stale (needs refresh) @@ -527,15 +547,20 @@ async def stream( episode, ) except DebridAuthError as e: - return { - "streams": [ - { - "name": "[❌] Comet", - "description": e.display_message, - "url": "https://comet.feels.legal", - } - ] - } + return _build_stream_response( + request, + { + "streams": [ + { + "name": "[❌] Comet", + "description": e.display_message, + "url": "https://comet.feels.legal", + } + ] + }, + is_public=False, + is_empty=True, + ) if debrid_service != "torrent": cached_count = sum( @@ -641,14 +666,15 @@ async def stream( non_cached_results.append(the_stream) if sort_mixed: - return _build_stream_response( - request, - {"streams": cached_results}, - is_public=is_public_request, - ) + final_streams = cached_results + else: + final_streams = cached_results + non_cached_results + + has_results = len(final_streams) > 0 return _build_stream_response( request, - {"streams": cached_results + non_cached_results}, - is_public=is_public_request, + {"streams": final_streams}, + is_public=is_public_request or not has_results, + is_empty=not has_results, ) diff --git a/comet/core/config_validation.py b/comet/core/config_validation.py index dce9ca3..e2032a7 100644 --- a/comet/core/config_validation.py +++ b/comet/core/config_validation.py @@ -59,3 +59,58 @@ def config_check(b64config: str): return validated_config except Exception: return default_config # if it doesn't pass, return default config + + +def is_default_config(config: dict) -> bool: + if config is None: + return True + + ignored_fields = { + "debridApiKey", + "debridStreamProxyPassword", + "rtnSettings", + "rtnRanking", + "debridService", + } + + if config.get("debridService") != "torrent": + return False + + for field, default_value in default_config.items(): + if field in ignored_fields: + continue + + config_value = config.get(field) + + if field == "resolutions": + if isinstance(config_value, dict): + for res, enabled in config_value.items(): + if enabled is False: + return False + continue + + if field == "languages": + config_lang = config_value or {} + default_lang = default_value or {} + if config_lang.get("exclude", []) != default_lang.get("exclude", []): + return False + if config_lang.get("preferred", []) != default_lang.get("preferred", []): + return False + continue + + if field == "options": + config_opts = config_value or {} + default_opts = default_value or {} + for key in [ + "remove_ranks_under", + "allow_english_in_languages", + "remove_unknown_languages", + ]: + if config_opts.get(key) != default_opts.get(key): + return False + continue + + if config_value != default_value: + return False + + return True diff --git a/comet/templates/admin_dashboard.html b/comet/templates/admin_dashboard.html index 6868eae..3299924 100644 --- a/comet/templates/admin_dashboard.html +++ b/comet/templates/admin_dashboard.html @@ -1,4 +1,4 @@ - +
@@ -44,9 +44,19 @@ #25292c 0%, #0c0d13 100% ); - font-family: system-ui, -apple-system, "Segoe UI", Roboto, - "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, - "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + font-family: + system-ui, + -apple-system, + "Segoe UI", + Roboto, + "Helvetica Neue", + "Noto Sans", + "Liberation Sans", + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1rem; font-weight: 400; @@ -308,7 +318,8 @@ border-radius: 50%; filter: drop-shadow(0 0 6px currentColor); transform: translate3d(104em, 0, 0); - animation: fall var(--fall-duration) var(--fall-delay) linear infinite, + animation: + fall var(--fall-duration) var(--fall-delay) linear infinite, tail-fade var(--tail-fade-duration) var(--fall-delay) ease-out infinite; } @@ -780,7 +791,7 @@ star.style.setProperty("--top-offset", `${randomTopOffset}vh`); star.style.setProperty( "--star-tail-length", - `${randomTailLength}em` + `${randomTailLength}em`, ); star.style.setProperty("--fall-duration", `${randomFallDuration}s`); star.style.setProperty("--fall-delay", "0s"); @@ -956,9 +967,21 @@
-
- Comet
-
- Comet is a passion project fueled by late nights and coffee. Your support helps keep the lights on and the - updates rolling! -
++ Comet is a passion project fueled by late nights and coffee. Your + support helps keep the lights on and the updates rolling! +
+ +