Hanni und Nanni ist nicht Hanni und Nanni 3
Deine drei Fälle haben eines gemeinsam, und es ist nicht das, was ich zuerst vermutet hatte: keiner der Dateinamen nennt ein Jahr. Der Riegel von gestern greift deshalb nicht. Gemessen, woran es wirklich liegt. Bei TMDB heisst der Film „Hanni & Nanni", auf der Platte „Hanni und Nanni". Das Kaufmanns-Und fällt im Vergleichs- schlüssel als Sonderzeichen heraus, das Wort „und" bleibt stehen — die Namensgleichheit griff also nie. Gewählt wurde stattdessen der erstbeste Treffer, und das war „Hanni & Nanni 3". Der richtige stand auf Platz zwei, und alle vier Treffer hatten dieselbe Beliebtheit: die Reihenfolge war Zufall. Bindewörter zwischen zwei Namen zählen jetzt nicht mehr mit — gestrichen, nicht übersetzt, sonst bliebe „Batman and Robin" aussen vor. Am Wortanfang bleiben sie stehen: „Und dann kam Polly" ist kein „dann kam Polly". Und die Suche vergleicht über den Schlüssel statt Zeichen für Zeichen. Das verhindert aber nur Neues. Was schon zusammengelegt ist, bleibt es — deshalb gibt es jetzt „Eigener Film": eine Datei löst sich aus ihrem Titel und wird ein eigener Eintrag, mit dem Titel aus dem Dateinamen und ohne Kennung. Eine zu raten hiesse, denselben Fehler zu wiederholen; so steht sie unter „Ohne Zuordnung" und ist in zwei Klicks richtig. Der Super-Mario-Fall liegt anders: beide Titel treffen heute richtig. Der steckt noch aus einem früheren Lauf fest und braucht das Trennen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c3124ba27c
commit
58e06d0539
+11
-1
@@ -815,10 +815,11 @@ export type OhneZuordnung = {
|
||||
export const ohneZuordnung = (bibliothek: string, anzahl = 300) =>
|
||||
anfrage<OhneZuordnung[]>(`/libraries/${bibliothek}/unmatched?take=${anzahl}`);
|
||||
|
||||
export type Fassungsdatei = { id: string; name: string };
|
||||
export type Mehrfachtitel = {
|
||||
id: string; art: 'movie' | 'series';
|
||||
titel: string; jahr: number | null;
|
||||
dateien: string[];
|
||||
dateien: Fassungsdatei[];
|
||||
};
|
||||
export type Mehrfachbericht = { gesamt: number; titel: Mehrfachtitel[] };
|
||||
|
||||
@@ -826,6 +827,15 @@ export type Mehrfachbericht = { gesamt: number; titel: Mehrfachtitel[] };
|
||||
export const mehrfachfassungen = (bibliothek: string, anzahl = 300) =>
|
||||
anfrage<Mehrfachbericht>(`/libraries/${bibliothek}/versions?take=${anzahl}`);
|
||||
|
||||
/** Löst eine Datei aus ihrem Titel heraus — sie wird ein eigener Film.
|
||||
*
|
||||
* **Für falsch Zusammengelegtes.** Zwei Dateien an einem Eintrag sind meist
|
||||
* zwei Fassungen; sind es zwei Filme, war einer davon nicht mehr zu sehen.
|
||||
* Der neue Eintrag bekommt den Titel aus dem Dateinamen und keine Kennung —
|
||||
* er steht danach unter „Ohne Zuordnung" und lässt sich dort richtigstellen. */
|
||||
export const dateiHerausloesen = (datei: string) =>
|
||||
anfrage<Zuordnungsstand>(`/files/${datei}/split`, { method: 'POST' });
|
||||
|
||||
export type VermissteDatei = {
|
||||
fileId: string; path: string; versionLabel: string | null;
|
||||
missingSince: string; libraryName: string;
|
||||
|
||||
@@ -1609,3 +1609,12 @@ body:has(.auswahlleiste:not(.hidden)) .hinweise { bottom: 104px; }
|
||||
font-size: 12px; color: var(--text-muted); flex: 1 1 auto;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Jede Datei eines mehrfach belegten Titels einzeln, mit einem Weg heraus. */
|
||||
.fassungstitel { padding: 4px 0; }
|
||||
.fassungsdatei {
|
||||
display: flex; align-items: center; gap: var(--s-snug);
|
||||
padding: 3px var(--s-snug) 3px 24px;
|
||||
}
|
||||
.fassungsdatei .oz-dazu { flex: 1 1 auto; }
|
||||
.btn.klein { padding: 4px 10px; font-size: 12px; flex: 0 0 auto; }
|
||||
|
||||
+68
-10
@@ -10,10 +10,11 @@ import {
|
||||
servernameSetzen, systemauskunft,
|
||||
laufendeWiedergaben, serverzustand, bildAdresse,
|
||||
speicherorte, bildspeicherLeeren, unzugeordnet, ohneZuordnung, mehrfachfassungen,
|
||||
dateiHerausloesen, type Mehrfachtitel,
|
||||
sprachverteilung, abweichendeAuffrischen,
|
||||
type Bibliothek, type Wiedergabe, ApiFehler,
|
||||
} from '../api';
|
||||
import { esc, dauer, groesse, knopf, fehlerzeile, leer, meldung } from '../util';
|
||||
import { esc, dauer, groesse, knopf, fehlerzeile, leer, meldung, hinweisZeigen } from '../util';
|
||||
import { dialog, nachfragen } from '../dialog';
|
||||
import { icon, icons } from '../icons';
|
||||
import { kontextmenue, menueAnZiel, type Menuepunkt } from '../menue';
|
||||
@@ -473,16 +474,12 @@ function ohneZuordnungBereich(): HTMLElement {
|
||||
}
|
||||
|
||||
if (mehrfach.gesamt > 0) {
|
||||
liste.appendChild(gruppe(
|
||||
liste.appendChild(fassungsgruppe(
|
||||
`${b.name} — ${anzahl(mehrfach.gesamt, 'Titel')} mit mehreren Dateien`,
|
||||
'Meist zwei Fassungen desselben Films. Stehen hier aber zwei '
|
||||
+ 'verschiedene Filme, lief einer von beiden auf den falschen Treffer — '
|
||||
+ 'dann hilft „Zuordnung korrigieren".',
|
||||
mehrfach.titel.map(t => ({
|
||||
titel: t.titel + (t.jahr ? ` (${t.jahr})` : ''),
|
||||
dazu: t.dateien.join(' · '),
|
||||
tun: () => bearbeiten(t.art === 'series' ? 'series' : 'movies', t.id, () => void laden()),
|
||||
}))));
|
||||
'Meist zwei Fassungen desselben Films — dann ist alles in Ordnung. '
|
||||
+ 'Stehen hier zwei verschiedene Filme, war einer davon nicht mehr zu '
|
||||
+ 'sehen: „Eigener Film" löst ihn wieder heraus.',
|
||||
mehrfach.titel));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -491,6 +488,67 @@ function ohneZuordnungBereich(): HTMLElement {
|
||||
return `${n} ${n === 1 ? wort : (wort === 'Datei' ? 'Dateien' : wort)}`;
|
||||
}
|
||||
|
||||
/** Dieselbe Gruppe, aber jede Datei einzeln mit einem Weg heraus. */
|
||||
function fassungsgruppe(
|
||||
ueberschrift: string, hinweis: string, titel: Mehrfachtitel[],
|
||||
): HTMLElement {
|
||||
const d = document.createElement('div');
|
||||
d.className = 'einstellung';
|
||||
|
||||
const kopf = document.createElement('div');
|
||||
kopf.className = 'zeile';
|
||||
kopf.innerHTML = `<strong>${esc(ueberschrift)}</strong>`
|
||||
+ `<span class="winzig">${esc(hinweis)}</span>`;
|
||||
d.appendChild(kopf);
|
||||
|
||||
const innen = document.createElement('div');
|
||||
innen.className = 'ohnezuordnung';
|
||||
|
||||
titel.forEach(t => {
|
||||
const zeile = document.createElement('div');
|
||||
zeile.className = 'fassungstitel';
|
||||
|
||||
const name = document.createElement('button');
|
||||
name.className = 'ohnezuordnung-zeile';
|
||||
name.innerHTML = `<span class="oz-titel">${esc(t.titel + (t.jahr ? ` (${t.jahr})` : ''))}</span>`;
|
||||
name.onclick = () => bearbeiten(
|
||||
t.art === 'series' ? 'series' : 'movies', t.id, () => void laden());
|
||||
zeile.appendChild(name);
|
||||
|
||||
t.dateien.forEach(f => {
|
||||
const d2 = document.createElement('div');
|
||||
d2.className = 'fassungsdatei';
|
||||
|
||||
const n = document.createElement('span');
|
||||
n.className = 'oz-dazu';
|
||||
n.textContent = f.name;
|
||||
|
||||
// **Nur bei mehr als einer Datei sinnvoll** — und mehr als eine ist
|
||||
// hier die Bedingung, überhaupt in der Liste zu stehen.
|
||||
const raus = knopf('Eigener Film', 'btn klein');
|
||||
raus.onclick = async () => {
|
||||
raus.disabled = true;
|
||||
try {
|
||||
const neu = await dateiHerausloesen(f.id);
|
||||
hinweisZeigen(`„${neu.title}" ist jetzt ein eigener Film — ohne Zuordnung.`);
|
||||
await laden();
|
||||
} catch (fehler) {
|
||||
hinweisZeigen(meldung(fehler), 'fehler');
|
||||
raus.disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
d2.append(n, raus);
|
||||
zeile.appendChild(d2);
|
||||
});
|
||||
|
||||
innen.appendChild(zeile);
|
||||
});
|
||||
|
||||
d.appendChild(innen);
|
||||
return d;
|
||||
}
|
||||
|
||||
function gruppe(
|
||||
ueberschrift: string, hinweis: string,
|
||||
zeilen: { titel: string; dazu: string; tun: () => void }[],
|
||||
|
||||
Reference in New Issue
Block a user