DNB rewrite: - Multiple query strategies with fallback (title+author+mat=ton → title+author → title+mat=ton → title-only → fulltext). Returns on first hit. Most German audiobooks aren't tagged mat=ton in DNB, which was killing all searches. - Strip CQL wildcard chars (?, *, <, >, =, /, quotes) from search terms. The "???" in "Die drei ???" was breaking the CQL parser. - Log HTTP status, body snippet on non-200, and numberOfRecords on every query so log shows exactly what DNB returned. - Parse SRU diagnostic elements (DNB error messages buried in XML). - Convert author/narrator from "Lastname, Firstname" to "Firstname Lastname" for consistency with other sources. Matcher: - Split series patterns: WITH_EPISODE (need digit) and SERIES_ONLY (just the series name). "Die drei ??? und der Fluch des Rubins" now properly detects "Die drei ???" as series even without folge#. - New _build_search_title: removes ??? sequences, trailing parens, collapses whitespace, before sending to APIs. - Manual search also passes through normalization. Logs source + hit count per query. Debug endpoint: - GET /api/items/match/debug?title=...&author=... returns raw results from all 4 sources with status, error messages, and full metadata. - "Debug" button added in BookDetail — shows what each API actually returns inline, so the user can see if it's a search problem, parse problem, or threshold problem. - "Cover aus Datei" button — triggers local cover extraction (folder.jpg or embedded artwork) on demand. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
37 lines
1.4 KiB
TypeScript
37 lines
1.4 KiB
TypeScript
import api from './client'
|
|
|
|
export const getItem = (id: string) =>
|
|
api.get(`/api/items/${id}`).then((r) => r.data)
|
|
|
|
export const updateItem = (id: string, data: object) =>
|
|
api.patch(`/api/items/${id}`, data).then((r) => r.data)
|
|
|
|
export const deleteItem = (id: string) =>
|
|
api.delete(`/api/items/${id}`).then((r) => r.data)
|
|
|
|
export const startPlayback = (id: string, body?: object) =>
|
|
api.post(`/api/items/${id}/play`, body || {}).then((r) => r.data)
|
|
|
|
export const syncSession = (sessionId: string, data: object) =>
|
|
api.post(`/api/playback-session/${sessionId}/sync`, data).then((r) => r.data)
|
|
|
|
export const closeSession = (sessionId: string) =>
|
|
api.delete(`/api/playback-session/${sessionId}`).then((r) => r.data)
|
|
|
|
export const searchMatch = (id: string, q?: string) =>
|
|
api.get(`/api/items/${id}/match/search`, { params: q ? { q } : {} }).then((r) => r.data)
|
|
|
|
export const applyMatch = (id: string, match: object) =>
|
|
api.post(`/api/items/${id}/match/apply`, match).then((r) => r.data)
|
|
|
|
export const triggerMatch = (id: string) =>
|
|
api.post(`/api/items/${id}/match`).then((r) => r.data)
|
|
|
|
export const debugMatch = (title: string, author?: string) =>
|
|
api.get(`/api/items/match/debug`, { params: { title, author } }).then((r) => r.data)
|
|
|
|
export const extractCover = (id: string) =>
|
|
api.post(`/api/items/${id}/extract-cover`).then((r) => r.data)
|
|
|
|
export const coverUrl = (id: string) => `/api/items/${id}/cover`
|