Initial commit

This commit is contained in:
2026-05-09 18:41:03 +02:00
commit d384f1f896
18 changed files with 1339 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
import hashlib
import logging
import mimetypes
from pathlib import Path
import requests
import db
from config import CalibreConfig
log = logging.getLogger(__name__)
MIME_TYPES = {
".epub": "application/epub+zip",
".pdf": "application/pdf",
}
class CalibreClient:
def __init__(self, cfg: CalibreConfig):
self._cfg = cfg
self._session = requests.Session()
self._authenticated = False
def _ensure_auth(self) -> None:
if self._authenticated:
return
resp = self._session.post(
f"{self._cfg.url}/login",
data={"username": self._cfg.user, "password": self._cfg.password},
allow_redirects=True,
timeout=30,
)
resp.raise_for_status()
# Calibre-Web redirects to / on success; a 200 on /login means bad creds
if resp.url.endswith("/login"):
raise RuntimeError("Calibre-Web authentication failed — check credentials")
self._authenticated = True
log.info("Authenticated to Calibre-Web at %s", self._cfg.url)
def upload(self, book_path: Path, zip_source: str) -> str:
"""Upload a book file. Returns status: 'uploaded' | 'skipped_duplicate' | 'error'."""
file_hash = _sha256(book_path)
if db.is_book_uploaded(file_hash):
log.info("Skipping duplicate: %s (hash %s)", book_path.name, file_hash[:8])
db.record_book(book_path.name, file_hash, zip_source, "skipped_duplicate")
return "skipped_duplicate"
try:
self._ensure_auth()
mime = MIME_TYPES.get(book_path.suffix.lower(), "application/octet-stream")
with book_path.open("rb") as fh:
resp = self._session.post(
f"{self._cfg.url}/upload",
files={"btn-upload": (book_path.name, fh, mime)},
timeout=120,
)
resp.raise_for_status()
log.info("Uploaded: %s", book_path.name)
db.record_book(book_path.name, file_hash, zip_source, "uploaded")
return "uploaded"
except Exception as e:
log.error("Upload failed for %s: %s", book_path.name, e)
db.record_book(book_path.name, file_hash, zip_source, "error")
return "error"
def _sha256(path: Path) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(65536), b""):
h.update(chunk)
return h.hexdigest()