From 1242c3ed6b2572f4be4d7a5cc3409601a18a36dc Mon Sep 17 00:00:00 2001 From: Factiven Date: Sun, 28 May 2023 20:27:27 +0700 Subject: Update v3.6.2 > Added Zoro and Enime provider --- components/videoPlayer.js | 88 ++++- lib/Artplayer.js | 63 +++- pages/anime/[...id].js | 767 +++++++++++++++++++++++++---------------- pages/anime/watch/[...info].js | 53 +-- 4 files changed, 645 insertions(+), 326 deletions(-) diff --git a/components/videoPlayer.js b/components/videoPlayer.js index 784d8e9..8c137d1 100644 --- a/components/videoPlayer.js +++ b/components/videoPlayer.js @@ -2,6 +2,21 @@ import Player from "../lib/Artplayer"; import { useEffect, useState } from "react"; import { useAniList } from "../lib/useAnilist"; +const fontSize = [ + { + html: "Small", + size: "16px", + }, + { + html: "Medium", + size: "36px", + }, + { + html: "Large", + size: "56px", + }, +]; + export default function VideoPlayer({ data, id, @@ -14,19 +29,40 @@ export default function VideoPlayer({ title, poster, proxy, + provider, }) { const [url, setUrl] = useState(""); const [source, setSource] = useState([]); const { markProgress } = useAniList(session); const [resolution, setResolution] = useState("auto"); + const [subSize, setSubSize] = useState({ size: "16px", html: "Small" }); + const [defSize, setDefSize] = useState(); + const [subtitle, setSubtitle] = useState(); + const [defSub, setDefSub] = useState(); useEffect(() => { const resol = localStorage.getItem("quality"); + const sub = JSON.parse(localStorage.getItem("subSize")); if (resol) { setResolution(resol); } + if (provider === "zoro") { + const size = fontSize.map((i) => { + const isDefault = !sub ? i.html === "Small" : i.html === sub?.html; + return { + ...(isDefault && { default: true }), + html: i.html, + size: i.size, + }; + }); + + const defSize = size?.find((i) => i?.default === true); + setDefSize(defSize); + setSubSize(size); + } + async function compiler() { try { const referer = data?.headers?.Referer; @@ -39,9 +75,12 @@ export default function VideoPlayer({ ...(isDefault && { default: true }), html: items.quality === "default" ? "adaptive" : items.quality, // url: `${proxy}${items.url}`, - url: `https://cors.moopa.my.id/?url=${encodeURIComponent( - items.url - )}${referer ? `&referer=${encodeURIComponent(referer)}` : ""}`, + url: + provider === "gogoanime" + ? `https://cors.moopa.my.id/?url=${encodeURIComponent( + items.url + )}${referer ? `&referer=${encodeURIComponent(referer)}` : ""}` + : `${proxy}${items.url}`, }; // url: `https://m3u8proxy.moopa.workers.dev/?url=${encodeURIComponent(items.url)}${ // referer ? `&referer=${encodeURIComponent(referer)}` : "" @@ -54,6 +93,28 @@ export default function VideoPlayer({ setUrl(defSource.url); } + if (provider === "zoro") { + const subtitle = data?.subtitles + .filter((subtitle) => subtitle.lang !== "Thumbnails") + .map((subtitle) => { + const isEnglish = subtitle.lang === "English"; + return { + ...(isEnglish && { default: true }), + url: subtitle.url, + html: `${subtitle.lang}`, + }; + }); + + const defSub = data?.subtitles.find((i) => i.lang === "English"); + // const thumb = data?.subtitles.find((i) => i.lang === "Thumbnails"); + + // setThumbnails(thumb?.url); + setDefSub(defSub?.url); + + // console.log(subtitle); + setSubtitle(subtitle); + } + // const defUrl = `https://cors.moopa.my.id/?url=${encodeURIComponent( // sumber.url // )}${referer ? `&referer=${encodeURIComponent(referer)}` : ""}`; @@ -77,9 +138,26 @@ export default function VideoPlayer({ autoplay: true, screenshot: true, poster: poster ? poster : "", + ...(provider === "zoro" && { + subtitle: { + url: `${defSub}`, + // type: "vtt", + encoding: "utf-8", + default: true, + name: "English", + escape: false, + style: { + color: "#FFFF", + fontSize: `${defSize?.size}`, + }, + }, + }), }} res={resolution} quality={source} + subSize={subSize} + subtitles={subtitle} + provider={provider} style={{ width: "100%", height: "100%", @@ -93,6 +171,10 @@ export default function VideoPlayer({ const duration = art.duration; const percentage = seekTime / duration; + if (subSize) { + art.subtitle.style.fontSize = subSize?.size; + } + if (percentage >= 0.9) { art.currentTime = 0; console.log("Video started from the beginning"); diff --git a/lib/Artplayer.js b/lib/Artplayer.js index de454bb..64b5c4d 100644 --- a/lib/Artplayer.js +++ b/lib/Artplayer.js @@ -6,6 +6,9 @@ export default function Player({ option, res, quality, + subSize, + subtitles, + provider, getInstance, ...rest }) { @@ -44,6 +47,64 @@ export default function Player({ pip: true, theme: "#f97316", settings: [ + provider === "zoro" && { + html: "Subtitle", + width: 300, + tooltip: "English", + selector: [ + { + html: "Display", + tooltip: "Show", + switch: true, + onSwitch: function (item) { + item.tooltip = item.switch ? "Hide" : "Show"; + art.subtitle.show = !item.switch; + return !item.switch; + }, + }, + { + html: "Font Size", + 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", + }) + ); + } + }, + }, + ...subtitles, + ], + onSelect: function (item) { + art.subtitle.switch(item.url, { + name: item.html, + }); + return item.html; + }, + }, { html: "Quality", width: 150, @@ -55,7 +116,7 @@ export default function Player({ return item.html; }, }, - ], + ].filter(Boolean), }); if (getInstance && typeof getInstance === "function") { diff --git a/pages/anime/[...id].js b/pages/anime/[...id].js index 200a7f4..ed97b5c 100644 --- a/pages/anime/[...id].js +++ b/pages/anime/[...id].js @@ -1,7 +1,11 @@ import Skeleton, { SkeletonTheme } from "react-loading-skeleton"; import "react-loading-skeleton/dist/skeleton.css"; -import { ClockIcon, HeartIcon } from "@heroicons/react/20/solid"; +import { + ChevronDownIcon, + ClockIcon, + HeartIcon, +} from "@heroicons/react/20/solid"; import { TvIcon, ArrowTrendingUpIcon, @@ -35,6 +39,7 @@ export default function Info({ info, color }) { const [statuses, setStatuses] = useState(null); const [domainUrl, setDomainUrl] = useState(""); const [showAll, setShowAll] = useState(false); + const [visible, setVisible] = useState(false); const [open, setOpen] = useState(false); const [time, setTime] = useState(0); const { id } = useRouter().query; @@ -47,6 +52,20 @@ export default function Info({ info, color }) { (data) => data.mediaRecommendation ); + const [provider, setProvider] = useState(); + const [prvValue, setPrvValue] = useState("gogoanime"); + // const [err, setErr] = useState(''); + + function handleProvider(e) { + setEpisode( + Array.isArray(provider[e.target.value]) + ? provider[e.target.value]?.reverse() + : provider[e.target.value] + ); + setPrvValue(e.target.value); + localStorage.setItem("provider", e.target.value); + } + useEffect(() => { handleClose(); async function fetchData() { @@ -54,10 +73,17 @@ export default function Info({ info, color }) { if (id) { try { const { protocol, host } = window.location; + const prv = localStorage.getItem("provider"); const url = `${protocol}//${host}`; const view = localStorage.getItem("epiView"); + if (prv) { + setPrvValue(prv); + } else { + setPrvValue("gogoanime"); + } + setDomainUrl(url); setArtStorage(JSON.parse(localStorage.getItem("artplayer_settings"))); @@ -66,71 +92,136 @@ export default function Info({ info, color }) { setProgress(0); setStatuses(null); - const res = await fetch( - `https://api.moopa.my.id/meta/anilist/info/${info.id}` - ); - // const res = true; - if (res.status === 500 || res.status === 404) { - // if (res === false) { - setEpisode([]); - } else { - const data = await res.json(); - // const data = aniInfo; - if (!data || data?.episodes?.length === 0) { + let reloadCount = 0; + + try { + const fetchPromises = [ + fetch( + `https://api.moopa.my.id/meta/anilist/info/${info.id}?provider=enime` + ), + fetch( + `https://api.moopa.my.id/meta/anilist/info/${info.id}?provider=zoro` + ), + fetch( + `https://api.moopa.my.id/meta/anilist/info/${info.id}?provider=gogoanime` + ), + ]; + + const results = await Promise.allSettled(fetchPromises); + const successfulResponses = []; + let errorCount = 0; + + results.forEach((result) => { + if (result.status === "fulfilled") { + successfulResponses.push(result.value); + } else { + errorCount++; + } + }); + + if (errorCount === fetchPromises.length) { + // All fetch requests failed, handle the error here setEpisode([]); } else { - if (data.episodes?.some((i) => i.title === null)) { - setEpiView("3"); - } else if (view) { - setEpiView(view); + // Process the successfulResponses here + const responsesData = await Promise.all( + successfulResponses.map((response) => response.json()) + ); + const [enime, zoro, gogoanime] = responsesData; + + const prov = { + enime: enime?.episodes || enime, + zoro: zoro?.episodes || zoro, + gogoanime: gogoanime?.episodes || gogoanime, + }; + + const infProv = { + enime: enime, + zoro: zoro, + gogoanime: gogoanime, + }; + + if (prv) { + setEpisode( + Array.isArray(prov[prv]) ? prov[prv]?.reverse() : prov[prv] + ); } else { - setEpiView("3"); + setEpisode( + Array.isArray(prov["gogoanime"]) + ? prov["gogoanime"]?.reverse() + : prov["gogoanime"] + ); } - setEpisode(data?.episodes.reverse()); - } - if (session?.user?.name) { - const response = await fetch("https://graphql.anilist.co/", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - query: GET_MEDIA_USER, - variables: { - username: session?.user?.name, + const data = infProv[prv] || infProv["gogoanime"]; + // const data = aniInfo; + if (!data || data?.episodes?.length === 0) { + setEpisode([]); + } else { + if (data.episodes?.some((i) => i.title === null)) { + setEpiView("3"); + } else if (view) { + setEpiView(view); + } else { + setEpiView("3"); + } + } + + if (session?.user?.name) { + const response = await fetch("https://graphql.anilist.co/", { + method: "POST", + headers: { + "Content-Type": "application/json", }, - }), - }); - - const responseData = await response.json(); - - const prog = responseData?.data?.MediaListCollection; - - if (prog && prog.lists.length > 0) { - const gut = prog.lists - .flatMap((item) => item.entries) - .find((item) => item.mediaId === parseInt(id[0])); - - if (gut) { - setProgress(gut.progress); - const statusMapping = { - CURRENT: { name: "Watching", value: "CURRENT" }, - PLANNING: { name: "Plan to watch", value: "PLANNING" }, - COMPLETED: { name: "Completed", value: "COMPLETED" }, - DROPPED: { name: "Dropped", value: "DROPPED" }, - PAUSED: { name: "Paused", value: "PAUSED" }, - REPEATING: { name: "Rewatching", value: "REPEATING" }, - }; - setStatuses(statusMapping[gut.status]); + body: JSON.stringify({ + query: GET_MEDIA_USER, + variables: { + username: session?.user?.name, + }, + }), + }); + + const responseData = await response.json(); + + const prog = responseData?.data?.MediaListCollection; + + if (prog && prog.lists.length > 0) { + const gut = prog.lists + .flatMap((item) => item.entries) + .find((item) => item.mediaId === parseInt(id[0])); + + if (gut) { + setProgress(gut.progress); + const statusMapping = { + CURRENT: { name: "Watching", value: "CURRENT" }, + PLANNING: { name: "Plan to watch", value: "PLANNING" }, + COMPLETED: { name: "Completed", value: "COMPLETED" }, + DROPPED: { name: "Dropped", value: "DROPPED" }, + PAUSED: { name: "Paused", value: "PAUSED" }, + REPEATING: { name: "Rewatching", value: "REPEATING" }, + }; + setStatuses(statusMapping[gut.status]); + } } } - } - if (data.nextAiringEpisode) { - setTime( - convertSecondsToTime(data.nextAiringEpisode.timeUntilAiring) - ); + if (data.nextAiringEpisode) { + setTime( + convertSecondsToTime(data.nextAiringEpisode.timeUntilAiring) + ); + } + + setProvider(prov); + } + } catch (error) { + console.error(error); + if (reloadCount < 2) { + reloadCount++; + setTimeout(() => { + window.location.reload(); + }, 1000); + } else { + setEpisode([]); } } } catch (error) { @@ -509,211 +600,211 @@ export default function Info({ info, color }) {
-
-
- {info && ( -

- Episodes -

- )} - {info?.nextAiringEpisode && ( -
-
-

Next :

-
- {time} +
+
+
+ {info && ( +

+ Episodes +

+ )} + {info?.nextAiringEpisode && ( +
+
+

Next :

+
+ {time} +
+
+
+
-
- -
-
- )} -
-
+ )} +
0 - ? episode?.some((item) => item?.title === null) - ? "pointer-events-none" - : "cursor-pointer" - : "pointer-events-none" - } - onClick={() => { - setEpiView("1"); - localStorage.setItem("epiView", "1"); - }} + className="lg:hidden bg-secondary p-1 rounded-md cursor-pointer" + onClick={() => setVisible(!visible)} > + + +
+
+
+
+ + +
+
+
0 + ? episode?.some((item) => item?.title === null) + ? "pointer-events-none" + : "cursor-pointer" + : "pointer-events-none" + } + onClick={() => { + setEpiView("1"); + localStorage.setItem("epiView", "1"); + }} > - + 0 + ? episode?.some((item) => item?.title === null) + ? "fill-[#1c1c22]" + : epiView === "1" + ? "fill-action" + : "fill-[#3A3A44]" + : "fill-[#1c1c22]" + }`} + rx="3" + > + +
+
0 + ? episode?.some((item) => item?.title === null) + ? "pointer-events-none" + : "cursor-pointer" + : "pointer-events-none" + } + onClick={() => { + setEpiView("2"); + localStorage.setItem("epiView", "2"); + }} + > + 0 ? episode?.some((item) => item?.title === null) ? "fill-[#1c1c22]" - : epiView === "1" + : epiView === "2" ? "fill-action" : "fill-[#3A3A44]" : "fill-[#1c1c22]" }`} - rx="3" - > - -
-
0 - ? episode?.some((item) => item?.title === null) - ? "pointer-events-none" - : "cursor-pointer" - : "pointer-events-none" - } - onClick={() => { - setEpiView("2"); - localStorage.setItem("epiView", "2"); - }} - > - 0 - ? episode?.some((item) => item?.title === null) - ? "fill-[#1c1c22]" - : epiView === "2" - ? "fill-action" - : "fill-[#3A3A44]" - : "fill-[#1c1c22]" - }`} - viewBox="0 0 33 20" - > - - - -
-
0 - ? `cursor-pointer` - : "pointer-events-none" - } - onClick={() => { - setEpiView("3"); - localStorage.setItem("epiView", "3"); - }} - > - + + + +
+
0 - ? epiView === "3" - ? "fill-action" - : "fill-[#3A3A44]" - : "fill-[#1c1c22]" - }`} - viewBox="0 0 33 20" + ? `cursor-pointer` + : "pointer-events-none" + } + onClick={() => { + setEpiView("3"); + localStorage.setItem("epiView", "3"); + }} > - - - - + 0 + ? epiView === "3" + ? "fill-action" + : "fill-[#3A3A44]" + : "fill-[#1c1c22]" + }`} + viewBox="0 0 33 20" + > + + + + +
{!loading ? ( - episode && ( -
- {episode?.length !== 0 && episode ? ( -
- {epiView === "1" - ? episode?.map((epi, index) => { - const time = artStorage?.[epi?.id]?.time; - const duration = - artStorage?.[epi?.id]?.duration; - let prog = (time / duration) * 100; - if (prog > 90) prog = 100; - return ( - - - Episode {epi?.number} - - -
- epi image - - ); - }) - : ""} - {epiView === "2" && - episode?.map((epi, index) => { - const time = artStorage?.[epi?.id]?.time; - const duration = artStorage?.[epi?.id]?.duration; - let prog = (time / duration) * 100; - if (prog > 90) prog = 100; - return ( - -
-
- Anime Cover + Array.isArray(episode) ? ( + episode && ( +
+ {episode?.length !== 0 && episode ? ( +
+ {epiView === "1" + ? episode?.map((epi, index) => { + const time = artStorage?.[epi?.id]?.time; + const duration = + artStorage?.[epi?.id]?.duration; + let prog = (time / duration) * 100; + if (prog > 90) prog = 100; + return ( + + + Episode {epi?.number} + - - Episode {epi?.number} - -
- - - +
+ epi image + + ); + }) + : ""} + {epiView === "2" && + episode?.map((epi, index) => { + const time = artStorage?.[epi?.id]?.time; + const duration = + artStorage?.[epi?.id]?.duration; + let prog = (time / duration) * 100; + if (prog > 90) prog = 100; + return ( + +
+
+ Anime Cover + + + Episode {epi?.number} + +
+ + + +
-
+
+

+ {epi?.title} +

+ {epi?.description && ( +

+ {epi?.description} +

+ )} +
+ + ); + })} + {epiView === "3" && + episode?.map((epi, index) => { + return (
-

- {epi?.title} -

- {epi?.description && ( -

- {epi?.description} -

+ +

Episode {epi.number}

+ {epi.title && ( +

+ "{epi.title}" +

+ )} + + {index !== episode?.length - 1 && ( + )}
- - ); - })} - {epiView === "3" && - episode?.map((epi, index) => { - return ( -
- -

Episode {epi.number}

- {epi.title && ( -

- "{epi.title}" -

- )} - - {index !== episode?.length - 1 && ( - - )} -
- ); - })} -
- ) : ( -

No Episodes Available

- )} + ); + })} +
+ ) : ( +

No Episodes Available

+ )} +
+ ) + ) : ( +
+
+                        {episode?.message}
+                      
) ) : ( @@ -903,3 +1052,17 @@ function setTxtColor(hexColor) { const brightness = getBrightness(hexColor); return brightness < 150 ? "#fff" : "#000"; } + +const getLanguageClassName = (language) => { + switch (language) { + case "javascript": + return "language-javascript"; + case "html": + return "language-html"; + case "bash": + return "language-bash"; + // add more languages here as needed + default: + return ""; + } +}; diff --git a/pages/anime/watch/[...info].js b/pages/anime/watch/[...info].js index b3d02cf..c1ec46e 100644 --- a/pages/anime/watch/[...info].js +++ b/pages/anime/watch/[...info].js @@ -39,6 +39,8 @@ export default function Info({ sessions, id, aniId, provider, proxy }) { const router = useRouter(); + // console.log(data); + useEffect(() => { const defaultState = { epiData: null, @@ -72,7 +74,7 @@ export default function Info({ sessions, id, aniId, provider, proxy }) { try { if (provider) { const res = await fetch( - `https://api.consumet.org/meta/anilist/watch/${id}?provider=9anime` + `https://api.moopa.my.id/meta/anilist/watch/${id}?provider=${provider}` ); const epiData = await res.json(); setEpiData(epiData); @@ -94,9 +96,10 @@ export default function Info({ sessions, id, aniId, provider, proxy }) { if (provider) { const res = await fetch( - `https://api.consumet.org/meta/anilist/info/${aniId}?provider=9anime` + `https://api.moopa.my.id/meta/anilist/info/${aniId}?provider=${provider}` ); aniData = await res.json(); + setEpisodes(aniData.episodes?.reverse()); setAniData(aniData); } else { const res2 = await fetch( @@ -220,22 +223,32 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
{loading ? ( -
- -
+ Array.isArray(epiData?.sources) ? ( +
+ +
+ ) : ( +
+

+ Whoops! Something went wrong. Please reload the page or + try other sources. {`:(`} +

+
+ ) ) : (
)} @@ -441,7 +454,7 @@ export default function Info({ sessions, id, aniId, provider, proxy }) { return ( - + Episode {item.number} {item.id == id && ( -- cgit v1.2.3