Videos: Stufe 5 -- fuehrt der Knopf noch irgendwohin?
Ein Video kann bei TikTok geloescht oder auf privat gestellt werden.
Bei uns blieb der Eintrag stehen -- mit Cover, Text und einem Knopf
auf eine Fehlerseite. Das faellt beim Bauen nicht auf und beim Testen
nicht; es faellt dem auf, der klickt, und das ist die Community.
DREI ANTWORTEN, NICHT ZWEI. Die naheliegende Fassung fragt TikTok und
setzt bei einem Fehlschlag "weg". Die waere an einem einzigen
schlechten Nachmittag von TikTok in der Lage, die halbe Galerie als
geloescht zu markieren -- und wer das hinterher sucht, sucht lange,
denn im Protokoll stuende sauber, dass gefragt wurde. Also:
Daten kommen an -> da. Zaehler zurueck, eine frueher gesetzte
Markierung faellt weg (privat gestellte
Videos kommen wieder).
"gibt es nicht" (404) -> ein Fehlversuch. Erst der DRITTE an drei
verschiedenen Tagen markiert.
niemand antwortet -> weiss nicht. Aendert gar nichts, nicht
einmal den Zeitstempel: Wer ihn setzte,
verschoebe die naechste Nachfrage um sieben
Tage, obwohl nichts gemessen wurde.
Drei Geschwindigkeiten beim Nachsehen: unauffaellig woechentlich,
verdaechtig taeglich (sonst dauerte eine Loeschung drei Wochen bis zur
Anzeige), schon markiert wieder woechentlich -- taeglich nachzufragen
waere Hammern fuer eine Auskunft, die wir schon haben. Gefunden hat
das eine rote Pruefung, nicht das Nachdenken davor.
Der Knopf verschwindet nicht, er sagt "Bei TikTok nicht mehr da".
Bewusst kein Rot: Es ist kein Fehler, sondern eine Auskunft -- Titel,
Text und Cover stimmen weiter, die liegen bei uns.
Geprueft: pruef-video 37 -> 51. Gegenprobe (Stoerung als "weg" werten
plus Markieren ab dem ersten Versuch) macht 8 rot, darunter woertlich
"eine Stoerung erhoeht den Zaehler NICHT (0 -> 1)".
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -63,6 +63,10 @@ const PNG = Buffer.from(
|
||||
"base64");
|
||||
let coverAbrufe = 0;
|
||||
let oembedAbrufe = 0;
|
||||
/* Welche Videos gerade „geloescht" sind und welche „stoeren".
|
||||
Zwei getrennte Mengen, weil es zwei getrennte Faelle sind. */
|
||||
const verschwunden = new Set();
|
||||
const stoerung = new Set();
|
||||
const coverAdresse = (was) => `http://127.0.0.1:${TIKTOK}/${was}`
|
||||
+ `?x-expires=${Math.floor(Date.now() / 1000) + 172800}&x-signature=abc`;
|
||||
|
||||
@@ -75,6 +79,11 @@ const tiktok = createServer((q, a) => {
|
||||
Dienst ist es genauso. */
|
||||
const wer = (ziel.match(/@([^/?]+)/) || [])[1] || "";
|
||||
if (!wer) { a.writeHead(404); a.end("{}"); return; }
|
||||
/* UMSCHALTBAR FUER DIE WACHE (Abschnitt 5b): Ein Video kann
|
||||
verschwinden und wiederkommen, und TikTok kann stoeren. Beides
|
||||
sind verschiedene Dinge, und genau das muss messbar sein. */
|
||||
if (verschwunden.has(ziel)) { a.writeHead(404); a.end("{}"); return; }
|
||||
if (stoerung.has(ziel)) { a.writeHead(503); a.end("{}"); return; }
|
||||
/* Welches Cover? Am Videonamen. So lassen sich die Sonderfälle
|
||||
auslösen, ohne den Dienst umzubauen. */
|
||||
let bild = coverAdresse("cover.jpg");
|
||||
@@ -303,6 +312,115 @@ melde("=== 5. Die Byteprüfung ===");
|
||||
ok(b.status === 201, `ein Video ohne Coverbild geht auch (${b.status})`);
|
||||
}
|
||||
|
||||
/* =======================================================================
|
||||
5b. FUEHRT DER KNOPF NOCH IRGENDWOHIN? (Stufe 5)
|
||||
|
||||
Der wichtigste Satz dieses Abschnitts ist nicht „geloeschte Videos
|
||||
werden erkannt", sondern: EINE STOERUNG BEI TIKTOK AENDERT NICHTS.
|
||||
Die naheliegende Fassung setzt bei jedem misslungenen Abruf „weg" --
|
||||
und markiert an einem schlechten Nachmittag die halbe Galerie als
|
||||
geloescht. Wer das hinterher sucht, sucht lange, denn im Protokoll
|
||||
steht dann sauber, dass TikTok gefragt wurde.
|
||||
======================================================================= */
|
||||
melde("");
|
||||
melde("=== 5b. Wenn ein Video bei TikTok verschwindet ===");
|
||||
{
|
||||
const video = await import("./workspace-video.js");
|
||||
const db2 = new DatabaseSync(process.env.WORKSPACE_DB);
|
||||
const nimm = (id) => db2.prepare(
|
||||
"SELECT quelle_geprueft_am, quelle_fehlt_seit,"
|
||||
+ " COALESCE(quelle_fehlversuche,0) AS fehl FROM eintraege WHERE id = ?").get(id);
|
||||
/* Stellt den naechsten Tag dar. Die Wache sieht verdaechtige Videos
|
||||
TAEGLICH nach -- ohne Zurueckdatieren waeren alle drei Laeufe am
|
||||
selben Tag, und nur der erste taete etwas. Genau so ist es
|
||||
gewollt; die Pruefung muss deshalb die Uhr weiterstellen, nicht
|
||||
die Regel umgehen. */
|
||||
const morgen = (id, stunden = 36) => db2.prepare(
|
||||
"UPDATE eintraege SET quelle_geprueft_am = ? WHERE id = ?")
|
||||
.run(new Date(Date.now() - stunden * 3600_000).toISOString(), id);
|
||||
|
||||
/* Derselbe Account wie in Abschnitt 1 -- ein ERFUNDENER wird von der
|
||||
Route zu Recht abgewiesen, und die Pruefung haette dann gemessen,
|
||||
dass sie sich selbst vertippt hat. */
|
||||
const adresse = videoVon("dogfather0804", "5b1");
|
||||
const ein = await holen(adresse);
|
||||
const id5b = ein.daten?.id;
|
||||
ok(ein.status === 201 && !!id5b, `ein Video zum Beobachten ist da (#${id5b})`);
|
||||
|
||||
/* ---- Die drei Antworten einzeln ---------------------------------- */
|
||||
ok((await video.videoNochDa(adresse)).da === true,
|
||||
"ein vorhandenes Video meldet: da");
|
||||
stoerung.add(adresse);
|
||||
const beiStoerung = await video.videoNochDa(adresse);
|
||||
ok(beiStoerung.da === null,
|
||||
`eine Stoerung meldet WEISS NICHT, nicht „weg" (${beiStoerung.grund})`);
|
||||
stoerung.delete(adresse);
|
||||
verschwunden.add(adresse);
|
||||
const beiWeg = await video.videoNochDa(adresse);
|
||||
ok(beiWeg.da === false, `ein geloeschtes meldet: weg (${beiWeg.grund})`);
|
||||
|
||||
/* ---- Ein einzelner Fehlversuch markiert NICHT --------------------- */
|
||||
const l1 = await video.videoWacheLauf();
|
||||
const n1 = nimm(id5b);
|
||||
ok(n1.fehl === 1 && !n1.quelle_fehlt_seit,
|
||||
`nach dem ersten Fehlversuch ist es noch NICHT „weg" (Zaehler ${n1.fehl})`);
|
||||
|
||||
morgen(id5b);
|
||||
await video.videoWacheLauf();
|
||||
const n2 = nimm(id5b);
|
||||
ok(n2.fehl === 2 && !n2.quelle_fehlt_seit,
|
||||
`nach dem zweiten auch nicht (Zaehler ${n2.fehl})`);
|
||||
|
||||
morgen(id5b);
|
||||
const l3 = await video.videoWacheLauf();
|
||||
const n3 = nimm(id5b);
|
||||
ok(n3.fehl === 3 && !!n3.quelle_fehlt_seit,
|
||||
`erst der dritte markiert es (Zaehler ${n3.fehl}, seit ${String(n3.quelle_fehlt_seit).slice(0, 10)})`);
|
||||
ok(l3.weg === 1, `und der Lauf sagt es auch (weg: ${l3.weg})`);
|
||||
|
||||
/* ---- Die Oberflaeche erfaehrt davon ------------------------------- */
|
||||
const e5b = (await liste()).find((x) => x.id === id5b);
|
||||
ok(!!e5b?.quelle_fehlt_seit,
|
||||
"die Liste liefert den Zustand mit -- sonst zeigte die Kachel weiter den Knopf");
|
||||
|
||||
/* ---- DER KERN: eine Stoerung aendert NICHTS ----------------------- */
|
||||
verschwunden.delete(adresse);
|
||||
/* ACHT TAGE, nicht 36 Stunden: Ein bereits markiertes Video wird
|
||||
absichtlich nur noch woechentlich nachgefragt (siehe die drei
|
||||
Geschwindigkeiten in workspace-video.js). Die Pruefung muss die
|
||||
echte Regel abbilden, nicht die bequemere. */
|
||||
morgen(id5b, 8 * 24);
|
||||
await video.videoWacheLauf(); /* wieder da -> Zaehler zurueck */
|
||||
const zurueck = nimm(id5b);
|
||||
ok(zurueck.fehl === 0 && !zurueck.quelle_fehlt_seit,
|
||||
"kommt es zurueck (privat gestellt und wieder oeffentlich), faellt die Markierung weg");
|
||||
|
||||
/* Ebenfalls acht Tage: Nach der Rueckkehr steht der Zaehler auf
|
||||
null, das Video gilt also wieder als unauffaellig -- und
|
||||
unauffaellige werden nur woechentlich gefragt. */
|
||||
morgen(id5b, 8 * 24);
|
||||
stoerung.add(adresse);
|
||||
const vorher5b = nimm(id5b);
|
||||
const lS = await video.videoWacheLauf();
|
||||
const nachher5b = nimm(id5b);
|
||||
stoerung.delete(adresse);
|
||||
ok(nachher5b.fehl === vorher5b.fehl && !nachher5b.quelle_fehlt_seit,
|
||||
`eine Stoerung erhoeht den Zaehler NICHT (${vorher5b.fehl} -> ${nachher5b.fehl})`);
|
||||
ok(nachher5b.quelle_geprueft_am === vorher5b.quelle_geprueft_am,
|
||||
"und verschiebt auch den Zeitpunkt nicht -- sonst waere sieben Tage Ruhe,"
|
||||
+ " obwohl nichts gemessen wurde");
|
||||
ok(lS.unklar >= 1 && lS.geprueft === 0,
|
||||
`der Lauf zaehlt sie als „weiss nicht" (unklar ${lS.unklar}, geprueft ${lS.geprueft})`);
|
||||
|
||||
/* ---- Und ein gesundes Video bleibt unberuehrt --------------------- */
|
||||
const heil = (await liste()).find((x) => x.id === eintragId);
|
||||
ok(!heil?.quelle_fehlt_seit,
|
||||
"ein Video, das es noch gibt, wird nicht angefasst");
|
||||
|
||||
db2.close();
|
||||
void l1;
|
||||
}
|
||||
|
||||
/* =======================================================================
|
||||
6. UND ES ÜBERLEBT, WENN TIKTOK WEG IST ← der eigentliche Punkt
|
||||
======================================================================= */
|
||||
|
||||
Reference in New Issue
Block a user