feat: the duplicates review says what each match rests on and plays every copy (#6168)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m25s
release / go (push) Successful in 1m34s
release / android (push) Successful in 4m58s
release / integration (push) Successful in 5m4s
release / Build signed APK (releases and dev) (push) Successful in 5m9s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped

Each group now states its evidence: identical audio data, or the share of
audio fingerprints that agree. Copies titled as different songs in one
acoustic group say so and ask the reviewer to listen, and each copy has a
play button so they can.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 10:28:29 -04:00
co-authored by Claude Opus 5.5
parent 460e78c955
commit e3eddab80f
6 changed files with 111 additions and 13 deletions
@@ -17,8 +17,10 @@ vi.mock('#lib/api/admin.js', () => ({
removed_paths: ['/music/Moe Shop/WWW (2020)/www-02.mp3']
})
}));
vi.mock('#lib/player/store.svelte.js', () => ({ playQueue: vi.fn() }));
import AdminDuplicatesPage from './+page.svelte';
import { playQueue } from '#lib/player/store.svelte.js';
import {
createDuplicatesQuery,
createResolvedDuplicatesQuery,
@@ -45,6 +47,7 @@ function member(id: string, extra: Partial<AdminDuplicatesResponse['groups'][num
return {
track_id: id,
title: 'WWW',
artist_id: 'ar-1',
artist_name: 'Moe Shop',
album_id: 'al-1',
album_title: 'WWW',
@@ -57,6 +60,7 @@ function member(id: string, extra: Partial<AdminDuplicatesResponse['groups'][num
play_count: 0,
disc_number: null,
track_number: null,
stream_url: `/api/tracks/${id}/stream`,
...extra
};
}
@@ -164,7 +168,30 @@ describe('admin duplicates', () => {
const r = response();
r.groups[0] = { ...r.groups[0], tier: 'acoustic', worst_bit_error_rate: 0.04 };
renderWith(r);
expect(text(screen.getByTestId('duplicate-tier'))).toBe('Same recording · 96% match');
expect(text(screen.getByTestId('duplicate-tier'))).toBe('Same music · 96% match');
});
// The operator took the match for a guess from size and length (#6168).
test('each group says what the match rests on', () => {
const r = response();
r.groups.push({ ...r.groups[0], id: 'g-2', tier: 'acoustic', worst_bit_error_rate: 0.04 });
renderWith(r);
const lines = screen.getAllByTestId('match-evidence').map(text);
expect(lines[0]).toContain('the same audio data, byte for byte');
expect(lines[1]).toBe(
'Matched by listening, not by size or length: 96% of their audio fingerprints agree, so these files play the same music.'
);
});
test('each copy can be played', async () => {
renderWith(response());
const plays = screen.getAllByTestId('member-play');
expect(plays).toHaveLength(2);
await fireEvent.click(plays[1]);
expect(playQueue).toHaveBeenLastCalledWith(
[expect.objectContaining({ id: 'www-02', artist_id: 'ar-1', stream_url: '/api/tracks/www-02/stream' })],
0
);
});
// #3885: identical audio titled "WWW" and "WWW (instrumental)". One file
@@ -220,6 +247,17 @@ describe('admin duplicates', () => {
renderWith(r);
expect(screen.queryByTestId('title-mismatch')).toBeNull();
});
// Unless the resolver found different songs on one album: Savant's Mortals
// held one recording as 16 tracks, each cut to its own song's length (#6169).
test('an acoustic group the resolver found to be different songs says so', () => {
const r = www();
r.groups[0] = { ...r.groups[0], tier: 'acoustic', worst_bit_error_rate: 0, class: 'mismatch' };
renderWith(r);
const notice = text(screen.getByTestId('title-mismatch'));
expect(notice).toContain('The music is the same, but the copies are titled “WWW” and “WWW (instrumental)”');
expect(notice).toContain('Play each');
});
});
// Three states all show zero groups. Each must say which it is.