Spaces:
Sleeping
Sleeping
| import express from 'express'; | |
| import { YoutubeTranscript } from 'youtube-transcript'; | |
| import path from 'path'; | |
| import { fileURLToPath } from 'url'; | |
| // Configuration pour __dirname avec ES Modules | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = path.dirname(__filename); | |
| const app = express(); | |
| // Hugging Face Spaces utilise le port 7860 par défaut | |
| const port = process.env.PORT || 7860; | |
| // Servir les fichiers statiques du dossier 'public' | |
| app.use(express.static(path.join(__dirname, 'public'))); | |
| app.get('/get-transcript', async (req, res) => { | |
| const videoUrl = req.query.url; | |
| if (!videoUrl) { | |
| return res.status(400).json({ error: 'URL de la vidéo manquante' }); | |
| } | |
| try { | |
| // Essayer d'extraire l'ID de différentes formes d'URL YouTube | |
| let videoId = ''; | |
| if (videoUrl.includes('v=')) { | |
| videoId = videoUrl.split('v=')[1].split('&')[0]; | |
| } else if (videoUrl.includes('youtu.be/')) { | |
| videoId = videoUrl.split('youtu.be/')[1].split('?')[0]; | |
| } else { | |
| // On pourrait ajouter d'autres formats d'URL ici (shorts, etc.) | |
| // Pour l'instant, on assume que c'est un ID direct si ce n'est pas une URL connue | |
| videoId = videoUrl; | |
| } | |
| if (!videoId) { | |
| return res.status(400).json({ error: "Impossible d'extraire l'ID de la vidéo depuis l'URL." }); | |
| } | |
| console.log(`Fetching transcript for video ID: ${videoId}`); | |
| // Ajout d'un timeout pour éviter que la requête reste bloquée trop longtemps | |
| const timeoutPromise = new Promise((_, reject) => | |
| setTimeout(() => reject(new Error('Timeout dépassé lors de la récupération de la transcription')), 15000) | |
| ); | |
| // Utilisation de Promise.race pour implémenter un timeout | |
| const transcript = await Promise.race([ | |
| YoutubeTranscript.fetchTranscript(videoId), | |
| timeoutPromise | |
| ]); | |
| if (!transcript || transcript.length === 0) { | |
| return res.status(404).json({ error: 'Transcription non trouvée ou vide pour cette vidéo.' }); | |
| } | |
| // Concaténer les textes de la transcription | |
| const fullText = transcript.map(item => item.text).join(' '); | |
| res.json({ transcript: fullText }); | |
| } catch (error) { | |
| // Log détaillé de l'erreur pour le débogage | |
| console.error('Erreur détaillée lors de la récupération de la transcription:', { | |
| message: error.message, | |
| stack: error.stack, | |
| name: error.name | |
| }); | |
| // Gestion des cas d'erreur spécifiques | |
| if (error.message && error.message.includes('Could not find transcripts')) { | |
| return res.status(404).json({ error: "Aucune transcription disponible pour cette vidéo (elles sont peut-être désactivées ou n'existent pas en auto-généré)." }); | |
| } | |
| if (error.message && error.message.includes('is not a valid video ID')) { | |
| return res.status(400).json({ error: `L'ID vidéo extrait ('${error.message.split("'")[1]}') n'est pas valide. Vérifiez l'URL.` }); | |
| } | |
| if (error.message && error.message.includes('Timeout dépassé')) { | |
| return res.status(504).json({ error: 'Délai d\'attente dépassé lors de la récupération de la transcription. Veuillez réessayer.' }); | |
| } | |
| // Nouvelle gestion spécifique pour les transcriptions désactivées | |
| if (error.message && error.message.includes('Transcript is disabled')) { | |
| const videoId = error.message.match(/\(([^)]+)\)/)?.[1] || "cette vidéo"; | |
| return res.status(404).json({ | |
| error: `Les sous-titres/transcriptions sont désactivés sur cette vidéo (ID: ${videoId}).`, | |
| solution: "Essayez une autre vidéo qui possède des sous-titres activés." | |
| }); | |
| } | |
| // Message d'erreur plus détaillé pour les autres cas | |
| res.status(500).json({ | |
| error: 'Erreur interne du serveur lors de la récupération de la transcription.', | |
| details: error.message | |
| }); | |
| } | |
| }); | |
| // Route pour vérifier l'état du serveur (utile pour Hugging Face) | |
| app.get('/health', (req, res) => { | |
| res.status(200).json({ status: 'ok' }); | |
| }); | |
| // Route par défaut | |
| app.get('/', (req, res) => { | |
| res.sendFile(path.join(__dirname, 'public', 'index.html')); | |
| }); | |
| app.listen(port, '0.0.0.0', () => { | |
| console.log(`Serveur démarré sur http://0.0.0.0:${port}`); | |
| }); |