Communitygithub.com

RaganaBloodedge/read-video-skill

Liest Videoinhalte aus Remote-Quellen, ohne das gesamte Video herunterzuladen. Unterstützt 1700+ Websites (Bilibili mit eigenem Adapter, andere über yt-dlp-Backend) und direkte Videolinks.

Was ist read-video-skill?

Diese Fähigkeit ermöglicht es einem KI-Agenten, selektiv Byte-Bereiche aus einem entfernten Video abzurufen, anstatt die gesamte Datei herunterzuladen. Sie löst das Problem, dass Benutzer oft nur eine kurze Szene oder Zusammenfassung eines Videos sehen möchten, ohne aufwändige Downloads. Die Fähigkeit erkennt automatisch, ob eine URL ein direkter Medien-Link oder eine Webseite (z. B. YouTube, Bilibili, TikTok) ist und extrahiert die erforderlichen Sign-URLs und Header. Nach einer HTTP-Range-Unterstützungsprüfung sucht sie mit FFmpeg eine exakte Position (input-seitiges `-ss`) und ruft nur die benötigten Daten (Einzelbild, Audiosegment) ab. Das Audio wird lokal mit SenseVoice offline transkribiert, und die Frames werden an ein Vision-Modell zur inhaltlichen Analyse übergeben. Nützlich für Antworten auf Fragen wie „Was passiert in diesem Video?“, „Was ist auf dem Bild bei Minute 5?“ oder für die Überprüfung, ob eine URL Range Requests unterstützt.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add RaganaBloodedge/read-video-skill

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

read-video – Video byteweise nach Bedarf lesen

Welches Problem löst diese Fähigkeit?

Ein Nutzer schickt einen Videolink und möchte den Inhalt verstehen. Der naive Ansatz ist, das gesamte Video herunterzuladen – langsam, speicherintensiv, urheberrechtlich bedenklich und meist nur für ein paar Sekunden nötig. Diese Fähigkeit geht anders vor: Sie ruft nur die Bytes ab, die in der Nähe des gewünschten Zeitpunkts liegen. Die Audiospur wird lokal offline in Text umgewandelt (Hauptmethode für „Worum geht es?“), und die Videospur gibt Schlüsselbilder an ein Vision-Modell weiter, um den visuellen Kontext zu liefern.

Tests mit einer 249 MB / 9 Min 56 Sek MP4 (nicht faststart):

AktionAbgerufene BytesAnteil am gesamten Video
Bild bei 30 Sek2,0 MB0,839 %
Bild bei 8 Min1,7 MB0,707 %
Audio ab 480 s für 20 Sek6,6 MB2,784 %

Wann verwenden / wann nicht

Verwenden: Der Benutzer gibt einen direkten Videolink oder einen Weblink mit Video (Plattformen wie Bilibili werden automatisch von resolve.py analysiert – kein manueller API-Aufruf nötig). Nicht verwenden: Lokale Dateien (direkt lesen), lange Videos, die vollständig verstanden werden müssen (Kosten zu hoch – zuerst nach Zeitpunkten fragen).

Harte Prinzipien

  1. Kein vollständiger Download. Kein Schritt darf wget/curl -O für die gesamte Datei verwenden.
  2. Erst prüfen, dann handeln. Ohne Prüfung zu seeken, wartet man auf einem Server ohne Range-Unterstützung vergeblich.
  3. -ss muss vor -i stehen. Dahinter ist Output-Seeking und entspricht einem vollständigen sequentiellen Lesen. Vor -i ist Input-Seeking, der Demuxer springt direkt.
  4. Messung ist an. Standardmäßig aktiviert: Der lokale Proxy zählt die abgerufenen Bytes – der einzige harte Beweis, dass wirklich nur Byteweise gelesen wird, und Nachweis, dass kein heimlicher Download stattfand.
  5. Weblinks an Skripte übergeben. Seiten-URL ≠ direkter Link, und direkte Links laufen mit Signatur ab. resolve.py nutzen oder den Link direkt an grab.py/transcribe.py übergeben (die erkennen und ergänzen automatisch die Header). Keine manuellen API-Aufrufe der Plattform im Chat schreiben – der Code variiert immer und ist ungeprüft.

Workflow

Schritt 0: Eingabe unterscheiden – Weblink oder Direktlink

  • Weblink (Bilibili, YouTube, TikTok, Weibo, Vimeo … insgesamt 1700+ Sites) → erst in direkten Link auflösen. Kann auch direkt an grab.py / transcribe.py übergeben werden, die erkennen und parsen automatisch und fügen die erforderlichen Header hinzu.
  • Direktlink (.mp4 / .m3u8 usw. Medienerweiterungen) → Auflösung überspringbar.

Die Entscheidungslogik in resolvers.is_page_url(): URLs mit Medienerweiterung gelten als Direktlinks; alle anderen HTTP-Links werden zur Auflösung geschickt.

Schritt 1: Abrufbaren Stream erhalten

python scripts/resolve.py "<Weblink>"

Ausgabe: video_url (für Bilder), audio_url (für Transkription – nicht identisch), headers (vom CDN geforderte Header), plus Titel, Dauer und eine Liste empfohlener Zeitpunkte für Bilder.

