fix(cover): restore audiobookcovers searches

Use separate title and author parameters to match the current upstream search form and restore cover results. Add regression coverage for title-only searches, whitespace trimming, and query encoding.
This commit is contained in:
neon
2026-10-07 21:33:50 +00:00
parent 2476195016
commit c35eb38485
2 changed files with 34 additions and 9 deletions
@@ -69,7 +69,35 @@ describe('AudiobookCoversCoverProvider', () => {
const [requestUrl] = fetchMock.mock.calls[0] as [string];
const parsed = new URL(requestUrl);
expect(parsed.pathname).toBe('/search');
expect(parsed.searchParams.get('q')).toBe('Dune Frank Herbert');
expect(parsed.searchParams.get('title')).toBe('Dune');
expect(parsed.searchParams.get('author')).toBe('Frank Herbert');
expect(parsed.searchParams.has('q')).toBe(false);
});
it.each([undefined, ' '])('searches by title when author is %j', async (author) => {
fetchMock.mockResolvedValueOnce(new Response(pageHtml(['1c98a3d5-9c05-4157-81a5-558cbb5ea87a']), { status: 200 }));
const results = await provider.search({ title: 'Dune', author, isAudiobook: true });
expect(results).toHaveLength(1);
const [requestUrl] = fetchMock.mock.calls[0] as [string];
const parsed = new URL(requestUrl);
expect(parsed.searchParams.get('title')).toBe('Dune');
expect(parsed.searchParams.has('author')).toBe(false);
expect(parsed.searchParams.has('q')).toBe(false);
});
it('trims and encodes title and author as separate search parameters', async () => {
fetchMock.mockResolvedValueOnce(new Response(pageHtml([]), { status: 200 }));
await provider.search({ title: ' Sense & Sensibility ', author: ' Jane Austen ', isAudiobook: true });
const [requestUrl] = fetchMock.mock.calls[0] as [string];
const parsed = new URL(requestUrl);
expect([...parsed.searchParams.entries()]).toEqual([
['title', 'Sense & Sensibility'],
['author', 'Jane Austen'],
]);
});
it('deduplicates repeated ids in the response', async () => {
@@ -21,11 +21,14 @@ export class AudiobookCoversCoverProvider implements CoverProvider {
async search(params: CoverSearchParams): Promise<CoverSearchResult[]> {
if (!params.isAudiobook) return [];
const query = this.buildQuery(params);
const title = params.title?.trim() ?? '';
const author = params.author?.trim() ?? '';
const query = author ? `${title} ${author}`.trim() : title;
if (!query) return [];
const url = new URL(AudiobookCoversCoverProvider.SEARCH_URL);
url.searchParams.set('q', query);
url.searchParams.set('title', title);
if (author) url.searchParams.set('author', author);
try {
const response = await fetch(url.toString(), {
@@ -69,10 +72,4 @@ export class AudiobookCoversCoverProvider implements CoverProvider {
return results;
}
private buildQuery(params: CoverSearchParams): string {
const title = params.title?.trim() ?? '';
const author = params.author?.trim() ?? '';
return author ? `${title} ${author}`.trim() : title;
}
}