Communitygithub.com

Persian Sub Tizone — ساخت زیرنویس SRT فارسی

Persian SRT aus Video/Audio: ffmpeg extrahieren → 9Router STT → Überlappungsblock-Abgleich → polierte persische .srt-Datei. Brandneu 2026-09-26.

Was ist Persian Sub Tizone — ساخت زیرنویس SRT فارسی?

Dieses Skill erstellt automatisch persische SRT-Untertitel aus Video- oder Audiodateien. Es verwendet eine Pipeline, die mit ffmpeg das Audio extrahiert, es an den 9Router STT-Dienst zur Transkription sendet und dann mit einem intelligenten Überlappungsblock-System die Wörter zeitlich ausrichtet. Die Qualität ist besonders hoch, da zuerst eine vollständige Transkription des gesamten Audiomaterials erstellt und dann jedes Wort durch Sequence Matching auf die korrekte Position in den Blöcken gemappt wird. Das Skill unterstützt Plattformen wie Claude Code, Cursor und Codex — jede Umgebung, die Python-Skripte ausführen kann. Es behandelt API-Quotas (429) elegant mit Retry und Fallback zu einem anderen Modell. Der Benutzer benötigt nur einen NINEROUTER_KEY, den er vom Anwender anfordern muss, und eine exportierte NINEROUTER_URL. Der Befehl 'python3 pipeline/stt.py $VIDEO' reicht aus, um eine .srt-Datei neben dem Video zu generieren, die direkt in Premiere importiert werden kann.

Funktioniert mit✓Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add peditx/persian-sub-tizone-skill

In Ihrer bevorzugten KI fragen

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

Dokumentation

Was macht Persian Sub Tizone — ساخت زیرنویس SRT فارسی?

Pipeline: ffmpeg (Audio extrahieren) → 9Router /v1/audio/transcriptions (Transkribieren) → Zeitliche Ausrichtung mit überlappenden Blöcken → Ausgabe .srt.

Schnellmethode — führe dies einfach aus

Ein Befehl erledigt alles (Audio extrahieren → einmaliger vollständiger Text → überlappende Blöcke mit Cache → Ausrichtung → .srt schreiben):

python3 pipeline/stt.py "$VIDEO"                       # → neben dem Video: video.srt
python3 pipeline/stt.py "$VIDEO" -m groq/whisper-large-v3-turbo   # Modell ersetzen

Ausgabe: Datei video.srt neben der Originaldatei — direkt in Premiere importierbar (File → Import oder in die Timeline ziehen).

Verhalten, das du kennen solltest:

  • Die Arbeit bleibt im Ordner <video>.pst/ neben der Datei; eine erneute Ausführung setzt dort fort (bereits abgeschlossene Blöcke werden nicht erneut aufgerufen, nur der unvollständige Block wird wiederholt).
  • 429 (Kontingent): Liest die Nachricht und schläft genau so lange (3 Mal), falls danach immer noch 429, wird auf gemini/gemini-2.5-flash-lite (separates Kontingent) zurückgegriffen. 3–5 Sekunden Abstand zwischen Aufrufen und ein Timeout von jeweils 60 Sekunden sind ebenfalls im Skript enthalten.
  • Standardmodell ist gemini/gemini-2.5-flash (bester persischer Text).
  • Ohne Schlüssel wird nicht gestartet: Es sagt NINEROUTER_KEY fehlt und stoppt — hole den Schlüssel vom Benutzer, rate nicht.

Tests (ohne Schlüssel und ohne Netzwerk):

python3 pipeline/stt.py --selftest    # Chunking + Multipart + Parsing von 429
python3 pipeline/test_e2e.py          # gesamte Pipeline auf lokalem Fake-STT-Server

Voraussetzung (einmalig)

export NINEROUTER_URL="https://9router.peditx.ir"   # oder der 9Router-Host des Benutzers
export NINEROUTER_KEY="sk-..."
curl -s "$NINEROUTER_URL/api/health"                 # sollte {"ok":true} zurückgeben

Wenn kein Schlüssel vorhanden, hole ihn vom Benutzer; rate nicht.


Pipeline-Details (nur zur Fehlerbehebung/Entwicklung)

1) Audio extrahieren

DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$VIDEO")
ffmpeg -y -i "$VIDEO" -vn -ac 1 -ar 16000 -b:a 64k /tmp/audio.mp3

