fix(shorts): embed PeerTube sur l'instance d'origine + FAB glissable + layout bureau
CI / build-and-test (push) Canceled after 0s

- PeerTube : l'adaptateur pt.ts reconstruisait l'item SANS `url` et le pont
  catalogue ne conservait l'URL que pour Odysee → /shorts reconstruisait
  l'embed sur l'instance ACTIVE → « Sorry this video does not exist » sur
  toute vidéo fédérée. `url` est désormais miroitée dans VideoItem (contrat
  v2), propagée par PtAdapter et gardée par catalogShortToVideo :
  peerTubeHostOf() dérive enfin le host d'origine. Vérifié de bout en bout :
  embed tube.blueben.net → 200 + vrai titre, cas de test dédié dans
  shorts-catalog.spec.
- FAB du menu : déplaçable au pointeur (seuil 6 px, position en % du cadre,
  persistée en localStorage). Le clic qui suit un glissement n'ouvre pas le
  menu, et le panneau s'ouvre TOUJOURS vers l'intérieur du cadre (classes
  pm-opens-left / pm-opens-right / pm-opens-up posées par applyAnchor) :
  sinon overflow:hidden le rognait dès qu'on déplaçait le bouton.
- Bureau : --shorts-chrome 9rem → 4rem (la vidéo passe de 691 à 771 px de
  haut en 1280x900, 389 → 434 de large) et menu compact au-delà de 768 px
  (FAB 36 → 30 px, panneau 233 → 202 px). Mobile inchangé (36 / 636 px).

Tests : test:shorts-catalog (nouveau cas PeerTube), test:kind,
test:section, test:search verts ; build ng OK ; sondage Playwright 19/19
sur l'instance locale (layout, glissement + restauration, embed PeerTube
200 sans erreur).
This commit is contained in:
2026-10-01 23:09:28 -04:00
parent 5f43fa1e59
commit 474de0570c
6 changed files with 167 additions and 6 deletions
+4
View File
@@ -45,6 +45,10 @@ export class PtAdapter implements ProviderAdapter<VideoItem> {
// Le serveur envoie `publishedAt` (ISO) quand l'instance l'expose.
publishedAt: typeof it.publishedAt === 'string' ? it.publishedAt : undefined,
channelExternalId,
// URL canonnique : instance d'origine (vidéos fédérées). Sans elle,
// /shorts reconstruit l'embed sur l'instance ACTIVE → « Sorry this
// video does not exist ».
url: typeof it.url === 'string' ? it.url : undefined,
// Signaux de type pour le raffinement client des filtres.
type: typeof it.type === 'string' ? it.type : undefined,
isShort: it.isShort === true ? true : undefined,
+9
View File
@@ -50,6 +50,15 @@ assertEqual(
assertEqual(v?.views, 0, 'vues inconnues → 0 (pas de devinette)');
assertEqual(v?.duration, 0, 'durée inconnue → 0');
}
{
// PeerTube fédéré : l'URL porte l'instance d'origine. Sans elle, /shorts
// reconstruit l'embed sur l'instance ACTIVE → « Sorry this video does not exist ».
const v: any = catalogShortToVideo({
id: 'p1', provider: 'peertube', title: 'P', thumbnailUrl: '', channelName: 'C',
url: 'https://makertube.net/videos/watch/p1',
} as any);
assertEqual(v?.url, 'https://makertube.net/videos/watch/p1', 'url fournisseur conservée (host PeerTube)');
}
{
const v: any = catalogShortToVideo({
id: 'y1', provider: 'youtube', title: 'Y', thumbnailUrl: '', channelName: 'C',
+3 -1
View File
@@ -56,7 +56,9 @@ export function catalogShortToVideo(item: VideoItem | null | undefined): Video |
const embeddableRaw = (item as { embeddable?: unknown }).embeddable;
const allowEmbed = typeof embeddableRaw === 'boolean' ? embeddableRaw : undefined;
return {
url: provider === 'odysee' && slug ? `https://odysee.com/${slug}` : '',
// Odysee : URL normalisée depuis son slug ; ailleurs on conserve l'URL
// du fournisseur (PeerTube fédéré en a besoin pour choisir le bon host).
url: provider === 'odysee' && slug ? `https://odysee.com/${slug}` : strOrEmpty(item.url),
type: item.isLive === true ? 'live' : (item.isShort === true ? 'short' : 'video'),
title: strOrEmpty(item.title),
thumbnail: strOrEmpty(item.thumbnailUrl),