Files
bookhoard/docs/developer/api/media-items/search_media_items.md
T
John O'Keefe 8aa66a30fc docs(api): sync mirrors with the retired rules CRUD and the chain-order endpoint
Three mirrors had drifted:

- The rules-endpoint retirement (4f71eda6) deleted the routes but not
  their mirrors: removed docs/developer/api/collections/
  {add_auto_assign_rule,remove_auto_assign_rule,test_rule,update_rule}
  .md + their bruno twins, and pruned /api/collections/test-rules,
  /{id}/rules, /{id}/rules/{ruleId} from the generated openapi spec
  (hand-edited — regenerating with -update would wipe hand-authored
  bruno suites that predate the docs mirrors).
- New endpoint PUT /api/collections/:id/view-settings gets a doc page
  + schema-registry entry + bruno mirror (repo convention: the route
  and its docs land together).
- 54 pre-existing TestDocsMatchRoutes failures: the media-item
  endpoints emit the 16 episode/download fields (source_feed_id,
  feed_position, download_state, enclosure_url, hosts/guests, …) and
  libraries emit purpose/allow_member_feeds, but the doc examples
  were never extended — the package only runs on the host, so the
  container suite never caught it. Examples now carry every key the
  handlers emit; internal/docs is fully green.
2026-10-31 15:40:21 -04:00

8.5 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,
    "source": null,
    "source_feed_id": null,
    "feed_position": null,
    "episode_number": null,
    "season_number": null,
    "episode_guid": null,
    "enclosure_url": null,
    "chapters_url": null,
    "transcript_url": null,
    "hosts": null,
    "guests": null,
    "declared_duration_seconds": null,
    "download_state": null,
    "download_attempts": null,
    "download_queue_pos": null,
    "download_error": 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).