perf(frontend): drop react-player — YouTube iframe natif, HLS.js lazy seulement si .m3u8
Some checks failed
CI/CD — Build & Deploy / Build (push) Failing after 35s
CI/CD — Build & Deploy / Deploy to VPS (push) Has been skipped

This commit is contained in:
2026-03-14 08:39:01 +01:00
parent 5eb0a43d7f
commit 9598cd8715
4 changed files with 109 additions and 638 deletions

View File

@@ -1,16 +1,14 @@
import { useState, useEffect, lazy, Suspense } from 'react';
import { useState, useEffect } from 'react';
import { useParams, Link } from 'react-router-dom';
import { apiFetch } from '../lib/api';
// Lazy — HLS/DASH chunks ne chargent que sur /video/:id, pas sur la homepage
const ReactPlayer = lazy(() => import('react-player'));
import VideoPlayer from '../components/VideoPlayer';
interface Video {
id: number;
id: string;
title: string;
description: string;
duration?: number;
storageType: 'youtube' | 's3' | 'local';
storageType: 'youtube' | 's3' | 'local' | 'external';
storageKey: string;
thumbnailUrl?: string;
requiredLevel: number;
@@ -22,23 +20,14 @@ interface VideoResponse {
data: { video: Video };
}
function buildPlayerUrl(storageType: Video['storageType'], storageKey: string): string {
switch (storageType) {
case 'youtube': return `https://www.youtube.com/watch?v=${storageKey}`;
case 's3': return storageKey; // URL S3 complète attendue dans storageKey
case 'local': return `${import.meta.env.VITE_API_URL}/stream/${storageKey}`;
}
}
export default function VideoPage() {
const { id } = useParams<{ id: string }>();
const [video, setVideo] = useState<Video | null>(null);
const [error, setError] = useState<'not_found' | 'forbidden' | 'unknown' | null>(null);
const [video, setVideo] = useState<Video | null>(null);
const [error, setError] = useState<'forbidden' | 'not_found' | 'unknown' | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!id) return;
apiFetch<VideoResponse>(`/videos/${id}`)
.then((res) => setVideo(res.data.video))
.catch((err: Error) => {
@@ -63,7 +52,7 @@ export default function VideoPage() {
return (
<div className="flex flex-col items-center gap-4 pt-16 text-center">
<span className="font-mono text-3xl text-od-accent"></span>
<p className="text-od-text font-medium">Contenu premium</p>
<p className="font-medium text-od-text">Contenu premium</p>
<p className="text-sm text-od-muted">Cette vidéo nécessite un abonnement supérieur.</p>
<Link to="/" className="font-mono text-xs text-od-muted hover:text-od-text transition-colors">
Retour
@@ -83,22 +72,13 @@ export default function VideoPage() {
);
}
const playerUrl = buildPlayerUrl(video.storageType, video.storageKey);
return (
<div className="flex flex-col gap-6">
{/* Player */}
<div className="overflow-hidden rounded border border-od-border bg-od-surface">
<div className="aspect-video w-full">
<Suspense fallback={<div className="h-full w-full bg-od-surface-hi animate-pulse" />}>
<ReactPlayer
src={playerUrl}
width="100%"
height="100%"
controls
/>
</Suspense>
<VideoPlayer storageType={video.storageType} storageKey={video.storageKey} />
</div>
</div>