fix(backend): Umschrift-Muster toleranter, Kanji-Kuenstler ueber Romaji erkennbar

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-25 00:09:01 +02:00
1 parent 06b13caea9
commit 748b1446a2
3 files changed
+49 -4

No files matched your search

+10 -2
View File
@@ -237,8 +237,16 @@ Die Android-App zählt eigenständig weiter (mehrere APKs pro Release). Welche d
- Bleibt am Ende weder ein Titel- noch ein Künstlermerkmal übrig, wird **gar nicht gesucht**:
ohne Merkmal landet sonst der erste Treffer passender Länge auf der Platte. Der Direktlink im
Importer ist dafür der vorgesehene Weg.
- Fünf neue Prüfungen in `backend/test/ytdlp.test.js` (59 grün), darunter „anderes Stück
desselben Albums darf nicht passen".
- **Die Umschrift ist nur *eine* Schreibweise.** Der Tokenizer liefert „Ginpatsu No Shounen",
Uploader schreiben „Ginpatsu no Shonen", setzen Bindestriche oder lassen den
Katakana-Längungsstrich weg (der bei „テーゼ" sogar unübersetzt stehenbleibt: „TeーZe"). Das
Muster lässt diese Abweichungen zu — langes o/u optional, Längungsstrich weg, Trennzeichen
frei. Sonst wäre die Alternative so streng, dass sie praktisch nie greift.
- Dieselbe Hilfe für **Kanji-Künstlernamen**: Kanäle und Videotitel schreiben sie meist
lateinisch, also zählt die Umschrift jetzt auch als Künstlermerkmal. Vorher blieb dort nur das
`artist`-Feld in Originalschrift.
- Sieben neue Prüfungen in `backend/test/ytdlp.test.js` (61 grün), darunter „anderes Stück
desselben Albums darf nicht passen" und die Schreibvarianten der Umschrift.
- **Das Mischen-Symbol zeigte nie an, dass es an ist (Android)** — und der Grund lag nicht in der
Anzeige. `toggleShuffle` baute den Rest der Warteschlange als Schleife aus `removeMediaItem` +
`addMediaItem` um; dazwischen hatte der Controller vorübergehend weniger Titel als unsere Liste.
+23 -2
View File
@@ -29,7 +29,17 @@ function buildTitleKeywords(title, romaji = '') {
const alternativen = [escRe(title.trim())];
const r = (romaji || '').trim();
if (r && r.toLowerCase() !== title.trim().toLowerCase() && !JP_RE.test(r)) {
alternativen.push(escRe(r).replace(/\s+/g, '[ -]?'));
// Die Umschrift des Tokenizers ist EINE Schreibweise von mehreren. Uploader schreiben
// "Shonen" statt "Shounen", setzen Bindestriche oder lassen den Katakana-Laengungsstrich
// weg. Das Muster laesst diese Abweichungen zu — sonst waere die Alternative so streng,
// dass sie praktisch nie greift.
alternativen.push(
escRe(r)
.replace(/ー/g, '') // kommt in lateinischen Titeln nie vor
.replace(/\s+/g, '[ -]?')
.replace(/ou/gi, '(?:ou|o|\u014d|oh)')
.replace(/uu/gi, '(?:uu|u|\u016b)')
);
}
return [`(?:${alternativen.join('|')})`];
}
@@ -212,8 +222,19 @@ async function downloadTrack({ jobId, artist, rawArtist, albumArtist, title, alb
// Ausnahme hatte ein japanischer Kuenstler ueberhaupt keine Identitaetspruefung.
const artistMetaPart = (artistFirstWord.length >= 3 || (JP_RE.test(artistFirstWord) && artistFirstWord.length >= 2))
? ` & artist ~= (?i)${escRe(artistFirstWord)}` : '';
// Kanji-Kuenstler: Kanaele und Videotitel schreiben den Namen meist lateinisch. Ohne diese
// Alternative bliebe fuer sie nur das artist-Feld in Originalschrift — und steht dort die
// lateinische Schreibweise, faellt der richtige Upload durch.
const artistRomajiWord = (JP_RE.test(artistFirstWord) && isTokenizerReady())
? ((romajiForStorage(artistFirstWord) || '').split(/\s+/)
.filter(w => w.length >= 3 && !JP_RE.test(w))
.sort((a, b) => b.length - a.length)[0] || '')
: '';
const artistRomajiParts = artistRomajiWord
? [` & channel ~= (?i)${escRe(artistRomajiWord)}`, ` & artist ~= (?i)${escRe(artistRomajiWord)}`]
: [];
// Alle Wege, den Kuenstler zu erkennen. yt-dlp verodert mehrere --match-filter.
const identitaet = [artistChannelPart, artistMetaPart].filter(Boolean);
const identitaet = [artistChannelPart, artistMetaPart, ...artistRomajiParts].filter(Boolean);
// Use a space (not " - ") between artist and title: this matches how users type
// in the YTM search box and ranks the exact official track first. A dash skews
+16
View File
@@ -149,3 +149,19 @@ test('lateinische Titel bleiben unveraendert', () => {
assert.deepEqual(buildTitleKeywords('Bohemian Rhapsody'), ['Bohemian', 'Rhapsody']);
assert.deepEqual(buildTitleKeywords('Dearly Beloved'), ['Beloved', 'Dearly']);
});
test('Umschrift toleriert die ueblichen Schreibvarianten', () => {
const re = new RegExp(buildTitleKeywords('銀髪の少年', 'Ginpatsu No Shounen')[0], 'i');
assert.ok(re.test('Ginpatsu no Shounen'), 'wie der Tokenizer schreibt');
assert.ok(re.test('Ginpatsu no Shonen'), 'ohne langes o — die haeufigste Variante');
assert.ok(re.test('Ginpatsu-no-Shonen'), 'mit Bindestrichen');
assert.ok(re.test('GINPATSU NO SHŌNEN'), 'mit Makron');
assert.ok(!re.test('Ginpatsu no Otona'), 'anderer Titel faellt weiterhin durch');
});
test('Katakana-Laengungsstrich faellt aus der Umschrift', () => {
// romajiForStorage laesst "ー" stehen ("TeーZe"); in einem lateinischen Titel steht es nie.
const re = new RegExp(buildTitleKeywords('残酷な天使のテーゼ', 'Zankoku Na Tenshi No TeーZe')[0], 'i');
assert.ok(re.test('Zankoku na Tenshi no Teze'), 'ohne Strich geschrieben');
assert.ok(re.test('残酷な天使のテーゼ'), 'Originaltitel weiterhin');
});