Commit Graph
21 Commits
Author SHA1 Message Date
bruno 6b32ede302 fix(shorts): flèches aux bords gauche/droite, toujours montées, visibles
CI / build-and-test (push) Successful in 14m55s
Retour utilisateur : les flèches Préc./Suiv. n'étaient toujours pas
visibles et la position attendue est précisée — une à GAUCHE et une à
DROITE de la vidéo, centrées verticalement.

- Flèches remises aux bords gauche/droite du cadre (top-1/2,
  -translate-y-1/2) avec contraste renforcé : ring-2 white/50, fond
  black/55 — lisibles sur toute image.
- Sorties de @if (current()) comme le menu : TOUJOURS montées, donc
  présentes même sur l'état de flux mort (désactivées) — on ne cherche
  plus où naviguer.
- Chaque changement de vidéo réveille les contrôles 2,5 s (poke sous
  matchMedia hover : sur tactile le chrome reste visible en permanence,
  un poke y aurait armé le minuteur et masqué le chrome — régression
  détectée par la recette mobile puis corrigée).
- Recette Playwright desktop+mobile : 17/17 (bords à 6 px, centrage
  vertical ±1 px, fondu repos 0.18, plein au mouvement, mobile plein,
  pas de chevauchement 2D avec la flèche retour, flèches + menu
  présents sur feed mort). Build + test:section + test:shorts-catalog
  verts avant commit.
2026-10-02 12:34:13 -04:00
bruno e44b545e01 feat(shorts): flèches en ligne avec le menu + fondu des contrôles au repos
CI / build-and-test (push) Successful in 14m54s
Demandes (page /shorts) : retrouver les flèches Préc./Suiv. là où se
trouve le menu, et des contrôles presque invisibles au repos pour
laisser la vidéo respirer (ton pro).

- Flèches déplacées du milieu des côtés vers la rangée HAUTE du cadre,
  centrées : même niveau que le FAB menu, sans chevaucher la flèche
  retour mobile (gauche) ni le FAB (droite). Le toast « Lien copié »
  passe en z-30 pour rester lisible sous la rangée.
- Fondu au repos : nouvelles règles index.css — flèches (.shorts-ctrl)
  et FAB à 0.18 d'opacité quand le chrome est au repos (2,5 s sans
  souris), pleins au moindre mouvement (chromeVisible) ou au survol
  direct (:hover), jamais atténués quand le panneau est ouvert
  (pm-fab-open). Sur tactile, le chrome ne se masque jamais (pas de
  mousemove : comportement voulu, mobile inchangé).
- Le minuteur d'immobilité est armé au chargement (pokeChrome sous
  matchMedia('(hover: hover)')) : sans un premier mousemove,
  chromeVisible restait true et le fondu ne s'armait jamais.
- mouseenter sur l'iframe : en entrant sur la vidéo, le document
  parent ne reçoit pas les mouvements internes à l'iframe — l'entrée
  réveille les contrôles.

Recette Playwright desktop+mobile, 14/14 : position haute centrée,
absence de chevauchements, repos 0.18 (flèches + FAB), retour plein
après mouvement réel, mobile plein en permanence. Build + test:section
verts avant commit.
2026-10-02 11:28:03 -04:00
bruno 3ab61821b2 fix(shorts): flux vide + menu absent + flèches invisibles (Rumble)
CI / build-and-test (push) Successful in 14m55s
Trois symptômes, deux racines — diagnostiqués au navigateur (Playwright
desktop + mobile) et hors navigateur (vraies réponses API + fonctions
front réelles importées via ts-node) :

1. Double dedup() dans handleShortsResponse : show() re-dédupliquait une
   liste déjà dédupliquée par son appelant → le second passage marquait
   tout comme « déjà vu » et posait items=[] en silence → écran
   « Aucun short à afficher » sans erreur ni requête suivante, dès que
   le catalogue type=shorts rendait moins de 3 items (aléa de la
   requête tirée au sort). Racine des écrans morts, présente depuis le
   commit 983c6cb.
2. Menu FAB et flèches Préc./Suiv. vivaient dans @if (current()) :
   absents de TOUS les états vides, donc impossibles à utiliser
   exactement quand le flux meurt (impossible de changer de
   fournisseur). Le menu est désormais toujours monté (z-30 au-dessus
   des placeholders), et la flèche désactivée passe en opacity 0.4
   (au 1er item, Préc. était quasi invisible à 0.3).
