mirror of
https://github.com/JustAnimeCore/JustAnime.git
synced 2026-04-17 22:01:45 +00:00
resolved servers
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable no-empty */
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* eslint-disable react/prop-types */
|
||||
import Hls from "hls.js";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
@@ -28,20 +30,22 @@ import website_name from "@/src/config/website";
|
||||
import getChapterStyles from "./getChapterStyle";
|
||||
import artplayerPluginHlsControl from "artplayer-plugin-hls-control";
|
||||
import artplayerPluginUploadSubtitle from "./artplayerPluginUploadSubtitle";
|
||||
import { getTitle } from "@/src/utils/title.utils";
|
||||
|
||||
Artplayer.LOG_VERSION = false;
|
||||
Artplayer.CONTEXTMENU = false;
|
||||
|
||||
const KEY_CODES = {
|
||||
M: "m",
|
||||
I: "i",
|
||||
F: "f",
|
||||
V: "v",
|
||||
SPACE: " ",
|
||||
ARROW_UP: "arrowup",
|
||||
ARROW_DOWN: "arrowdown",
|
||||
ARROW_RIGHT: "arrowright",
|
||||
ARROW_LEFT: "arrowleft",
|
||||
M: "KeyM",
|
||||
I: "KeyI",
|
||||
F: "KeyF",
|
||||
V: "KeyV",
|
||||
SPACE: "Space",
|
||||
SPACE_LEGACY: "Spacebar",
|
||||
ARROW_UP: "ArrowUp",
|
||||
ARROW_DOWN: "ArrowDown",
|
||||
ARROW_RIGHT: "ArrowRight",
|
||||
ARROW_LEFT: "ArrowLeft",
|
||||
};
|
||||
|
||||
export default function Player({
|
||||
@@ -59,17 +63,15 @@ export default function Player({
|
||||
animeInfo,
|
||||
episodeNum,
|
||||
streamInfo,
|
||||
serverName,
|
||||
activeServerName,
|
||||
}) {
|
||||
const artRef = useRef(null);
|
||||
const leftAtRef = useRef(0);
|
||||
const boundKeydownRef = useRef(null);
|
||||
const proxy = import.meta.env.VITE_PROXY_URL;
|
||||
const m3u8proxy = import.meta.env.VITE_M3U8_PROXY_URL?.split(",") || [];
|
||||
const m3u8proxyHD3 = import.meta.env.VITE_M3U8_PROXY_HD3;
|
||||
const [currentEpisodeIndex, setCurrentEpisodeIndex] = useState(
|
||||
episodes?.findIndex(
|
||||
(episode) => episode.id.match(/ep=(\d+)/)?.[1] === episodeId
|
||||
)
|
||||
episodes?.findIndex((episode) => episode.id.match(/ep=(\d+)/)?.[1] === episodeId)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -80,11 +82,10 @@ export default function Player({
|
||||
setCurrentEpisodeIndex(newIndex);
|
||||
}
|
||||
}, [episodeId, episodes]);
|
||||
|
||||
useEffect(() => {
|
||||
const applyChapterStyles = () => {
|
||||
const existingStyles = document.querySelectorAll(
|
||||
"style[data-chapter-styles]"
|
||||
);
|
||||
const existingStyles = document.querySelectorAll("style[data-chapter-styles]");
|
||||
existingStyles.forEach((style) => style.remove());
|
||||
const styleElement = document.createElement("style");
|
||||
styleElement.setAttribute("data-chapter-styles", "true");
|
||||
@@ -112,18 +113,13 @@ export default function Player({
|
||||
|
||||
art.on("destroy", () => hls.destroy());
|
||||
|
||||
// hls.on(Hls.Events.ERROR, (event, data) => {
|
||||
// console.error("HLS.js error:", data);
|
||||
// });
|
||||
video.addEventListener("timeupdate", () => {
|
||||
const currentTime = Math.round(video.currentTime);
|
||||
const duration = Math.round(video.duration);
|
||||
if (duration > 0 && currentTime >= duration) {
|
||||
art.pause();
|
||||
if (currentEpisodeIndex < episodes?.length - 1 && autoNext) {
|
||||
playNext(
|
||||
episodes[currentEpisodeIndex + 1].id.match(/ep=(\d+)/)?.[1]
|
||||
);
|
||||
playNext(episodes[currentEpisodeIndex + 1].id.match(/ep=(\d+)/)?.[1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -135,9 +131,7 @@ export default function Player({
|
||||
if (duration > 0 && currentTime >= duration) {
|
||||
art.pause();
|
||||
if (currentEpisodeIndex < episodes?.length - 1 && autoNext) {
|
||||
playNext(
|
||||
episodes[currentEpisodeIndex + 1].id.match(/ep=(\d+)/)?.[1]
|
||||
);
|
||||
playNext(episodes[currentEpisodeIndex + 1].id.match(/ep=(\d+)/)?.[1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -157,29 +151,76 @@ export default function Player({
|
||||
return chapters;
|
||||
};
|
||||
|
||||
const isEditableElement = (el) => {
|
||||
if (!el) return false;
|
||||
const tagName = el.tagName?.toLowerCase();
|
||||
if (tagName === "input" || tagName === "textarea" || el.isContentEditable) return true;
|
||||
if (el.closest) {
|
||||
const editable = el.closest("input, textarea, [contenteditable='true']");
|
||||
return !!editable;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleKeydown = (event, art) => {
|
||||
const tagName = event.target.tagName.toLowerCase();
|
||||
const container = artRef.current;
|
||||
if (!container || !art) return;
|
||||
|
||||
if (tagName === "input" || tagName === "textarea") return;
|
||||
const target = event.target;
|
||||
if (isEditableElement(target)) return;
|
||||
|
||||
switch (event.key.toLowerCase()) {
|
||||
const eventIsInsidePlayer =
|
||||
container.contains(target) || container.contains(document.activeElement);
|
||||
|
||||
if (!eventIsInsidePlayer) return;
|
||||
|
||||
const code = event.code;
|
||||
|
||||
switch (code) {
|
||||
case KEY_CODES.M:
|
||||
art.muted = !art.muted;
|
||||
break;
|
||||
case KEY_CODES.I:
|
||||
art.pip = !art.pip;
|
||||
break;
|
||||
case KEY_CODES.F:
|
||||
case KEY_CODES.F: {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
art.fullscreen = !art.fullscreen;
|
||||
|
||||
const container = artRef.current;
|
||||
const doc = document;
|
||||
const fsEl =
|
||||
doc.fullscreenElement ||
|
||||
doc.webkitFullscreenElement ||
|
||||
doc.mozFullScreenElement ||
|
||||
doc.msFullscreenElement;
|
||||
|
||||
if (fsEl && (fsEl === container || container.contains(fsEl))) {
|
||||
if (doc.exitFullscreen) doc.exitFullscreen();
|
||||
else if (doc.webkitExitFullscreen) doc.webkitExitFullscreen();
|
||||
else if (doc.mozCancelFullScreen) doc.mozCancelFullScreen();
|
||||
else if (doc.msExitFullscreen) doc.msExitFullscreen();
|
||||
} else {
|
||||
if (container.requestFullscreen) container.requestFullscreen();
|
||||
else if (container.webkitRequestFullscreen) container.webkitRequestFullscreen();
|
||||
else if (container.mozRequestFullScreen) container.mozRequestFullScreen();
|
||||
else if (container.msRequestFullscreen) container.msRequestFullscreen();
|
||||
}
|
||||
|
||||
try {
|
||||
art.fullscreen = !art.fullscreen;
|
||||
} catch (e) {
|
||||
// ignore if art not available
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_CODES.V:
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
art.subtitle.show = !art.subtitle.show;
|
||||
break;
|
||||
case KEY_CODES.SPACE:
|
||||
case KEY_CODES.SPACE_LEGACY:
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
art.playing ? art.pause() : art.play();
|
||||
@@ -211,20 +252,34 @@ export default function Player({
|
||||
|
||||
useEffect(() => {
|
||||
if (!streamUrl || !artRef.current) return;
|
||||
|
||||
const iframeUrl = streamInfo?.streamingLink?.iframe;
|
||||
const headers = {};
|
||||
headers.referer = new URL(iframeUrl).origin + "/";
|
||||
const finalProxy = (serverName === "hd-3" && m3u8proxyHD3)
|
||||
? m3u8proxyHD3
|
||||
const headers = {
|
||||
referer: iframeUrl ? new URL(iframeUrl).origin + "/" : window.location.origin + "/",
|
||||
};
|
||||
|
||||
const container = artRef.current;
|
||||
let fullscreenRefocusTimeout = null;
|
||||
|
||||
try {
|
||||
if (!container.hasAttribute("tabindex")) container.setAttribute("tabindex", "0");
|
||||
else {
|
||||
const current = parseInt(container.getAttribute("tabindex"), 10);
|
||||
if (isNaN(current) || current < 0) container.setAttribute("tabindex", "0");
|
||||
}
|
||||
container.style.outline = "none";
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const hd1Proxy = import.meta.env.VITE_HD_1_PROXY_URL;
|
||||
const currentProxy = (activeServerName === "HD-1" && hd1Proxy)
|
||||
? hd1Proxy
|
||||
: m3u8proxy[Math.floor(Math.random() * m3u8proxy?.length)];
|
||||
console.log(finalProxy +
|
||||
encodeURIComponent(streamUrl) +
|
||||
"&headers=" +
|
||||
encodeURIComponent(JSON.stringify(headers)));
|
||||
|
||||
const art = new Artplayer({
|
||||
url:
|
||||
finalProxy +
|
||||
currentProxy +
|
||||
encodeURIComponent(streamUrl) +
|
||||
"&headers=" +
|
||||
encodeURIComponent(JSON.stringify(headers)),
|
||||
@@ -245,8 +300,8 @@ export default function Player({
|
||||
fastForward: true,
|
||||
aspectRatio: true,
|
||||
moreVideoAttr: {
|
||||
crossOrigin: 'anonymous',
|
||||
preload: 'none',
|
||||
crossOrigin: "anonymous",
|
||||
preload: "none",
|
||||
playsInline: true,
|
||||
},
|
||||
plugins: [
|
||||
@@ -374,13 +429,55 @@ export default function Player({
|
||||
},
|
||||
customType: { m3u8: playM3u8 },
|
||||
});
|
||||
|
||||
art.on("resize", () => {
|
||||
art.subtitle.style({
|
||||
fontSize:
|
||||
(art.width > 500 ? art.width * 0.02 : art.width * 0.03) + "px",
|
||||
fontSize: (art.width > 500 ? art.width * 0.02 : art.width * 0.03) + "px",
|
||||
});
|
||||
});
|
||||
|
||||
const refocusIfNeeded = (delay = 30) => {
|
||||
try {
|
||||
if (!container) return;
|
||||
const active = document.activeElement;
|
||||
if (!container.contains(active)) {
|
||||
fullscreenRefocusTimeout = setTimeout(() => {
|
||||
try {
|
||||
container.focus();
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
};
|
||||
|
||||
const onFullscreenChange = () => {
|
||||
if (!document.fullscreenElement && !document.webkitIsFullScreen && !document.mozFullScreen && !document.msFullscreenElement) {
|
||||
refocusIfNeeded(40);
|
||||
} else {
|
||||
refocusIfNeeded(20);
|
||||
}
|
||||
};
|
||||
|
||||
// vendor event wrappers
|
||||
const fullscreenEvents = [
|
||||
"fullscreenchange",
|
||||
"webkitfullscreenchange",
|
||||
"mozfullscreenchange",
|
||||
"MSFullscreenChange",
|
||||
];
|
||||
fullscreenEvents.forEach((ev) => document.addEventListener(ev, onFullscreenChange));
|
||||
|
||||
art.on("ready", () => {
|
||||
try {
|
||||
container.focus();
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const continueWatchingList = JSON.parse(localStorage.getItem("continueWatching")) || [];
|
||||
const currentEntry = continueWatchingList.find((item) => item.episodeId === episodeId);
|
||||
if (currentEntry?.leftAt) art.currentTime = currentEntry.leftAt;
|
||||
@@ -393,7 +490,15 @@ export default function Player({
|
||||
art.layers[website_name].style.opacity = 0;
|
||||
}, 2000);
|
||||
|
||||
const defaultSubtitle = subtitles?.find((sub) => sub.label.toLowerCase() === "english");
|
||||
const subs = (subtitles || []).map((s) => ({ ...s }));
|
||||
|
||||
for (const sub of subs) {
|
||||
const encodedUrl = encodeURIComponent(sub.file);
|
||||
const encodedHeaders = encodeURIComponent(JSON.stringify(headers));
|
||||
sub.file = `${proxy}${encodedUrl}&headers=${encodedHeaders}`;
|
||||
}
|
||||
|
||||
const defaultSubtitle = subs?.find((sub) => sub.label.toLowerCase() === "english");
|
||||
if (defaultSubtitle) {
|
||||
art.subtitle.switch(defaultSubtitle.file, {
|
||||
name: defaultSubtitle.label,
|
||||
@@ -402,12 +507,38 @@ export default function Player({
|
||||
}
|
||||
|
||||
const skipRanges = [
|
||||
...(intro.start != null && intro.end != null ? [[intro.start + 1, intro.end - 1]] : []),
|
||||
...(outro.start != null && outro.end != null ? [[outro.start + 1, outro.end]] : []),
|
||||
...(intro?.start != null && intro?.end != null ? [[intro.start + 1, intro.end - 1]] : []),
|
||||
...(outro?.start != null && outro?.end != null ? [[outro.start + 1, outro.end]] : []),
|
||||
];
|
||||
autoSkipIntro && art.plugins.add(autoSkip(skipRanges));
|
||||
|
||||
document.addEventListener("keydown", (event) => handleKeydown(event, art));
|
||||
const boundKeydown = (event) => handleKeydown(event, art);
|
||||
boundKeydownRef.current = boundKeydown;
|
||||
document.addEventListener("keydown", boundKeydown);
|
||||
|
||||
const focusOnPointerDown = () => {
|
||||
try {
|
||||
container.focus();
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
};
|
||||
container.addEventListener("pointerdown", focusOnPointerDown, { passive: true });
|
||||
|
||||
const onWindowFocus = () => refocusIfNeeded(30);
|
||||
window.addEventListener("focus", onWindowFocus);
|
||||
|
||||
art.on("destroy", () => {
|
||||
try {
|
||||
document.removeEventListener("keydown", boundKeydown);
|
||||
} catch (e) { }
|
||||
try {
|
||||
container.removeEventListener("pointerdown", focusOnPointerDown);
|
||||
} catch (e) { }
|
||||
try {
|
||||
window.removeEventListener("focus", onWindowFocus);
|
||||
} catch (e) { }
|
||||
});
|
||||
|
||||
art.subtitle.style({
|
||||
fontSize: (art.width > 500 ? art.width * 0.02 : art.width * 0.03) + "px",
|
||||
@@ -420,6 +551,7 @@ export default function Player({
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const $rewind = art.layers["rewind"];
|
||||
const $forward = art.layers["forward"];
|
||||
Artplayer.utils.isMobile &&
|
||||
@@ -438,10 +570,11 @@ export default function Player({
|
||||
art.layers["forwardIcon"].style.opacity = 0;
|
||||
}, 300);
|
||||
});
|
||||
if (subtitles?.length > 0) {
|
||||
|
||||
if (subs?.length > 0) {
|
||||
const defaultEnglishSub =
|
||||
subtitles.find((sub) => sub.label.toLowerCase() === "english" && sub.default) ||
|
||||
subtitles.find((sub) => sub.label.toLowerCase() === "english");
|
||||
subs.find((sub) => sub.label.toLowerCase() === "english" && sub.default) ||
|
||||
subs.find((sub) => sub.label.toLowerCase() === "english");
|
||||
|
||||
art.setting.add({
|
||||
name: "captions",
|
||||
@@ -459,7 +592,7 @@ export default function Player({
|
||||
return !item.switch;
|
||||
},
|
||||
},
|
||||
...subtitles.map((sub) => ({
|
||||
...subs.map((sub) => ({
|
||||
default: sub.label.toLowerCase() === "english" && sub === defaultEnglishSub,
|
||||
html: sub.label,
|
||||
url: sub.file,
|
||||
@@ -477,32 +610,42 @@ export default function Player({
|
||||
if (art && art.destroy) {
|
||||
art.destroy(false);
|
||||
}
|
||||
document.removeEventListener("keydown", handleKeydown);
|
||||
const continueWatching = JSON.parse(localStorage.getItem("continueWatching")) || [];
|
||||
const newEntry = {
|
||||
id: animeInfo?.id,
|
||||
data_id: animeInfo?.data_id,
|
||||
episodeId,
|
||||
episodeNum,
|
||||
adultContent: animeInfo?.adultContent,
|
||||
poster: animeInfo?.poster,
|
||||
title: animeInfo?.title,
|
||||
japanese_title: animeInfo?.japanese_title,
|
||||
leftAt: leftAtRef.current,
|
||||
};
|
||||
|
||||
if (!newEntry.data_id) return;
|
||||
|
||||
const existingIndex = continueWatching.findIndex((item) => item.data_id === newEntry.data_id);
|
||||
if (existingIndex !== -1) {
|
||||
continueWatching[existingIndex] = newEntry;
|
||||
} else {
|
||||
continueWatching.push(newEntry);
|
||||
fullscreenEvents.forEach((ev) => document.removeEventListener(ev, onFullscreenChange));
|
||||
if (boundKeydownRef.current) {
|
||||
try {
|
||||
document.removeEventListener("keydown", boundKeydownRef.current);
|
||||
} catch (e) { }
|
||||
boundKeydownRef.current = null;
|
||||
}
|
||||
if (fullscreenRefocusTimeout) clearTimeout(fullscreenRefocusTimeout);
|
||||
|
||||
try {
|
||||
const continueWatching = JSON.parse(localStorage.getItem("continueWatching")) || [];
|
||||
const newEntry = {
|
||||
id: animeInfo?.id,
|
||||
data_id: animeInfo?.data_id,
|
||||
episodeId,
|
||||
episodeNum,
|
||||
adultContent: animeInfo?.adultContent,
|
||||
poster: animeInfo?.poster,
|
||||
title: getTitle(animeInfo, "EN"),
|
||||
japanese_title: getTitle(animeInfo, "JP"),
|
||||
leftAt: leftAtRef.current,
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
|
||||
if (!newEntry.data_id) return;
|
||||
|
||||
const filtered = continueWatching.filter((item) => item.data_id !== newEntry.data_id);
|
||||
filtered.unshift(newEntry);
|
||||
localStorage.setItem("continueWatching", JSON.stringify(filtered));
|
||||
} catch (err) {
|
||||
console.error("Failed to save continueWatching:", err);
|
||||
}
|
||||
localStorage.setItem("continueWatching", JSON.stringify(continueWatching));
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [streamUrl, subtitles, intro, outro]);
|
||||
|
||||
return <div ref={artRef} className="w-full h-full"></div>;
|
||||
return <div ref={artRef} className="w-full h-full" />;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import getAnimeInfo from "@/src/utils/getAnimeInfo.utils";
|
||||
@@ -113,58 +114,91 @@ export const useWatch = (animeId, initialEpisodeId) => {
|
||||
useEffect(() => {
|
||||
if (!episodeId || !episodes || isServerFetchInProgress.current) return;
|
||||
|
||||
let mounted = true;
|
||||
const controller = new AbortController();
|
||||
isServerFetchInProgress.current = true;
|
||||
setServerLoading(true);
|
||||
|
||||
const fetchServers = async () => {
|
||||
isServerFetchInProgress.current = true;
|
||||
setServerLoading(true);
|
||||
try {
|
||||
const data = await getServers(animeId, episodeId);
|
||||
console.log(data);
|
||||
const data = await getServers(animeId, episodeId, { signal: controller.signal });
|
||||
if (!mounted) return;
|
||||
|
||||
const filteredServers = data?.filter(
|
||||
(server) =>
|
||||
server.serverName === "HD-1" ||
|
||||
server.serverName === "HD-2" ||
|
||||
server.serverName === "HD-3"
|
||||
);
|
||||
if (filteredServers.some((s) => s.type === "sub")) {
|
||||
filteredServers.push({
|
||||
type: "sub",
|
||||
data_id: "69696969",
|
||||
server_id: "41",
|
||||
serverName: "HD-4",
|
||||
});
|
||||
// server.serverName === "HD-3" ||
|
||||
server.serverName === "Vidstreaming" ||
|
||||
server.serverName === "Vidcloud" ||
|
||||
server.serverName === "DouVideo"
|
||||
) || [];
|
||||
|
||||
let serversList = [...filteredServers];
|
||||
|
||||
if (serversList.some((s) => s.type === "sub")) {
|
||||
if (!serversList.some((s) => s.serverName === "HD-4" && s.type === "sub")) {
|
||||
serversList.push({
|
||||
type: "sub",
|
||||
data_id: "69696968",
|
||||
server_id: "41",
|
||||
serverName: "HD-4",
|
||||
});
|
||||
}
|
||||
}
|
||||
if (filteredServers.some((s) => s.type === "dub")) {
|
||||
filteredServers.push({
|
||||
type: "dub",
|
||||
data_id: "96969696",
|
||||
server_id: "42",
|
||||
serverName: "HD-4",
|
||||
});
|
||||
|
||||
if (serversList.some((s) => s.type === "dub")) {
|
||||
if (!serversList.some((s) => s.serverName === "HD-4" && s.type === "dub")) {
|
||||
serversList.push({
|
||||
type: "dub",
|
||||
data_id: "96969696",
|
||||
server_id: "42",
|
||||
serverName: "HD-4",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const savedServerName = localStorage.getItem("server_name");
|
||||
const savedServerType = localStorage.getItem("server_type");
|
||||
const initialServer =
|
||||
filteredServers.find(s => s.serverName === savedServerName && s.type === savedServerType) ||
|
||||
filteredServers.find(s => s.serverName === savedServerName) ||
|
||||
filteredServers.find(s => s.type === savedServerType && ["HD-1", "HD-2", "HD-3", "HD-4"].includes(s.serverName)) ||
|
||||
filteredServers.find(s => s.serverName === "HD-2") ||
|
||||
filteredServers[0];
|
||||
|
||||
setServers(filteredServers);
|
||||
const initialServer =
|
||||
serversList.find(s => s.serverName === savedServerName && s.type === savedServerType) ||
|
||||
serversList.find(s => s.serverName === savedServerName) ||
|
||||
serversList.find(s => s.serverName === "HD-2") ||
|
||||
serversList.find(
|
||||
s =>
|
||||
s.type === savedServerType &&
|
||||
["HD-1", "HD-2", "HD-3", "HD-4", "Vidstreaming", "Vidcloud", "DouVideo"].includes(s.serverName)
|
||||
) ||
|
||||
serversList[0];
|
||||
|
||||
setServers(serversList);
|
||||
setActiveServerType(initialServer?.type);
|
||||
setActiveServerName(initialServer?.serverName);
|
||||
setActiveServerId(initialServer?.data_id);
|
||||
} catch (error) {
|
||||
console.error("Error fetching servers:", error);
|
||||
setError(error.message || "An error occurred.");
|
||||
} catch (err) {
|
||||
if (err?.name === "AbortError") return;
|
||||
console.error("Error fetching servers:", err);
|
||||
if (mounted) setError(err.message || "An error occurred.");
|
||||
} finally {
|
||||
setServerLoading(false);
|
||||
isServerFetchInProgress.current = false;
|
||||
if (mounted) {
|
||||
setServerLoading(false);
|
||||
isServerFetchInProgress.current = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchServers();
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
try { controller.abort(); } catch (e) {
|
||||
// console.log(e.message);
|
||||
}
|
||||
isServerFetchInProgress.current = false;
|
||||
};
|
||||
}, [episodeId, episodes]);
|
||||
|
||||
// Fetch stream info only when episodeId, activeServerId, and servers are ready
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -175,11 +209,10 @@ export const useWatch = (animeId, initialEpisodeId) => {
|
||||
isStreamFetchInProgress.current
|
||||
)
|
||||
return;
|
||||
if (
|
||||
(activeServerName?.toLowerCase() === "hd-1" || activeServerName?.toLowerCase() === "hd-4")
|
||||
&&
|
||||
!serverLoading
|
||||
) {
|
||||
const iframeServers = [];
|
||||
// const iframeServers = ["hd-1", "hd-4", "vidstreaming", "vidcloud", "douvideo"];
|
||||
|
||||
if (iframeServers.includes(activeServerName?.toLowerCase()) && !serverLoading) {
|
||||
setBuffering(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useLocation, useParams, Link, useNavigate } from "react-router-dom";
|
||||
import { useLanguage } from "@/src/context/LanguageContext";
|
||||
import { useWatch } from "@/src/hooks/useWatch";
|
||||
import BouncingLoader from "@/src/components/ui/bouncingloader/Bouncingloader";
|
||||
import IframePlayer from "@/src/components/player/IframePlayer";
|
||||
import Episodelist from "@/src/components/episodelist/Episodelist";
|
||||
import website_name from "@/src/config/website";
|
||||
import Sidecard from "@/src/components/sidecard/Sidecard";
|
||||
@@ -200,48 +199,45 @@ export default function Watch() {
|
||||
<div ref={playerRef} className="player w-full h-fit bg-black flex flex-col rounded-xl overflow-hidden shadow-2xl">
|
||||
<div ref={videoContainerRef} className="w-full relative aspect-video bg-black">
|
||||
{!buffering ? (
|
||||
["hd-1", "hd-4"].includes(activeServerName.toLowerCase()) ? (
|
||||
<IframePlayer
|
||||
episodeId={episodeId}
|
||||
servertype={activeServerType}
|
||||
serverName={activeServerName}
|
||||
animeInfo={animeInfo}
|
||||
episodeNum={activeEpisodeNum}
|
||||
episodes={episodes}
|
||||
playNext={setEpisodeId}
|
||||
autoNext={autoNext}
|
||||
/>
|
||||
) : (
|
||||
<Player
|
||||
streamUrl={streamUrl}
|
||||
subtitles={subtitles}
|
||||
intro={intro}
|
||||
outro={outro}
|
||||
serverName={activeServerName.toLowerCase()}
|
||||
thumbnail={thumbnail}
|
||||
autoSkipIntro={autoSkipIntro}
|
||||
autoPlay={autoPlay}
|
||||
autoNext={autoNext}
|
||||
episodeId={episodeId}
|
||||
episodes={episodes}
|
||||
playNext={setEpisodeId}
|
||||
animeInfo={animeInfo}
|
||||
episodeNum={activeEpisodeNum}
|
||||
streamInfo={streamInfo}
|
||||
/>
|
||||
)
|
||||
<Player
|
||||
streamUrl={streamUrl}
|
||||
subtitles={subtitles}
|
||||
intro={intro}
|
||||
outro={outro}
|
||||
activeServerName={activeServerName}
|
||||
thumbnail={thumbnail}
|
||||
autoSkipIntro={autoSkipIntro}
|
||||
autoPlay={autoPlay}
|
||||
autoNext={autoNext}
|
||||
episodeId={episodeId}
|
||||
episodes={episodes}
|
||||
playNext={setEpisodeId}
|
||||
animeInfo={animeInfo}
|
||||
episodeNum={activeEpisodeNum}
|
||||
streamInfo={streamInfo}
|
||||
/>
|
||||
) : (
|
||||
<div className="absolute inset-0 flex justify-center items-center bg-black">
|
||||
<div className="absolute inset-0 flex justify-center items-center bg-black bg-opacity-50">
|
||||
<BouncingLoader />
|
||||
</div>
|
||||
)}
|
||||
{!buffering && !activeServerType && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm pointer-events-none">
|
||||
<p className="text-center text-gray-300 font-medium p-4 max-w-sm">
|
||||
Streaming server seems to be down. Please try another server or reload the page.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-center underline font-medium text-[15px] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 pointer-events-none">
|
||||
{!buffering && !streamInfo ? (
|
||||
servers ? (
|
||||
<>
|
||||
Probably this server is down, try other servers
|
||||
<br />
|
||||
Either reload or try again after sometime
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Probably streaming server is down
|
||||
<br />
|
||||
Either reload or try again after sometime
|
||||
</>
|
||||
)
|
||||
) : null}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#121212]">
|
||||
|
||||
14
src/utils/title.utils.js
Normal file
14
src/utils/title.utils.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export const getTitle = (item, language) => {
|
||||
if (!item) return "N/A";
|
||||
|
||||
const title = item.title;
|
||||
const japanese_title = item.japanese_title || item.japaneseTitle;
|
||||
|
||||
if (language === "EN") {
|
||||
if (typeof title === "string") return title;
|
||||
return title?.english || title?.romaji || "N/A";
|
||||
} else {
|
||||
// JP
|
||||
return japanese_title || (typeof title === "string" ? title : title?.romaji || title?.english || "N/A");
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user