fix(voices): drop the Source unknown badge from list rows

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-10-04 18:22:41 +02:00
parent fece9122d1
commit 281869709b
3 changed files with 5 additions and 2 deletions

View File

@ -6,6 +6,9 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
--- ---
## [Unreleased] ## [Unreleased]
### Changed
- **Voice list rows no longer show the "Source unknown" badge** (it crowded the play buttons). The badge stays in the voice inspector, next to the Source & consent panel.
### Fixed ### Fixed
- **LibriVox search returned 502 "unavailable" after 20-30 s.** Cause: the LibriVox API is erratic (10-40 s for any request, measured from host and container; egress/DNS/TLS fine) and the old call asked for `extended=1` (all chapters of 15 books) with a 30 s timeout, mapping every failure to one generic message. Now the list is light (no `extended`), the first chapter is fetched per book on demand (`GET /api/voice-sources/librivox/book/{id}`, UI "Load preview" / on import), timeout 25 s with one retry and backoff, failures cached 30 s, distinct messages (timeout / unreachable / HTTP status / unreadable) and a privacy-safe log line (exception class and query length only). Host/redirect rules unchanged. - **LibriVox search returned 502 "unavailable" after 20-30 s.** Cause: the LibriVox API is erratic (10-40 s for any request, measured from host and container; egress/DNS/TLS fine) and the old call asked for `extended=1` (all chapters of 15 books) with a 30 s timeout, mapping every failure to one generic message. Now the list is light (no `extended`), the first chapter is fetched per book on demand (`GET /api/voice-sources/librivox/book/{id}`, UI "Load preview" / on import), timeout 25 s with one retry and backoff, failures cached 30 s, distinct messages (timeout / unreachable / HTTP status / unreadable) and a privacy-safe log line (exception class and query length only). Host/redirect rules unchanged.
- **`export_provenance_default` missing from settings defaults.** It is now in the defaults (`true`), so `GET /api/settings` exposes it. - **`export_provenance_default` missing from settings defaults.** It is now in the defaults (`true`), so `GET /api/settings` exposes it.

View File

@ -2287,7 +2287,6 @@ function makeVoiceRow(v) {
${benchText !== '-' ? `<span class="vl-bench-chip ${benchCls}" title="${escHtml(benchTitle)}"><span class="mdi mdi-timer-outline"></span> ${escHtml(benchText.split(' ')[0])}</span>` : ''} ${benchText !== '-' ? `<span class="vl-bench-chip ${benchCls}" title="${escHtml(benchTitle)}"><span class="mdi mdi-timer-outline"></span> ${escHtml(benchText.split(' ')[0])}</span>` : ''}
<div class="vr-rating">${starsHtml}</div> <div class="vr-rating">${starsHtml}</div>
<span class="vl-type-label ${isClone ? 'vl-type-clone' : 'vl-type-design'}">${isClone ? 'Clone' : 'Design'}</span> <span class="vl-type-label ${isClone ? 'vl-type-clone' : 'vl-type-design'}">${isClone ? 'Clone' : 'Design'}</span>
${window.provenanceBadge ? window.provenanceBadge(v) : ''}
</div> </div>
</div> </div>
<div class="vr-play-group"> <div class="vr-play-group">

View File

@ -21,8 +21,9 @@ test('unknown badge, validation error text and save payload', async ({ page }) =
await page.waitForSelector('#app-skeleton', { state: 'detached', timeout: 15_000 }); await page.waitForSelector('#app-skeleton', { state: 'detached', timeout: 15_000 });
await page.evaluate(() => window.navTo('s-voices')); await page.evaluate(() => window.navTo('s-voices'));
const row = page.locator('[data-id="EN_F_Test"]').first(); const row = page.locator('[data-id="EN_F_Test"]').first();
await expect(row.locator('.vl-prov-badge')).toBeVisible(); await expect(row.locator('.vl-prov-badge')).toHaveCount(0); // not in the list rows: crowded the play buttons
await row.locator('.vl-name').click(); await row.locator('.vl-name').click();
await expect(page.locator('.vl-prov-badge').first()).toBeVisible(); // still shown in the inspector
const panel = page.locator('.insp-prov-panel'); const panel = page.locator('.insp-prov-panel');
await expect(panel.getByRole('heading', { name: 'Source & consent' })).toBeVisible(); await expect(panel.getByRole('heading', { name: 'Source & consent' })).toBeVisible();
await panel.getByLabel('Basis').selectOption('licensed'); await panel.getByLabel('Basis').selectOption('licensed');