Files
bookhoard/docs/developer/api/media-items/search_media_items.md
T
John O'Keefe 6f13dc2b63 docs(media-items core): Beam WO5 batch 4 — 12 endpoints backfilled, registry pinned
Beam backfilled list/get/create/update/delete media-item, search, ratings
CRUD, progress GET/PUT. Beam correctly identified create/update/delete as
jwt+admin (admin group in the router — verified).

Claude registry: 12 entries. Notable pins:
- get_media_item: hand-built ~44-key map pinned verbatim from the handler
- create/update return the full database.MediaItems row (74 columns) —
  examples merged up to the real shape via gate-driven merge script
- search returns []SearchMediaItemsRow (sqlc row — Real type pinned)
- rating scale is 1-10 int (odd = half-star); GET returns {rating: null} when
  absent; update reuses the create handler (201)
- progress GET: 25 base keys + 4 CONDITIONAL position-authority keys
  (css_selector/anchor_href/char_offset/context_text — added by the handler
  for convertible formats with a valid CFI); PUT progress binds
  sync.SaveProgressRequest and returns database.ReadingProgress
- Beam's examples were missing entirely on 4 files (list/search/progress
  GET/PUT) — relabeled existing fences or inserted contract-shaped blocks

Gate-driven merge scripts (object + array variants) brought all examples to
the exact handler key sets. make test 9/9.
2026-10-24 16:09:38 -04:00

8.1 KiB

method, path, auth, area
method path auth area
GET /api/media-items/search jwt media-items

Search Media Items (Unified):<|end|><|start|>edit to=assistant<|channel|>analysis<|message|>Edited docs/developer/api/media-items/create_media_item.md (1 replacement)<|end|><|start|>edit to=assistant<|channel|>analysis<|message|>Edited docs/developer/api/media-items/update_media_item.md (1 replacement)<|end|><|start|>edit to=assistant<|channel|>analysis<|channel|>Edited docs/developer/api/media-items/delete_media_item.md (1 replacement)<|end|><|start|>edit to=assistant<|channel|>analysis<|message|>Edited docs/developer/api/media-items/search_media_items.md (1 replacement)

Search and filter media items with fuzzy matching support.

Note: All text filters use fuzzy matching via PostgreSQL pg_trgm (threshold: 0.3 similarity). This handles typos and partial matches automatically. Use quotes for exact match.

Endpoint: GET /api/media-items/search Auth: Required

Query Parameters

Search Parameters

Parameter Type Required Description
q string No Search query (fuzzy by default, exact in quotes)
library_id string Yes Filter to specific library (UUID)
limit integer No Number of results (default 50, max 200)
offset integer No Number to skip for pagination

Filter Parameters (All Fuzzy Except Years/Booleans)

Parameter Type Description
author_filter string Fuzzy match author field
series_filter string Fuzzy match series field
tags_filter string Fuzzy match tags array
language_filter string Fuzzy match language field
year_min integer Minimum copyright year (exact range)
year_max integer Maximum copyright year (exact range)
has_cover boolean Filter by cover image presence (exact boolean)
Parameter Type Description
authors string Search author values for autocomplete dropdown
tagss string Search tags values for autocomplete dropdown
series string Search series values for autocomplete dropdown
languages string Search language values for autocomplete

Request Headers

Header Type Required Description
Authorization string Yes Bearer token

Search Behavior

Fuzzy Search (Default)

Handles typos and partial matches automatically:

  • "asimov" → matches "Asimov, Isaac", "Asimov, Foundation"
  • "scifi" → matches "Sci-Fi", "Science Fiction"
  • "azimov" → matches "Asimov, Isaac" (typo tolerance)

Exact Search (With Quotes)

Use double quotes for exact phrase matching:

  • "\"Foundation and Empire\"" → only "Foundation and Empire"
  • "\"Asimov, Isaac\"" → only "Asimov, Isaac"

Filter Behavior

Text filters (fuzzy):

  • author_filter=asimov → fuzzy matches author field
  • tags_filter=scifi → fuzzy matches tags field

