Docker faellt weg. Das Projekt hat keine npm-Abhaengigkeiten und Node fuehrt TypeScript direkt aus - der Container schrieb nur noch drei Programme fest, und dafuer braucht es keine Virtualisierung, sondern einen Ordner. Der Anlass war, dass ADR-0004 zwar `docker compose pull` versprach, es aber nie ein veroeffentlichtes Image gab. Wer installieren wollte, musste whisper.cpp aus dem Quelltext uebersetzen. Plattformschicht (packages/core/src/platform.ts): - Programme werden neben der Anwendung gesucht, nicht im PATH - Daten unter %LOCALAPPDATA%, damit Installation und Update ohne Administratorrechte auskommen - Schriften mitgeliefert: ohne fontsdir setzt libass wortlos eine Ersatzschrift ein - gemessen 720 statt 826 Pixel Zeilenbreite Windows-Eigenheiten, an echtem ffmpeg 8.1 durchprobiert: - Pfade im Filtergraphen brauchen alle drei Schritte (Vorwaertsschraegstriche, escapter Doppelpunkt, Anfuehrungszeichen); je zwei davon reichen nicht - `nice` gibt es nicht, ersetzt durch os.setPriority Auslieferung: - scripts/build-package.ts baut das Paket, laeuft auch unter Linux - install.ps1 ohne Administratorrechte, Autostart ueber den Aufgabenplaner - update legt neue Fassungen bereit; eingespielt wird beim naechsten Start, nie mitten im Stream - ZIP lesen und schreiben ohne Abhaengigkeiten (packages/core/src/zip.ts) Kein `irm ... | iex`-Einzeiler: git.zeasy.dev antwortete instanzweit mit einer Umleitung auf /user/login, und `iex` fuehrte die Anmeldeseite als PowerShell aus. Der Updater verfolgt Umleitungen jetzt nicht und hat keine erfundene Vorgabeadresse mehr. Ausserdem: backup.ps1 war an zwei Stellen dokumentiert, aber nie geschrieben. ADR-0007 ersetzt ADR-0004. 84 Tests, Typpruefung sauber. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AhVSfMFdWnXKCv5JfLnArZ
64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
// Auswertung einer OBS-Szene gegen den 9:16-Ausschnitt.
|
|
//
|
|
// Der Anlass: In einem fertigen Clip lagen fremde Untertitel im Bild, und
|
|
// niemand wusste, woher sie kommen. Raten hilft da nicht - sie sind ins
|
|
// Streambild eingebrannt, also muss man nachsehen, welche Quelle sie malt.
|
|
// Die reine Rechnerei steht hier, damit sie pruefbar ist; das Anzeigen und
|
|
// das Reden mit OBS bleibt im Entrypoint.
|
|
|
|
import type { Rect } from '#core/config.ts';
|
|
|
|
export type Box = { x: number; y: number; w: number; h: number };
|
|
|
|
/**
|
|
* Quellenarten und Namen, hinter denen erfahrungsgemaess Untertitel stecken.
|
|
* Bewusst weit gefasst: ein Fehlalarm kostet einen Blick, eine uebersehene
|
|
* Quelle kostet jeden Clip.
|
|
*/
|
|
export const CAPTION_HINTS =
|
|
/caption|untertitel|subtitle|transcri|speech|vocal|stt|dictat|closed.?cc|(^|\W)cc(\W|$)/i;
|
|
|
|
/** Wie viel Prozent des Ausschnitts die Quelle ueberdeckt. */
|
|
export function overlapPercent(box: Box, r: Rect): number {
|
|
const w = Math.max(0, Math.min(box.x + box.w, r.x + r.w) - Math.max(box.x, r.x));
|
|
const h = Math.max(0, Math.min(box.y + box.h, r.y + r.h) - Math.max(box.y, r.y));
|
|
const area = r.w * r.h;
|
|
return area > 0 ? Math.round(((w * h) / area) * 100) : 0;
|
|
}
|
|
|
|
export type SourceVerdict = {
|
|
cam: number;
|
|
game: number;
|
|
/** Steht die Quelle im fertigen Short? */
|
|
inShort: boolean;
|
|
/** Sieht sie nach fremden Untertiteln aus? */
|
|
suspectCaption: boolean;
|
|
};
|
|
|
|
/**
|
|
* Urteil ueber eine einzelne Quelle.
|
|
*
|
|
* Ausgeblendete Quellen sind nie im Bild - egal wo sie liegen. Und eine
|
|
* Untertitelquelle ausserhalb des Ausschnitts ist kein Problem, sondern genau
|
|
* das, was docs/obs-layout.md vorschlaegt: im Stream sichtbar lassen, aus dem
|
|
* Gameplay-Band herausschieben.
|
|
*/
|
|
export function judgeSource(args: {
|
|
box: Box;
|
|
enabled: boolean;
|
|
name: string;
|
|
kind: string;
|
|
url?: string;
|
|
cam: Rect;
|
|
game: Rect;
|
|
}): SourceVerdict {
|
|
const cam = overlapPercent(args.box, args.cam);
|
|
const game = overlapPercent(args.box, args.game);
|
|
const inShort = args.enabled && (cam > 0 || game > 0);
|
|
return {
|
|
cam, game, inShort,
|
|
suspectCaption: inShort &&
|
|
CAPTION_HINTS.test(`${args.name} ${args.kind} ${args.url ?? ''}`),
|
|
};
|
|
}
|