From de1b0a0363c9d4f41a58d858a9ede7b948d394e7 Mon Sep 17 00:00:00 2001 From: tejaspanchall Date: Wed, 18 Jun 2025 18:46:16 +0530 Subject: [PATCH] url passing correctly --- src/app/watch/[episodeId]/page.js | 28 ++++++++++-- src/components/VideoPlayer.js | 72 ++++++++++++++++++------------- src/lib/api.js | 28 +++++++----- 3 files changed, 84 insertions(+), 44 deletions(-) diff --git a/src/app/watch/[episodeId]/page.js b/src/app/watch/[episodeId]/page.js index c80eda1..b2c73d1 100644 --- a/src/app/watch/[episodeId]/page.js +++ b/src/app/watch/[episodeId]/page.js @@ -178,8 +178,28 @@ export default function WatchPage() { } // Set subtitles if available in the sources response - if (data.subtitles && data.subtitles.length > 0) { - setSubtitles(data.subtitles); + // Check both subtitles and tracks fields since API might return either + const subtitleData = data.subtitles || data.tracks || []; + if (subtitleData.length > 0) { + // Filter out thumbnails from subtitles array + const filteredSubtitles = subtitleData.filter(sub => + sub.lang && sub.lang.toLowerCase() !== 'thumbnails' + ); + + // Look for thumbnails separately + const thumbnailTrack = subtitleData.find(sub => + sub.lang && sub.lang.toLowerCase() === 'thumbnails' + ); + + if (thumbnailTrack && thumbnailTrack.url) { + console.log('[Watch] Found thumbnails track:', thumbnailTrack.url); + setThumbnails(thumbnailTrack.url); + } + + if (filteredSubtitles.length > 0) { + console.log('[Watch] Found subtitles:', filteredSubtitles.length); + setSubtitles(filteredSubtitles); + } } // Try to find the best source in order of preference @@ -421,8 +441,8 @@ export default function WatchPage() { subtitles={subtitles} thumbnails={thumbnails} category={isDub ? 'dub' : 'sub'} - intro={episodeData?.intro} - outro={episodeData?.outro} + intro={episodeData?.intro || null} + outro={episodeData?.outro || null} autoSkipIntro={autoSkip} autoSkipOutro={autoSkip} episodeId={currentEpisodeId} diff --git a/src/components/VideoPlayer.js b/src/components/VideoPlayer.js index c42b10b..01cfbfd 100644 --- a/src/components/VideoPlayer.js +++ b/src/components/VideoPlayer.js @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'; import Hls from 'hls.js'; -import Image from 'next/image'; +import NextImage from 'next/image'; // Get the M3U8 Proxy URL from environment variables const CORSPROXY_URL = process.env.NEXT_PUBLIC_CORSPROXY_URL; @@ -99,11 +99,22 @@ export default function VideoPlayer({ src, poster, headers = {}, subtitles = [], const getProxiedUrl = (url) => { if (!url) return url; + // Log the original URL for debugging + console.log('[VideoPlayer] Original URL:', url); + // Check if the URL is an M3U8 URL if (url.includes('.m3u8') || url.includes('application/vnd.apple.mpegurl')) { + // Check if we have a CORS proxy URL configured + if (!CORSPROXY_URL) { + console.warn('[VideoPlayer] No CORS proxy URL configured, using original URL'); + return url; + } + // Route through the external M3U8 proxy server const encodedUrl = encodeURIComponent(url); - return `${CORSPROXY_URL}/m3u8-proxy?url=${encodedUrl}`; + const proxiedUrl = `${CORSPROXY_URL}/m3u8-proxy?url=${encodedUrl}`; + console.log('[VideoPlayer] Using proxied URL:', proxiedUrl); + return proxiedUrl; } return url; @@ -259,7 +270,14 @@ export default function VideoPlayer({ src, poster, headers = {}, subtitles = [], maxMaxBufferLength: 60, startLevel: -1, // Auto level selection capLevelToPlayerSize: true, // Limit quality based on player size - debug: false + debug: false, + // Add more robust error recovery + fragLoadingMaxRetry: 5, + manifestLoadingMaxRetry: 5, + levelLoadingMaxRetry: 5, + fragLoadingRetryDelay: 1000, + manifestLoadingRetryDelay: 1000, + levelLoadingRetryDelay: 1000 }); window.hls = hls; // Save reference for debugging @@ -294,26 +312,28 @@ export default function VideoPlayer({ src, poster, headers = {}, subtitles = [], }); hls.on(Hls.Events.ERROR, (event, data) => { + console.error('[VideoPlayer] HLS error:', event, data); + if (data.fatal) { switch (data.type) { case Hls.ErrorTypes.NETWORK_ERROR: - console.error('HLS network error'); + console.error('[VideoPlayer] HLS network error, attempting recovery'); hls.startLoad(); break; case Hls.ErrorTypes.MEDIA_ERROR: - console.error('HLS media error'); + console.error('[VideoPlayer] HLS media error, attempting recovery'); hls.recoverMediaError(); break; default: - console.error('HLS fatal error'); - setError('Failed to load video'); + console.error('[VideoPlayer] HLS fatal error, cannot recover'); + setError('Failed to load video - please try another server'); break; } } }); } else { // For non-HLS streams, use native video player - video.src = src; + console.log('[VideoPlayer] Using native player for source:', src); // Set headers for direct video requests const fetchOptions = { @@ -322,7 +342,10 @@ export default function VideoPlayer({ src, poster, headers = {}, subtitles = [], try { const response = await fetch(src, fetchOptions); - if (!response.ok) throw new Error('Failed to load video'); + if (!response.ok) { + console.error('[VideoPlayer] Failed to fetch video:', response.status, response.statusText); + throw new Error('Failed to load video'); + } const blob = await response.blob(); const url = URL.createObjectURL(blob); @@ -330,18 +353,20 @@ export default function VideoPlayer({ src, poster, headers = {}, subtitles = [], // Auto-play when ready if (isPlaying) { - video.play().catch(console.error); + video.play().catch(err => { + console.error('[VideoPlayer] Autoplay error:', err); + }); } } catch (error) { - console.error('Error loading video:', error); - setError('Failed to load video'); + console.error('[VideoPlayer] Error loading video:', error); + setError('Failed to load video - please try another server'); } } setIsLoading(false); } catch (error) { - console.error('Error setting up video:', error); - setError('Failed to load video'); + console.error('[VideoPlayer] Error setting up video:', error); + setError('Failed to load video - please try another server'); setIsLoading(false); } }; @@ -562,18 +587,6 @@ export default function VideoPlayer({ src, poster, headers = {}, subtitles = [], }; }, []); - // Setup thumbnails for scrubbing preview - useEffect(() => { - if (thumbnails) { - console.log('Thumbnails URL available:', thumbnails); - const video = videoRef.current; - if (video) { - // Add data attribute for custom video player to use - video.setAttribute('data-thumbnails', thumbnails); - } - } - }, [thumbnails]); - // Toggle fullscreen const toggleFullscreen = () => { const container = videoRef.current?.parentElement; @@ -1045,14 +1058,13 @@ export default function VideoPlayer({ src, poster, headers = {}, subtitles = [], // Load and verify thumbnails useEffect(() => { if (thumbnails) { - const img = new Image(); + const img = new window.Image(); img.onload = () => { setThumbnailsLoaded(true); console.log('Thumbnails loaded successfully'); }; - img.onerror = () => { - console.error('Failed to load thumbnails'); - setThumbnailsLoaded(false); + img.onerror = (err) => { + console.error('Error loading thumbnails:', err); }; img.src = thumbnails; } diff --git a/src/lib/api.js b/src/lib/api.js index 9206d17..52fc204 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -586,33 +586,41 @@ export const fetchEpisodeSources = async (episodeId, dub = false, server = 'hd-2 return { sources: [] }; } - if (!data.success) { - console.error('[API Error] Response indicates failure - success flag is false'); + // Check if response is valid (status 200 or success flag) + // Some API responses use success flag, others use status code + const isValidResponse = (data.success === true) || (data.status === 200); + if (!isValidResponse) { + console.error('[API Error] Response indicates failure - invalid status or success flag'); return { sources: [] }; } - if (!data.data) { + // Get the data object from either data.data (new format) or data (old format) + const responseData = data.data || data; + + if (!responseData) { console.error('[API Error] Empty data object in response'); return { sources: [] }; } - if (!data.data.sources || data.data.sources.length === 0) { + if (!responseData.sources || responseData.sources.length === 0) { console.error('[API Error] No sources found in response data'); return { sources: [] }; } - console.log('[API Success] Found sources:', data.data.sources.map(s => ({ + console.log('[API Success] Found sources:', responseData.sources.map(s => ({ url: s.url.substring(0, 50) + '...', quality: s.quality, isM3U8: s.isM3U8 }))); return { - sources: data.data.sources || [], - headers: data.data.headers || { "Referer": "https://hianime.to/" }, - subtitles: data.data.subtitles || [], - anilistID: data.data.anilistID || null, - malID: data.data.malID || null + sources: responseData.sources || [], + headers: responseData.headers || { "Referer": "https://hianime.to/" }, + subtitles: responseData.tracks || responseData.subtitles || [], + anilistID: responseData.anilistID || null, + malID: responseData.malID || null, + intro: responseData.intro || null, + outro: responseData.outro || null }; } catch (error) { console.error('Error fetching episode sources:', error);