import { useEffect, useRef } from "react"; import Artplayer from "artplayer"; import Hls from "hls.js"; import { useWatchProvider } from "@/lib/context/watchPageProvider"; import artplayerPluginHlsQuality from "artplayer-plugin-hls-quality"; export default function NewPlayer({ playerRef, option, getInstance, provider, track, defSub, defSize, subtitles, subSize, res, quality, ...rest }) { const artRef = useRef(null); const { setTheaterMode, setPlayerState, setAutoPlay } = useWatchProvider(); function playM3u8(video, url, art) { if (Hls.isSupported()) { if (art.hls) art.hls.destroy(); const hls = new Hls(); hls.loadSource(url); hls.attachMedia(video); art.hls = hls; art.on("destroy", () => hls.destroy()); } else if (video.canPlayType("application/vnd.apple.mpegurl")) { video.src = url; } else { art.notice.show = "Unsupported playback format: m3u8"; } } useEffect(() => { Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.15, 1.2, 1.5, 1.7, 2]; const art = new Artplayer({ ...option, container: artRef.current, type: "m3u8", customType: { m3u8: playM3u8, }, ...(subtitles?.length > 0 && { subtitle: { url: `${defSub}`, // type: "vtt", encoding: "utf-8", default: true, name: "English", escape: false, style: { color: "#FFFF", fontSize: `${defSize?.size}`, fontFamily: localStorage.getItem("font") ? localStorage.getItem("font") : "Arial", textShadow: localStorage.getItem("subShadow") ? JSON.parse(localStorage.getItem("subShadow")).value : "0px 0px 10px #000000", }, }, }), plugins: [ artplayerPluginHlsQuality({ // Show quality in setting setting: true, // Get the resolution text from level getResolution: (level) => level.height + "P", // I18n title: "Quality", auto: "Auto", }), ], settings: [ // provider === "gogoanime" && { html: "Autoplay Next", icon: '', tooltip: "ON/OFF", switch: localStorage.getItem("autoplay") === "true" ? true : false, onSwitch: function (item) { // setPlayNext(!item.switch); localStorage.setItem("autoplay", !item.switch); return !item.switch; }, }, { html: "Autoplay Video", icon: '', // icon: '', tooltip: "ON/OFF", switch: localStorage.getItem("autoplay_video") === "true" ? true : false, onSwitch: function (item) { setAutoPlay(!item.switch); localStorage.setItem("autoplay_video", !item.switch); return !item.switch; }, }, { html: "Alternative Quality", width: 250, tooltip: `${res}`, selector: quality?.alt, icon: '', onSelect: function (item) { art.switchQuality(item.url, item.html); localStorage.setItem("quality", item.html); return item.html; }, }, { html: "Server", width: 250, tooltip: `${quality?.server[0].html}`, icon: '', selector: quality?.server, onSelect: function (item) { art.switchQuality(item.url, item.html); localStorage.setItem("quality", item.html); return item.html; }, }, subtitles?.length > 0 && { html: "Subtitles", icon: '', width: 300, tooltip: "Settings", selector: [ { html: "Display", icon: '', tooltip: "Show", switch: true, onSwitch: function (item) { item.tooltip = item.switch ? "Hide" : "Show"; art.subtitle.show = !item.switch; return !item.switch; }, }, { html: "Font Size", icon: '', selector: subSize, onSelect: function (item) { if (item.html === "Small") { art.subtitle.style({ fontSize: "16px" }); localStorage.setItem( "subSize", JSON.stringify({ size: "16px", html: "Small", }) ); } else if (item.html === "Medium") { art.subtitle.style({ fontSize: "36px" }); localStorage.setItem( "subSize", JSON.stringify({ size: "36px", html: "Medium", }) ); } else if (item.html === "Large") { art.subtitle.style({ fontSize: "56px" }); localStorage.setItem( "subSize", JSON.stringify({ size: "56px", html: "Large", }) ); } }, }, { html: "Language", icon: '', tooltip: "English", selector: [...subtitles], onSelect: function (item) { art.subtitle.switch(item.url, { name: item.html, }); return item.html; }, }, { html: "Font Family", tooltip: localStorage.getItem("font") ? localStorage.getItem("font") : "Arial", selector: [ { html: "Arial" }, { html: "Comic Sans MS" }, { html: "Verdana" }, { html: "Tahoma" }, { html: "Trebuchet MS" }, { html: "Times New Roman" }, { html: "Georgia" }, { html: "Impact " }, { html: "Andalé Mono" }, { html: "Palatino" }, { html: "Baskerville" }, { html: "Garamond" }, { html: "Courier New" }, { html: "Brush Script MT" }, ], onSelect: function (item) { art.subtitle.style({ fontFamily: item.html }); localStorage.setItem("font", item.html); return item.html; }, }, { html: "Font Shadow", tooltip: localStorage.getItem("subShadow") ? JSON.parse(localStorage.getItem("subShadow")).shadow : "Default", selector: [ { html: "None", value: "none" }, { html: "Uniform", value: "2px 2px 0px #000, -2px -2px 0px #000, 2px -2px 0px #000, -2px 2px 0px #000", }, { html: "Raised", value: "-1px 2px 3px rgba(0, 0, 0, 1)" }, { html: "Depressed", value: "-2px -3px 3px rgba(0, 0, 0, 1)" }, { html: "Glow", value: "0 0 10px rgba(0, 0, 0, 0.8)" }, { html: "Block", value: "-3px 3px 4px rgba(0, 0, 0, 1),2px 2px 4px rgba(0, 0, 0, 1),1px -1px 3px rgba(0, 0, 0, 1),-3px -2px 4px rgba(0, 0, 0, 1)", }, ], onSelect: function (item) { art.subtitle.style({ textShadow: item.value }); localStorage.setItem( "subShadow", JSON.stringify({ shadow: item.html, value: item.value }) ); return item.html; }, }, ], }, ].filter(Boolean), controls: [ { name: "theater-button", index: 11, position: "right", tooltip: "Theater (t)", html: '', click: function (...args) { setPlayerState((prev) => ({ ...prev, currentTime: art.currentTime, isPlaying: art.playing, })); setTheaterMode((prev) => !prev); }, }, { index: 10, name: "fast-rewind", position: "left", html: '', tooltip: "Backward 5s", click: function () { art.backward = 5; }, }, { index: 11, name: "fast-forward", position: "left", html: '', tooltip: "Forward 5s", click: function () { art.forward = 5; }, }, ], }); if ("mediaSession" in navigator) { art.on("video:timeupdate", () => { const session = navigator.mediaSession; if (!session) return; session.setPositionState({ duration: art.duration, playbackRate: art.playbackRate, position: art.currentTime, }); }); navigator.mediaSession.setActionHandler("play", () => { art.play(); }); navigator.mediaSession.setActionHandler("pause", () => { art.pause(); }); navigator.mediaSession.setActionHandler("previoustrack", () => { if (track?.prev) { router.push( `/en/anime/watch/${id}/${provider}?id=${encodeURIComponent( track?.prev?.id )}&num=${track?.prev?.number}` ); } }); navigator.mediaSession.setActionHandler("nexttrack", () => { if (track?.next) { router.push( `/en/anime/watch/${id}/${provider}?id=${encodeURIComponent( track?.next?.id )}&num=${track?.next?.number}` ); } }); } playerRef.current = art; art.events.proxy(document, "keydown", (event) => { // Check if the focus is on an input field or textarea const isInputFocused = document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA"; if (!isInputFocused) { if (event.key === "f" || event.key === "F") { art.fullscreen = !art.fullscreen; } if (event.key === "t" || event.key === "T") { setPlayerState((prev) => ({ ...prev, currentTime: art.currentTime, isPlaying: art.playing, })); setTheaterMode((prev) => !prev); } } }); art.events.proxy(document, "keypress", (event) => { // Check if the focus is on an input field or textarea const isInputFocused = document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA"; if (!isInputFocused && event.code === "Space") { event.preventDefault(); art.playing ? art.pause() : art.play(); } }); if (getInstance && typeof getInstance === "function") { getInstance(art); } return () => { if (art && art.destroy) { art.destroy(false); } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return
; }