Feat : Streamer watch list
Some checks failed
release / build (push) Successful in 28s
release / verify-windows (push) Failing after 1m13s

This commit is contained in:
jeanotx32
2026-08-11 19:24:31 +02:00
parent b85a535dd8
commit e87afc49c0
13 changed files with 936 additions and 48 deletions

View File

@@ -1,12 +1,8 @@
import { EventEmitter } from 'node:events';
import type { LogLevel, StreamState, WatchSettings, WatchState } from '@stream-control/shared';
import { emptyWatchState, mapStreamStatus } from '@stream-control/shared';
import { emptyWatchState, fetchStripchatStatus } from '@stream-control/shared';
import { sendHotkey } from './hotkey.ts';
const PROBE_TIMEOUT_MS = 8000;
const BROWSER_UA =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36';
export interface ProbeResult {
/** Statut brut renvoyé par la plateforme. */
raw: string;
@@ -14,40 +10,10 @@ export interface ProbeResult {
}
/**
* Sonde Stripchat.
*
* Le champ autoritatif est `user.user.status` sur
* `/api/front/v2/models/username/{pseudo}/cam`. Valeurs relevées en production :
* `public`, `private`, `p2p`, `groupShow`, `idle`.
* (`cam.privateMode` existe mais reste vide y compris pendant un privé : ne pas
* s'en servir.)
* Sonde Stripchat. L'implémentation vit dans le paquet partagé : le serveur s'en
* sert aussi pour la veille, et l'endpoint ne doit être défini qu'à un endroit.
*/
export async function probeStripchat(
username: string,
privateStatuses: string[],
): Promise<ProbeResult> {
const url = `https://fr.stripchat.com/api/front/v2/models/username/${encodeURIComponent(
username,
)}/cam`;
const response = await fetch(url, {
headers: { 'user-agent': BROWSER_UA, accept: 'application/json' },
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
});
if (response.status === 404) return { raw: 'notFound', state: 'offline' };
if (!response.ok) throw new Error(`API Stripchat : HTTP ${response.status}`);
const payload = (await response.json()) as {
user?: { user?: { status?: string; isLive?: boolean } };
};
const raw = payload?.user?.user?.status;
if (typeof raw !== 'string') {
throw new Error('Réponse Stripchat inattendue : user.user.status absent');
}
return { raw, state: mapStreamStatus(raw, privateStatuses) };
}
export const probeStripchat = fetchStripchatStatus;
/** Ce que le surveillant doit pouvoir demander à OBS. */
export interface WatchActions {