import React, { useEffect, useRef } from 'react';
import Hls from 'hls.js'; // Import hls.js
import './Player.css';
const Playerconcak = () => {
const playPauseBtnRef = useRef(null);
const theaterBtnRef = useRef(null);
const fullScreenBtnRef = useRef(null);
const miniPlayerBtnRef = useRef(null);
const muteBtnRef = useRef(null);
const captionsBtnRef = useRef(null);
const speedBtnRef = useRef(null);
const currentTimeElemRef = useRef(null);
const totalTimeElemRef = useRef(null);
const previewImgRef = useRef(null);
const thumbnailImgRef = useRef(null);
const volumeSliderRef = useRef(null);
const videoContainerRef = useRef(null);
const timelineContainerRef = useRef(null);
const videoRef = useRef(null);
const videoControlsContainerRef = useRef(null);
const videoListRef = useRef(null);
const titleeRef = useRef(null);
let isScrubbing = false;
let wasPaused;
let timeout;
useEffect(() => {
const playPauseBtn = playPauseBtnRef.current;
const theaterBtn = theaterBtnRef.current;
const fullScreenBtn = fullScreenBtnRef.current;
const miniPlayerBtn = miniPlayerBtnRef.current;
const muteBtn = muteBtnRef.current;
const captionsBtn = captionsBtnRef.current;
const speedBtn = speedBtnRef.current;
const currentTimeElem = currentTimeElemRef.current;
const totalTimeElem = totalTimeElemRef.current;
const previewImg = previewImgRef.current;
const thumbnailImg = thumbnailImgRef.current;
const volumeSlider = volumeSliderRef.current;
const videoContainer = videoContainerRef.current;
const timelineContainer = timelineContainerRef.current;
const video = videoRef.current;
const videoControlsContainer = videoControlsContainerRef.current;
const videoList = videoListRef.current;
const titlee = titleeRef.current;
// Initialize HLS.js
let hls = null;
if (Hls.isSupported()) {
hls = new Hls();
hls.loadSource(video.src); // Load initial .m3u8 source
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Native HLS support (e.g., Safari)
video.src = video.src;
}
// Keydown event
const handleKeydown = (e) => {
const tagName = document.activeElement.tagName.toLowerCase();
if (tagName === 'input') return;
switch (e.key.toLowerCase()) {
case ' ':
if (tagName === 'button') return;
case 'k':
togglePlay();
break;
case 'f':
toggleFullScreenMode();
break;
case 't':
toggleTheaterMode();
break;
case 'i':
toggleMiniPlayerMode();
break;
case 'm':
toggleMute();
break;
case 'arrowleft':
case 'j':
skip(-5);
break;
case 'arrowright':
case 'l':
skip(5);
break;
case 'c':
toggleCaptions();
break;
default:
break;
}
};
// Timeline
const handleTimelineUpdate = (e) => {
const rect = timelineContainer.getBoundingClientRect();
const percent = Math.min(Math.max(0, e.x - rect.x), rect.width) / rect.width;
const previewImgNumber = Math.max(1, Math.floor((percent * video.duration) / 10));
const previewImgSrc = `assets/previewImgs/preview${previewImgNumber}.jpg`;
if (previewImg) {
previewImg.src = previewImgSrc;
}
timelineContainer.style.setProperty('--preview-position', percent);
if (isScrubbing && thumbnailImg) {
e.preventDefault();
thumbnailImg.src = previewImgSrc;
timelineContainer.style.setProperty('--progress-position', percent);
}
};
const toggleScrubbing = (e) => {
const rect = timelineContainer.getBoundingClientRect();
const percent = Math.min(Math.max(0, e.x - rect.x), rect.width) / rect.width;
isScrubbing = (e.buttons & 1) === 1;
videoContainer.classList.toggle('scrubbing', isScrubbing);
if (isScrubbing) {
wasPaused = video.paused;
video.pause();
} else {
video.currentTime = percent * video.duration;
if (!wasPaused) video.play();
}
handleTimelineUpdate(e);
};
// Playback Speed
const changePlaybackSpeed = () => {
let newPlaybackRate = video.playbackRate + 0.25;
if (newPlaybackRate > 2) newPlaybackRate = 0.25;
video.playbackRate = newPlaybackRate;
speedBtn.textContent = `${newPlaybackRate}x`;
};
// Captions
const captions = video.textTracks[0];
captions.mode = 'hidden';
const toggleCaptions = () => {
const isHidden = captions.mode === 'hidden';
captions.mode = isHidden ? 'showing' : 'hidden';
videoContainer.classList.toggle('captions', isHidden);
};
// Duration
const formatDuration = (time) => {
const seconds = Math.floor(time % 60);
const minutes = Math.floor(time / 60) % 60;
const hours = Math.floor(time / 3600);
const leadingZeroFormatter = new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 });
return hours === 0
? `${minutes}:${leadingZeroFormatter.format(seconds)}`
: `${hours}:${leadingZeroFormatter.format(minutes)}:${leadingZeroFormatter.format(seconds)}`;
};
const skip = (duration) => {
video.currentTime += duration;
};
// Volume
const toggleMute = () => {
video.muted = !video.muted;
};
const handleVolumeChange = () => {
volumeSlider.value = video.volume;
let volumeLevel;
if (video.muted || video.volume === 0) {
volumeSlider.value = 0;
volumeLevel = 'muted';
} else if (video.volume >= 0.5) {
volumeLevel = 'high';
} else {
volumeLevel = 'low';
}
videoContainer.dataset.volumeLevel = volumeLevel;
};
// View Modes
const toggleTheaterMode = () => {
videoContainer.classList.toggle('theater');
};
const toggleFullScreenMode = () => {
if (!document.fullscreenElement) {
videoContainer.requestFullscreen();
} else {
document.exitFullscreen();
}
};
const toggleMiniPlayerMode = () => {
if (videoContainer.classList.contains('mini-player')) {
document.exitPictureInPicture();
} else {
video.requestPictureInPicture();
}
};
// Play/Pause
const togglePlay = () => {
video.paused ? video.play() : video.pause();
};
// Show/Hide Controls
const showControls = () => {
videoControlsContainer.style.opacity = '1';
clearTimeout(timeout);
};
const hideControls = () => {
timeout = setTimeout(() => {
videoControlsContainer.style.opacity = '0';
}, 2000);
};
// Handle video selection
const handleVideoSelect = (e) => {
const vidElement = e.currentTarget;
const videoElement = vidElement.querySelector('video');
const newSrc = videoElement.getAttribute('src');
const newTitle = vidElement.querySelector('.title').textContent;
// Update the main video source with HLS.js
if (Hls.isSupported() && hls) {
hls.destroy(); // Clean up previous HLS instance
hls = new Hls();
hls.loadSource(newSrc);
hls.attachMedia(video);
video.play();
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = newSrc;
video.load();
video.play();
}
// Remove 'active' class from all .vid elements
const allVidElements = videoList.querySelectorAll('.vid');
allVidElements.forEach((vid) => vid.classList.remove('active'));
// Add 'active' class to the clicked .vid element
vidElement.classList.add('active');
// Update the titlee element with the new title
if (titlee) {
titlee.textContent = newTitle;
}
};
// Add click event listeners to all .vid elements
const vidElements = videoList.querySelectorAll('.vid');
vidElements.forEach((vid) => {
vid.addEventListener('click', handleVideoSelect);
});
// Event Listeners
document.addEventListener('keydown', handleKeydown);
timelineContainer.addEventListener('mousemove', handleTimelineUpdate);
timelineContainer.addEventListener('mousedown', toggleScrubbing);
document.addEventListener('mouseup', (e) => {
if (isScrubbing) toggleScrubbing(e);
});
document.addEventListener('mousemove', (e) => {
if (isScrubbing) handleTimelineUpdate(e);
});
speedBtn.addEventListener('click', changePlaybackSpeed);
captionsBtn.addEventListener('click', toggleCaptions);
video.addEventListener('loadeddata', () => {
totalTimeElem.textContent = formatDuration(video.duration);
});
video.addEventListener('timeupdate', () => {
currentTimeElem.textContent = formatDuration(video.currentTime);
const percent = video.currentTime / video.duration;
timelineContainer.style.setProperty('--progress-position', percent);
});
muteBtn.addEventListener('click', toggleMute);
volumeSlider.addEventListener('input', (e) => {
video.volume = e.target.value;
video.muted = e.target.value === 0;
});
video.addEventListener('volumechange', handleVolumeChange);
theaterBtn.addEventListener('click', toggleTheaterMode);
fullScreenBtn.addEventListener('click', toggleFullScreenMode);
miniPlayerBtn.addEventListener('click', toggleMiniPlayerMode);
document.addEventListener('fullscreenchange', () => {
videoContainer.classList.toggle('full-screen', !!document.fullscreenElement);
});
video.addEventListener('enterpictureinpicture', () => {
videoContainer.classList.add('mini-player');
});
video.addEventListener('leavepictureinpicture', () => {
videoContainer.classList.remove('mini-player');
});
playPauseBtn.addEventListener('click', togglePlay);
video.addEventListener('click', togglePlay);
video.addEventListener('play', () => {
videoContainer.classList.remove('paused');
});
video.addEventListener('pause', () => {
videoContainer.classList.add('paused');
});
document.addEventListener('mousemove', showControls);
document.addEventListener('keydown', showControls);
videoControlsContainer.addEventListener('mouseover', showControls);
document.addEventListener('mouseout', hideControls);
document.addEventListener('keyup', hideControls);
videoControlsContainer.addEventListener('mouseleave', hideControls);
document.addEventListener('fullscreenchange', () => {
if (document.fullscreenElement) {
hideControls();
} else {
showControls();
}
});
// Cleanup event listeners and HLS
return () => {
document.removeEventListener('keydown', handleKeydown);
timelineContainer.removeEventListener('mousemove', handleTimelineUpdate);
timelineContainer.removeEventListener('mousedown', toggleScrubbing);
document.removeEventListener('mouseup', toggleScrubbing);
document.removeEventListener('mousemove', handleTimelineUpdate);
speedBtn.removeEventListener('click', changePlaybackSpeed);
captionsBtn.removeEventListener('click', toggleCaptions);
video.removeEventListener('loadeddata', () => {});
video.removeEventListener('timeupdate', () => {});
muteBtn.removeEventListener('click', toggleMute);
volumeSlider.removeEventListener('input', () => {});
video.removeEventListener('volumechange', handleVolumeChange);
theaterBtn.removeEventListener('click', toggleTheaterMode);
fullScreenBtn.removeEventListener('click', toggleFullScreenMode);
miniPlayerBtn.removeEventListener('click', toggleMiniPlayerMode);
document.removeEventListener('fullscreenchange', () => {});
video.removeEventListener('enterpictureinpicture', () => {});
video.removeEventListener('leavepictureinpicture', () => {});
playPauseBtn.removeEventListener('click', togglePlay);
video.removeEventListener('click', togglePlay);
video.removeEventListener('play', () => {});
video.removeEventListener('pause', () => {});
document.removeEventListener('mousemove', showControls);
document.removeEventListener('keydown', showControls);
videoControlsContainer.removeEventListener('mouseover', showControls);
document.removeEventListener('mouseout', hideControls);
document.removeEventListener('keyup', hideControls);
videoControlsContainer.removeEventListener('mouseleave', hideControls);
document.removeEventListener('fullscreenchange', () => {});
vidElements.forEach((vid) => {
vid.removeEventListener('click', handleVideoSelect);
});
if (hls) {
hls.destroy(); // Clean up HLS instance
}
};
}, []);
return (
);
};
export default Playerconcak;
0:00
/
Tập 1 - "Ta yêu em" và Tự động thủ kí nhân hình
Tập 2 - "Sẽ không quay về nữa"
Tập 3 - 'Vậy là em đã trở thành một Tự Động Thủ Kí Nhân Hình chuẩn mực rồi đấy'
Tập 4 - "Em nào phải thứ công cụ gì, mà là một người rất tương xứng với cái tên này."
Tập 4.5 - "Chắc chắn, cái ngày cháu hiểu được 'YÊU' là gì cũng sẽ đến thôi"
Tập 5 - "Ngươi lại đi viết thư gắn kết mọi người với nhau sao?"
Tập 6 - "Tại nơi nào đó, dưới bầu trời đầy sao"
Tập 7
Tập 8
Tập 9 - Violet Evergarden
Tập 10 - "Người thân yêu vẫn sẽ luôn dõi theo mình"
Tập 11 - "Tôi không muốn có bất kì ai phải chết nữa"
Tập 12
Tập 13 - Tự Động Thủ Kí Nhân Hình và "Ta yêu em"
Violet Evergarden: Hồi ức không quên
Violet Evergarden: The Movie
Tập 1 - "Ta yêu em" và Tự động thủ kí nhân hình