feat(server/web/coverart): manual Re-search missing art button

POST /api/admin/cover-sources/research bumps cover_art_sources_meta.
current_version unconditionally; the next enrichment pass re-eligibles
every 'none' row. Existing positively-sourced rows are not affected —
the version-mismatch eligibility rule only kicks in for 'none'.

Admin Cover Art panel gains a "Re-search missing art" button that
calls the endpoint and shows a confirmation toast. Operator's escape
hatch when:

- They've added a Last.fm key and want to retry failed rows
  immediately rather than waiting for the next scheduled scan.
- An upstream provider's catalog has updated (e.g. Deezer added a
  back-catalog import).
- They want to verify a fix end-to-end before the next scheduled
  scan fires.

SettingsService.BumpVersion (the unconditional version of T5's
BumpVersionIfProvidersChanged) is the single-call DB writer; both
endpoints route through it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 07:59:40 -04:00
parent 8f5ec4c304
commit c53bcb6c99
9 changed files with 224 additions and 1 deletions
+11
View File
@@ -320,6 +320,17 @@ export async function testCoverProvider(id: string): Promise<TestCoverProviderRe
return api.post<TestCoverProviderResponse>(`/api/admin/cover-sources/${id}/test`, {});
}
// Re-search missing art --------------------------------------------------
export type ResearchMissingArtResponse = { version: number };
// Bumps cover_art_sources_meta.current_version. Every 'none' row becomes
// eligible for retry against the current provider chain on the next
// enrichment pass. Existing positively-sourced rows are not affected.
export async function researchMissingArt(): Promise<ResearchMissingArtResponse> {
return api.post<ResearchMissingArtResponse>('/api/admin/cover-sources/research', {});
}
// Settings rarely change in operator time. 60s staleTime; refetches
// on window focus + after any mutation rather than polling.
export function createCoverProvidersQuery() {