Der Publikumswert steht auf der Seite, also wird er von dort gelesen
OMDb führt im Feld `Ratings` nur eine Zahl je Dienst, und bei Rotten
Tomatoes ist das die der Kritik. Die erweiterten Felder gibt es, sie
stehen aber seit Jahren auf `N/A`; Jellyfin fragt sie an und liest sie
nicht einmal aus — deren Antwortklasse kennt `tomatoUserMeter` gar nicht.
Dort hat den Publikumswert also niemand.
Auf der Seite selbst steht er. Gemessen an `/m/the_matrix`: im Quelltext
liegt `"audienceScore":{… "score":"85" …}` neben `"criticsScore"`, dazu
ein `application/ld+json` mit Titel und Erscheinungsdatum; bei Serien
unter `/tv/…` dasselbe, und ein unbekannter Weg antwortet mit 404. Eine
Prüfung mit `[Explicit]` geht einmal wirklich hinaus und bestätigt es:
`rottenTomatoes 83%, rottenTomatoesAudience 85%`.
Das ist Auslesen einer fremden Webseite, und es hat seinen Preis. Eine
offene Suche gibt es nicht — `/napi/search` antwortet mit 401 —, also
wird der Weg aus dem Titel geraten und hinterher am Jahr geprüft: auf der
Seite steht keine IMDb-Kennung, und `/m/the_lion_king` ist der von 1994.
Weicht das Jahr um mehr als eines ab, wird verworfen; lieber keine Zahl
als die eines fremden Films. Der Originaltitel kommt zuerst dran, sonst
fände ein deutscher Bestand dort fast nichts. Ohne Jahr zuerst, weil der
Normalfall den blanken Namen trägt — mit Jahr zuerst kostete jeder Titel
eine Anfrage zu viel.
Deshalb ein Schalter, und der steht aus, bis jemand ihn umlegt. Dazu eine
Bremse: höchstens eine Anfrage je Sekunde, prozessweit. Achthundert Titel
in einem Schwall von einer Adresse wären eine Zumutung und würden
gesperrt. Der Scan dauert dadurch länger; das ist der Preis fürs
Mitbenutzen.
Die Probe unter Einstellungen → Metadaten fragt die Quelle mit, und dort
ist sie mehr als eine Höflichkeit: wird die Seite umgebaut, merkt man es
genau da und sonst nirgends.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e05bbfc2cd
commit
8397e042b8
@@ -89,11 +89,26 @@ export function sprachbereich(): HTMLElement {
|
||||
tmdb: stand.hasApiKey || stand.usingProjectKey,
|
||||
fanart: stand.hasFanartKey,
|
||||
omdb: stand.hasOmdbKey,
|
||||
rottenTomatoes: stand.rottenTomatoes,
|
||||
};
|
||||
|
||||
quellenliste.innerHTML = '';
|
||||
|
||||
QUELLEN.forEach(q => {
|
||||
// **Ein Schalter, kein Schlüsselfeld.** Ein Dialog mit einem leeren
|
||||
// Eingabefeld fragte nach etwas, das es dort nicht zu holen gibt.
|
||||
if (q.schalter) {
|
||||
const an = hinterlegt[q.kennung];
|
||||
quellenliste.appendChild(zeile(
|
||||
q.name, an ? 'Eingeschaltet' : 'Ausgeschaltet', `${q.was} ${q.hinweis}`,
|
||||
async () => {
|
||||
await metadatenSetzen({ rottenTomatoes: !an });
|
||||
await quellenLaden();
|
||||
},
|
||||
an ? 'Ausschalten' : 'Einschalten'));
|
||||
return;
|
||||
}
|
||||
|
||||
const wert = q.kennung === 'tmdb' && stand!.usingProjectKey
|
||||
? 'Mitgelieferter Zugang'
|
||||
: hinterlegt[q.kennung] ? 'Eigener Zugang hinterlegt' : 'Nicht eingerichtet';
|
||||
@@ -101,7 +116,7 @@ export function sprachbereich(): HTMLElement {
|
||||
quellenliste.appendChild(zeile(q.name, wert, q.was, () => dialog({
|
||||
titel: q.name,
|
||||
felder: [{
|
||||
name: 'schluessel', beschriftung: q.feld, art: 'password',
|
||||
name: 'schluessel', beschriftung: q.feld ?? 'Schlüssel', art: 'password',
|
||||
platzhalter: hinterlegt[q.kennung] ? 'Hinterlegt — leer lassen, um ihn zu behalten' : '',
|
||||
hinweis: q.hinweis,
|
||||
}],
|
||||
@@ -271,8 +286,19 @@ export function sprachbereich(): HTMLElement {
|
||||
|
||||
/* ---------- Die Quellen ---------- */
|
||||
|
||||
type Quellenangabe = {
|
||||
kennung: 'tmdb' | 'fanart' | 'omdb' | 'rottenTomatoes';
|
||||
name: string;
|
||||
was: string;
|
||||
hinweis: string;
|
||||
/** Die Beschriftung des Schlüsselfeldes — fehlt bei einer, die keinen hat. */
|
||||
feld?: string;
|
||||
/** Kein Schlüssel, sondern an oder aus. */
|
||||
schalter?: boolean;
|
||||
};
|
||||
|
||||
/** Was jede Quelle liefert und was sie dafür braucht. */
|
||||
const QUELLEN = [
|
||||
const QUELLEN: Quellenangabe[] = [
|
||||
{
|
||||
kennung: 'tmdb' as const,
|
||||
name: 'TMDB',
|
||||
@@ -295,4 +321,15 @@ const QUELLEN = [
|
||||
feld: 'Persönlicher API-Schlüssel',
|
||||
hinweis: 'Kostenlos bis tausend Abrufe am Tag — deshalb kein mitgelieferter.',
|
||||
},
|
||||
{
|
||||
kennung: 'rottenTomatoes' as const,
|
||||
name: 'Rotten Tomatoes',
|
||||
was: 'Beide Werte: die Wertung der Kritik und die des Publikums. '
|
||||
+ 'OMDb gibt nur die der Kritik weiter.',
|
||||
schalter: true,
|
||||
hinweis: 'Dort gibt es keine Zugänge zu vergeben — die Zahlen stehen nur auf der Seite '
|
||||
+ 'selbst und werden von dort gelesen. Das geschieht ohne Einverständnis des Betreibers '
|
||||
+ 'und hört auf zu wirken, sobald die Seite umgebaut wird. Deshalb ist es ausgeschaltet, '
|
||||
+ 'bis du es einschaltest.',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -30,6 +30,10 @@ export function abschnitt(titel: string, knoepfe: HTMLElement[] = []): HTMLEleme
|
||||
*/
|
||||
export function zeile(
|
||||
name: string, wert: string, hinweis: string | null, bearbeiten?: () => void,
|
||||
/** Steht auf dem Knopf. **Ein Stift gehört nur auf „Ändern".** Ein Schalter
|
||||
* ändert nichts, er schaltet um; das Zeichen soll nicht etwas anderes
|
||||
* versprechen als der Text daneben. */
|
||||
knopftext?: string,
|
||||
): HTMLElement {
|
||||
const d = document.createElement('div');
|
||||
d.className = 'einstellung';
|
||||
@@ -43,8 +47,8 @@ export function zeile(
|
||||
oben.appendChild(text);
|
||||
|
||||
if (bearbeiten) {
|
||||
const b = knopf('Ändern', 'btn');
|
||||
b.prepend(icon('stift'));
|
||||
const b = knopf(knopftext ?? 'Ändern', 'btn');
|
||||
if (!knopftext) b.prepend(icon('stift'));
|
||||
b.onclick = bearbeiten;
|
||||
oben.appendChild(b);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user