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/db/repository.py

176 lines
4.5 KiB

# ============================================================
# File: db/repository.py
# Purpose:
# High-level BookScraper database interface.
# This is the ONLY module Celery tasks and Flask should use.
#
# New additions for INIT-flow:
# - register_book()
# - update_book_after_full_scrape()
# - get_registered_books()
# - get_active_books()
#
# Existing functions remain unchanged for backward compatibility.
# ============================================================
from db.db import (
upsert_book,
_raw_get_book,
_raw_get_all_books,
get_db,
)
# ------------------------------------------------------------
# FETCH OPERATIONS
# ------------------------------------------------------------
def fetch_book(book_id):
"""Return a single book dict or None."""
return _raw_get_book(book_id)
def fetch_all_books():
"""Return all books ordered newest → oldest."""
return _raw_get_all_books()
# ============================================================
# NEW — INIT-FLOW SUPPORT
# ============================================================
def register_book(book_id, title, author=None, description=None, cover_url=None):
"""
Create a new book entry with initial metadata.
Called when user enters a URL and presses INIT.
"""
fields = {
"title": title,
"author": author,
"description": description,
"cover_url": cover_url,
"chapters_total": 0,
"status": "registered",
}
upsert_book(book_id, **fields)
def update_book_after_full_scrape(
book_id,
title=None,
author=None,
description=None,
cover_url=None,
chapters_total=None,
):
"""
Called after a FULL scrape when chapters are known.
Moves the book into 'active' state.
"""
fields = {}
if title is not None:
fields["title"] = title
if author is not None:
fields["author"] = author
if description is not None:
fields["description"] = description
if cover_url is not None:
fields["cover_url"] = cover_url
if chapters_total is not None:
fields["chapters_total"] = chapters_total
fields["status"] = "active"
upsert_book(book_id, **fields)
def get_registered_books():
"""
Return books registered but not yet scraped.
"""
conn = get_db()
cur = conn.execute(
"""SELECT * FROM books WHERE status='registered'
ORDER BY created_at DESC"""
)
return [dict(row) for row in cur.fetchall()]
def get_active_books():
"""
Return books currently in progress.
"""
conn = get_db()
cur = conn.execute(
"""SELECT * FROM books
WHERE status IN ('active', 'downloading')
ORDER BY created_at DESC"""
)
return [dict(row) for row in cur.fetchall()]
# ------------------------------------------------------------
# BOOK CREATION / METADATA (existing)
# ------------------------------------------------------------
def create_or_update_book(
book_id,
title=None,
author=None,
chapters_total=None,
cover_url=None,
cover_path=None,
status=None,
):
fields = {}
if title is not None:
fields["title"] = title
if author is not None:
fields["author"] = author
if chapters_total is not None:
fields["chapters_total"] = chapters_total
if cover_url is not None:
fields["cover_url"] = cover_url
if cover_path is not None:
fields["cover_path"] = cover_path
if status is not None:
fields["status"] = status
if fields:
upsert_book(book_id, **fields)
# ------------------------------------------------------------
# STATUS MANAGEMENT (existing)
# ------------------------------------------------------------
def set_status(book_id, status):
upsert_book(book_id, status=status)
# ------------------------------------------------------------
# INCREMENTING COUNTERS (existing — backward compat only)
# ------------------------------------------------------------
def inc_downloaded(book_id, amount=1):
book = _raw_get_book(book_id)
if not book:
return
cur = book.get("downloaded", 0) or 0
upsert_book(book_id, downloaded=cur + amount)
def inc_parsed(book_id, amount=1):
book = _raw_get_book(book_id)
if not book:
return
cur = book.get("parsed", 0) or 0
upsert_book(book_id, parsed=cur + amount)
def inc_audio_done(book_id, amount=1):
book = _raw_get_book(book_id)
if not book:
return
cur = book.get("audio_done", 0) or 0
upsert_book(book_id, audio_done=cur + amount)