# ============================================================ # File: db/state_redis.py (UPDATED for book_idx-only architecture) # Purpose: # Low-level Redis counters/state for BookScraper. # Used ONLY by db.repository façade. # ============================================================ import os import time import redis from logbus.publisher import log REDIS_URL = os.getenv("REDIS_BROKER", "redis://redis:6379/0") r = redis.Redis.from_url(REDIS_URL, decode_responses=True) # ------------------------------------------------------------ # INTERNAL KEY BUILDER # ------------------------------------------------------------ def _key(book_idx: str) -> str: return f"book:{book_idx}:state" # ------------------------------------------------------------ # STATUS # ------------------------------------------------------------ def redis_set_status(book_idx: str, status: str): key = _key(book_idx) r.hset(key, "status", status) r.hset(key, "last_update", int(time.time())) # ------------------------------------------------------------ # TOTAL CHAPTERS # ------------------------------------------------------------ def redis_set_chapters_total(book_idx: str, total: int): key = _key(book_idx) r.hset(key, "chapters_total", total) r.hset(key, "last_update", int(time.time())) # ------------------------------------------------------------ # DOWNLOAD COUNTERS # ------------------------------------------------------------ def redis_inc_download_done(book_idx: str, amount: int = 1): key = _key(book_idx) r.hincrby(key, "chapters_download_done", amount) r.hset(key, "last_update", int(time.time())) def redis_inc_download_skipped(book_idx: str, amount: int = 1): log(f"[DB-REDIS] Incrementing download skipped for {book_idx} by {amount}") key = _key(book_idx) r.hincrby(key, "chapters_download_skipped", amount) r.hset(key, "last_update", int(time.time())) # ------------------------------------------------------------ # PARSE COUNTERS # ------------------------------------------------------------ def redis_inc_parsed_done(book_idx: str, amount: int = 1): key = _key(book_idx) r.hincrby(key, "chapters_parsed_done", amount) r.hset(key, "last_update", int(time.time())) # ------------------------------------------------------------ # AUDIO COUNTERS # ------------------------------------------------------------ def redis_inc_audio_done(book_idx: str, amount: int = 1): log(f"[DB-REDIS] Incrementing audio done for {book_idx} by {amount}") key = _key(book_idx) r.hincrby(key, "audio_done", amount) r.hset(key, "last_update", int(time.time())) def redis_inc_audio_skipped(book_idx: str, amount: int = 1): log(f"[DB-REDIS] Incrementing audio skipped for {book_idx} by {amount}") """ New: Count skipped audio chapters (timeouts, pre-existing files, abort, etc.) SQL does NOT track this; Redis-only metric. """ key = _key(book_idx) r.hincrby(key, "audio_skipped", amount) r.hset(key, "last_update", int(time.time())) # ------------------------------------------------------------ # INITIALISE BOOK STATE # ------------------------------------------------------------ def init_book_state(book_id: str, title: str, url: str, chapters_total: int): """ Initialiseert de complete Redis state voor een nieuw boek. LET OP: - Als een key al bestaat → NIET resetten (progress behouden). - Alleen missende velden worden toegevoegd. """ key = f"book:{book_id}:state" # Bestaat al? Dan vullen we alleen missende velden aan. exists = r.exists(key) pipeline = r.pipeline() # Basis metadata pipeline.hsetnx(key, "book_id", book_id) pipeline.hsetnx(key, "title", title or "") pipeline.hsetnx(key, "url", url or "") # State pipeline.hsetnx(key, "status", "registered") # Counters pipeline.hsetnx(key, "chapters_total", chapters_total) pipeline.hsetnx(key, "chapters_download_done", 0) pipeline.hsetnx(key, "chapters_download_skipped", 0) pipeline.hsetnx(key, "chapters_parsed_done", 0) pipeline.hsetnx(key, "audio_done", 0) pipeline.hsetnx(key, "audio_skipped", 0) # Timestamp pipeline.hset(key, "last_update", int(time.time())) pipeline.execute() if exists: log(f"[DB-REDIS] init_book_state(): UPDATED existing state for {book_id}") else: log(f"[DB-REDIS] init_book_state(): CREATED new state for {book_id}")