From fe1dad48e526101b0f3c31b8db75b557086d286a Mon Sep 17 00:00:00 2001 From: Dogfather Date: Tue, 22 Sep 2026 13:25:28 +0200 Subject: [PATCH] screen1: Wohin ein geholtes Video gelegt wird, darf man waehlen Filipe: "ich will das wenn man da video holt das man auch aussuchen kann in welcher account es unten angezeigt werden soll." Bis heute entschied allein der Link: kanalVonHandle liest den Account aus der TikTok-Adresse, und dort landete das Video. Das ist gut geraten, aber es IST geraten -- ein Ausschnitt vom Hauptkanal gehoert oft unter "Clips", und seit dem 21.09. hat jeder Account seine eigene Spalte, in der das sichtbar wird. DIE SCHRANKE BLEIBT UNANGETASTET. Der ABSENDER muss weiterhin einer der drei eigenen Kanaele sein; gewaehlt wird nur die SPALTE. Sonst waere aus einer Ablagehilfe ein Loch fuer fremde Inhalte geworden -- die Pruefung haelt genau das fest ("ein fremder Absender kommt auch MIT Wahl nicht herein", 403). Ohne Angabe bleibt alles wie bisher. Das ist der haeufigste Fall und soll keinen zusaetzlichen Handgriff kosten; die Vorgabe heisst "Aus dem Link erkennen". ZWEI FUNDE BEIM PRUEFEN - Die Antwort meldete `auskunft.kanal` -- also das ERKANNTE, nicht das, wohin der Eintrag wirklich ging. Seit beides auseinanderfallen kann, haette die Seite "DogFather" gemeldet, waehrend das Video unter "Clips" steht. - `coverAbrufe === 3` in pruef-video war eine Rechnung von dem Tag, an dem die Pruefung drei Videos anlegte. Der neue Abschnitt legte vier weitere an, und die Zeile wurde rot, ohne dass etwas kaputt war. Gemeint war nie eine Summe, sondern eine DIFFERENZ: holt derselbe Link ein zweites Mal? Das bleibt richtig, egal wie viele Videos davor liefen. Die Wahl steht UNTER der Zeile, nicht darin: Am 21.09. hat genau so ein drittes Element in derselben Reihe das Chat-Eingabefeld auf einen Buchstaben zusammengedrueckt. Am Bildschirm gemessen (1044 px). Gemessen: pruef-video 71/0 (vier neue Aussagen samt Gegenprobe, dass ohne Wahl weiterhin der Link entscheidet), pruef-highlights 31/0 (fuenf neue am echten Bildschirm), pruef-meldungen 8/0, pruef-teilen 27/0. Co-Authored-By: Claude Opus 5 --- server/pruef-highlights.mjs | 46 +++++++++++++++++++++ server/pruef-video.mjs | 70 ++++++++++++++++++++++++++++++-- server/workspace-video.js | 36 ++++++++++++++-- workspace/anruf-probe.html | 8 ++-- workspace/app.webmanifest | 8 ++-- workspace/assets/css/bereich.css | 15 +++++++ workspace/assets/js/bereich.js | 28 ++++++++++++- workspace/assets/js/meldung.js | 2 + workspace/aufgaben.html | 34 ++++++++-------- workspace/automation.html | 30 +++++++------- workspace/befinden.html | 28 ++++++------- workspace/bereich.html | 49 +++++++++++++--------- workspace/bewerben.html | 34 ++++++++-------- workspace/bewerbungen.html | 32 +++++++-------- workspace/calls.html | 32 +++++++-------- workspace/chat.html | 36 ++++++++-------- workspace/content.html | 32 +++++++-------- workspace/crew-index.html | 10 ++--- workspace/crew.webmanifest | 8 ++-- workspace/dateien.html | 32 +++++++-------- workspace/entwicklung.html | 28 ++++++------- workspace/hilfe.html | 26 ++++++------ workspace/index.html | 8 ++-- workspace/kalender.html | 32 +++++++-------- workspace/leistung.html | 30 +++++++------- workspace/material.html | 30 +++++++------- workspace/personen.html | 30 +++++++------- workspace/profil.html | 34 ++++++++-------- workspace/rechte.html | 28 ++++++------- workspace/report.html | 32 +++++++-------- workspace/scouting.html | 30 +++++++------- workspace/start.html | 30 +++++++------- workspace/startcheck.html | 32 +++++++-------- workspace/steckbrief.html | 34 ++++++++-------- workspace/talente.html | 30 +++++++------- workspace/team.html | 28 ++++++------- workspace/teamlage.html | 28 ++++++------- workspace/teilen.html | 26 ++++++------ workspace/treff-moderation.html | 28 ++++++------- workspace/treff-regeln.html | 28 ++++++------- workspace/uebersicht.html | 30 +++++++------- workspace/unsere-seiten.html | 26 ++++++------ workspace/werdegang.html | 28 ++++++------- workspace/willkommen.html | 28 ++++++------- workspace/wissen.html | 32 +++++++-------- 45 files changed, 738 insertions(+), 548 deletions(-) diff --git a/server/pruef-highlights.mjs b/server/pruef-highlights.mjs index 83f62b0d..7f23b7a0 100644 --- a/server/pruef-highlights.mjs +++ b/server/pruef-highlights.mjs @@ -258,6 +258,52 @@ try { ok(zuNachher.sagt === "false", ` und sagt es auch Vorleseprogrammen (aria-expanded=${zuNachher.sagt})`); + /* ===================================================================== + DIE ABLAGE LAESST SICH WAEHLEN (22.09.2026) + --------------------------------------------------------------------- + Filipe: „ich will das wenn man da video holt das man auch aussuchen + kann in welcher account es unten angezeigt werden soll." + + Geprueft wird am BILDSCHIRM, nicht im Quelltext: dass die Wahl da + ist, dass sie genau die Kanaele anbietet (plus „aus dem Link"), und + dass sie das Eingabefeld nicht quetscht. Das Letzte ist kein + Schoenheitspunkt -- am 21.09. hat genau so ein drittes Element in + derselben Reihe das Chat-Feld auf einen Buchstaben zusammengedrueckt. + ================================================================== */ + { + const { KANAELE } = await import("./workspace.js"); + const v = await s.evaluate(() => { + const w = document.getElementById("video-kanal"); + const feld = document.getElementById("video-url"); + const knopf = document.getElementById("video-holen"); + const r = (e) => (e ? e.getBoundingClientRect() : null); + const fr = r(feld), kr = r(knopf), wr = r(w); + return { + da: !!w, + werte: w ? [...w.options].map((o) => o.value) : [], + erste: w ? w.options[0]?.textContent.trim() : "", + vorgabe: w ? w.value : null, + feldBreite: fr ? Math.round(fr.width) : 0, + /* Steht die Wahl UNTER der Zeile, nicht darin? */ + unterhalb: wr && kr ? Math.round(wr.top) >= Math.round(kr.bottom) - 2 : false, + }; + }); + ok(v.da, "die Wahl fuer den Account steht da"); + /* DIE LISTE IST ABGELEITET, NICHT ABGESCHRIEBEN: sie muss genau die + Kanaele des Hauses anbieten, plus den leeren Eintrag. */ + const soll = ["", ...KANAELE.map((k) => k.wert)]; + ok(KANAELE.length >= 3 + && JSON.stringify(v.werte) === JSON.stringify(soll), + `sie bietet genau die ${KANAELE.length} Kanaele an, plus den leeren Eintrag ` + + `(${v.werte.join(", ")})`); + ok(v.vorgabe === "" && /Link/.test(v.erste), + `und steht auf: ${v.erste} — ohne Zutun bleibt alles wie bisher`); + ok(v.feldBreite > 400, + `das Eingabefeld bleibt breit (${v.feldBreite} px)`); + ok(v.unterhalb, + "die Wahl steht unter der Zeile, nicht darin"); + } + await ctx.close(); } finally { await browser.close(); diff --git a/server/pruef-video.mjs b/server/pruef-video.mjs index 25e60693..5bfb0fcf 100644 --- a/server/pruef-video.mjs +++ b/server/pruef-video.mjs @@ -159,9 +159,10 @@ const an = await fetch(BASIS + "/workspace/api/anmelden", { const keks = (an.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); const kopf = { "Content-Type": "application/json", cookie: keks, origin: BASIS }; -async function holen(url, bereich = "highlight") { +async function holen(url, bereich = "highlight", kanal = undefined) { const a = await fetch(`${BASIS}/workspace/api/bereich/${bereich}/video`, { - method: "POST", headers: kopf, body: JSON.stringify({ url }), + method: "POST", headers: kopf, + body: JSON.stringify(kanal === undefined ? { url } : { url, kanal }), }); return { status: a.status, daten: await a.json().catch(() => null) }; } @@ -247,6 +248,58 @@ melde("=== 3. Die drei Kanäle ==="); `drei verschiedene Kanäle in der Liste (${[...kanaele].join(", ")})`); } +/* ======================================================================= + 3b. WOHIN ES GELEGT WIRD, DARF MAN WAEHLEN (22.09.2026) + ----------------------------------------------------------------------- + Filipe: „ich will das wenn man da video holt das man auch aussuchen + kann in welcher account es unten angezeigt werden soll." + + Bis heute entschied allein der Link. Das ist gut geraten, aber es IST + geraten: Ein Ausschnitt vom Hauptkanal gehoert oft unter „Clips". + + DREI FRAGEN, und die dritte ist die wichtigste: + 1. Eine Wahl schlaegt das Erkannte. + 2. Ein erfundener Kanal wird abgelehnt. + 3. OHNE Wahl bleibt alles wie vorher -- sonst waere aus einer + Zugabe eine Verhaltensaenderung geworden, die niemand bestellt + hat. + ======================================================================= */ +melde(""); +melde("=== 3b. Die Ablage waehlen ==="); +{ + const { KANAELE } = await import("./workspace.js"); + const haupt = KANAELE.find((k) => k.wert === "dogfather"); + const anders = KANAELE.find((k) => k.wert !== "dogfather"); + + /* 1. Ein Video VOM Hauptkanal, abgelegt woanders. */ + const gewaehlt = await holen( + videoVon(haupt.handle.replace(/^@/, ""), "901"), "highlight", anders.wert); + ok(gewaehlt.status === 201 && gewaehlt.daten?.kanal === anders.wert, + `ein Video von ${haupt.handle} laesst sich unter „${anders.name}" ablegen ` + + `(${gewaehlt.status}, ${gewaehlt.daten?.kanal})`); + + /* 2. Ein erfundener Kanal. Ohne diese Zeile koennte jeder Text in + der Spalte landen -- und die Galerie zeigt ihn dann als Fach. */ + const erfunden = await holen( + videoVon(haupt.handle.replace(/^@/, ""), "902"), "highlight", "gibtsnicht"); + ok(erfunden.status === 400 && erfunden.daten?.fehler === "kanal_unbekannt", + `ein erfundener Kanal wird abgelehnt (${erfunden.status}, ${erfunden.daten?.fehler})`); + + /* 3. DIE GEGENPROBE. Ohne Wahl muss weiterhin der Link entscheiden -- + sonst waere die Zeile oben auch gruen, wenn die Erkennung + stillschweigend abgeschaltet worden waere. */ + const ohne = await holen(videoVon(haupt.handle.replace(/^@/, ""), "903")); + ok(ohne.status === 201 && ohne.daten?.kanal === "dogfather", + `ohne Wahl entscheidet weiterhin der Link (${ohne.status}, ${ohne.daten?.kanal})`); + + /* 4. UND DIE SCHRANKE BLEIBT. Eine Wahl darf kein Schluessel fuer + fremde Inhalte sein -- gewaehlt wird die Spalte, nicht, wer + hereindarf. */ + const fremd = await holen(videoVon("irgendwerfremd", "904"), "highlight", anders.wert); + ok(fremd.status === 403, + `ein fremder Absender kommt auch MIT Wahl nicht herein (${fremd.status})`); +} + /* ======================================================================= 4. WAS NICHT HINEINKOMMT ======================================================================= */ @@ -276,12 +329,21 @@ melde("=== 4. Die Gegenprobe ==="); /* DERSELBE LINK ZWEIMAL. Wer den Knopf zweimal drückt, meint nicht zwei Videos. */ + /* GEMESSEN WIRD DER UNTERSCHIED, NICHT DIE SUMME (berichtigt 22.09.2026). + Hier stand `coverAbrufe === 3` -- eine Rechnung von dem Tag, an dem + die Prüfung drei Videos anlegte. Am 22.09. kam ein Abschnitt dazu, + und die Zeile wurde rot, ohne dass irgendetwas kaputt war. + + Die Frage lautet nicht "wie viele Cover insgesamt", sondern + "holt derselbe Link ein zweites Mal?" -- das ist eine Differenz + und bleibt richtig, egal wie viele Videos davor liefen. */ + const coverVorher = coverAbrufe; const wieder = await holen(videoVon("dogfather0804")); ok(wieder.status === 200 && wieder.daten?.schon === true, `derselbe Link gibt denselben Eintrag zurück (${wieder.status}, schon=${wieder.daten?.schon})`); ok(wieder.daten?.id === eintragId, `und zwar wirklich denselben (${wieder.daten?.id})`); - ok(coverAbrufe === 3, - `und holt das Cover kein zweites Mal (${coverAbrufe} Abrufe für 3 Videos)`); + ok(coverAbrufe === coverVorher, + `und holt das Cover kein zweites Mal (${coverVorher} vor, ${coverAbrufe} nach dem zweiten Versuch)`); const nachher = (await liste()).length; ok(nachher === vorher, `kein Eintrag ist dazugekommen (${nachher} von ${vorher})`); diff --git a/server/workspace-video.js b/server/workspace-video.js index 9447b9f5..20cc3835 100644 --- a/server/workspace-video.js +++ b/server/workspace-video.js @@ -237,6 +237,30 @@ videoRouter.post("/workspace/api/bereich/:bereich/video", async (req, res) => { }); } + /* WOHIN ES GELEGT WIRD, DARF MAN WAEHLEN (22.09.2026). + =================================================================== + Filipe: „ich will das wenn man da video holt das man auch + aussuchen kann in welcher account es unten angezeigt werden soll." + + Bis heute entschied das allein der Link: `kanalVonHandle` liest + den Account aus der TikTok-Adresse, und dort landete das Video. + Das ist richtig geraten, aber es IST geraten -- ein Ausschnitt + vom Hauptkanal gehoert oft unter „Clips", und ein Video, das + jemand anders hochgeladen hat, steht dann in der falschen Spalte. + + Die Schranke darueber bleibt unangetastet: Der ABSENDER muss + weiterhin einer der drei eigenen Kanaele sein. Gewaehlt wird nur + die SPALTE, nicht, ob fremde Inhalte hereinduerfen -- sonst waere + aus einer Ablagehilfe ein Loch geworden. + + Ohne Angabe bleibt alles wie bisher. Das ist der haeufigste Fall + und soll keinen zusaetzlichen Handgriff kosten. */ + const gewaehlt = String(req.body?.kanal ?? "").trim(); + if (gewaehlt && !KANAELE.some((k) => k.wert === gewaehlt)) { + return res.status(400).json({ fehler: "kanal_unbekannt" }); + } + const ablage = gewaehlt || auskunft.kanal; + abgelegt = await coverAblegen(auskunft.cover); const jetzt = new Date().toISOString(); @@ -250,7 +274,7 @@ videoRouter.post("/workspace/api/bereich/:bereich/video", async (req, res) => { db().prepare(`UPDATE eintraege SET quelle_url = ?, quelle_kanal = ?, quelle_geholt_am = ?, geaendert = ? WHERE id = ?`) - .run(url, auskunft.kanal, jetzt, jetzt, anhaengenAn); + .run(url, ablage, jetzt, jetzt, anhaengenAn); eintragId = anhaengenAn; } else { const { lastInsertRowid } = db().prepare(` @@ -259,7 +283,7 @@ videoRouter.post("/workspace/api/bereich/:bereich/video", async (req, res) => { quelle_url, quelle_kanal, quelle_geholt_am, aus_eintrag_id) VALUES (?,?,?,?, 'offen', ?,?,?,?,?,?)`) .run(bereich, arten[bereich] || "clip", auskunft.titel, jetzt.slice(0, 10), - jetzt, req.person.id, url, auskunft.kanal, jetzt, ausQuelle ? aus : null); + jetzt, req.person.id, url, ablage, jetzt, ausQuelle ? aus : null); eintragId = Number(lastInsertRowid); } @@ -278,7 +302,13 @@ videoRouter.post("/workspace/api/bereich/:bereich/video", async (req, res) => { detail: `${auskunft.kanal} ${url}${ausQuelle ? ` (aus #${aus})` : ""}`.slice(0, 120), }); res.status(201).json({ - id: eintragId, schon: false, kanal: auskunft.kanal, + /* GEMELDET WIRD DIE ABLAGE, NICHT DAS ERKANNTE (22.09.2026). + Hier stand `auskunft.kanal` -- also das, was aus dem Link + gelesen wurde. Seit die Spalte waehlbar ist, sind das zwei + verschiedene Dinge, und die Antwort muss sagen, wo der Eintrag + wirklich gelandet ist. Sonst meldet die Seite "DogFather", + waehrend das Video unter "Clips" steht. */ + id: eintragId, schon: false, kanal: ablage, titel: auskunft.titel, cover: !!abgelegt || undefined, ...(ausQuelle ? { aus: aus, angehaengt: !!anhaengenAn } : {}), }); diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index d4a7e12b..dfba0cec 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,15 +16,15 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +