Feat : page streamer
This commit is contained in:
@@ -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,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user