Exact filters:

  • year_min=2000&year_max=2010 → exact year range
  • has_cover=true → exact boolean match

Example Requests

Search all fields for "foundation":

GET /api/media-items/search?library_id=123e4567-e89b-12d3-a456-426614174000&q=foundation
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

2. Fuzzy Author Filter

Find books by "asimov" (matches "Asimov, Isaac"):

GET /api/media-items/search?library_id=123e4567-e89b-12d3-a456-426614174000&author_filter=asimov
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

3. Combined Search + Filters

Search "foundation" within books by "asimov":

GET /api/media-items/search?library_id=123e4567-e89b-12d3-a456-426614174000&q=foundation&author_filter=asimov
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

4. Exact Match with Quotes

Exact phrase search:

GET /api/media-items/search?library_id=123e4567-e89b-12d3-a456-426614174000&q="Foundation%20and%20Empire"
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

5. Multiple Fuzzy Filters

Fiction books from 2000-2010:

GET /api/media-items/search?library_id=123e4567-e89b-12d3-a456-426614174000&tags_filter=fiction&year_min=2000&year_max=2010
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

6. Field-Specific Search (Autocomplete)

Get author values for dropdown:

GET /api/media-items/search?library_id=123e4567-e89b-12d3-a456-426614174000&authors=asimov&limit=50
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response:

{
  "results": [
    {"value": "Asimov, Isaac", "count": 47, "score": 0.8},
    {"value": "Asimov, Isaac & Robert Silverberg", "count": 2, "score": 0.75}
  ],
  "total": 2
}

Response (200 OK)

Media items search:

[
  {
    "id": "uuid",
    "title": "Foundation",
    "author": "Isaac Asimov",
    "tags": [
      "Science Fiction",
      "Adventure"
    ],
    "library_id": "uuid",
    "library_name": "E-Books",
    "abridged": null,
    "added_by_admin_id": null,
    "age_rating": null,
    "alternate_info": null,
    "archived_at": null,
    "asin": null,
    "audio_metadata": null,
    "authors": null,
    "authors_search": null,
    "chapter_count": null,
    "chapter_metadata": null,
    "community_rating": null,
    "contributors": null,
    "contributors_search": null,
    "copyright_year": null,
    "cover_image_path": null,
    "created_at": null,
    "date_published": null,
    "description": null,
    "edition": null,
    "entitlement_id": null,
    "explicit": null,
    "file_path": null,
    "file_sha256": null,
    "file_size": null,
    "format_group": null,
    "format_mimetype": null,
    "genre": null,
    "goodreads_id": null,
    "google_books_id": null,
    "has_fixed_layout": null,
    "hash_confidence": null,
    "imported_at": null,
    "imprint": null,
    "is_black_and_white": null,
    "is_reflowable": null,
    "isbn": null,
    "kobo_content_id": null,
    "kobo_metadata": null,
    "language": null,
    "library_type_name": null,
    "library_type_name_2": null,
    "manga_type": null,
    "metadata_notes": null,
    "metadata_overrides": null,
    "mime_type": null,
    "missing_scan_count": null,
    "narrators": null,
    "narrators_search": null,
    "openlibrary_id": null,
    "opf_identifier": null,
    "opf_uuid": null,
    "page_count": null,
    "publisher": null,
    "publishers": null,
    "publishers_search": null,
    "reading_direction": null,
    "revision_number": null,
    "scan_information": null,
    "series": null,
    "series_count": null,
    "series_number": null,
    "story_arc": null,
    "subtitle": null,
    "summary": null,
    "tags_search": null,
    "total_characters": null,
    "updated_at": null,
    "volume": null,
    "web_url": null
  }
]

Field values search (autocomplete):

{
  "results": [
    {"value": "Asimov, Isaac", "count": 47, "score": 0.8}
  ],
  "total": 1
}

Error Responses

Code Description
400 Invalid library_id
400 Missing library_id
401 Invalid or expired token
404 No results found

Backward Compatibility

The genre_filter parameter is deprecated but still supported for backward compatibility. It will return 0 results for books imported from Calibre (genre field is NULL).