This repository has been archived on 2026-07-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
cloud-reader/docs/backend/010-open-library-metadata.md
crisleo94 6b4c0c43f8 feat: uv config other feats
- add uv configuration for the backend
- update frontend to make auth work
- add new auth endpoints
- add bookmars feat
- add reader feat
2026-06-03 22:06:01 -05:00

3.6 KiB
Raw Permalink Blame History

010 — Open Library metadata on import

Status: Implemented
Created: 2026-06-03

Objective

After a user uploads an EPUB/PDF (POST /api/books/ebooks/), enrich the EBook with metadata and a cover from Open Library, using only title and author from the upload form. Prefer Spanish editions when available; fall back to English/any.

Upload must never fail if Open Library is down or no match is found.

Trigger

  • Automatic: EBookUploadSerializer.create() calls enrich_ebook_metadata(ebook) after file save.
  • Manual: POST /api/books/ebooks/{id}/enrich-metadata/ re-runs enrichment (owner only).

Open Library usage

GET https://openlibrary.org/search.json

Param Value
title User-provided title
author User-provided author
lang es (primary) or en (fallback)
limit 5
fields key,title,author_name,cover_i,first_publish_year,subject,language,edition_key,number_of_pages_median,publisher

Primary pass also uses query filter language:spa. Fallback omits language filter.

Covers

GET https://covers.openlibrary.org/b/id/{cover_i}-L.jpg — downloaded and stored on EBook.cover_image.

Match scoring

Score Behavior
≥ 0.8 Apply OL title/author + cover + full metadata
0.6 0.8 Metadata + cover only; keep user title/author
< 0.6 match_status: not_found; no field changes except metadata stub

Author overlap + title similarity (normalized strings, difflib.SequenceMatcher). Prefer hits with cover_i.

Data model

No migration. Uses existing fields on EBook:

  • metadata_json — full enrichment payload (see below)
  • cover_image — downloaded cover file
  • title / author — updated when match score ≥ 0.8

metadata_json shape

{
  "source": "openlibrary",
  "matched_at": "2026-06-03T12:00:00+00:00",
  "match_language": "es",
  "match_score": 0.92,
  "match_status": "matched",
  "user_input": { "title": "...", "author": "..." },
  "openlibrary": {
    "work_key": "/works/OL...",
    "edition_key": "...",
    "title": "...",
    "authors": ["..."],
    "cover_id": 12345,
    "cover_url": "https://covers.openlibrary.org/b/id/12345-L.jpg",
    "first_publish_year": 1605,
    "subjects": ["..."],
    "languages": ["spa"],
    "publishers": ["..."],
    "number_of_pages_median": 320
  }
}

API changes

Upload response (unchanged path)

POST /api/books/ebooks/ — response may include populated cover_image and updated title/author after sync enrichment.

Detail

GET /api/books/ebooks/{id}/ — adds read-only metadata (alias of metadata_json).

Manual refresh

POST /api/books/ebooks/{id}/enrich-metadata/ — returns updated EBookDetailSerializer payload.

Configuration

Env var Default Description
OPENLIBRARY_ENABLED true Kill switch
OPENLIBRARY_PREFERRED_LANG es Primary lang param
OPENLIBRARY_FALLBACK_LANG en Fallback lang param
OPENLIBRARY_TIMEOUT_SECONDS 5 HTTP timeout
OPENLIBRARY_USER_AGENT CloudReader/1.0 User-Agent header

Code layout

backend/apps/books/services/
├── openlibrary.py   # Search, scoring, cover download
└── metadata.py      # enrich_ebook_metadata orchestrator

Verification

  1. Upload with title Don Quijote, author Cervantes → cover + Spanish-friendly metadata.
  2. Upload with nonsense title/author → 201, no cover, match_status: not_found.
  3. POST .../enrich-metadata/ on existing ebook refreshes metadata.