3. Format : Rumble n'expose AUCUNE dimension — vérifié : vignettes og:image
   toutes en crop fixe 16:9 (9/9 échantillons, 1280x720 et 480x270) et
   aucun width/height dans les pages vidéo → un filtre d'orientation
   par vignette est impossible, la classification reste durée-seule.
   En revanche le flux natif rumble.com/shorts (les vrais shorts
   officiels) devient la voie primaire : loadFeed va droit au chemin
   historique au lieu du catalogue qui ne rendait que des brives 16:9.

Tests verts avant commit : npm run build, test:section,
test:shorts-catalog, test:filters.
2026-10-02 10:26:58 -04:00
bruno 4d1d44f4ee feat(shorts): flèches Préc./Suivant SUR la vidéo + embed Rumble en 16:9
CI / build-and-test (push) Canceled after 0s
- Flèches : elles vivaient EN DEHORS du cadre (et se fadaient avec le
  chrome auto-hide). Elles sont désormais posées dans le cadre, à mi-hauteur
  sur les bords, toujours visibles (classe `shorts-chrome` retirée), sur
  mobile comme sur bureau, et le stopPropagation protège le geste tactile.
- Rumble : la plateforme est16:9 mais n'expose ni largeur ni hauteur →
  l'embed tombait dans un cadre 9:16 (étiré / réduit). `isWideEmbed()`
  (pur + testé) décide de la boîte : dimensions connues => orientation
  réelle, sinon repli « rumble = paysage » ; la CSS `.embed-wide` rend une
  iframe 16:9 centrée (434x244 dans un cadre 434x771, mesuré). Les vidéos
  verticales (dimensions connues) gardent le cadre pleine hauteur.
- État vide : un fournisseur sans résultat laissait un cadre NOIR muet
  (ni squelette, ni message) — il affiche désormais « Aucun short à afficher
  pour ce fournisseur » + Réessayer.

Tests : test:shorts-catalog (3 cas isWideEmbed), test:kind, test:section,
test:search verts ; build ng OK ; sondage Playwright local : flèches dans
le cadre + navigation suivant/précédent réelle, boîte embed-wide 16:9
centrée, short vertical inchangé (iframe pleine hauteur), état vide affiché.
2026-10-01 23:37:10 -04:00
bruno 059481b9ea feat(twitch): l'embed ne se charge qu'apres un geste (autoplay)
CI / build-and-test (push) Canceled after 10m52s
- Methode « touch listener b4 loading the iframe » : l'URL de l'embed Twitch
  n'est produite qu'apres un premier geste — navigator.userActivation.
  hasBeenActive a l'arrivee (clic sur un lien = fenetre d'activation de 5 s),
  sinon pointerdown / keydown / wheel. Le premier chargement de l'iframe
  tombe donc dans un contexte d'activation utilisateur.
- Invite « Touchez pour charger la vidéo » sur /watch et /shorts pendant
  l'attente (sinon spinner infini sur /watch, cadre noir sur /shorts).
- /shorts : pas d'avance auto tant que l'embed n'est pas charge — le flux
  ne switchait plus d'une video a l'autre sans jamais jouer.
- Le nudge (recharge &r=1 au premier geste) est conserve pour les videos
  montees sans geste (avance auto, arrivee avec activation deja consommee).
- Verifs instance locale : 8/8 (arrivee a froid : invite + montage au geste)
  et 6/6 (arrivee avec activation : montage immediat + recharge unique).
2026-10-01 12:08:03 -04:00
bruno 01e0671de9 feat(lecteur): menu FAB partage /watch et /shorts
CI / build-and-test (push) Successful in 14m48s
- PlayerMenuComponent : FAB circulaire translucide (haut-gauche) + panneau
  deroulant, commun aux deux pages (position, style, open/close, clic exterieur)
- /shorts : consolidation de tous les boutons (fournisseurs, langue, actions)
  dans le menu FAB ; suppression du rail a droite et de la rangee du haut
- /watch : actions (cinema, qualite, j'aime, playlist, transcription,
  telechargement, partage, ouvrir) deplacees dans le menu FAB
- AddToPlaylistComponent : variante menuItem pour s'integrer au menu
- styles .pm-item/.pm-sep/.pm-section-label dans index.css
2026-09-30 22:50:46 -04:00
bruno c391be80e5 fix(shorts): aligner referrerpolicy de l'iframe sur /watch (origin)
CI / build-and-test (push) Successful in 14m54s
L'iframe Shorts utilisait referrerpolicy=strict-origin-when-cross-origin
alors que /watch utilise 'origin'. C'est la seule difference restante entre
les deux pages pour Dailymotion (URL identique, allow_embed=true) et elle
fait repondre 'Forbidden' au player. On aligne sur 'origin'.

