Instagram: Scraper raus, Beitraege einzeln ueber oEmbed aufnehmen

bin/instagram-sync.php lieferte seit dem 03.09.2026 bei jedem Lauf "Keine Posts
ermittelbar". Von einem privaten Anschluss gegengeprueft: feed/user und
web_profile_info antworten mit 401 require_login, das Profil-HTML traegt keine
Beitragsdaten mehr, auch /embed/ liefert nur noch eine App-Huelle. Es lag also
nicht an der Server-IP, und der Scraper ist geloescht, damit ihn niemand
wiederbelebt. Graph API (Meta-Konto noetig) und kommerzielle Dienste wurden
verworfen.

Neu: bin/instagram-add.php. --profil liest die Beitragsliste ueber headless
Chrome aus dem gerenderten Profil-DOM (im HTML stehen die Codes nicht) und holt
zu jedem neuen Beitrag Bild, Caption und Datum ueber Instagrams oEmbed-Endpunkt;
das Datum steckt in der media_id. Daneben einzelne URLs, --liste, --entfernen und
--bild als Notfall. Der Shortcode ist Primaerschluessel und damit die komplette
Dedupe-Logik. Die Struktur von data/instagram.json bleibt exakt gleich, deshalb
war an Startseite, News-Feed und Stadionzeitung nichts zu aendern.

Kein Cron mehr: der Job faellt aus public/cron.php, auf dem Webspace gibt es kein
Chrome. Die Chrome-Suche liegt jetzt gemeinsam in bin/chrome-lib.php, genutzt von
bin/logo-build.php und bin/instagram-add.php.

data/instagram.json ist ab jetzt versioniert. Solange sie ignoriert war, lief sie
gegen die versionierten Bilder auseinander: lokal lagen 10 Bilder zu 9 Eintraegen,
drei Beitraege fehlten im Feed, zwei Eintraege hatten kein Bild. Repariert, jetzt
16 Eintraege zu 16 Bildern. bin/preflight.php prueft das in beide Richtungen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J9mubC8gtpjtJntbhSJBRS
This commit is contained in:
2026-09-17 11:23:12 +02:00
parent 75fce4f680
commit fef80bf669
25 changed files with 753 additions and 357 deletions

View File

@@ -159,8 +159,10 @@ if ($phpPost <= $phpUpload) {
$warnings[] = "post_max_size ({$mb($phpPost)}) ist nicht größer als upload_max_filesize ({$mb($phpUpload)}) — Uploads am oberen Rand scheitern dann ohne Fehlermeldung.";
}
// --- Datenstände der Cron-Skripte (fehlen nur beim Erstlauf) ---
foreach (['instagram' => 'bin/instagram-sync.php', 'matchcenter' => 'bin/matchcenter-sync.php'] as $name => $script) {
// --- Datenstand des Cron-Skripts (fehlt nur beim Erstlauf) ---
// Nur noch matchcenter: data/instagram.json ist seit dem 17.09.2026 chat-gepflegt
// (bin/instagram-add.php) und nicht „alt“, nur weil eine Woche nichts passiert ist.
foreach (['matchcenter' => 'bin/matchcenter-sync.php'] as $name => $script) {
$file = DATA_PATH . '/' . $name . '.json';
if (!is_file($file)) {
$warnings[] = "data/{$name}.json fehlt — einmal \"php {$script}\" von Hand anstoßen.";
@@ -169,6 +171,29 @@ foreach (['instagram' => 'bin/instagram-sync.php', 'matchcenter' => 'bin/matchce
}
}
// --- Instagram: Einträge und Bilder müssen zusammenpassen ---
// Genau daran ist es am 17.09.2026 auseinandergelaufen: die Bilder waren versioniert,
// data/instagram.json nicht. Ein Eintrag ohne Bild ist auf der Startseite eine kaputte
// Kachel, ein Bild ohne Eintrag eine Leiche, die niemand mehr findet.
$igPosts = json_load('instagram')['posts'] ?? [];
$igFehlt = [];
foreach ($igPosts as $igPost) {
if (!empty($igPost['image']) && !is_file(PUBLIC_PATH . '/assets/' . $igPost['image'])) {
$igFehlt[] = $igPost['image'];
}
}
if ($igFehlt !== []) {
$errors[] = 'Instagram-Beiträge ohne Bild: ' . implode(', ', $igFehlt)
. '. Bild nachholen mit: php bin/instagram-add.php https://www.instagram.com/p/<shortcode>/';
}
$igCodes = array_column($igPosts, 'shortcode');
foreach (glob(PUBLIC_PATH . '/assets/img/instagram/*.jpg') ?: [] as $igDatei) {
if (!in_array(basename($igDatei, '.jpg'), $igCodes, true)) {
$warnings[] = 'Instagram-Bild ohne Eintrag im Feed: ' . basename($igDatei)
. ' — entweder aufnehmen oder löschen.';
}
}
// --- Termin-Quellen: events.json vs. veranstaltungen.json ---
// Ein Fest gehört in genau EINE der beiden Dateien (siehe CLAUDE.md): ohne
// eigene Seite in events.json, mit eigener Seite in veranstaltungen.json.