Feat : page streamer
This commit is contained in:
@@ -346,11 +346,22 @@ export interface WatchTarget {
|
||||
notify: boolean;
|
||||
state: StreamState;
|
||||
rawStatus: string | null;
|
||||
/** Depuis quand l'état est stable. */
|
||||
/** Depuis quand l'état est stable, selon nos propres observations. */
|
||||
stateSince: number;
|
||||
lastCheckedAt: number | null;
|
||||
lastError: string | null;
|
||||
createdAt: number;
|
||||
|
||||
/** Photo de profil. */
|
||||
avatarUrl: string | null;
|
||||
/**
|
||||
* Début du statut courant d'après la plateforme. Quand `state` vaut `public`,
|
||||
* c'est l'heure de début du stream en cours.
|
||||
*/
|
||||
statusChangedAt: number | null;
|
||||
/** Dernier stream terminé : début et fin observés. */
|
||||
lastLiveStartedAt: number | null;
|
||||
lastLiveEndedAt: number | null;
|
||||
}
|
||||
|
||||
export type ServerToDashboard =
|
||||
@@ -467,11 +478,23 @@ export function stripchatProfileUrl(username: string): string {
|
||||
* Mutualisé entre l'agent (pause automatique) et le serveur (veille) : une seule
|
||||
* définition de l'endpoint et du chemin du champ à maintenir.
|
||||
*/
|
||||
export interface StripchatStatus {
|
||||
raw: string;
|
||||
state: StreamState;
|
||||
/** Photo de profil, absente si le modèle n'en a pas. */
|
||||
avatarUrl: string | null;
|
||||
/**
|
||||
* Début du statut courant. Quand le modèle est public, c'est l'heure de début
|
||||
* du stream en cours — bien plus précis que notre propre première observation.
|
||||
*/
|
||||
statusChangedAt: number | null;
|
||||
}
|
||||
|
||||
export async function fetchStripchatStatus(
|
||||
username: string,
|
||||
privateStatuses: string[],
|
||||
timeoutMs = 8000,
|
||||
): Promise<{ raw: string; state: StreamState }> {
|
||||
): Promise<StripchatStatus> {
|
||||
const url = `https://fr.stripchat.com/api/front/v2/models/username/${encodeURIComponent(
|
||||
username,
|
||||
)}/cam`;
|
||||
@@ -485,18 +508,30 @@ export async function fetchStripchatStatus(
|
||||
signal: AbortSignal.timeout(timeoutMs),
|
||||
});
|
||||
|
||||
if (response.status === 404) return { raw: 'notFound', state: 'offline' };
|
||||
if (response.status === 404) {
|
||||
return { raw: 'notFound', state: 'offline', avatarUrl: null, statusChangedAt: null };
|
||||
}
|
||||
if (!response.ok) throw new Error(`API Stripchat : HTTP ${response.status}`);
|
||||
|
||||
const payload = (await response.json()) as {
|
||||
user?: { user?: { status?: string } };
|
||||
user?: { user?: { status?: string; avatarUrl?: string; statusChangedAt?: string } };
|
||||
};
|
||||
const raw = payload?.user?.user?.status;
|
||||
const profile = payload?.user?.user;
|
||||
const raw = profile?.status;
|
||||
if (typeof raw !== 'string') {
|
||||
throw new Error('Réponse Stripchat inattendue : user.user.status absent');
|
||||
}
|
||||
|
||||
return { raw, state: mapStreamStatus(raw, privateStatuses) };
|
||||
const changedAt = profile?.statusChangedAt
|
||||
? Date.parse(profile.statusChangedAt)
|
||||
: Number.NaN;
|
||||
|
||||
return {
|
||||
raw,
|
||||
state: mapStreamStatus(raw, privateStatuses),
|
||||
avatarUrl: typeof profile?.avatarUrl === 'string' && profile.avatarUrl ? profile.avatarUrl : null,
|
||||
statusChangedAt: Number.isFinite(changedAt) ? changedAt : null,
|
||||
};
|
||||
}
|
||||
|
||||
/** Traduit un statut brut de l'API en état normalisé. */
|
||||
|
||||
Reference in New Issue
Block a user