Revert du referrerPolicy helmet (no-op pour les iframes qui ont leur propre
attribut, risque de side-effects inutile sur les CDN de vignettes).
2026-09-30 21:22:33 -04:00
bruno 6b20b1ce79 fix(shorts): anti-Forbidden Dailymotion + selecteur icon-only
CI / build-and-test (push) Successful in 14m55s
- DM: embed mute par defaut (comme /watch) + son sur action explicite
- helmet: Referrer-Policy strict-origin-when-cross-origin (Dailymotion exige un Referer)
- searchVideosPage DM: champs allow_embed/width/height/language/owner.id
- iframes shorts/watch: allow fullscreen (conforme embed officiel DM)
- selecteur shorts icon-only (pastilles + globe cyclique)
2026-09-30 19:55:23 -04:00
bruno 49859f4e81 feat(shorts): pastilles a logos + filtre de langues preferees
CI / build-and-test (push) Successful in 14m49s
Boutons fournisseurs avec disque aux couleurs de la marque + glyphe SVG (play YT, bulle Twitch, initiale sinon) ; icone etincelles pour Pour toi. Selecteur de langues Profil/FR/EN/FR+EN/Toutes (persiste newtube.shorts.langFilter, invite compris) : chaque flux passe par effectiveShortsLangs (resolveShortsLangs pur + spec). Docs 9.9.
2026-09-30 12:57:31 -04:00
bruno 3e1980283a fix(shorts): hover-chrome, swipe mobile garanti, avance auto fiabilisee
CI / build-and-test (push) Successful in 15m2s
Chrome auto-hide au hover desktop (2,5 s). Capteur tactile mobile : swipe garanti (l'iframe mangeait les touchers), tap = play/pause YT ou 6 s d'acces direct au lecteur sinon. Fleche retour accueil mobile, cadre quasi plein ecran. Avance auto : handshake YT listening (les evenements player n'arrivaient jamais), onStateChange canonique, retry borne anti-prefetch. Docs 9.9.
2026-09-30 12:21:15 -04:00
bruno 8e087daf93 feat(shorts): page /shorts alimentee par le catalogue + refonte pro/mobile
CI / build-and-test (push) Successful in 14m45s
SearchService.fetchCatalogShorts (type shorts via /api/search : cache, provenance, FF) + pont pur shorts-catalog.ts (mapping, meta, fraicheur, spec 27 assertions). WatchShortComponent : catalogue d'abord (feed, pagination, Pour toi), repli legacy, Twitch clips inchanges, avatars paresseux via channelMeta. UI facon YouTube : plein ecran 100dvh, fond d'ambiance, rail overlay 48px, meta/fraicheur/pastille provider, safe-area.
2026-09-30 09:16:56 -04:00
bruno 37681c4f53 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
2026-09-29 14:51:56 -04:00
bruno d4895bae92 fix(shorts): autoplay muet, langues FR/EN, proxy prod et Dailymotion embeds
CI / build-and-test (push) Successful in 14m9s
- autoplay: les Shorts demarrent muets (comme Watch) pour garantir l'autoplay des iframes; le son se debloque a la premiere interaction (unlockSound) et reste controlable
- proxy prod: ajoute les alias /proxy/twitch-api, /proxy/twitch-auth, /proxy/dm, /proxy/odysee (evite le fallback SPA -> parse JSON 'status 200 ok:false'); forwardJson accepte les deux prefixes. Corrige aussi la validation des clips Twitch morts
- Dailymotion: allow_embed demande dans les flux shorts/trending -> les videos non-embeddables ('Forbidden') sont exclues
- langues: mapping language (Dailymotion/PeerTube/Odysee) + shortsLangOk applique a tous les fournisseurs; en+fr toujours acceptes
- PeerTube shorts: durationMin/Max cote serveur (plus de videos longues au hasard)
- Twitch: validation helix/clips de nouveau fonctionnelle + autoplay muet
2026-09-29 14:22:45 -04:00
bruno 3f4cd56f14 fix(shorts): pré-validation (clips morts, Rumble 404), autoplay Rumble, onError auto-skip, zone sous-vidéo retirée
CI / build-and-test (push) Successful in 14m16s
2026-09-29 11:23:33 -04:00
bruno f76a3795c2 fix(twitch,rumble,shorts): replis serveur, embed Rumble autoritaire, refonte UX Shorts
CI / build-and-test (push) Successful in 14m15s
2026-09-29 10:39:03 -04:00
bruno 5994841bda fix(shorts): embeds DM/PT/Rumble/Twitch + flux Pour toi multi-fournisseurs
CI / build-and-test (push) Successful in 14m16s
2026-09-29 09:38:13 -04:00
bruno 34f432a7c1 fix(shorts): embeds par fournisseur + flux infini (153/Forbidden/not-found) 2026-09-29 09:04:09 -04:00
bruno 66f1da1d72 feat(mobile): refonte responsive complète (header, drawer, dvh, cibles tactiles)
Le header était en grid-cols-[auto_1fr_auto] avec une barre de recherche
non-wrappable (7 chips + input + 2 boutons, aucun min-w-0) : ~1000px de
largeur intrinsèque dans un viewport de 375px. Toutes les routes
débordaient horizontalement et les boutons Connexion/Inscription partaient
hors écran.

Socle
- --header-h / --header-offset / --app-vh centralisent la métrique du
  header : supprime les top-16 codés en dur (channel-tabs était en top-0 et
  glissait sous le header au scroll).
- Safe-area iOS, viewport-fit=cover, color-scheme/theme-color.
- dvh partout (100vh > hauteur visible sur iOS), overflow-x: clip au lieu de
  hidden (hidden cassait silencieusement tous les sticky).
- Cible tactile 44px sur pointeur grossier, skip link, focus-ring clavier,
  scroll-rail pour les tab strips.

Header
- Barre mobile (burger, logo, recherche, menu ⋮) + barre desktop inchangée.
- Le menu ⋮ expose ce qui disparaissait : bande des thèmes, préférences,
  historique, favoris, téléchargements, thème, connexion/inscription.
- Recherche en feuille sous le header avec focus automatique.
- Échap / clic extérieur / navigation ferment les panneaux transitoires.

Drawer
- Partait à inset-y-0 : les 56 premiers px du menu étaient derrière le
  header. Descend sous le header, bouton fermer intégré, verrouille le
  scroll, se ferme à Échap.

Barre de recherche
- Chips masquées sous lg, remplacées par un bouton résumé qui ouvre le
  sélecteur de fournisseurs. Suggestions en dvh, menu Ctrl+K plein écran
  sur mobile.

Pages
- Shorts : cadre 9:16 contraint par dvh ET vw (il débordait en paysage),
  Préc./Suiv. qui étaient hors du conteneur height-capped.
- Watch : barre d'actions qui wrappe, mode cinéma en opacity-0 group-hover
  donc invisible au doigt, thumbnails fluides, playsinline sur les iframes.
- Historique, thèmes, chaîne, playlists, préférences, sessions : rails
  swipables, min-w-0, truncate, en-têtes qui wrappent.

Vérifié : audit navigateur (CDP) sur 17 routes x 7 largeurs (320→1440),
zéro débordement horizontal ; 19 tests d'interaction mobile ; suites de
tests du dépôt vertes (api 40/40, transcript 27/27, search, suggest,
playlists, preferences, subscriptions, highlight, telemetry).
2026-09-28 14:38:31 -04:00
bruno d0d1c07535 fix(shorts): flux dedie avec filtre duree serveur + loop + replis 2026-09-27 16:53:01 -04:00
bruno 97e5de74f5 feat(channel): page details chaine multi-providers avec onglets et infinite scroll
CI / build-and-test (push) Successful in 13m34s
- Strategy Pattern front: ChannelProviderInterface + 6 providers (yt/dm/tw/pt/od/ru) + factory (ids longs/courts)
- ChannelContentService: cache par onglet/tri/recherche (TTL 5min), pagination nextPage
- ChannelPage: header (banniere/avatar/subs/description ...plus), tabs dynamiques par capabilities, grilles videos/shorts 9:16/playlists/live, recherche debounced, tri recent/populaire, infinite scroll IntersectionObserver, skeletons/empty/error
- Backend: GET /api/channels/:provider/:id/content (videos/shorts/playlists/live) natif par provider
2026-09-25 10:15:12 -04:00
bruno 2866d74b32 first commit 2025-09-14 23:05:30 -04:00