stream-fusion-better/stream_fusion/services/postgresql/models/debridcache_model.py
LimeDrive 0c1d305784 feat(debrid): add PostgreSQL L2 cache for persistent debrid availability
Add a two-level caching architecture for debrid service availability lookups:
- L1: Redis (existing) with 10-day TTL for fast in-memory access
- L2: PostgreSQL with 30-day TTL for persistent caching across Redis restarts

Changes:
- Add `debrid_cache` table with unique constraint on (info_hash, service) and indexes for efficient queries
- Create `DebridCacheDAO` with batch get/upsert and invalidation methods
- Add pgCron job to periodically clean up expired cache entries
- Extend `get_availability_bulk_cached` to check PG on Redis miss, warm Redis from PG hits, and write confirmed-cached results to PG
- Add `invalidate_availability_cache` method to remove false positives from both caches when NO_CACHE_VIDEO_URL is returned during playback
- Integrate `db_session` dependency into playback and search views
- Add retry handling to Yggflix API (3 retries, ignore Retry-After headers) and rate-limiting delay (0.3s) between consecutive queries
2026-03-26 15:47:37 +01:00

28 lines
1.2 KiB
Python

from typing import Optional
from sqlalchemy import BigInteger, String, UniqueConstraint
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column
from stream_fusion.services.postgresql.base import Base
class DebridCacheModel(Base):
"""Persistent cache of debrid availability results, shared across all users.
Only confirmed-cached hashes are stored (no negative / not-cached entries).
All data stored here has been sanitised: no private tokens, no announce URLs.
"""
__tablename__ = "debrid_cache"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
info_hash: Mapped[str] = mapped_column(String(40), nullable=False)
service: Mapped[str] = mapped_column(String(20), nullable=False) # e.g. 'realdebrid', 'alldebrid'
cached_data: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True) # sanitised file metadata
checked_at: Mapped[int] = mapped_column(BigInteger, nullable=False) # Unix timestamp
expires_at: Mapped[int] = mapped_column(BigInteger, nullable=False) # Unix timestamp
__table_args__ = (
UniqueConstraint("info_hash", "service", name="uq_debrid_cache_hash_service"),
)