feat(web): duplicates report flags identical audio under different titles (#3885)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m10s
release / go (push) Successful in 1m28s
release / integration (push) Successful in 4m21s
release / android (push) Successful in 4m43s
release / Build signed APK (releases and dev) (push) Successful in 4m57s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped

An exact-tier group whose copies carry different titles means at least one
file's tags are wrong, and the recording the other title names may be missing
from the library. WWW (2020) was this: "WWW" was a second copy of the
instrumental, the vocal was absent, and nothing said so. The report now names
the titles and says what it implies, so the absence surfaces at the moment of
choosing which copy to keep.

Titles compare case- and whitespace-insensitively. Acoustic-tier groups are
left alone: across encodings a "Remastered" suffix is routine, not a mislabel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 06:33:37 -04:00
co-authored by Claude Opus 5.5
parent 43c369f082
commit 5dffe51b95
2 changed files with 92 additions and 1 deletions
+37 -1
View File
@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { pageTitle } from '$lib/branding'; import { pageTitle } from '$lib/branding';
import { Copy } from 'lucide-svelte'; import { Copy, TriangleAlert } from 'lucide-svelte';
import { import {
createDuplicatesQuery, createDuplicatesQuery,
runDuplicateSweep, runDuplicateSweep,
@@ -122,6 +122,27 @@
return n === 1 ? `1 ${one}` : `${n} ${many}`; return n === 1 ? `1 ${one}` : `${n} ${many}`;
} }
// Identical audio under different titles means at least one file's tags are
// wrong, and the recording the other title names may not be in the library at
// all. #3885: "WWW" was a second copy of the instrumental, and the vocal was
// missing with nothing to say so. Exact tier only: an acoustic match spans
// encodings, where a "Remastered" suffix is routine rather than a lie.
function differingTitles(g: AdminDuplicateGroup): string[] {
if (g.tier !== 'exact') return [];
const byKey = new Map<string, string>();
for (const m of g.members) {
const title = m.title.trim().replace(/\s+/g, ' ');
const key = title.toLowerCase();
if (!byKey.has(key)) byKey.set(key, title);
}
return byKey.size > 1 ? [...byKey.values()] : [];
}
function quotedList(titles: string[]): string {
const q = titles.map((t) => `“${t}”`);
return q.length <= 2 ? q.join(' and ') : `${q.slice(0, -1).join(', ')} and ${q[q.length - 1]}`;
}
// What the copy carries is the fact that decides which to keep. // What the copy carries is the fact that decides which to keep.
function historyLabel(m: AdminDuplicateMember): string { function historyLabel(m: AdminDuplicateMember): string {
if (m.like_count === 0 && m.play_count === 0) return 'no likes or plays'; if (m.like_count === 0 && m.play_count === 0) return 'no likes or plays';
@@ -224,6 +245,7 @@
{:else} {:else}
<ul class="space-y-4"> <ul class="space-y-4">
{#each groups as group (group.id)} {#each groups as group (group.id)}
{@const titles = differingTitles(group)}
<li class="overflow-hidden rounded-lg border border-border bg-surface" data-testid="duplicate-group"> <li class="overflow-hidden rounded-lg border border-border bg-surface" data-testid="duplicate-group">
<div class="flex items-center justify-between gap-4 border-b border-border px-4 py-3"> <div class="flex items-center justify-between gap-4 border-b border-border px-4 py-3">
<div class="min-w-0"> <div class="min-w-0">
@@ -258,6 +280,20 @@
</div> </div>
</div> </div>
{#if titles.length > 0}
<p
class="flex items-start gap-2 border-b border-border bg-surface-hover px-4 py-3 text-xs text-text-secondary"
data-testid="title-mismatch"
>
<TriangleAlert size={14} class="mt-0.5 flex-shrink-0 text-warning-fg" aria-hidden="true" />
<span>
The audio is identical, but the copies are titled {quotedList(titles)}. If those
name different recordings, one file is mislabelled and the other recording isn't in
your library. Keep the copy whose title matches what you hear.
</span>
</p>
{/if}
{#if confirmingMerge === group.id} {#if confirmingMerge === group.id}
<!-- What the second click will do, said plainly before it is done. --> <!-- What the second click will do, said plainly before it is done. -->
<div class="space-y-2 border-b border-border bg-surface-hover px-4 py-3 text-sm" data-testid="merge-confirm"> <div class="space-y-2 border-b border-border bg-surface-hover px-4 py-3 text-sm" data-testid="merge-confirm">
@@ -124,6 +124,61 @@ describe('admin duplicates', () => {
expect(text(screen.getByTestId('duplicate-tier'))).toBe('Same recording · 96% match'); expect(text(screen.getByTestId('duplicate-tier'))).toBe('Same recording · 96% match');
}); });
// #3885: identical audio titled "WWW" and "WWW (instrumental)". One file
// claimed to be the vocal and wasn't, and nothing said the vocal was missing.
describe('identical audio under different titles', () => {
function www() {
const r = response();
r.groups[0] = {
...r.groups[0],
members: [member('www-01'), member('www-02', { title: 'WWW (instrumental)' })]
};
return r;
}
test('says the copies are titled differently and names both titles', () => {
renderWith(www());
const notice = text(screen.getByTestId('title-mismatch'));
expect(notice).toContain('titled “WWW” and “WWW (instrumental)”');
expect(notice).toContain("isn't in your library");
});
test('three different titles are all named', () => {
const r = www();
r.groups[0].members.push(member('www-03', { title: 'WWW (Radio Edit)' }));
renderWith(r);
expect(text(screen.getByTestId('title-mismatch'))).toContain(
'“WWW”, “WWW (instrumental)” and “WWW (Radio Edit)”'
);
});
test('titles differing only in case or spacing are the same title', () => {
const r = response();
r.groups[0] = {
...r.groups[0],
members: [
member('www-01', { title: 'WWW (Instrumental)' }),
member('www-02', { title: ' www (instrumental) ' })
]
};
renderWith(r);
expect(screen.queryByTestId('title-mismatch')).toBeNull();
});
test('matching titles raise nothing', () => {
renderWith(response());
expect(screen.queryByTestId('title-mismatch')).toBeNull();
});
// Across encodings a "Remastered" suffix is routine, not a mislabel.
test('an acoustic group with different titles raises nothing', () => {
const r = www();
r.groups[0] = { ...r.groups[0], tier: 'acoustic', worst_bit_error_rate: 0.04 };
renderWith(r);
expect(screen.queryByTestId('title-mismatch')).toBeNull();
});
});
// Three states all show zero groups. Each must say which it is. // Three states all show zero groups. Each must say which it is.
test('empty while still fingerprinting says so', () => { test('empty while still fingerprinting says so', () => {
renderWith( renderWith(