diff --git a/README.md b/README.md index a918995..2e34947 100644 --- a/README.md +++ b/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 plan, quitte à déborder sur les cartes voisines. -Source : le même appel que le statut (`/api/front/v2/models/username/{pseudo}/cam`) inclut -déjà `previewUrlThumbBig` et `snapshotTimestamp` — aucune requête supplémentaire. L'URL de -la vignette ne change pas d'une image à l'autre (le CDN la sert avec un cache de 30 jours), -donc le client y ajoute `?t={snapshotTimestamp}` pour forcer un frame à jour à chaque sonde -plutôt que de garder indéfiniment la toute première image vue. +Source : le même appel que le statut (`/api/front/v2/models/username/{pseudo}/cam`), sans +requête supplémentaire — mais pas son champ `previewUrlThumbBig` / `previewUrlThumbSmall` : +malgré leur nom, ce sont ceux de la photo de couverture du profil, fixe, choisie par le +modèle, pas une image de la diffusion en cours (repéré à l'usage : l'aperçu ne changeait +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 aperçu, pas un flux temps réel. diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 5fd70bf..19c79af 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1206,17 +1206,26 @@ export interface StripchatStatus { */ statusChangedAt: number | null; /** - * Vignette du flux (`previewUrlThumbBig`) — une image, pas un flux vidéo : - * l'agent seul pilote un navigateur, le serveur n'a que cette API REST. - * Absente si le modèle n'a jamais diffusé. + * Image du flux — pas le flux lui-même : l'agent seul pilote un navigateur, + * le serveur n'a que cette API REST. + * + * 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; /** - * Horodatage de cette vignette côté plateforme, pour invalider le cache du - * navigateur : l'URL, elle, ne change pas d'une image à l'autre — le CDN la - * sert avec un `max-age` de 30 jours. Sans un paramètre qui varie à chaque - * rafraîchissement, le navigateur garderait indéfiniment la toute première - * image vue. + * Horodatage de cette vignette côté plateforme — déjà encodé dans + * `previewUrl`, donc sans utilité pour le cache : une nouvelle vignette porte + * de toute façon une URL différente. Exposé pour l'affichage seulement + * (« vignette vieille de X »). */ snapshotAt: number | null; } @@ -1254,10 +1263,10 @@ export async function fetchStripchatStatus( const payload = (await response.json()) as { user?: { user?: { + id?: number; status?: string; avatarUrl?: string; statusChangedAt?: string; - previewUrlThumbBig?: string; snapshotTimestamp?: number; }; }; @@ -1273,6 +1282,7 @@ export async function fetchStripchatStatus( : Number.NaN; // Secondes côté API, comme tous les timestamps Unix bruts de cette plateforme. const snapshotAt = Number(profile?.snapshotTimestamp) * 1000; + const modelId = Number(profile?.id); return { raw, @@ -1280,8 +1290,8 @@ export async function fetchStripchatStatus( avatarUrl: typeof profile?.avatarUrl === 'string' && profile.avatarUrl ? profile.avatarUrl : null, statusChangedAt: Number.isFinite(changedAt) ? changedAt : null, previewUrl: - typeof profile?.previewUrlThumbBig === 'string' && profile.previewUrlThumbBig - ? profile.previewUrlThumbBig + Number.isFinite(modelId) && modelId > 0 && Number.isFinite(snapshotAt) && snapshotAt > 0 + ? `https://img.doppiocdn.net/thumbs/${Math.round(snapshotAt / 1000)}/${modelId}` : null, snapshotAt: Number.isFinite(snapshotAt) && snapshotAt > 0 ? snapshotAt : null, }; diff --git a/packages/web/src/streamers.ts b/packages/web/src/streamers.ts index eb54521..8ead28f 100644 --- a/packages/web/src/streamers.ts +++ b/packages/web/src/streamers.ts @@ -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 - * avec un `max-age` de 30 jours — donc sans `snapshotAt` en paramètre, le - * navigateur garderait indéfiniment la toute première image vue au lieu de la - * rafraîchir à chaque sonde. + * Un simple passe-plat aujourd'hui — `previewUrl` porte déjà l'horodatage de + * la vignette dans son chemin, donc chaque nouvelle image a naturellement sa + * propre URL, sans paramètre de cache à ajouter. Gardé comme fonction plutôt + * 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): string | null { - if (!target.previewUrl) return null; - return target.snapshotAt ? `${target.previewUrl}?t=${target.snapshotAt}` : target.previewUrl; +export function previewSrc(target: Pick): string | null { + return target.previewUrl; } /** Fenêtres proposées sous les frises. */