You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmftools/bookscraper/scraper/abort.py

125 lines
3.2 KiB

import os
import redis
from scraper.logger_decorators import logcall
# GUI log (non-breaking)
from scraper.ui_log import push_ui
# ---------------------------------------------------------
# Default Redis connection (Docker workers)
# ---------------------------------------------------------
REDIS_URL = os.getenv("REDIS_URL", "redis://redis:6379/0")
r = redis.Redis.from_url(REDIS_URL, decode_responses=True)
# Debug mode (optional)
ABORT_DEBUG = os.getenv("ABORT_DEBUG", "1") == "1"
# Internal flag to avoid spamming the same message
_seen_debug_keys = set()
# =========================================================
# ABORT FLAG
# =========================================================
def _debug(msg: str):
"""Print + GUI log (non-breaking, minimal noise)."""
print(msg)
push_ui(msg)
def set_abort(book_id: str):
"""Enable abort mode for this book."""
key = f"abort:{book_id}"
r.set(key, "1")
if ABORT_DEBUG:
_debug(f"[ABORT] SET {key}")
def clear_abort(book_id: str):
"""Clear abort flag."""
key = f"abort:{book_id}"
r.delete(key)
if ABORT_DEBUG:
_debug(f"[ABORT] CLEAR {key}")
def abort_requested(book_id: str, redis_client=None) -> bool:
"""
Return True if abort flag is set.
redis_client:
- Docker workers → None → use default Redis (r)
- Local macOS audio → passes Redis(host=127.0.0.1)
"""
client = redis_client or r
key = f"abort:{book_id}"
try:
exists = client.exists(key)
if ABORT_DEBUG:
# Log once per key
if key not in _seen_debug_keys:
try:
conn = client.connection_pool.connection_kwargs
host = conn.get("host")
port = conn.get("port")
db = conn.get("db")
_debug(
f"[ABORT_DEBUG] first check book_id={book_id} "
f"redis={host}:{port} db={db}"
)
except Exception:
_debug(f"[ABORT_DEBUG] first check book_id={book_id}")
_seen_debug_keys.add(key)
# Only log abort ACTIVE
if exists == 1:
_debug(f"[ABORT] ACTIVE for {book_id}")
return exists == 1
except Exception as e:
if ABORT_DEBUG:
_debug(f"[ABORT_DEBUG] ERROR checking {key}: {e}")
return False
# =========================================================
# PER-CHAPTER STATE
# =========================================================
def mark_chapter_started(book_id: str, chapter_num: int):
key = f"started:{book_id}:{chapter_num}"
r.set(key, "1")
def chapter_started(book_id: str, chapter_num: int) -> bool:
key = f"started:{book_id}:{chapter_num}"
return r.exists(key) == 1
# =========================================================
# UTILITY: RESET FOR A BOOK
# =========================================================
def reset_book_state(book_id: str):
"""
Remove abort flag and all chapter-start markers.
"""
key = f"abort:{book_id}"
r.delete(key)
pattern = f"started:{book_id}:*"
for k in r.scan_iter(pattern):
r.delete(k)