Feat : page streamer
Some checks failed
release / build (push) Successful in 27s
release / verify-windows (push) Failing after 1m3s

This commit is contained in:
jeanotx32
2026-08-11 20:04:08 +02:00
parent da9025fbf1
commit 4f7b8f56ae
12 changed files with 698 additions and 330 deletions

View File

@@ -87,6 +87,12 @@ function addColumnIfMissing(table: string, column: string, definition: string):
// que la table (nouveaux fournisseurs, nouveaux statuts).
addColumnIfMissing('agents', 'watch_json', 'TEXT');
// Enrichissement des profils surveillés : photo et historique de diffusion.
addColumnIfMissing('watch_targets', 'avatar_url', 'TEXT');
addColumnIfMissing('watch_targets', 'status_changed_at', 'INTEGER');
addColumnIfMissing('watch_targets', 'last_live_started_at', 'INTEGER');
addColumnIfMissing('watch_targets', 'last_live_ended_at', 'INTEGER');
export interface AgentRow {
id: string;
name: string;
@@ -287,8 +293,14 @@ interface TargetRow {
last_checked_at: number | null;
last_error: string | null;
created_at: number;
avatar_url: string | null;
status_changed_at: number | null;
last_live_started_at: number | null;
last_live_ended_at: number | null;
}
const num = (value: number | null): number | null => (value === null ? null : Number(value));
function toTarget(row: TargetRow): WatchTarget {
return {
id: row.id,
@@ -301,9 +313,13 @@ function toTarget(row: TargetRow): WatchTarget {
state: (row.state as StreamState) ?? 'unknown',
rawStatus: row.raw_status,
stateSince: Number(row.state_since),
lastCheckedAt: row.last_checked_at === null ? null : Number(row.last_checked_at),
lastCheckedAt: num(row.last_checked_at),
lastError: row.last_error,
createdAt: Number(row.created_at),
avatarUrl: row.avatar_url,
statusChangedAt: num(row.status_changed_at),
lastLiveStartedAt: num(row.last_live_started_at),
lastLiveEndedAt: num(row.last_live_ended_at),
};
}
@@ -321,7 +337,9 @@ const targetStmts = {
),
updateState: db.prepare(`
UPDATE watch_targets
SET state = ?, raw_status = ?, state_since = ?, last_checked_at = ?, last_error = ?
SET state = ?, raw_status = ?, state_since = ?, last_checked_at = ?, last_error = ?,
avatar_url = ?, status_changed_at = ?,
last_live_started_at = ?, last_live_ended_at = ?
WHERE id = ?
`),
remove: db.prepare('DELETE FROM watch_targets WHERE id = ?'),
@@ -385,6 +403,10 @@ export const targetsRepo = {
rawStatus: string | null;
stateSince: number;
lastError: string | null;
avatarUrl: string | null;
statusChangedAt: number | null;
lastLiveStartedAt: number | null;
lastLiveEndedAt: number | null;
},
): void {
targetStmts.updateState.run(
@@ -393,6 +415,10 @@ export const targetsRepo = {
state.stateSince,
Date.now(),
state.lastError,
state.avatarUrl,
state.statusChangedAt,
state.lastLiveStartedAt,
state.lastLiveEndedAt,
id,
);
},

View File

@@ -55,6 +55,8 @@ class Watchlist {
let next: StreamState;
let raw: string | null = null;
let error: string | null = null;
let avatarUrl = target.avatarUrl;
let statusChangedAt = target.statusChangedAt;
try {
const result = await fetchStripchatStatus(
@@ -63,6 +65,9 @@ class Watchlist {
);
next = result.state;
raw = result.raw;
// On conserve la dernière valeur connue si la plateforme ne la renvoie pas.
avatarUrl = result.avatarUrl ?? target.avatarUrl;
statusChangedAt = result.statusChangedAt ?? target.statusChangedAt;
} catch (err) {
// Une sonde en échec ne change pas l'état connu : on garde le dernier
// verdict fiable plutôt que d'annoncer un faux passage hors-ligne.
@@ -71,11 +76,26 @@ class Watchlist {
}
const changed = next !== target.state;
// Fin de diffusion : on fige le stream qui vient de se terminer. Son début
// est le statusChangedAt d'avant la transition, que la plateforme vient de
// remplacer par celui du nouveau statut.
let lastLiveStartedAt = target.lastLiveStartedAt;
let lastLiveEndedAt = target.lastLiveEndedAt;
if (changed && target.state === 'public') {
lastLiveStartedAt = target.statusChangedAt ?? target.stateSince;
lastLiveEndedAt = Date.now();
}
targetsRepo.updateState(target.id, {
state: next,
rawStatus: raw ?? target.rawStatus,
stateSince: changed ? Date.now() : target.stateSince,
lastError: error,
avatarUrl,
statusChangedAt,
lastLiveStartedAt,
lastLiveEndedAt,
});
const updated = targetsRepo.get(target.id);