2) Transkribieren — überlappende Blöcke von 6 Sekunden (hop=4s)

# jedes Wort ist in ≥ einem Block
ffmpeg -i audio.mp3 -ss <t> -t 6 -c copy ch/NN_t.mp3
# jeder Block: POST /v1/audio/transcriptions  model=gemini/gemini-2.5-flash  response_format=json
  • Nimm 429 ernst: Lies die Nachricht, schlafe reset after Xm lang, versuche es erneut.
  • Beschädigte/unvollständige Antworten mit try/except abfangen und maximal 3 Mal wiederholen.
  • Ergebnisse in chunks.json speichern, damit Resume funktioniert.

3) Zeitliche Ausrichtung (Qualitätsschlüssel)

Hole den vollständigen Text einmal aus dem gesamten Video, gleiche dann die Wörter mit difflib.SequenceMatcher auf die Blöcke ab und interpoliere jedem Wort eine Zeit:

import difflib, re
W = lambda s: re.findall(r"[^\s]+", s)
norm = lambda w: re.sub(r"[^\w؀-ۿ]", "", w.lower())
gw = W(full_text)
# für jeden Block: beste Startposition in gw mit SequenceMatcher finden
# word j ← time = start + 6 * i/(n-1) ; Lücken interpolieren

Wenn ratio < 0.45, block verwerfen und Zeiten aus den segments des gleichen Blocks als Fallback verwenden.

4) SRT erstellen

MAX_CHARS, MAX_DUR = 84, 7.0
SOFT_CHARS, SOFT_DUR = 72, 6.0
# Aufteilen: zuerst Satzende (. ؟ !) mit Länge ≥30 → Priorität; sonst Komma/Länge/Dauer
# Wenn ein Cue unter 22 Zeichen hat, mit vorherigem Cue zusammenführen
def ts(x): return f"{int(x//3600):02d}:{int(x%3600//60):02d}:{int(x%60):02d},{int(round((x-int(x))*1000)):03d}"
# Zeilenumbruch: Ausgeglichenheit zweier Zeilen in 46 Zeichen (maximal 2 Zeilen)

Implementierung: pipeline/mk_srt.py

python3 pipeline/mk_srt.py -t g.json -c chunks.json --media "$VIDEO" -o "${VIDEO%.*}.srt"
python3 pipeline/mk_srt.py --selftest

5) Persische Rechtschreibkorrektur (optional)

{"model":"claude-sonnet-4-6","temperature":0.1,
 "messages":[{"role":"system","content":"Persischer Redakteur. Ausgabe nur gültiges JSON."},
   {"role":"user","content":"Korrigiere nur die persische Rechtschreibung; ändere nicht Bedeutung/Wortanzahl/Reihenfolge. Ausgabe: [{\"i\":..,\"t\":\"..\"}]"}]}

Die Ausgabe muss exakt die gleiche Anzahl an Cues zurückgeben; sonst assert und zum rohen Text zurückkehren. Sichere Normalisierung: ي → ی und ك → ک.

6) Endgültige Überprüfung

  • Lese an mehreren Stellen einen Frame des Videos (fps=1/6) und überprüfe den Untertiteltext auf dem Bild mit den Cues.
  • Führe an einigen separaten kurzen Abschnitten (ffmpeg -ss) STT durch und gleiche mit den Cue-Zeiten ab; falls Abweichung > 2 Sekunden, korrigiere die Zeiten.

Praktische Hinweise

  • ffmpeg/ffprobe sind immer vorhanden; whisper ist nicht lokal installiert.
  • Führe das Skript mit python3 - <<'PY' aus; für große Payloads -d @file.json verwenden, nicht argv.
  • Begrenze die Zeit jedes Aufrufs (-m 60); das Umgebungs-Timeout beträgt etwa 175 Sekunden → Aufrufe aufteilen.
  • Endgültiger Dateiname: neben dem Video mit der Erweiterung .srt.

Ausgabedateien, die in Premiere verwendet werden können:

DateiVerwendung
video.srtUntertitel — direkt File → Import oder in die Timeline ziehen
video.mp4.pst/chunks.jsonSTT-Cache (für spätere manuelle Korrektur)
video.mp4.pst/full.jsonReferenzvolltext

Verwandte Skills