fix(shorts): flux vide + menu absent + flèches invisibles (Rumble)
CI / build-and-test (push) Successful in 14m55s
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.
This commit is contained in:
@@ -54,7 +54,6 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (current(); as v) {
|
||||
<!-- Menu FAB : toutes les options (fournisseur, langue, actions). -->
|
||||
<app-player-menu [(open)]="menuOpen">
|
||||
<div class="pm-section-label">Fournisseur</div>
|
||||
@@ -146,6 +145,7 @@
|
||||
<span class="pm-item-label">Passer (vidéo illisible)</span>
|
||||
</button>
|
||||
</app-player-menu>
|
||||
@if (current(); as v) {
|
||||
|
||||
<!-- Capteur tactile (mobile uniquement) : l'iframe mange les
|
||||
touchers, donc le swipe up/down passerait à la trappe. Cette
|
||||
@@ -208,12 +208,12 @@
|
||||
<!-- Navigation précédent / suivant : SUR la vidéo (hors auto-hide du
|
||||
chrome, hors geste tactile — stopPropagation dans les handlers). -->
|
||||
<button type="button" (click)="prev(); $event.stopPropagation()" [disabled]="!canPrev()"
|
||||
class="absolute left-1.5 top-1/2 z-20 flex h-10 w-10 -translate-y-1/2 items-center justify-center rounded-full bg-black/45 text-white ring-1 ring-white/15 backdrop-blur-md transition hover:bg-black/70 disabled:opacity-30"
|
||||
class="absolute left-1.5 top-1/2 z-20 flex h-10 w-10 -translate-y-1/2 items-center justify-center rounded-full bg-black/45 text-white ring-1 ring-white/15 backdrop-blur-md transition hover:bg-black/70 disabled:opacity-40"
|
||||
aria-label="Short précédent">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M15.5 4.5 8 12l7.5 7.5z"/></svg>
|
||||
</button>
|
||||
<button type="button" (click)="next(); $event.stopPropagation()" [disabled]="!canNext()"
|
||||
class="absolute right-1.5 top-1/2 z-20 flex h-10 w-10 -translate-y-1/2 items-center justify-center rounded-full bg-black/45 text-white ring-1 ring-white/15 backdrop-blur-md transition hover:bg-black/70 disabled:opacity-30"
|
||||
class="absolute right-1.5 top-1/2 z-20 flex h-10 w-10 -translate-y-1/2 items-center justify-center rounded-full bg-black/45 text-white ring-1 ring-white/15 backdrop-blur-md transition hover:bg-black/70 disabled:opacity-40"
|
||||
aria-label="Short suivant">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M8.5 4.5 16 12l-7.5 7.5z"/></svg>
|
||||
</button>
|
||||
|
||||
@@ -1492,6 +1492,16 @@ export class WatchShortComponent implements OnDestroy {
|
||||
return;
|
||||
}
|
||||
const provider = this.provider();
|
||||
// Rumble : on va droit au chemin historique (flux natif rumble.com/shorts
|
||||
// + remplissage recherche). Le catalogue `type=shorts` ne rend que des
|
||||
// vidéos <=75 s HORizontales (Rumble n'expose aucune dimension : ni largeur
|
||||
// ni hauteur dans les pages, vignettes en crop fixe 16:9 — vérifié 9/9),
|
||||
// ce qui donnait un feed de « briques » 16:9 au lieu des shorts officiels.
|
||||
if (provider === 'rumble') {
|
||||
this.catalogActive = false;
|
||||
this.loadLegacyFeed();
|
||||
return;
|
||||
}
|
||||
// Shorts via le CATALOGUE d'abord (`/api/search?type=shorts` : cache,
|
||||
// provenance, feature-flags). Twitch garde son flux de clips historique
|
||||
// (pas d'équivalent catalogue : la recherche serveur renvoie des VOD).
|
||||
@@ -1646,8 +1656,12 @@ export class WatchShortComponent implements OnDestroy {
|
||||
const raw = (res.items || []).filter(v => !!v.videoId);
|
||||
this.nextCursor.set(res.nextCursor || null);
|
||||
if (!res.nextCursor) this.exhaustedQueries.add(this.currentQuery());
|
||||
// NOTE : `list` est DÉJÀ dédupliqué par chaque appelant (ligne 1671 /
|
||||
// branche YouTube). Un second passage ici marquait tout comme « déjà vu »
|
||||
// et posait une liste VIDE en silence — écran « Aucun short » sans erreur
|
||||
// ni requête suivante (bug reproduit au navigateur, fix racine).
|
||||
const show = (list: Video[]) => {
|
||||
const deduped = this.dedup(list);
|
||||
const deduped = list;
|
||||
this.items.set(deduped);
|
||||
this.index.set(0);
|
||||
this.error.set(null);
|
||||
|
||||
Reference in New Issue
Block a user