Fix : Stream Preview
This commit is contained in:
15
README.md
15
README.md
@@ -603,11 +603,16 @@ flux — pas une vidéo : le serveur n'a que l'API REST publique de la plateform
|
|||||||
pas l'agent qui pilote un navigateur ici. Au survol, l'image grandit et passe au premier
|
pas l'agent qui pilote un navigateur ici. Au survol, l'image grandit et passe au premier
|
||||||
plan, quitte à déborder sur les cartes voisines.
|
plan, quitte à déborder sur les cartes voisines.
|
||||||
|
|
||||||
Source : le même appel que le statut (`/api/front/v2/models/username/{pseudo}/cam`) inclut
|
Source : le même appel que le statut (`/api/front/v2/models/username/{pseudo}/cam`), sans
|
||||||
déjà `previewUrlThumbBig` et `snapshotTimestamp` — aucune requête supplémentaire. L'URL de
|
requête supplémentaire — mais pas son champ `previewUrlThumbBig` / `previewUrlThumbSmall` :
|
||||||
la vignette ne change pas d'une image à l'autre (le CDN la sert avec un cache de 30 jours),
|
malgré leur nom, ce sont ceux de la photo de couverture du profil, fixe, choisie par le
|
||||||
donc le client y ajoute `?t={snapshotTimestamp}` pour forcer un frame à jour à chaque sonde
|
modèle, pas une image de la diffusion en cours (repéré à l'usage : l'aperçu ne changeait
|
||||||
plutôt que de garder indéfiniment la toute première image vue.
|
jamais). La vraie vignette caméra se reconstruit à partir de deux autres champs de la même
|
||||||
|
réponse, `id` et `snapshotTimestamp`, en `https://img.doppiocdn.net/thumbs/{snapshotTimestamp}/{id}`
|
||||||
|
— confirmé en comparant les deux : contenu différent, cache CDN de 30 minutes au lieu de
|
||||||
|
30 jours, `Last-Modified` à quelques secondes de la requête. Cet horodatage étant dans le
|
||||||
|
chemin de l'URL et non dans un paramètre, chaque nouvelle vignette porte déjà sa propre URL —
|
||||||
|
inutile de forcer l'invalidation du cache navigateur en plus.
|
||||||
|
|
||||||
Se rafraîchit donc au rythme de la veille (`WATCHLIST_INTERVAL_MS`, 30 s par défaut) — un
|
Se rafraîchit donc au rythme de la veille (`WATCHLIST_INTERVAL_MS`, 30 s par défaut) — un
|
||||||
aperçu, pas un flux temps réel.
|
aperçu, pas un flux temps réel.
|
||||||
|
|||||||
@@ -1206,17 +1206,26 @@ export interface StripchatStatus {
|
|||||||
*/
|
*/
|
||||||
statusChangedAt: number | null;
|
statusChangedAt: number | null;
|
||||||
/**
|
/**
|
||||||
* Vignette du flux (`previewUrlThumbBig`) — une image, pas un flux vidéo :
|
* Image du flux — pas le flux lui-même : l'agent seul pilote un navigateur,
|
||||||
* l'agent seul pilote un navigateur, le serveur n'a que cette API REST.
|
* le serveur n'a que cette API REST.
|
||||||
* Absente si le modèle n'a jamais diffusé.
|
*
|
||||||
|
* Reconstruite depuis `img.doppiocdn.net/thumbs/{snapshotTimestamp}/{id}` et
|
||||||
|
* non lue telle quelle sur `previewUrlThumbBig` / `previewUrlThumbSmall` :
|
||||||
|
* ces deux champs, malgré leur nom, pointent vers la photo de couverture du
|
||||||
|
* profil — fixe, choisie par le modèle — et non vers une image de la
|
||||||
|
* diffusion en cours. `img.doppiocdn.net` est la vraie vignette caméra,
|
||||||
|
* confirmée en comparant les deux : contenu différent, cache CDN de 30 min
|
||||||
|
* au lieu de 30 jours, `Last-Modified` à quelques secondes de la requête.
|
||||||
|
*
|
||||||
|
* Absente si le modèle n'a jamais diffusé (pas d'identifiant numérique ou
|
||||||
|
* d'horodatage exploitable côté plateforme).
|
||||||
*/
|
*/
|
||||||
previewUrl: string | null;
|
previewUrl: string | null;
|
||||||
/**
|
/**
|
||||||
* Horodatage de cette vignette côté plateforme, pour invalider le cache du
|
* Horodatage de cette vignette côté plateforme — déjà encodé dans
|
||||||
* navigateur : l'URL, elle, ne change pas d'une image à l'autre — le CDN la
|
* `previewUrl`, donc sans utilité pour le cache : une nouvelle vignette porte
|
||||||
* sert avec un `max-age` de 30 jours. Sans un paramètre qui varie à chaque
|
* de toute façon une URL différente. Exposé pour l'affichage seulement
|
||||||
* rafraîchissement, le navigateur garderait indéfiniment la toute première
|
* (« vignette vieille de X »).
|
||||||
* image vue.
|
|
||||||
*/
|
*/
|
||||||
snapshotAt: number | null;
|
snapshotAt: number | null;
|
||||||
}
|
}
|
||||||
@@ -1254,10 +1263,10 @@ export async function fetchStripchatStatus(
|
|||||||
const payload = (await response.json()) as {
|
const payload = (await response.json()) as {
|
||||||
user?: {
|
user?: {
|
||||||
user?: {
|
user?: {
|
||||||
|
id?: number;
|
||||||
status?: string;
|
status?: string;
|
||||||
avatarUrl?: string;
|
avatarUrl?: string;
|
||||||
statusChangedAt?: string;
|
statusChangedAt?: string;
|
||||||
previewUrlThumbBig?: string;
|
|
||||||
snapshotTimestamp?: number;
|
snapshotTimestamp?: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1273,6 +1282,7 @@ export async function fetchStripchatStatus(
|
|||||||
: Number.NaN;
|
: Number.NaN;
|
||||||
// Secondes côté API, comme tous les timestamps Unix bruts de cette plateforme.
|
// Secondes côté API, comme tous les timestamps Unix bruts de cette plateforme.
|
||||||
const snapshotAt = Number(profile?.snapshotTimestamp) * 1000;
|
const snapshotAt = Number(profile?.snapshotTimestamp) * 1000;
|
||||||
|
const modelId = Number(profile?.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
raw,
|
raw,
|
||||||
@@ -1280,8 +1290,8 @@ export async function fetchStripchatStatus(
|
|||||||
avatarUrl: typeof profile?.avatarUrl === 'string' && profile.avatarUrl ? profile.avatarUrl : null,
|
avatarUrl: typeof profile?.avatarUrl === 'string' && profile.avatarUrl ? profile.avatarUrl : null,
|
||||||
statusChangedAt: Number.isFinite(changedAt) ? changedAt : null,
|
statusChangedAt: Number.isFinite(changedAt) ? changedAt : null,
|
||||||
previewUrl:
|
previewUrl:
|
||||||
typeof profile?.previewUrlThumbBig === 'string' && profile.previewUrlThumbBig
|
Number.isFinite(modelId) && modelId > 0 && Number.isFinite(snapshotAt) && snapshotAt > 0
|
||||||
? profile.previewUrlThumbBig
|
? `https://img.doppiocdn.net/thumbs/${Math.round(snapshotAt / 1000)}/${modelId}`
|
||||||
: null,
|
: null,
|
||||||
snapshotAt: Number.isFinite(snapshotAt) && snapshotAt > 0 ? snapshotAt : null,
|
snapshotAt: Number.isFinite(snapshotAt) && snapshotAt > 0 ? snapshotAt : null,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -122,16 +122,16 @@ export function autoRecordHint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL de la vignette du flux, invalidée par un paramètre de cache.
|
* URL de la vignette du flux.
|
||||||
*
|
*
|
||||||
* `previewUrl` ne change pas d'une image à l'autre — c'est le CDN qui la sert
|
* Un simple passe-plat aujourd'hui — `previewUrl` porte déjà l'horodatage de
|
||||||
* avec un `max-age` de 30 jours — donc sans `snapshotAt` en paramètre, le
|
* la vignette dans son chemin, donc chaque nouvelle image a naturellement sa
|
||||||
* navigateur garderait indéfiniment la toute première image vue au lieu de la
|
* propre URL, sans paramètre de cache à ajouter. Gardé comme fonction plutôt
|
||||||
* rafraîchir à chaque sonde.
|
* qu'un accès direct au champ : c'est le seul point à changer si la source
|
||||||
|
* de la vignette évolue encore une fois.
|
||||||
*/
|
*/
|
||||||
export function previewSrc(target: Pick<WatchTarget, 'previewUrl' | 'snapshotAt'>): string | null {
|
export function previewSrc(target: Pick<WatchTarget, 'previewUrl'>): string | null {
|
||||||
if (!target.previewUrl) return null;
|
return target.previewUrl;
|
||||||
return target.snapshotAt ? `${target.previewUrl}?t=${target.snapshotAt}` : target.previewUrl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fenêtres proposées sous les frises. */
|
/** Fenêtres proposées sous les frises. */
|
||||||
|
|||||||
Reference in New Issue
Block a user