Die Zeile plattform zeigt das verwendete Backend: native (eigener Adapter, derzeit Bilibili) oder yt-dlp (allgemein, 1700+ Sites). Erzwingbar mit --backend native|yt-dlp|auto.

Ein Befehl für alles (Auflösung und Abruf automatisch verknüpft – empfohlen):

python scripts/transcribe.py --url "<Weblink>" --seconds 90
python scripts/grab.py "<Weblink>" --times 14 29 44 58 73 --prefix shot --outdir ./out

Schritt 2: Überprüfung (bei Direktlinks empfohlen, bei Weblinks überspringbar)

python scripts/probe.py <Direktlink> --json

Wenn der Direktlink vom CDN stammt, den Ursprung angeben: --header 'Referer: https://www.bilibili.com'.

Drei Felder beachten:

  • seekable – bei false abbrechen. Der Server ignoriert Range, punktgenaues Bilderlesen degeneriert zu sequentiellem Streaming. Alternativ: „Während des Downloads dekodieren“ (-i <url> ohne -ss, nimm das erste Bild) oder dem Benutzer mitteilen, dass es nicht möglich ist.
  • container.moov_offset / faststart – Index am Anfang (faststart): Fixkosten einige Dutzend KB. Am Ende: zuerst das Dateiende abrufen (gemessen ca. 441 KB). Dies sind die Fixkosten für „ein Bild holen“, unvermeidbar.
  • content_length – Nenner für den später berechneten Prozentsatz „Anteil am gesamten Video“.

Schritt 3: Nach Benutzerabsicht Daten abrufen

Benutzer gibt konkreten Zeitpunkt an → punktgenau Bild holen:

python scripts/grab.py <url> --time 183.5 --out shot.jpg

Benutzer gibt keinen Zeitpunkt an → ein paar Bilder für Überblick:

python scripts/grab.py <url> --times 5 60 180 420 --prefix shot --outdir /tmp/rv

Tipp zur Auswahl: 4–6 Bilder nach Inhaltsdichte, nicht gleichmäßig über die gesamte Länge verteilen (das entspricht dem Dekodieren des gesamten Videos). Bei Unsicherheit erst 3 Bilder holen, dann entscheiden, ob ein bestimmter Abschnitt genauer betrachtet werden soll.

Um zu verstehen, worum es geht → direkt in Text umwandeln (empfohlen zuerst):

python scripts/transcribe.py --url <url> --segments 0:90 320:90 630:97

Ein Befehl erledigt: „Audio extrahieren → lokal erkennen“. Ausgabe ist chinesischer Text mit Zeitstempeln. Keine externe API, keine Online-Inferenz nötig. Beim ersten Start wird das SenseVoice-Modell automatisch heruntergeladen (ca. 240 MB, von hf-mirror, nur einmal).

Bei langen Videos 3–4 Segmente zu je 90 Sekunden reichen, um die Haupthandlung abzudecken – nicht das gesamte Video transkribieren. Das ist viel schneller als jedes Bild zu analysieren und besser geeignet für Fragen wie „Worum geht es?“. Zuerst Text, dann Bilder zur visuellen Ergänzung – diese Reihenfolge.

Nach der Transkription zuerst die Ausbeute prüfen. Normale Sprechgeschwindigkeit ca. 4–6 Zeichen/Sek. Die Skriptausgabe enthält chars_per_second. Liegt sie unter 1 Zeichen/Sek, wird aktiv darauf hingewiesen. In diesem Fall (reine Musik, Gameplay, stumme Demo) die wenigen Zeichen nicht als Inhalt werten, sondern auf dichtere Bilder (8–10) für die visuelle Analyse umsteigen – die Antwort liegt nur im Bild.

Nur die Audiodatei selbst benötigt (z. B. für externe Transkription):

python scripts/grab.py <url> --start 0 --seconds 60 --audio clip.wav

Bei eingebetteten Untertiteln zuerst diese lesen (ffmpeg -i <url> prüfen, ob subtitle-Stream vorhanden) – genauer und schneller als ASR.

Schritt 4: Bilder an das Vision-Modell übergeben

grab.py holt nur die Pixel lokal, versteht den Inhalt nicht. Den Pfad des ausgegebenen jpg an das Vision-Modell übergeben mit einer Frage („Was ist in diesem Bild?“, „Worum geht es hier?“). Bei mehreren Bildern in zeitlicher Reihenfolge zusammen übergeben, damit das Modell eine zusammenhängende Erzählung bilden kann.

Ausgabe lesen

grab.py gibt JSON aus, jeder Eintrag mit Byte-Buchhaltung:

{
  "ok": true,
  "actions": [{
    "kind": "frame", "time": 30,
    "out_bytes": 48211,
    "upstream_bytes": 2097152,
    "requests": 4,
    "wall_seconds": 2.317
  }],
  "total_upstream_bytes": 2097152
}
  • upstream_bytes / content_length ist der prozentuale Anteil am gesamten Video. Über 5 % bedeutet: Stopp und Überprüfung – meist falsche -ss-Position oder Server erkennt Range nicht.
  • requests > 1 ist normal: ffmpeg holt in mehreren Schritten (moov, zwischen Keyframe und Ziel, Audio-Header).
  • Bei ok: false in err_tail nachsehen – häufig Timeout oder 5XX. Das Skript hat bereits einen Wiederholungsmechanismus; bei Misserfolg anderen Zeitpunkt versuchen.

