check for doubles
This commit is contained in:
@@ -13,7 +13,7 @@ import db
|
|||||||
import sftp as sftp_module
|
import sftp as sftp_module
|
||||||
import sync
|
import sync
|
||||||
import uploader
|
import uploader
|
||||||
from uploader import delete_book, fetch_all_books, find_duplicate_groups
|
from uploader import CalibreClient, delete_book, fetch_all_books, find_duplicate_groups
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s — %(message)s")
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s — %(message)s")
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -222,13 +222,15 @@ def _run_dedup():
|
|||||||
try:
|
try:
|
||||||
cfg = config.load()
|
cfg = config.load()
|
||||||
log.info("Dedup: fetching all books ...")
|
log.info("Dedup: fetching all books ...")
|
||||||
|
client = CalibreClient(cfg.calibre)
|
||||||
|
client._ensure_auth()
|
||||||
books = fetch_all_books(cfg.calibre)
|
books = fetch_all_books(cfg.calibre)
|
||||||
groups = find_duplicate_groups(books)
|
groups = find_duplicate_groups(books)
|
||||||
to_delete = [b for group in groups for b in sorted(group, key=lambda x: x.get("id", 0))[1:]]
|
to_delete = [b for group in groups for b in sorted(group, key=lambda x: x.get("id", 0))[1:]]
|
||||||
_dedup_state.update({"total": len(to_delete), "deleted": 0, "failed": 0})
|
_dedup_state.update({"total": len(to_delete), "deleted": 0, "failed": 0})
|
||||||
log.info("Dedup: %d duplicate(s) to delete across %d group(s)", len(to_delete), len(groups))
|
log.info("Dedup: %d duplicate(s) to delete across %d group(s)", len(to_delete), len(groups))
|
||||||
for book in to_delete:
|
for book in to_delete:
|
||||||
ok, msg = delete_book(cfg.calibre, book["id"])
|
ok, msg = delete_book(cfg.calibre, book["id"], client)
|
||||||
if ok:
|
if ok:
|
||||||
_dedup_state["deleted"] += 1
|
_dedup_state["deleted"] += 1
|
||||||
else:
|
else:
|
||||||
|
|||||||
+19
-6
@@ -174,7 +174,10 @@ def fetch_all_books(cfg: CalibreConfig) -> list[dict]:
|
|||||||
data = resp.json()
|
data = resp.json()
|
||||||
# Calibre-Web uses DataTables format: "data"/"recordsTotal", older versions use "rows"/"total_count"
|
# Calibre-Web uses DataTables format: "data"/"recordsTotal", older versions use "rows"/"total_count"
|
||||||
rows = data.get("rows") or data.get("data") or []
|
rows = data.get("rows") or data.get("data") or []
|
||||||
total = data.get("total") or data.get("totalNotFiltered") or 0
|
total = (
|
||||||
|
data.get("recordsTotal") or data.get("total_count") or
|
||||||
|
data.get("total") or data.get("totalNotFiltered") or 0
|
||||||
|
)
|
||||||
all_books.extend(rows)
|
all_books.extend(rows)
|
||||||
log.info("Books fetched: %d / %d", len(all_books), total)
|
log.info("Books fetched: %d / %d", len(all_books), total)
|
||||||
if not rows or len(all_books) >= total:
|
if not rows or len(all_books) >= total:
|
||||||
@@ -183,13 +186,23 @@ def fetch_all_books(cfg: CalibreConfig) -> list[dict]:
|
|||||||
return all_books
|
return all_books
|
||||||
|
|
||||||
|
|
||||||
def delete_book(cfg: CalibreConfig, book_id: int) -> tuple[bool, str]:
|
def delete_book(cfg: CalibreConfig, book_id: int, client: "CalibreClient | None" = None) -> tuple[bool, str]:
|
||||||
"""Delete a book from Calibre-Web by ID."""
|
"""Delete a book from Calibre-Web by ID. Pass a pre-authenticated client to avoid re-auth overhead."""
|
||||||
client = CalibreClient(cfg)
|
if client is None:
|
||||||
client._ensure_auth()
|
client = CalibreClient(cfg)
|
||||||
|
client._ensure_auth()
|
||||||
|
csrf = client._upload_csrf
|
||||||
|
if not csrf:
|
||||||
|
# Try to fetch a CSRF token from the book detail page
|
||||||
|
try:
|
||||||
|
page = client._session.get(f"{cfg.url}/book/{book_id}", timeout=15)
|
||||||
|
csrf = _extract_csrf(page.text)
|
||||||
|
client._upload_csrf = csrf
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
resp = client._session.post(
|
resp = client._session.post(
|
||||||
f"{cfg.url}/delete/{book_id}",
|
f"{cfg.url}/delete/{book_id}",
|
||||||
data={"csrf_token": client._upload_csrf} if client._upload_csrf else {},
|
data={"csrf_token": csrf} if csrf else {},
|
||||||
timeout=30,
|
timeout=30,
|
||||||
)
|
)
|
||||||
if resp.ok:
|
if resp.ok:
|
||||||
|
|||||||
Reference in New Issue
Block a user