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 <[email protected]>
This commit is contained in:
2026-09-22 13:25:28 +02:00
co-authored by Claude Opus 5
parent 1a7d074e94
commit fe1dad48e5
45 changed files with 738 additions and 548 deletions
+46
View File
@@ -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();
+66 -4
View File
@@ -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})`);
+33 -3
View File
@@ -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 } : {}),
});