Ausgabe von transcribe.py:

{
  "ok": true,
  "text": "Dies ist ein von Flüssen und Bergen umgebenes Land…",
  "segments": [{"start": 0, "end": 25, "text": "…"}],
  "audio_seconds": 276.7,
  "model": "SenseVoiceSmall-int8"
}

text ist der zusammengesetzte gesamte Text; segments enthalten Zeitstempel – nützlich für die Frage „Was wurde in Sekunde X gesagt?“.

Umgebung

  • Interpreter: Lokal gehostetes venv-python. Unter Windows Pfad ähnlich ~/.workbuddy/binaries/python/envs/default/Scripts/python.exe. Achtung: Scripts/, nicht Unix-typisch bin/ (bei bin/python kommt „Datei nicht gefunden“).
  • Abhängigkeiten: httpx, imageio-ffmpeg (Abruf), sherpa-onnx, numpy (Transkription), yt-dlp (allgemeine Plattformauflösung) – alle im selben venv installiert. Fehlt eine, meldet das Skript genau, welche. Fehlt yt-dlp, funktioniert Bilibili weiterhin (eigener Adapter), aber andere Websites scheitern.
  • ffmpeg: Wird von imageio-ffmpeg mit statischem Build mitgeliefert, keine Systeminstallation nötig. Umleitung mit Umgebungsvariable RV_FFMPEG oder --ffmpeg.
  • ASR-Modell-Cache: ~/.workbuddy/cache/read-video/models (ca. 240 MB, erster Download automatisch). Bei vorhandener Datei und passender Byteanzahl wird Download übersprungen.

Bekannte Grenzen

  • CDN prüft häufig den Ursprung: CDN von Bilibili etc. verlangt Referer, sonst 403. Mit resolve.py oder --page automatisch gesetzt; bei manuell eingegebenem Direktlink --header 'Referer: https://www.bilibili.com' nicht vergessen (alle drei Skripte unterstützen dies, wiederholbar).
  • Direktlinks laufen ab: Die Signatur und Deadline der Plattform-Links sind zeitlich begrenzt. Einmal 403 erhalten → resolve.py erneut ausführen.
  • Plattformabdeckung = Abdeckung von yt-dlp (1700+ Sites), nicht selbst gepflegt. Bei fehlschlagender Auflösung zuerst --backend yt-dlp verwenden, um die Rohfehler zu sehen; Sites, die Login/Cookies benötigen, scheitern – dann nur aufgeben oder Cookie manuell bereitstellen. yt-dlp selbst muss regelmäßig aktualisiert werden (nach Website-Änderungen) – pip install -U yt-dlp.
  • „Auflösung okay“ ≠ „Abruf möglich“: Die Auflösung liefert nur die URL. Bei Abruffehler zuerst unterscheiden, ob Auflösung oder Netzwerk nicht erreichbar war – getestet: Lokal zu YouTube / Vimeo nicht erreichbar (Proxy 502), aber TikTok / Weibo / Xigua erreichbar.
  • HLS / m3u8: Keine Einzeldatei, daher schlägt die box-Analyse von probe.py fehl (enthält error-Feld). grab.py funktioniert trotzdem; ffmpeg holt die benötigten Segmente selbst; content_length ist leer, prozentualer Anteil nicht berechenbar.
  • DASH mit getrenntem Audio/Video: Viele Websites (Bilibili usw.) haben separate URLs für Video- und Audiostreams. Bilder vom Video-Stream, Transkription vom Audio-Stream – falsch verwendet gibt es leere Ergebnisse.
  • -ss-Genauigkeit durch GOP begrenzt: Für ein Bild zu einer bestimmten Sekunde muss vom nächsten Keyframe aus dekodiert werden. Die kleinste abrufbare Einheit ist daher „Keyframe bis Zielbild“, nicht „ein Byte-Intervall“.
  • ASR-Homophone: SenseVoiceSmall arbeitet gut mit Chinesisch, aber bei Eigennamen, Ortsnamen und alten Wörtern häufig falsche Zeichen (getestet: „阪泉之野“ → „版圈之也“, „涿鹿“ → „涿陆“). Vor dem Zitieren von Eigennamen kontextuell korrigieren, den transkribierten Text nicht als Tatsache übernehmen.
  • Abhängigkeiten: httpx + imageio-ffmpeg (Abruf) + sherpa-onnx + numpy (Transkription). Fehlt eine, meldet das Skript genau, welche installiert werden muss.

Ausführlichere Details, Fallstricke und Testdaten finden sich in references/methodology.md. Das Verhältnis dieser Fähigkeit zum dsh-Plugin dsh-readvideo ist in references/dsh-dual-form.md beschrieben.

Verwandte Skills