fix(shorts): orientation autoritaire, langues YouTube et autoplay fiable
CI / build-and-test (push) Successful in 14m18s

- format: des que largeur/hauteur sont connues, l'orientation fait autorite (horizontale/carree => jamais short, meme <75 s). Repli duree reserve aux providers muets
- dimensions mappees: Dailymotion (width,height), PeerTube (aspectRatio), Odysee (value.video.width/height) => validation verticale reelle
- YouTube: langue via snippet.defaultAudioLanguage (filtre FR/EN)
- autoplay: demarrage muet, suppression du deblocage automatique au scroll/selection (reload d'embed hors geste => ecran noir); son via le bouton dedie
- PeerTube embed: muted=1 pour l'autoplay
- server/search-filters.mjs: miroir de la regle d'orientation + tests mis a jour
This commit is contained in:
2026-09-29 14:51:56 -04:00
parent d4895bae92
commit 37681c4f53
7 changed files with 73 additions and 50 deletions
+3 -3
View File
@@ -63,9 +63,9 @@ assertEqual(
false,
'verticale durée 0 ⇒ pas short',
);
// Règle 4 : repli durée seule (non-régression).
assertEqual(isShortVideo({ duration: 50, width: 1280, height: 720 }), true, 'horizontale 50 s ⇒ short');
assertEqual(isShortVideo({ duration: 50 }), true, '50 s sans dimensions ⇒ short');
// Dimensions connues non verticales ⇒ jamais short (orientation autoritaire).
assertEqual(isShortVideo({ duration: 50, width: 1280, height: 720 }), false, 'horizontale 50 s (dims connues) ⇒ pas short');
assertEqual(isShortVideo({ duration: 50 }), true, '50 s sans dimensions ⇒ short (repli durée)');
assertEqual(isShortVideo({ duration: 72 }), true, '72 s non-YouTube ⇒ short (≤ 75)');
assertEqual(isShortVideo({ duration: 72, provider: 'youtube' }), false, '72 s YouTube ⇒ pas short (> 70)');
assertEqual(isShortVideo({ duration: 0 }), false, 'durée 0 ⇒ jamais short');
+12 -6
View File
@@ -6,11 +6,12 @@
* construction ; une durée aberrante est du bruit, pas une preuve).
* 2. Flag natif (`isShort`, `type === 'short'`, URL `/shorts/`) ⇒ Short,
* sauf durée connue > SHORT_MAX_SECONDS.
* 3. Orientation verticale stricte (`height > width`, ratio ≤ 0.8) ET durée
* connue ≤ VERTICAL_SHORT_MAX_SECONDS (90 s) ⇒ Short.
* 4. Verticale SANS durée connue ⇒ PAS un Short (même doctrine que
* « durée 0 ne qualifie jamais »).
* 5. Repli durée seule : 1..70 s (YouTube), 1..75 s (autres).
* 3. Dimensions connues : l'orientation fait autorité.
* - verticale (`height > width`, ratio ≤ 0.8) ET durée connue ≤ 90 s ⇒ Short ;
* - verticale sans durée connue ⇒ PAS un Short ;
* - horizontale/carrée ⇒ JAMAIS un Short (même si ≤ 70/75 s).
* 4. Dimensions inconnues (YouTube Data API, Dailymotion, PeerTube, Rumble…) :
* repli durée seule : 1..70 s (YouTube), 1..75 s (autres).
*/
export type VideoKind = 'short' | 'live' | 'video';
@@ -79,17 +80,22 @@ export function isShortVideo(v: ClassifiableVideo | null | undefined): boolean {
}
// 3) + 4) Orientation (width/height quand le provider les expose).
// DÈS QUE les dimensions sont connues, l'orientation fait AUTORITÉ : une
// vidéo horizontale/carrée n'est jamais un short, même si elle est courte.
const w = numOrZero((v as { width?: unknown }).width);
const h = numOrZero((v as { height?: unknown }).height);
if (w > 0 && h > 0) {
const vertical = h > w && w / h <= VERTICAL_MAX_RATIO;
if (vertical) {
// Verticale sans durée connue ⇒ PAS un short (doctrine historique).
if (!hasKnownDuration) return false;
return duration <= VERTICAL_SHORT_MAX_SECONDS;
}
return false;
}
// 5) Repli durée seule (comportement historique inchangé).
// 5) Repli durée seule, UNIQUEMENT quand le provider n'expose pas
// l'orientation (YouTube Data API, Dailymotion, PeerTube, Rumble…).
if (!hasKnownDuration) return false;
if (provider === 'youtube') return duration <= YOUTUBE_SHORT_MAX_SECONDS;
return duration <= SHORT_MAX_SECONDS;