import React, { useEffect, useRef, useMemo } from 'react'; import videojs from 'video.js'; import 'video.js/dist/video-js.css'; // Import the separated components import EndScreenOverlay from '../overlays/EndScreenOverlay'; import AutoplayCountdownOverlay from '../overlays/AutoplayCountdownOverlay'; import ChapterMarkers from '../markers/ChapterMarkers'; import SpritePreview from '../markers/SpritePreview'; import NextVideoButton from '../controls/NextVideoButton'; import AutoplayToggleButton from '../controls/AutoplayToggleButton'; import CustomRemainingTime from '../controls/CustomRemainingTime'; import CustomChaptersOverlay from '../controls/CustomChaptersOverlay'; import CustomSettingsMenu from '../controls/CustomSettingsMenu'; import SeekIndicator from '../controls/SeekIndicator'; import UserPreferences from '../../utils/UserPreferences'; function VideoJSPlayer() { const videoRef = useRef(null); const playerRef = useRef(null); // Track the player instance const userPreferences = useRef(new UserPreferences()); // User preferences instance const customComponents = useRef({}); // Store custom components for cleanup const isDevelopment = process.env.NODE_ENV === 'development' || window.location.hostname === 'localhost'; // Safely access window.MEDIA_DATA with fallback using useMemo const mediaData = useMemo( () => typeof window !== 'undefined' && window.MEDIA_DATA ? window.MEDIA_DATA : { data: { __hls_info: { "master_file": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/master.m3u8", "480_iframe": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-1/iframes.m3u8", "720_iframe": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-2/iframes.m3u8", "240_iframe": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-3/iframes.m3u8", "360_iframe": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-4/iframes.m3u8", "480_playlist": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-1/stream.m3u8", "720_playlist": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-2/stream.m3u8", "240_playlist": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-3/stream.m3u8", "360_playlist": "http://localhost/media/hls/c868df836ac34688b876e741b58ada93/media-4/stream.m3u8" }, __original_media_url: "http://localhost/media/original/user/admin/c868df836ac34688b876e741b58ada93.SampleVideo_1280x720_30mb.mp4", __encodings_info: { "144": {}, "240": { "h264": { "title": "h264-240", "url": "http://localhost/media/encoded/2/admin/c868df836ac34688b876e741b58ada93.c868df836ac34688b876e741b58ada93.SampleVideo_1280x720_30mb.mp4.mp4", "progress": 100, "size": "8.2MB", "encoding_id": 22, "status": "success" } }, "360": { "h264": { "title": "h264-360", "url": "http://localhost/media/encoded/3/admin/c868df836ac34688b876e741b58ada93.c868df836ac34688b876e741b58ada93.SampleVideo_1280x720_30mb.mp4.mp4", "progress": 100, "size": "12.3MB", "encoding_id": 23, "status": "success" } }, "480": { "h264": { "title": "h264-480", "url": "http://localhost/media/encoded/13/admin/c868df836ac34688b876e741b58ada93.c868df836ac34688b876e741b58ada93.SampleVideo_1280x720_30mb.mp4.mp4", "progress": 100, "size": "17.4MB", "encoding_id": 24, "status": "success" } }, "720": { "h264": { "title": "h264-720", "url": "http://localhost/media/encoded/10/admin/c868df836ac34688b876e741b58ada93.c868df836ac34688b876e741b58ada93.SampleVideo_1280x720_30mb.mp4.mp4", "progress": 100, "size": "27.4MB", "encoding_id": 25, "status": "success" } }, "1080": {}, "1440": {}, }, __chapter_data: [ { startTime: 0, endTime: 4, text: 'A1 test' }, { startTime: 5, endTime: 10, text: 'A2 of Marine Life' }, { startTime: 10, endTime: 15, text: 'A3 Reef Ecosystems' }, ], related_media: [ { friendly_token: 'jgLkic37V', url: 'http://localhost/view?m=jgLkic37V', api_url: 'http://localhost/api/v1/media/jgLkic37V', user: 'admin', title: 'Screenshot20250312at15.58.35.png', description: '', add_date: '2025-03-12T14:28:24.757807Z', views: 5, media_type: 'image', state: 'public', duration: 0, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/ad827f53568c4565b69ee59da88966c8.Screenshot20250312at15.58.35.png.jpg', is_reviewed: true, preview_url: null, author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: null, }, { friendly_token: '54Ip78oPK', url: 'http://localhost/view?m=54Ip78oPK', api_url: 'http://localhost/api/v1/media/54Ip78oPK', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed) 2', description: '', add_date: '2025-05-19T01:22:10.354407+01:00', views: 8, media_type: 'video', state: 'public', duration: 1, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/ca19044d26af4eada1669c3373c771cb_nhCvKcl.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/ca19044d26af4eada1669c3373c771cb.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '0.6MB', }, { friendly_token: '0VpZtWduU', url: 'http://localhost/view?m=0VpZtWduU', api_url: 'http://localhost/api/v1/media/0VpZtWduU', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed) (Trimmed)', description: '', add_date: '2025-05-19T01:30:55.374863+01:00', views: 13, media_type: 'video', state: 'public', duration: 6, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/46b2bec8d79f496682640ce99b5c53af_RA16Oba.884cac6a306e4ae9995726fcd3c7aa49.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/46b2bec8d79f496682640ce99b5c53af.884cac6a306e4ae9995726fcd3c7aa49.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '4.0MB', }, { friendly_token: 'efM2aLP4P', url: 'http://localhost/view?m=efM2aLP4P', api_url: 'http://localhost/api/v1/media/efM2aLP4P', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed) 1', description: '', add_date: '2025-05-19T01:22:08.117300+01:00', views: 11, media_type: 'video', state: 'public', duration: 8, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/c27f570a84d64cdc857f87c50dace993_Ma3ap4p.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/c27f570a84d64cdc857f87c50dace993.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 2, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '4.8MB', }, { friendly_token: '8RUHRjnji', url: 'http://localhost/view?m=8RUHRjnji', api_url: 'http://localhost/api/v1/media/8RUHRjnji', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed)', description: '', add_date: '2025-05-19T01:29:48.308159+01:00', views: 7, media_type: 'video', state: 'public', duration: 7, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/884cac6a306e4ae9995726fcd3c7aa49_fT7pnM4.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/884cac6a306e4ae9995726fcd3c7aa49.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '4.6MB', }, { friendly_token: 'N5Vpnqfpf', url: 'http://localhost/view?m=N5Vpnqfpf', api_url: 'http://localhost/api/v1/media/N5Vpnqfpf', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov', description: '', add_date: '2025-05-19T01:15:03.594646+01:00', views: 11, media_type: 'video', state: 'public', duration: 37, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/e549ebb4b1dc41a48cf76ebccf592836_1xqZHHc.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/e549ebb4b1dc41a48cf76ebccf592836.tmpu6x4f3js.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '22.3MB', }, { friendly_token: 'MmyuYCEfC', url: 'http://localhost/view?m=MmyuYCEfC', api_url: 'http://localhost/api/v1/media/MmyuYCEfC', user: 'admin', title: 'JmailLogIdeasforYiannis.mp4', description: 'check the 00:12 and then the 00:39', add_date: '2025-03-12T02:37:42Z', views: 49, media_type: 'video', state: 'public', duration: 112, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/3d4e6f1c7e014720bc6390ed9d61aba5_BppzBiz.JmailLogIdeasforYiannis.mp4.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/3d4e6f1c7e014720bc6390ed9d61aba5.tmpcjd0bvr5.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '40.6MB', }, { friendly_token: 'E8ia0lfir', url: 'http://localhost/view?m=E8ia0lfir', api_url: 'http://localhost/api/v1/media/E8ia0lfir', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed)', description: '', add_date: '2025-05-19T01:22:27.251447+01:00', views: 12, media_type: 'video', state: 'public', duration: 37, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/8572a325a9d649f79cc60181fbece78c_0H5arHy.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/8572a325a9d649f79cc60181fbece78c.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '22.4MB', }, { friendly_token: 'eZAl84zg6', url: 'http://localhost/view?m=eZAl84zg6', api_url: 'http://localhost/api/v1/media/eZAl84zg6', user: 'admin', title: '20257855hd_1920_1080_60fps.mp4', description: '', add_date: '2025-03-12T02:35:59.779098Z', views: 29, media_type: 'video', state: 'public', duration: 90, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/ed9c61a72c0445debfbedee011b6eba1_8HjWGZX.20257855hd_1920_1080_60fps.mp4.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/ed9c61a72c0445debfbedee011b6eba1.tmpil72jnbv.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '64.4MB', }, { friendly_token: '6WShYNxZx', url: 'http://localhost/view?m=6WShYNxZx', api_url: 'http://localhost/api/v1/media/6WShYNxZx', user: 'admin', title: 'SampleVideo_1280x720_30mb.mp4 test abc', description: 'test 123 yiannis', add_date: '2025-04-14T00:00:00+01:00', views: 43, media_type: 'video', state: 'public', duration: 171, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/c868df836ac34688b876e741b58ada93_LRvu388.SampleVideo_1280x720_30mb.mp4.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/c868df836ac34688b876e741b58ada93.tmpyl_r01_l.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 3, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '31.5MB', }, { friendly_token: 'SOgLTsrAH', url: 'http://localhost/view?m=SOgLTsrAH', api_url: 'http://localhost/api/v1/media/SOgLTsrAH', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed) (Trimmed) 1', description: '', add_date: '2025-05-19T01:31:11.057879+01:00', views: 8, media_type: 'video', state: 'public', duration: 2, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/46c75315947e4a5f9dd464c1721206fd_6KJzqBH.884cac6a306e4ae9995726fcd3c7aa49.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/46c75315947e4a5f9dd464c1721206fd.884cac6a306e4ae9995726fcd3c7aa49.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '1.5MB', }, { friendly_token: 'PoDk009ue', url: 'http://localhost/view?m=PoDk009ue', api_url: 'http://localhost/api/v1/media/PoDk009ue', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov', description: '', add_date: '2025-05-19T01:17:44.296445+01:00', views: 12, media_type: 'video', state: 'public', duration: 37, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/fd1d31460e614ca9b4645228e62c9eec_DB8nan8.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '22.4MB', }, { friendly_token: 'b7e06rUz5', url: 'http://localhost/view?m=b7e06rUz5', api_url: 'http://localhost/api/v1/media/b7e06rUz5', user: 'admin', title: 'Proto.cyTimesheet03_03_202507_03_2025.pdf', description: '', add_date: '2025-03-12T14:29:15.245599Z', views: 16, media_type: 'pdf', state: 'public', duration: 0, thumbnail_url: null, is_reviewed: true, preview_url: null, author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: null, }, { friendly_token: 'wUu76zL5a', url: 'http://localhost/view?m=wUu76zL5a', api_url: 'http://localhost/api/v1/media/wUu76zL5a', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed) 2 (Trimmed)', description: '', add_date: '2025-05-19T01:28:52.829907+01:00', views: 2, media_type: 'video', state: 'public', duration: 0, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/1b3e7dc2431b46a5b7e40b297662137a_1V0DJz5.ca19044d26af4eada1669c3373c771cb.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/1b3e7dc2431b46a5b7e40b297662137a.ca19044d26af4eada1669c3373c771cb.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '0.3MB', }, { friendly_token: 'JBjMHLfLZ', url: 'http://localhost/view?m=JBjMHLfLZ', api_url: 'http://localhost/api/v1/media/JBjMHLfLZ', user: 'admin', title: 'att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov (Trimmed) (Trimmed) 2', description: '', add_date: '2025-05-19T01:31:11.848403+01:00', views: 19, media_type: 'video', state: 'public', duration: 4, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/7759ca3e0ba1482aa9149201bd14139d_ISBMqD4.884cac6a306e4ae9995726fcd3c7aa49.fd1d31460e614ca9b4645228e62c9eec.att.24Cz35hRdjJ9FV0RlxCPVVtc6XVAdJvrU4eb8Gkykc.mov.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/7759ca3e0ba1482aa9149201bd14139d.884cac6a306e4ae9995726fcd3c7aa49.fd1d31460e614ca9b4645228e62c9eec.tmpjohj96hu.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '2.5MB', }, { friendly_token: 'w13x5uUXc', url: 'http://localhost/view?m=w13x5uUXc', api_url: 'http://localhost/api/v1/media/w13x5uUXc', user: 'admin', title: 'Web357202503112025_05_33_AM.png', description: '', add_date: '2025-03-12T14:27:55.078360Z', views: 3, media_type: 'image', state: 'public', duration: 0, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/1da967bcdca540efa1d2362af2f3a34b.Web357202503112025_05_33_AM.png.jpg', is_reviewed: true, preview_url: null, author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: null, }, { friendly_token: 'sZxPpdon5', url: 'http://localhost/view?m=sZxPpdon5', api_url: 'http://localhost/api/v1/media/sZxPpdon5', user: 'admin', title: 'JmailLogIdeasforYiannis.mp4 (Trimmed)', description: 'check the 00:12 and then the 00:39', add_date: '2025-05-15T02:16:19.580745+01:00', views: 9, media_type: 'video', state: 'public', duration: 17, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/7191a59cbfcd402ebed400e604a76840_5WRh0cp.3d4e6f1c7e014720bc6390ed9d61aba5.JmailLogIdeasforYiannis.mp4.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/7191a59cbfcd402ebed400e604a76840.3d4e6f1c7e014720bc6390ed9d61aba5.tmpcjd0bvr5.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '4.5MB', }, { friendly_token: 'TCycDZROI', url: 'http://localhost/view?m=TCycDZROI', api_url: 'http://localhost/api/v1/media/TCycDZROI', user: 'admin', title: 'JmailLogIdeasforYiannis.mp4 (Trimmed)', description: 'check the 00:12 and then the 00:39', add_date: '2025-05-15T02:14:58.855935+01:00', views: 8, media_type: 'video', state: 'public', duration: 112, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/5cbfbe93d06c453487c65d9d54749318_CUIZl8y.3d4e6f1c7e014720bc6390ed9d61aba5.JmailLogIdeasforYiannis.mp4.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/5cbfbe93d06c453487c65d9d54749318.3d4e6f1c7e014720bc6390ed9d61aba5.tmpcjd0bvr5.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 1, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '40.6MB', }, { friendly_token: 'YjGJafibO', url: 'http://localhost/view?m=YjGJafibO', api_url: 'http://localhost/api/v1/media/YjGJafibO', user: 'admin', title: 'file_example_MP4_480_1_5MG.mp4', description: '', add_date: '2025-04-14T00:07:11.074523+01:00', views: 18, media_type: 'video', state: 'public', duration: 30, thumbnail_url: 'http://localhost/media/original/thumbnails/user/admin/e76f4fff2b3d42adbadb0f1204b21b81_s8EEvSE.file_example_MP4_480_1_5MG.mp4.jpg', is_reviewed: true, preview_url: '/media/encoded/1/admin/e76f4fff2b3d42adbadb0f1204b21b81.tmp04azp_tc.gif', author_name: '', author_profile: 'http://localhost/user/admin/', author_thumbnail: 'http://localhost/media/userlogos/user.jpg', encoding_status: 'success', likes: 2, dislikes: 0, reported_times: 0, featured: false, user_featured: false, size: '1.6MB', }, ], }, previewSprite: { url: 'https://demo.mediacms.io/media/original/thumbnails/user/markos/fe4933d67b884d4da507dd60e77f7438.VID_20200909_141053.mp4sprites.jpg', frame: { width: 160, height: 90, seconds: 10 }, }, siteUrl: '', nextLink: 'https://demo.mediacms.io/view?m=YjGJafibO', }, [] ); // Define chapters as JSON object // Note: The sample-chapters.vtt file is no longer needed as chapters are now loaded from this JSON // CONDITIONAL LOGIC: // - When chaptersData has content: Uses original ChapterMarkers with sprite preview // - When chaptersData is empty: Uses separate SpritePreview component // Toggle between these two lines to test both scenarios: const chaptersData = mediaData?.data?.chapter_data && mediaData?.data?.chapter_data.length > 0 ? mediaData?.data?.chapter_data : isDevelopment ? [ { startTime: 0, endTime: 4, text: 'Introduction' }, { startTime: 5, endTime: 10, text: 'Overview of Marine Life' }, { startTime: 10, endTime: 15, text: 'Coral Reef Ecosystems' }, { startTime: 15, endTime: 20, text: 'Deep Sea Creatures' }, { startTime: 20, endTime: 30, text: 'Ocean Conservation' }, { startTime: 240, endTime: 320, text: 'Ocean Conservation' }, { startTime: 320, endTime: 400, text: 'Climate Change Impact' }, { startTime: 400, endTime: 480, text: 'Marine Protected Areas' }, { startTime: 480, endTime: 560, text: 'Sustainable Fishing' }, { startTime: 560, endTime: 640, text: 'Research Methods' }, { startTime: 640, endTime: 720, text: 'Future Challenges' }, { startTime: 720, endTime: 800, text: 'Conclusion' }, { startTime: 800, endTime: 880, text: 'Marine Biodiversity Hotspots' }, { startTime: 880, endTime: 960, text: 'Underwater Photography' }, { startTime: 960, endTime: 1040, text: 'Whale Migration Patterns' }, { startTime: 1040, endTime: 1120, text: 'Plastic Pollution Crisis' }, { startTime: 1120, endTime: 1200, text: 'Seagrass Meadows' }, { startTime: 1200, endTime: 1280, text: 'Ocean Acidification' }, { startTime: 1280, endTime: 1360, text: 'Marine Archaeology' }, { startTime: 1360, endTime: 1440, text: 'Tidal Pool Ecosystems' }, { startTime: 1440, endTime: 1520, text: 'Commercial Aquaculture' }, { startTime: 1520, endTime: 1600, text: 'Ocean Exploration Technology' }, ] : []; // const chaptersData = []; // NO CHAPTERS (uses separate SpritePreview) // Get video data from mediaData const currentVideo = useMemo( () => { // Get video sources based on available data const getVideoSources = () => { // Check if HLS info is available and not empty if (mediaData.data?.hls_info && mediaData.data.hls_info.master_file) { // Use master file as the primary source (auto quality) return [ { src: mediaData.siteUrl + mediaData.data.hls_info.master_file, type: 'application/x-mpegURL', // HLS MIME type label: 'Auto', }, ]; } // Fallback to encoded qualities if available if (mediaData.data?.encodings_info) { const sources = []; const encodings = mediaData.data.encodings_info; // Get available qualities dynamically from encodings_info const availableQualities = Object.keys(encodings) .filter(quality => encodings[quality] && encodings[quality].h264 && encodings[quality].h264.url) .sort((a, b) => parseInt(b) - parseInt(a)); // Sort descending (highest first) for (const quality of availableQualities) { sources.push({ src: mediaData.siteUrl + encodings[quality].h264.url, type: 'video/mp4', label: `${quality}p`, }); } if (sources.length > 0) { return sources; } } // Final fallback to original media URL or sample video if (mediaData.data?.original_media_url) { return [ { src: mediaData.siteUrl + mediaData.data.original_media_url, type: 'video/mp4', }, ]; } // Default sample video return [ { src: '/videos/sample-video.mp4', type: 'video/mp4', }, ]; }; return { id: mediaData.data?.friendly_token || 'default-video', title: mediaData.data?.title || 'Video', poster: mediaData.siteUrl + mediaData.data?.poster_url || '', previewSprite: mediaData?.previewSprite || {}, related_media: mediaData.data?.related_media || [], nextLink: mediaData?.nextLink || null, sources: getVideoSources(), }; }, [mediaData] ); // Compute available qualities. Prefer JSON (mediaData.data.qualities), otherwise build from encodings_info or current source. const availableQualities = useMemo(() => { // Generate desiredOrder dynamically based on available data const generateDesiredOrder = () => { const baseOrder = ['auto']; // Add qualities from encodings_info if available if (mediaData.data?.encodings_info) { const availableQualities = Object.keys(mediaData.data.encodings_info) .filter(quality => { const encoding = mediaData.data.encodings_info[quality]; return encoding && encoding.h264 && encoding.h264.url; }) .map(quality => `${quality}p`) .sort((a, b) => parseInt(a) - parseInt(b)); // Sort ascending baseOrder.push(...availableQualities); } else { // Fallback to standard order baseOrder.push('144p', '240p', '360p', '480p', '720p', '1080p', '1440p', '2160p'); } return baseOrder; }; const desiredOrder = generateDesiredOrder(); const normalize = (arr) => { const norm = arr.map((q) => ({ label: q.label || q.value || 'Auto', value: (q.value || q.label || 'auto').toString().toLowerCase(), src: q.src || q.url || q.href, type: q.type || 'video/mp4', })); // Only include qualities that have actual sources const validQualities = norm.filter(q => q.src); // sort based on desired order const idx = (v) => { const i = desiredOrder.indexOf(String(v).toLowerCase()); return i === -1 ? 999 : i; }; validQualities.sort((a, b) => idx(a.value) - idx(b.value)); return validQualities; }; const jsonList = mediaData?.data?.qualities; if (Array.isArray(jsonList) && jsonList.length) { return normalize(jsonList); } // If HLS is available, build qualities from HLS playlists if (mediaData.data?.hls_info && mediaData.data.hls_info.master_file) { const hlsInfo = mediaData.data.hls_info; const qualities = []; // Add master file as auto quality qualities.push({ label: 'Auto', value: 'auto', src: mediaData.siteUrl + hlsInfo.master_file, type: 'application/x-mpegURL', }); // Add individual HLS playlists Object.keys(hlsInfo).forEach(key => { if (key.endsWith('_playlist')) { const quality = key.replace('_playlist', ''); qualities.push({ label: `${quality}p`, value: `${quality}p`, src: mediaData.siteUrl + hlsInfo[key], type: 'application/x-mpegURL', }); } }); return normalize(qualities); } // Build from encodings_info if available if (mediaData.data?.encodings_info) { const encodings = mediaData.data.encodings_info; const qualities = []; // Add auto quality first qualities.push({ label: 'Auto', value: 'auto', src: null, // Will use the highest available quality type: 'video/mp4', }); // Add available encoded qualities dynamically Object.keys(encodings).forEach(quality => { if (encodings[quality] && encodings[quality].h264 && encodings[quality].h264.url) { qualities.push({ label: `${quality}p`, value: `${quality}p`, src: mediaData.siteUrl + encodings[quality].h264.url, type: 'video/mp4', }); } }); if (qualities.length > 1) { // More than just auto return normalize(qualities); } } // Build from current source as fallback - only if we have a valid source const baseSrc = (currentVideo?.sources && currentVideo.sources[0]?.src) || null; const type = (currentVideo?.sources && currentVideo.sources[0]?.type) || 'video/mp4'; if (baseSrc) { const buildFromBase = [{ label: 'Auto', value: 'auto', src: baseSrc, type, }]; return normalize(buildFromBase); } // Return empty array if no valid sources found return []; }, [mediaData, currentVideo]); // Get related videos from mediaData instead of static data const relatedVideos = useMemo(() => { if (!mediaData?.data?.related_media) { return []; } return mediaData.data.related_media .slice(0, 12) // Limit to maximum 12 items .map((media) => ({ id: media.friendly_token, title: media.title, author: media.user || media.author_name || 'Unknown', views: `${media.views} views`, thumbnail: media.thumbnail_url || media.author_thumbnail, category: media.media_type, url: media.url, duration: media.duration, size: media.size, likes: media.likes, dislikes: media.dislikes, add_date: media.add_date, description: media.description, })); }, [mediaData]); // Demo array for testing purposes const demoSubtitleTracks = [ { kind: 'subtitles', src: '/sample-subtitles.vtt', srclang: 'en', label: 'English Subtitles', default: false, }, { kind: 'subtitles', src: '/sample-subtitles-greek.vtt', srclang: 'el', label: 'Greek Subtitles (Ελληνικά)', default: false, }, ]; // const demoSubtitleTracks = []; // NO Subtitles. TODO: hide it on production // Get subtitle tracks from backend response or fallback based on environment const backendSubtitles = mediaData?.data?.subtitles_info || (isDevelopment ? demoSubtitleTracks : []); const hasSubtitles = backendSubtitles.length > 0; const subtitleTracks = hasSubtitles ? backendSubtitles.map(track => ({ kind: 'subtitles', src: track.src, srclang: track.srclang, label: track.label, default: false, })) : []; console.log('mediaData?.data?.thumbnail_time', mediaData?.data?.thumbnail_time); console.log('mediaData?.data?.sprites_url', mediaData?.data?.sprites_url); console.log('mediaData', mediaData); // Function to navigate to next video const goToNextVideo = () => { console.log('Next video functionality disabled for single video mode'); if (mediaData.onClickNextCallback && typeof mediaData.onClickNextCallback === 'function') { mediaData.onClickNextCallback(); } }; useEffect(() => { // Only initialize if we don't already have a player and element exists if (videoRef.current && !playerRef.current) { // Check if element is already a Video.js player if (videoRef.current.player) { // console.log('Video.js already initialized on this element'); return; } const timer = setTimeout(() => { // Double-check that we still don't have a player and element exists if (!playerRef.current && videoRef.current && !videoRef.current.player) { playerRef.current = videojs(videoRef.current, { // ===== STANDARD