Ein Klick auf den Buchstabenkreis meldete ab. Keine Rückfrage, kein Menü, kein Weg zurück — hinter einer Geste, die überall sonst „mein Konto" heisst. Jetzt führt er auf `#/profil`; Abmelden steht dort als Knopf, mit Nachfrage. Auf der Seite: Bild wählen, tauschen, entfernen. Dazu „Meine Sprache" — **umgezogen, nicht kopiert.** Sie stand mitten in der Verwaltung, und die zeigt der Client nur Administratoren; der Endpunkt erlaubte sie längst jedem. Wer kein Admin war, konnte seine eigene Sprache nirgends ändern. Der Warnhinweis „weicht ab" bleibt in der Verwaltung, denn dort entsteht die Verwirrung — er verweist jetzt aufs Profil. **Vorher musste ein Fehler weg, der seit Monaten dasteht.** `ImageCache.StoreStreamAsync` baute den Schlüssel aus 32 Hexzeichen plus Dateiendung; `PfadFür` verlangt genau 64 Hexzeichen und nichts sonst. Es gab keinen Wert, den beide gelten liessen: **jeder Bildupload gab `null` zurück und endete in einem 502.** Kein Test fragte je danach — jetzt vier. Damit geht nebenbei auch „eigenes Bild hochladen" für Filme und Serien wieder. Weil der Schlüssel keine Endung mehr trägt, kommt der Medientyp beim Ausliefern aus den ersten Bytes der Datei. Vorher ging alles als `image/jpeg` hinaus — bei TMDB stimmte das, bei einem hochgeladenen PNG nicht. **Und die gemerkte Sitzung war eine Kopie, die nie nachzog.** Sie wurde bei der Anmeldung geschrieben und danach nie wieder. Wer sein Bild am Telefon setzt und den Browser am Schreibtisch öffnet, fand dort den alten Buchstaben — bis zum nächsten Anmelden. Gemessen und behoben: beim Hochfahren wird das Konto abgeglichen, und das Profil meldet Änderungen an die Kopfleiste, damit sie ohne Neuladen nachzieht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
178 lines
7.8 KiB
TypeScript
178 lines
7.8 KiB
TypeScript
import {
|
||
sprachen, uebersetzungenHolen, meineSprache, metadatenEinstellung,
|
||
metadatenSetzen, sprachverteilung, abweichendeAuffrischen,
|
||
} from '../../api';
|
||
import { knopf, fehlerzeile, meldung } from '../../util';
|
||
import { dialog } from '../../dialog';
|
||
|
||
import { abschnitt, zeile } from './teile';
|
||
|
||
/** Sprache und Herkunft der Metadaten. */
|
||
|
||
/* ---------- Server ---------- */
|
||
|
||
/** Sprache — eigener Abschnitt, ganz oben.
|
||
*
|
||
* **Warum nicht in der Serverliste.** Dort stand sie, zwischen „Name",
|
||
* „Metadaten", „Doppelte Einträge" und „Fassung". Gesucht wurde sie
|
||
* trotzdem, gefunden nicht — und das ist die Antwort: eine Einstellung, die
|
||
* man sucht und nicht findet, steht am falschen Platz, egal wie gut sie
|
||
* beschriftet ist.
|
||
*
|
||
* **Oben, weil sie alles andere färbt.** In dieser Sprache werden Metadaten
|
||
* geholt und gespeichert; wer sie spät umstellt, frischt den ganzen Bestand
|
||
* noch einmal auf.
|
||
*/
|
||
export function sprachbereich(): HTMLElement {
|
||
const bereich = document.createElement('section');
|
||
bereich.appendChild(abschnitt('Sprache'));
|
||
|
||
const liste = document.createElement('div');
|
||
liste.className = 'einstellungen';
|
||
bereich.appendChild(liste);
|
||
|
||
void (async () => {
|
||
try {
|
||
const stand = await metadatenEinstellung();
|
||
const eigeneSprache = meineSprache();
|
||
liste.innerHTML = '';
|
||
// **Die Sprache des Servers als eigene Zeile.**
|
||
//
|
||
// Sie steckte im Dialog „Metadaten" — zusammen mit dem TMDB-Schlüssel,
|
||
// also dort, wo niemand nach einer Sprache sucht. Wer die Mediathek auf
|
||
// Englisch vorfand, sah nur „Meine Sprache" und hielt das für die
|
||
// einzige Möglichkeit.
|
||
liste.appendChild(zeile(
|
||
'Sprache des Servers',
|
||
sprachen.find(x => x.wert === stand.language)?.text ?? stand.language,
|
||
'In dieser Sprache werden Titel und Beschreibungen geholt, und sie '
|
||
+ 'bestimmt die Altersfreigabe. Gilt für alle. Vorhandene Titel behalten '
|
||
+ 'ihre alte Sprache — dafür gibt es bei jeder Mediathek „Metadaten '
|
||
+ 'auffrischen".',
|
||
() => dialog({
|
||
titel: 'Sprache des Servers',
|
||
text: 'Die Umstellung wirkt auf neue Funde sofort. Für den vorhandenen '
|
||
+ 'Bestand drückst du danach bei jeder Mediathek „Metadaten auffrischen" '
|
||
+ '— sonst behalten die Titel ihre alte Sprache.',
|
||
felder: [{
|
||
name: 'sprache', beschriftung: 'Sprache', auswahl: sprachen, wert: stand.language,
|
||
}],
|
||
bestaetigen: 'Übernehmen',
|
||
tun: async wert => {
|
||
await metadatenSetzen({ language: wert('sprache') });
|
||
location.reload();
|
||
},
|
||
})));
|
||
|
||
// **Die eigene Sprache, getrennt von der des Servers.** Die obere
|
||
// bestimmt, was geholt wird; diese nur, was man selbst zu sehen bekommt.
|
||
// **Was tatsächlich vorliegt — nicht was eingestellt ist.**
|
||
//
|
||
// Der eigentliche Fehler war nicht, dass Titel englisch blieben, sondern
|
||
// dass sich nicht feststellen liess, ob sie es sind: nirgends stand, in
|
||
// welcher Sprache ein Titel geholt wurde. Hier steht es, als Zahl.
|
||
void sprachverteilung().then(v => {
|
||
const benennen = (k: string | null) => k === null
|
||
? 'unbekannt (vor dieser Fassung geholt)'
|
||
: sprachen.find(x => x.wert === k)?.text ?? k;
|
||
|
||
const zeileBestand = zeile(
|
||
'Bestand',
|
||
v.anteile.length === 0
|
||
? 'Noch nichts zugeordnet'
|
||
: v.anteile.map(a => `${a.anzahl} × ${benennen(a.sprache)}`).join(' · '),
|
||
v.abweichend === 0
|
||
? 'Alles liegt in der Serversprache vor.'
|
||
: `${v.abweichend} Titel liegen in einer anderen Sprache vor. Das Auffrischen `
|
||
+ 'holt genau diese neu — nicht den ganzen Bestand.');
|
||
|
||
if (v.abweichend > 0) {
|
||
const los = knopf(`${v.abweichend} auffrischen`, 'btn btn-primary');
|
||
los.onclick = async () => {
|
||
los.disabled = true;
|
||
try {
|
||
await abweichendeAuffrischen();
|
||
los.textContent = 'Läuft…';
|
||
} catch (fehler) {
|
||
zeileBestand.appendChild(fehlerzeile(meldung(fehler)));
|
||
los.disabled = false;
|
||
}
|
||
};
|
||
zeileBestand.querySelector('.knopfreihe')?.appendChild(los);
|
||
}
|
||
|
||
// Direkt unter die Serversprache, denn dort wird die Frage gestellt.
|
||
liste.insertBefore(zeileBestand, liste.children[1] ?? null);
|
||
}).catch(() => { /* Ohne Verteilung fehlt nur die Zeile. */ });
|
||
|
||
// **Weicht sie ab, steht das deutlich dabei.**
|
||
//
|
||
// Eine eigene Sprache ändert nicht, was der Server holt — nur was man
|
||
// selbst sieht. Steht sie auf Englisch, während der Server auf Deutsch
|
||
// holt, sieht die ganze Mediathek englisch aus, und jedes „Metadaten
|
||
// auffrischen" scheint wirkungslos. Genau in diese Falle läuft man,
|
||
// ohne je zu erfahren, warum.
|
||
const weichtAb = eigeneSprache !== null && eigeneSprache !== stand.language;
|
||
const serversprache = sprachen.find(x => x.wert === stand.language)?.text ?? stand.language;
|
||
|
||
// **Geändert wird sie im Profil, nicht hier.**
|
||
//
|
||
// Sie gehört einem Menschen, nicht dem Server — und sie stand in einem
|
||
// Bereich, den der Client nur Administratoren zeigt. Wer kein Admin war,
|
||
// konnte seine eigene Sprache nirgends umstellen, obwohl der Endpunkt es
|
||
// längst erlaubte.
|
||
//
|
||
// Der Hinweis bleibt trotzdem hier: Die Verwirrung entsteht an dieser
|
||
// Stelle. Wer die Mediathek englisch vorfindet und hier die Serversprache
|
||
// auf Deutsch stehen sieht, sucht den Fehler sonst beim Auffrischen.
|
||
if (weichtAb) {
|
||
liste.appendChild(zeile(
|
||
'Deine Sprache weicht ab',
|
||
sprachen.find(x => x.wert === eigeneSprache)?.text ?? eigeneSprache!,
|
||
`Du siehst alles auf ${sprachen.find(x => x.wert === eigeneSprache)?.text ?? eigeneSprache}, `
|
||
+ `obwohl der Server auf ${serversprache} holt. Titel ohne Übersetzung bleiben `
|
||
+ `auf ${serversprache}. Umstellen kannst du das in deinem Profil.`,
|
||
() => { location.hash = '#/profil'; }));
|
||
}
|
||
|
||
liste.appendChild(zeile(
|
||
'Übersetzungen holen',
|
||
`Füllt eine zweite Sprache neben ${serversprache} auf`,
|
||
`Der Bestand liegt auf ${serversprache} vor. Das hier legt zusätzlich `
|
||
+ 'eine zweite Fassung an, für Benutzer, die eine andere Sprache gewählt '
|
||
+ 'haben — am Bestand selbst ändert es nichts. Kostet je Titel eine '
|
||
+ 'Anfrage an TMDB.',
|
||
() => dialog({
|
||
titel: 'Übersetzungen holen',
|
||
text: `Die Titel des Servers bleiben auf ${serversprache}. Geholt wird `
|
||
+ 'eine zusätzliche Fassung, die nur Benutzer mit genau dieser Sprache '
|
||
+ 'zu sehen bekommen.',
|
||
felder: [{
|
||
name: 'sprache', beschriftung: 'Für welche Sprache',
|
||
// **Nicht stur en-US.** Stand dort „Englisch", während der Server
|
||
// auf Deutsch steht, las sich das wie eine Aussage über den
|
||
// Server — und führte zu der Vermutung, die Spracheinstellung
|
||
// wirke nicht. Vorgewählt wird die eigene Sprache, sonst die
|
||
// erste, die nicht schon die des Servers ist.
|
||
auswahl: sprachen,
|
||
wert: eigeneSprache
|
||
?? sprachen.find(x => x.wert !== stand.language)?.wert
|
||
?? stand.language,
|
||
}],
|
||
bestaetigen: 'Holen',
|
||
tun: async wert => {
|
||
const bericht = await uebersetzungenHolen(wert('sprache'));
|
||
alert(`${bericht.gesamt} Übersetzungen geholt, ${bericht.fehlend} ohne Treffer.`);
|
||
},
|
||
})));
|
||
} catch (fehler) {
|
||
liste.innerHTML = '';
|
||
liste.appendChild(fehlerzeile(meldung(fehler)));
|
||
}
|
||
})();
|
||
|
||
return bereich;
|
||
|
||
}
|
||
|