\documentclass[11pt,a4paper]{article} \usepackage[ngerman]{babel} \usepackage{fontspec} \usepackage[a4paper,margin=2.4cm,headsep=14pt]{geometry} \usepackage{xcolor} \usepackage{titlesec} \usepackage{enumitem} \usepackage{booktabs} \usepackage{tabularx} \usepackage{fancyhdr} \usepackage{fancyvrb} \usepackage{mdframed} \usepackage[hidelinks]{hyperref} \setmainfont{Segoe UI} \setmonofont{Consolas}[Scale=0.92] \definecolor{lila}{HTML}{6B3FA0} \definecolor{grau}{HTML}{555555} \definecolor{hellgrau}{HTML}{F2F2F4} \definecolor{rahmen}{HTML}{D8D8DE} \titleformat{\section}{\Large\bfseries\color{lila}}{\thesection}{0.7em}{} \titleformat{\subsection}{\large\bfseries}{\thesubsection}{0.6em}{} \titlespacing*{\section}{0pt}{20pt}{8pt} \titlespacing*{\subsection}{0pt}{14pt}{5pt} \pagestyle{fancy} \fancyhf{} \fancyhead[L]{\small\color{grau}abdulive-toolkit} \fancyhead[R]{\small\color{grau}\leftmark} \fancyfoot[C]{\small\color{grau}\thepage} \renewcommand{\headrulewidth}{0.4pt} \renewcommand{\headrule}{\color{rahmen}\hrule height 0.4pt} \renewcommand{\sectionmark}[1]{\markboth{#1}{}} % Keine Einrueckung, dafuer Abstand zwischen den Absaetzen. Sonst wirkt jeder % Absatz nach einer Liste oder Tabelle wie ein neuer Einzug. \setlength{\parindent}{0pt} \setlength{\parskip}{7pt} \renewcommand{\arraystretch}{1.15} \setlist[itemize]{leftmargin=1.3em,itemsep=2pt,topsep=4pt,parsep=0pt} \setlist[enumerate]{leftmargin=1.6em,itemsep=3pt,topsep=4pt,parsep=0pt} % Ohne commandchars: Backslashes in Windows-Pfaden bleiben woertlich. Mit % commandchars wuerde aus \textbackslash ein Backslash plus Leerzeichen, % und ein kopierter Pfad waere kaputt. \DefineVerbatimEnvironment{code}{Verbatim} {fontsize=\small,xleftmargin=8pt,frame=leftline,framerule=1.6pt, rulecolor=\color{rahmen},framesep=8pt} % Nur fuer Bloecke, die eine Einfaerbung brauchen. \DefineVerbatimEnvironment{codef}{Verbatim} {fontsize=\small,xleftmargin=8pt,frame=leftline,framerule=1.6pt, rulecolor=\color{rahmen},framesep=8pt,commandchars=\\\{\}} \newmdenv[backgroundcolor=hellgrau,linecolor=rahmen,linewidth=0.6pt, innertopmargin=8pt,innerbottommargin=8pt,innerleftmargin=10pt, innerrightmargin=10pt,skipabove=10pt,skipbelow=10pt,roundcorner=2pt]{kasten} \newcommand{\pfad}[1]{\texttt{\small #1}} \begin{document} \thispagestyle{empty} \vspace*{2.5cm} {\Huge\bfseries\color{lila} abdulive-toolkit} \vspace{6pt} {\Large Handbuch} \vspace{28pt} {\large Aus einem Zuruf im Chat wird ein fertiges Hochformat-Video.} \vspace{40pt} \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule Version & 0.5.4 \\ Stand & 9. September 2026 \\ Gilt für & Windows 10 und 11, 64 Bit \\ Quelltext & \url{https://git.zeasy.dev/ZeasyAlex/abdulive} \\ \bottomrule \end{tabularx} \vfill \noindent\small\color{grau} Das Toolkit speichert Chatverläufe. Die Datenbank enthält damit personenbezogene Daten und gehört weder ins Repository noch in eine Cloud ohne Absprache. \newpage \tableofcontents \newpage \section{Was das Werkzeug tut} Jemand tippt \texttt{!clip} in den Chat. Etwa eine Minute später liegt ein fertiges 9:16-Video mit Untertiteln auf der Platte, bereit für TikTok, Reels oder Shorts. Dazwischen passiert Folgendes: \begin{enumerate} \item Das Toolkit liest den Chat mit und erkennt den Befehl. \item Es weist OBS an, den Wiedergabepuffer zu speichern. OBS hat die letzten 90 Sekunden ohnehin im Speicher, der Moment ist also schon vorbei und trotzdem noch da. \item OBS meldet den Dateipfad zurück. Das Toolkit wartet, bis die Datei fertig geschrieben ist. \item Aus den letzten 45 Sekunden wird ein Hochformat gebaut: Facecam oben, Gameplay unten, beides ohne Verzerrung zugeschnitten. \item Die Mikrofonspur wird transkribiert und als Untertitel ins Bild gebrannt. \end{enumerate} \begin{kasten} \textbf{Während des Streams wird nicht gerendert.} Das Encodieren nimmt Rechenzeit, die der Stream braucht. Die Warteschlange arbeitet erst nach Streamende. Wer das anders will, setzt \texttt{renderWhileLive: true}. \end{kasten} \subsection{Was dabei herauskommt} Je Clip entsteht ein Ordner mit: \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule \pfad{final.mp4} & das fertige Video mit eingebrannten Untertiteln \\ \pfad{vertical.mp4} & dasselbe ohne Untertitel \\ \pfad{thumb.jpg} & Vorschaubild \\ \pfad{subs.srt} & Untertitel als Textdatei, praktisch für die Beschreibung \\ \pfad{transcript.txt} & reiner Text des Gesagten \\ \bottomrule \end{tabularx} \subsection{Was es noch nicht tut} Es lädt nichts hoch. Es entscheidet nicht, welcher Clip gut ist. Die Sichtungsseite, auf der man Clips durchgeht und aussortiert, ist noch nicht gebaut. \section{Installation} Vorausgesetzt wird Windows 10 oder 11 in 64 Bit und OBS Studio 30 oder neuer. Sonst nichts. Node, ffmpeg, whisper.cpp und die Schriften sind im Paket enthalten. In PowerShell: \begin{code} irm https://git.zeasy.dev/ZeasyAlex/abdulive/raw/branch/main/scripts/install.ps1 | iex \end{code} Das Skript lädt das Paket, prüft die Prüfsumme, installiert, holt das Sprachmodell (etwa 465 MB), startet den Dienst und öffnet die Einrichtungsseite im Browser. Es braucht keine Administratorrechte. Beim ersten Start warnt Windows SmartScreen vor einem unbekannten Herausgeber, weil das Paket nicht signiert ist. Einmal auf \emph{Weitere Informationen}, dann \emph{Trotzdem ausführen}. \subsection{Wohin es installiert} \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule Programm & \pfad{\%LOCALAPPDATA\%\textbackslash Programs\textbackslash abdulive} \\ Daten & \pfad{\%LOCALAPPDATA\%\textbackslash abdulive} \\ Autostart & Aufgabe \texttt{abdulive}, bei jeder Anmeldung \\ Updates & Aufgabe \texttt{abdulive-update}, täglich 5:00 Uhr \\ \bottomrule \end{tabularx} Programm und Daten liegen getrennt. Ein Update tauscht den Programmordner komplett aus, die Datenbank bleibt davon unberührt. \section{Einrichtung} Die Einrichtungsseite liegt unter \url{http://localhost:4792/setup} und ist nur vom eigenen Rechner erreichbar. Sie zeigt Zugangsdaten im Klartext, also nicht während des Streams öffnen. \subsection{Schritt 1: Zwei Twitch-Anwendungen anlegen} Unter \url{https://dev.twitch.tv/console/apps} zwei Anwendungen erstellen. Bei beiden als OAuth-Redirect-URL exakt eintragen: \begin{code} http://localhost:4792/callback \end{code} Die Anwendungen hängen nicht am Kanal. Sie können auch unter einem anderen Konto angelegt werden. \subsection{Schritt 2: Broadcaster-Konto verbinden} Client-ID und Secret der ersten Anwendung auf der Einrichtungsseite eintragen, speichern, dann auf \emph{Mit Twitch verbinden} klicken. \begin{kasten} \textbf{Das kann nur der Streamer selbst.} Twitch bindet die Berechtigungen an das Konto, das sich anmeldet. Es gibt keine Rolle, mit der jemand anderes das übernehmen kann. Moderator und Redakteur helfen hier nicht. \end{kasten} Damit bekommt das Toolkit Zugriff auf Clips, Titel und Kategorie, Abonnenten, Follower, Raids, Kanalpunkte und Bits. \subsection{Schritt 3: Bot-Konto verbinden} Dasselbe mit der zweiten Anwendung, angemeldet als Bot-Konto. Das ist ein eigenes, kostenloses Twitch-Konto, damit Antworten im Chat als Bot erkennbar sind. Ohne dieses Konto liest das Toolkit den Chat trotzdem mit. Es kann nur nicht antworten. \begin{kasten} \textbf{Das Bot-Konto sollte Moderator im Kanal sein.} Der Streamer tippt dafür einmal \texttt{/mod botname} in seinen Chat. Ohne Moderatorrechte gilt ein Limit von 20 Nachrichten je 30 Sekunden statt 100, und im Follower-only-Modus kommt der Bot gar nicht durch. \end{kasten} \subsection{Schritt 4: OBS-Passwort} In OBS unter \emph{Werkzeuge} $\rightarrow$ \emph{WebSocket-Servereinstellungen} den Server aktivieren, Port 4455. Das dort angezeigte Passwort auf der Einrichtungsseite eintragen. \subsection{Fertig?} Unten auf der Seite steht \texttt{bereit} oder \texttt{unvollständig}. Solange das Broadcaster-Konto fehlt, läuft das Toolkit im Lesemodus: Chat wird mitgeschrieben, Zuschauerzahlen und Clips bleiben aus. \section{OBS einrichten} Ohne diese vier Punkte entstehen keine Clips oder sie sitzen schief. \subsection{Wiedergabepuffer} \emph{Einstellungen} $\rightarrow$ \emph{Ausgabe} $\rightarrow$ \emph{Wiedergabepuffer} aktivieren, 90 Sekunden. Unter \emph{Einstellungen} $\rightarrow$ \emph{Hotkeys} eine Taste auf \emph{Wiedergabepuffer speichern} legen. Das ist der Clip-Knopf für den Streamer selbst. Ein eigener Windows-Hotkey wird bewusst nicht gebaut: OBS meldet den gespeicherten Puffer ohnehin über WebSocket, das ist derselbe Auslöser. \subsection{Getrennte Tonspuren} \emph{Einstellungen} $\rightarrow$ \emph{Ausgabe} $\rightarrow$ \emph{Aufnahme} $\rightarrow$ \emph{Audiospuren}, und im Audiomixer je Quelle die Zuordnung prüfen: \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule Spur 1 & Mischung, kommt ins fertige Video \\ Spur 2 & Mikrofon, daraus entstehen die Untertitel \\ Spur 3 & Spielton \\ \bottomrule \end{tabularx} Das ist bei lauten Spielen der Unterschied zwischen brauchbarem und unbrauchbarem Transkript. \subsection{Bildaufteilung} Der Zuschnitt nimmt feste Bereiche aus dem fertigen Streambild. Verrutscht die Kamera um 50 Pixel, sitzt in jedem Short der Kopf schief. Deshalb liegt die Position fest: \begin{tabularx}{\textwidth}{@{}lll@{}} \toprule \textbf{Element} & \textbf{Position} & \textbf{Größe} \\ \midrule Facecam & x 0, y 0 & 480 $\times$ 270 \\ Gameplay-Band & x 515 bis 1405 & 890 $\times$ 1080 \\ Chat, Alerts, Overlays & ab x 1405 & 515 px Spalte \\ \bottomrule \end{tabularx} Zwischen Kamera und Gameplay-Band liegen 35 Pixel Luft. Ein leicht verrutschter Kamerarahmen schiebt so nicht sofort einen Streifen Gesicht ins Spielbild. Zum Ausrichten liegt eine Vorlage bei. Als Bildquelle in OBS laden, ganz nach oben ziehen, Deckkraft über einen Farbkorrektur-Filter auf etwa 60 Prozent, eigene Quellen einpassen, Vorlage wieder ausblenden. Steht die Kamera in OBS als 4:3, vorher in den Kameraeinstellungen auf 16:9 umstellen. Ein 4:3-Bild in einen 16:9-Rahmen zu ziehen staucht das Gesicht. \subsection{Fremder Text im Bild} Was im Streambild steht, ist eingebrannt und lässt sich nachträglich nicht entfernen. Untertitel des Spiels und Live-Caption-Overlays landen also im Short, zusätzlich zu den eigenen Untertiteln. \begin{itemize} \item \textbf{Spieluntertitel:} abschalten. Sie laufen über die volle Bildbreite, werden vom Zuschnitt angeschnitten und bringen im Short nichts. \item \textbf{Live-Captions:} verschieben statt abschalten. Für Zuschauer ohne Ton sind sie wertvoll. Sie müssen nur aus dem Gameplay-Band heraus, etwa nach unten links oder in die rechte Spalte. \end{itemize} Welche OBS-Quelle den Text überhaupt malt, sagt \texttt{abdulive sources}. \section{Der laufende Betrieb} \subsection{Clips auslösen} \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule \texttt{!clip} im Chat & jeder Zuschauer \\ OBS-Hotkey & der Streamer \\ Chat-Spitze & erkennt auffällige Reaktionen, standardmäßig aus \\ \bottomrule \end{tabularx} Abklingzeiten sind nicht optional. Ohne sie ist \texttt{!clip} nach zwei Streams ein Spielzeug: 60 Sekunden global, 300 Sekunden je Zuschauer. Wer zu früh dran ist, bekommt eine Antwort im Chat. Die Spitzen-Erkennung läuft von Anfang an mit und schreibt jeden Kandidaten samt Punktzahl mit, löst aber nichts aus. Sobald ein paar Streams protokolliert sind, lässt sie sich an echten Daten kalibrieren und scharfschalten. \subsection{Befehle} \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule \texttt{abdulive check-env} & Selbsttest: Programme, Schriften, Modell, Verzeichnisse, OBS \\ \texttt{abdulive sources} & listet die OBS-Quellen und sagt, welche im 9:16-Ausschnitt landen \\ \texttt{abdulive calibrate} & prüft den Bildzuschnitt an einer echten Aufnahme \\ \texttt{abdulive render } & rendert eine Rohdatei nach, etwa nach einer Layoutänderung \\ \texttt{abdulive fetch-model} & lädt ein Sprachmodell \\ \texttt{abdulive update} & prüft auf eine neue Fassung \\ \bottomrule \end{tabularx} \subsection{Läuft es?} \begin{codef} Start-ScheduledTask -TaskName abdulive \textcolor{grau}{# starten} Stop-ScheduledTask -TaskName abdulive \textcolor{grau}{# stoppen} \end{codef} Status und Zahlen liefert \url{http://127.0.0.1:4792/health}. Die Protokolle liegen unter \pfad{\%LOCALAPPDATA\%\textbackslash abdulive\textbackslash logs}. \begin{kasten} Bei einer Adresse im Browser immer \texttt{127.0.0.1} statt \texttt{localhost} verwenden, wenn etwas hängt. Der Dienst lauscht nur auf IPv4, und Windows probiert bei \texttt{localhost} zuerst IPv6. Das kostet zwei Sekunden. \end{kasten} \section{Updates} Die Aufgabe \texttt{abdulive-update} sieht täglich um 5:00 Uhr nach. Findet sie eine neue Fassung, lädt sie das Paket, prüft die Prüfsumme und legt es bereit. \textbf{Eingespielt wird beim nächsten Start.} Mitten im Stream wird nichts ausgetauscht. Schlägt der Tausch fehl, läuft die alte Fassung weiter. Sofort übernehmen: \begin{code} Stop-ScheduledTask -TaskName abdulive; Start-ScheduledTask -TaskName abdulive \end{code} \section{Sicherung} \begin{code} & "$env:LOCALAPPDATA\Programs\abdulive\backup.ps1" \end{code} Schreibt eine in sich stimmige Kopie der Datenbank und hält 30 Generationen. Die Datenbank wird im laufenden Betrieb beschrieben, ein einfaches Kopieren ergäbe eine unbrauchbare Sicherung. \section{Deinstallation} \begin{code} & "$env:LOCALAPPDATA\Programs\abdulive\uninstall.ps1" \end{code} Nimmt die beiden Aufgaben, beendet den Dienst und löscht den Programmordner. Die Daten bleiben stehen, weil in der Datenbank Chatverläufe liegen. Wer neu installiert, findet seine Einrichtung wieder. Wirklich alles weg, auch Datenbank, Clips und Sprachmodell: \begin{code} & "$env:LOCALAPPDATA\Programs\abdulive\uninstall.ps1" -AuchDaten \end{code} \section{Wenn etwas nicht geht} \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule \textbf{Symptom} & \textbf{Ursache und Abhilfe} \\ \midrule Keine Clips & OBS-WebSocket aus oder Passwort fehlt. \texttt{check-env} zeigt es unter \emph{OBS}. \\ Clips ohne Untertitel & Sprachmodell fehlt. \texttt{abdulive fetch-model}. \\ Untertitel voller Unsinn & Transkribiert wird die falsche Tonspur. Mikrofon gehört auf Spur 2. \\ Kopf sitzt schief & OBS-Layout weicht von der Vorgabe ab. \texttt{abdulive calibrate}. \\ Fremder Text im Short & Eine OBS-Quelle liegt im Gameplay-Band. \texttt{abdulive sources}. \\ Chat wird nur gelesen & Broadcaster-Konto nicht verbunden. \\ Oberfläche antwortet nicht & Protokolle unter \pfad{\%LOCALAPPDATA\%\textbackslash abdulive\textbackslash logs} ansehen. \\ \bottomrule \end{tabularx} \section{Wo was liegt} \begin{tabularx}{\textwidth}{@{}lX@{}} \toprule \pfad{config\textbackslash config.yaml} & Einstellungen. Keine Geheimnisse. \\ \pfad{config\textbackslash layout.yaml} & Bildaufteilung für den Zuschnitt \\ \pfad{db\textbackslash} & Datenbank und verschlüsselte Zugangsdaten \\ \pfad{clips\textbackslash} & fertige Videos \\ \pfad{work\textbackslash} & Rohdateien der Verarbeitung \\ \pfad{models\textbackslash} & Sprachmodelle \\ \pfad{logs\textbackslash} & Protokolle \\ \bottomrule \end{tabularx} Alles unterhalb von \pfad{\%LOCALAPPDATA\%\textbackslash abdulive}. \begin{kasten} \textbf{Der Arbeitsordner wird noch nicht aufgeräumt.} Rohdateien sammeln sich unbegrenzt an, mehrere hundert MB je Clip. Bis eine Aufbewahrungsregel gebaut ist, gelegentlich selbst nachsehen. \end{kasten} \end{document}