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.
176 lines
4.5 KiB
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)
|