aboutsummaryrefslogtreecommitdiff
path: root/pages/en
diff options
context:
space:
mode:
Diffstat (limited to 'pages/en')
-rw-r--r--pages/en/anime/[...id].js1000
-rw-r--r--pages/en/anime/watch/[...info].js749
-rw-r--r--pages/en/index.js7
-rw-r--r--pages/en/test.js11
4 files changed, 270 insertions, 1497 deletions
diff --git a/pages/en/anime/[...id].js b/pages/en/anime/[...id].js
index 86396e3..0b83f24 100644
--- a/pages/en/anime/[...id].js
+++ b/pages/en/anime/[...id].js
@@ -1,22 +1,8 @@
-import Skeleton from "react-loading-skeleton";
-
-import {
- ChevronDownIcon,
- ClockIcon,
- HeartIcon,
-} from "@heroicons/react/20/solid";
-import {
- TvIcon,
- ArrowTrendingUpIcon,
- RectangleStackIcon,
-} from "@heroicons/react/24/outline";
-
import Head from "next/head";
import Image from "next/image";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import Layout from "../../../components/layout";
-import Link from "next/link";
import Content from "../../../components/home/content";
import Modal from "../../../components/modal";
@@ -28,252 +14,75 @@ import { GET_MEDIA_USER } from "../../../queries";
import { GET_MEDIA_INFO } from "../../../queries";
import { ToastContainer } from "react-toastify";
-import { convertSecondsToTime } from "../../../utils/getTimes";
-
-// import { aniInfo } from "../../components/devComp/data";
-// console.log(GET_MEDIA_USER);
-export default function Info({ info, color, api }) {
- // Episodes dropdown
- const [firstEpisodeIndex, setFirstEpisodeIndex] = useState(0);
- const [lastEpisodeIndex, setLastEpisodeIndex] = useState();
- const [selectedRange, setSelectedRange] = useState("All");
- function onEpisodeIndexChange(e) {
- if (e.target.value === "All") {
- setFirstEpisodeIndex(0);
- setLastEpisodeIndex();
- setSelectedRange("All");
- return;
- }
- setFirstEpisodeIndex(e.target.value.split("-")[0] - 1);
- setLastEpisodeIndex(e.target.value.split("-")[1]);
- setSelectedRange(e.target.value);
- }
+import DetailTop from "../../../components/anime/mobile/topSection";
+import DesktopDetails from "../../../components/anime/infoDetails";
+import AnimeEpisode from "../../../components/anime/episode";
+export default function Info({ info, color }) {
const { data: session } = useSession();
- const [episode, setEpisode] = useState(null);
const [loading, setLoading] = useState(false);
const [progress, setProgress] = useState(0);
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;
- const [epiView, setEpiView] = useState("3");
-
- const [artStorage, setArtStorage] = useState(null);
-
const rec = info?.recommendations?.nodes?.map(
(data) => data.mediaRecommendation
);
- const [provider, setProvider] = useState();
- const [prvValue, setPrvValue] = useState("gogoanime");
-
- const [availableProviders, setAvailableProviders] = useState([]);
- // 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);
- }
-
- //for episodes dropdown
- useEffect(() => {
- setFirstEpisodeIndex(0);
- setLastEpisodeIndex();
- setSelectedRange("All");
- }, [info, prvValue]);
-
useEffect(() => {
handleClose();
async function fetchData() {
setLoading(true);
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);
+ setDomainUrl(window.location.origin);
- setArtStorage(JSON.parse(localStorage.getItem("artplayer_settings")));
-
- setEpisode(null);
setProgress(0);
setStatuses(null);
- let reloadCount = 0;
-
- try {
- const fetchPromises = [
- fetch(`${api}/meta/anilist/info/${info.id}?provider=enime`),
- fetch(`${api}/meta/anilist/info/${info.id}?provider=zoro`),
- fetch(`${api}/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 {
- // 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 aPrv = [
- {
- name: "enime",
- available:
- enime?.episodes && enime?.episodes.length > 0
- ? true
- : false,
+ 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,
},
- {
- name: "zoro",
- available:
- zoro?.episodes && zoro?.episodes.length > 0 ? true : false,
- },
- {
- name: "gogoanime",
- available:
- gogoanime?.episodes && gogoanime?.episodes.length > 0
- ? true
- : false,
- },
- ];
-
- setAvailableProviders(aPrv);
-
- const infProv = {
- enime: enime,
- zoro: zoro,
- gogoanime: gogoanime,
- };
-
- if (prv) {
- setEpisode(
- Array.isArray(prov[prv]) ? prov[prv]?.reverse() : prov[prv]
- );
- } else {
- setEpisode(
- Array.isArray(prov["gogoanime"])
- ? prov["gogoanime"]?.reverse()
- : prov["gogoanime"]
- );
- }
-
- 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",
- },
- 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)
- );
+ 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]);
}
-
- setProvider(prov);
- }
- } catch (error) {
- console.error(error);
- if (reloadCount < 2) {
- reloadCount++;
- setTimeout(() => {
- window.location.reload();
- }, 1000);
- } else {
- setEpisode([]);
}
}
} catch (error) {
console.error(error);
- setTimeout(() => {
- window.location.reload();
- }, 1000);
} finally {
setLoading(false);
}
@@ -292,8 +101,6 @@ export default function Info({ info, color, api }) {
document.body.style.overflow = "auto";
}
- const filterProviders = availableProviders?.filter((x) => x.available);
-
return (
<>
<Head>
@@ -343,7 +150,7 @@ export default function Info({ info, color, api }) {
<ListEditor
animeId={info?.id}
session={session}
- stats={statuses}
+ stats={statuses?.value}
prg={progress}
max={info?.episodes}
image={info}
@@ -356,691 +163,56 @@ export default function Info({ info, color, api }) {
<div className="bg-image w-screen">
<div className="bg-gradient-to-t from-primary from-10% to-transparent absolute h-[300px] w-screen z-10 inset-0" />
{info ? (
- <Image
- src={
- info?.bannerImage ||
- info?.coverImage?.extraLarge ||
- info?.coverImage.large
- }
- priority={true}
- alt="banner anime"
- height={1000}
- width={1000}
- className="object-cover bg-image w-screen absolute top-0 left-0 h-[300px] brightness-[70%] z-0"
- />
+ <>
+ <Image
+ src={
+ info?.bannerImage ||
+ info?.coverImage?.extraLarge ||
+ info?.coverImage.large
+ }
+ priority={true}
+ alt="banner anime"
+ height={1000}
+ width={1000}
+ className="hidden md:block object-cover bg-image w-screen absolute top-0 left-0 h-[300px] brightness-[70%] z-0"
+ />
+ <Image
+ src={info?.coverImage.extraLarge || info?.coverImage.large}
+ priority={true}
+ alt="banner anime"
+ height={1000}
+ width={1000}
+ className="md:hidden object-cover bg-image w-screen absolute top-0 left-0 h-[300px] brightness-[70%] z-0"
+ />
+ </>
) : (
<div className="bg-image w-screen absolute top-0 left-0 h-[300px]" />
)}
</div>
<div className="lg:w-[90%] xl:w-[75%] lg:pt-[10rem] z-30 flex flex-col gap-5">
- {/* Mobile */}
+ {/* Mobile Anime Information */}
- <div className="lg:hidden pt-5 w-screen px-5 flex flex-col">
- <div className="h-[250px] flex flex-col gap-1 justify-center">
- <h1 className="font-karla font-extrabold text-lg line-clamp-1 w-[70%]">
- {info?.title?.romaji || info?.title?.english}
- </h1>
- <p
- className="line-clamp-2 text-sm font-light antialiased w-[56%]"
- dangerouslySetInnerHTML={{ __html: info?.description }}
- />
- <div className="font-light flex gap-1 py-1 flex-wrap font-outfit text-[10px] text-[#ffffff] w-[70%]">
- {info?.genres
- ?.slice(
- 0,
- info?.genres?.length > 3 ? info?.genres?.length : 3
- )
- .map((item, index) => (
- <span
- key={index}
- className="px-2 py-1 bg-secondary shadow-lg font-outfit font-light rounded-full"
- >
- <span className="">{item}</span>
- </span>
- ))}
- </div>
- {info && (
- <div className="flex items-center gap-5 pt-3 text-center">
- <div className="flex items-center gap-2 text-center">
- <button
- type="button"
- className="bg-action px-10 rounded-sm font-karla font-bold"
- onClick={() => handleOpen()}
- >
- {!loading
- ? statuses
- ? statuses.name
- : "Add to List"
- : "Loading..."}
- </button>
- <div className="h-6 w-6">
- <HeartIcon />
- </div>
- </div>
- </div>
- )}
- </div>
- <div className="bg-secondary rounded-sm xs:h-[30px]">
- <div className="grid grid-cols-3 place-content-center xxs:flex items-center justify-center h-full xxs:gap-10 p-2 text-sm">
- {info && info.status !== "NOT_YET_RELEASED" ? (
- <>
- <div className="flex-center flex-col xxs:flex-row gap-2">
- <TvIcon className="w-5 h-5 text-action" />
- <h4 className="font-karla">{info?.type}</h4>
- </div>
- <div className="flex-center flex-col xxs:flex-row gap-2">
- <ArrowTrendingUpIcon className="w-5 h-5 text-action" />
- <h4>{info?.averageScore}%</h4>
- </div>
- <div className="flex-center flex-col xxs:flex-row gap-2">
- <RectangleStackIcon className="w-5 h-5 text-action" />
- {info?.episodes ? (
- <h1>{info?.episodes} Episodes</h1>
- ) : (
- <h1>TBA</h1>
- )}
- </div>
- </>
- ) : (
- <div>{info && "Not Yet Released"}</div>
- )}
- </div>
- </div>
- </div>
-
- {/* PC */}
- <div className="hidden lg:flex gap-8 w-full flex-nowrap">
- <div className="shrink-0 lg:h-[250px] lg:w-[180px] w-[115px] h-[164px] relative">
- {info ? (
- <>
- <div className="bg-image lg:h-[250px] lg:w-[180px] w-[115px] h-[164px] bg-opacity-30 absolute backdrop-blur-lg z-10 -top-7" />
- <Image
- src={info.coverImage.extraLarge || info.coverImage.large}
- priority={true}
- alt="poster anime"
- height={700}
- width={700}
- className="object-cover lg:h-[250px] lg:w-[180px] w-[115px] h-[164px] z-20 absolute rounded-md -top-7"
- />
- <button
- type="button"
- className="bg-action flex-center z-20 h-[20px] w-[180px] absolute bottom-0 rounded-sm font-karla font-bold"
- onClick={() => handleOpen()}
- >
- {!loading
- ? statuses
- ? statuses.name
- : "Add to List"
- : "Loading..."}
- </button>
- </>
- ) : (
- <Skeleton className="h-[250px] w-[180px]" />
- )}
- </div>
+ <DetailTop
+ info={info}
+ handleOpen={handleOpen}
+ loading={loading}
+ statuses={statuses}
+ />
- {/* PC */}
- <div className="hidden lg:flex w-full flex-col gap-5 h-[250px]">
- <div className="flex flex-col gap-2">
- <h1 className=" font-inter font-bold text-[36px] text-white line-clamp-1">
- {info ? (
- info?.title?.romaji || info?.title?.english
- ) : (
- <Skeleton width={450} />
- )}
- </h1>
- {info ? (
- <div className="flex gap-6">
- {info?.episodes && (
- <div
- className={`dynamic-text rounded-md px-2 font-karla font-bold`}
- style={color}
- >
- {info?.episodes} Episodes
- </div>
- )}
- {info?.startDate?.year && (
- <div
- className={`dynamic-text rounded-md px-2 font-karla font-bold`}
- style={color}
- >
- {info?.startDate?.year}
- </div>
- )}
- {info?.averageScore && (
- <div
- className={`dynamic-text rounded-md px-2 font-karla font-bold`}
- style={color}
- >
- {info?.averageScore}%
- </div>
- )}
- {info?.type && (
- <div
- className={`dynamic-text rounded-md px-2 font-karla font-bold`}
- style={color}
- >
- {info?.type}
- </div>
- )}
- {info?.status && (
- <div
- className={`dynamic-text rounded-md px-2 font-karla font-bold`}
- style={color}
- >
- {info?.status}
- </div>
- )}
- <div
- className={`dynamic-text rounded-md px-2 font-karla font-bold`}
- style={color}
- >
- Sub | EN
- </div>
- </div>
- ) : (
- <Skeleton width={240} height={32} />
- )}
- </div>
- {info ? (
- <p
- dangerouslySetInnerHTML={{ __html: info?.description }}
- className="overflow-y-scroll scrollbar-thin pr-2 scrollbar-thumb-secondary scrollbar-thumb-rounded-lg h-[140px]"
- />
- ) : (
- <Skeleton className="h-[130px]" />
- )}
- </div>
- </div>
+ {/* PC Anime Information*/}
+ <DesktopDetails
+ info={info}
+ color={color}
+ handleOpen={handleOpen}
+ loading={loading}
+ statuses={statuses}
+ setShowAll={setShowAll}
+ showAll={showAll}
+ />
- <div>
- <div className="flex gap-5 items-center">
- {info?.relations?.edges?.length > 0 && (
- <div className="p-3 lg:p-0 text-[20px] lg:text-2xl font-bold font-karla">
- Relations
- </div>
- )}
- {info?.relations?.edges?.length > 3 && (
- <div
- className="cursor-pointer"
- onClick={() => setShowAll(!showAll)}
- >
- {showAll ? "show less" : "show more"}
- </div>
- )}
- </div>
- <div
- className={`w-screen lg:w-full flex gap-5 overflow-x-scroll snap-x scroll-px-5 scrollbar-none lg:grid lg:grid-cols-3 justify-items-center lg:pt-7 lg:pb-5 px-3 lg:px-4 pt-4 rounded-xl`}
- >
- {info?.relations?.edges ? (
- info?.relations?.edges
- .slice(0, showAll ? info?.relations?.edges.length : 3)
- .map((r, index) => {
- const rel = r.node;
- return (
- <Link
- key={rel.id}
- href={
- rel.type === "ANIME" ||
- rel.type === "OVA" ||
- rel.type === "MOVIE" ||
- rel.type === "SPECIAL" ||
- rel.type === "ONA"
- ? `/en/anime/${rel.id}`
- : `/en/manga/${rel.id}`
- }
- className={`lg:hover:scale-[1.02] snap-start hover:shadow-lg scale-100 transition-transform duration-200 ease-out w-full ${
- rel.type === "MUSIC" ? "pointer-events-none" : ""
- }`}
- >
- <div
- key={rel.id}
- className="w-[400px] lg:w-full h-[126px] bg-secondary flex rounded-md"
- >
- <div className="w-[90px] bg-image rounded-l-md shrink-0">
- <Image
- src={
- rel.coverImage.extraLarge ||
- rel.coverImage.large
- }
- alt={rel.id}
- height={500}
- width={500}
- className="object-cover h-full w-full shrink-0 rounded-l-md"
- />
- </div>
- <div className="h-full grid px-3 items-center">
- <div className="text-action font-outfit font-bold">
- {r.relationType}
- </div>
- <div className="font-outfit font-thin line-clamp-2">
- {rel.title.userPreferred || rel.title.romaji}
- </div>
- <div className={``}>{rel.type}</div>
- </div>
- </div>
- </Link>
- );
- })
- ) : (
- <>
- {[1, 2, 3].map((item) => (
- <div key={item} className="w-full hidden lg:block">
- <Skeleton className="h-[126px]" />
- </div>
- ))}
- <div className="w-full lg:hidden">
- <Skeleton className="h-[126px]" />
- </div>
- </>
- )}
- </div>
- </div>
- <div className="flex flex-col gap-5 lg:gap-10 p-3 lg:p-0">
- <div className="flex lg:flex-row flex-col gap-5 lg:gap-0 justify-between ">
- <div className="flex justify-between">
- <div className="flex items-center lg:gap-10 sm:gap-7 gap-3">
- {info && (
- <h1 className="text-[20px] lg:text-2xl font-bold font-karla">
- Episodes
- </h1>
- )}
- {info?.nextAiringEpisode && (
- <div className="flex items-center gap-2">
- <div className="flex items-center gap-4 text-[10px] xxs:text-sm lg:text-base">
- <h1>Next :</h1>
- <div className="px-4 rounded-sm font-karla font-bold bg-white text-black">
- {time}
- </div>
- </div>
- <div className="h-6 w-6">
- <ClockIcon />
- </div>
- </div>
- )}
- </div>
- <div
- className="lg:hidden bg-secondary p-1 rounded-md cursor-pointer"
- onClick={() => setVisible(!visible)}
- >
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- strokeWidth={1.5}
- stroke="currentColor"
- className="w-6 h-6"
- >
- <path
- strokeLinecap="round"
- strokeLinejoin="round"
- d="M6.75 12a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM12.75 12a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM18.75 12a.75.75 0 11-1.5 0 .75.75 0 011.5 0z"
- />
- </svg>
- </div>
- </div>
- <div
- className={`flex lg:flex items-center gap-0 lg:gap-5 justify-between ${
- visible ? "" : "hidden"
- }`}
- >
- <div className="flex items-end gap-3">
- {filterProviders?.length > 0 && (
- <div className="relative flex gap-2 items-center">
- <p className="hidden md:block">Provider</p>
- <select
- onChange={handleProvider}
- value={prvValue}
- className="flex items-center text-sm gap-5 rounded-[3px] bg-secondary py-1 px-3 pr-8 font-karla appearance-none cursor-pointer outline-none focus:ring-1 focus:ring-action"
- >
- {availableProviders
- ?.filter((p) => p.available === true)
- .map((p) => {
- return (
- <option key={p.name} value={p.name}>
- {p.name}
- </option>
- );
- })}
- </select>
- <ChevronDownIcon className="absolute right-2 top-1/2 transform -translate-y-1/2 w-5 h-5 pointer-events-none" />
- </div>
- )}
- {episode?.length > 50 && (
- <div className="relative flex gap-2 items-center">
- <p className="hidden md:block">Episodes</p>
- <select
- onChange={onEpisodeIndexChange}
- value={selectedRange}
- className="flex items-center text-sm gap-5 rounded-[3px] bg-secondary py-1 px-3 pr-8 font-karla appearance-none cursor-pointer outline-none focus:ring-1 focus:ring-action scrollbar-thin scrollbar-thumb-secondary scrollbar-thumb-rounded-lg"
- >
- <option value="All">All</option>
- {[...Array(Math.ceil(episode?.length / 50))].map(
- (_, index) => {
- const start = index * 50 + 1;
- const end = Math.min(
- start + 50 - 1,
- episode?.length
- );
- const optionLabel = `${start} to ${end}`;
- if (episode[0]?.number !== 1) {
- var valueLabel = `${episode.length - end + 1}-${
- episode.length - start + 1
- }`;
- } else {
- var valueLabel = `${start}-${end}`;
- }
- return (
- <option key={valueLabel} value={valueLabel}>
- {optionLabel}
- </option>
- );
- }
- )}
- </select>
- <ChevronDownIcon className="absolute right-2 top-1/2 transform -translate-y-1/2 w-5 h-5 pointer-events-none" />
- </div>
- )}
- </div>
- <div className="flex gap-3 rounded-sm items-center p-2">
- <div
- className={
- episode?.length > 0
- ? episode?.some((item) => item?.title === null)
- ? "pointer-events-none"
- : "cursor-pointer"
- : "pointer-events-none"
- }
- onClick={() => {
- setEpiView("1");
- localStorage.setItem("epiView", "1");
- }}
- >
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="31"
- height="20"
- fill="none"
- viewBox="0 0 31 20"
- >
- <rect
- width="31"
- height="20"
- className={`${
- episode?.length > 0
- ? episode?.some((item) => item?.title === null)
- ? "fill-[#1c1c22]"
- : epiView === "1"
- ? "fill-action"
- : "fill-[#3A3A44]"
- : "fill-[#1c1c22]"
- }`}
- rx="3"
- ></rect>
- </svg>
- </div>
- <div
- className={
- episode?.length > 0
- ? episode?.some((item) => item?.title === null)
- ? "pointer-events-none"
- : "cursor-pointer"
- : "pointer-events-none"
- }
- onClick={() => {
- setEpiView("2");
- localStorage.setItem("epiView", "2");
- }}
- >
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="33"
- height="20"
- fill="none"
- className={`${
- episode?.length > 0
- ? episode?.some((item) => item?.title === null)
- ? "fill-[#1c1c22]"
- : epiView === "2"
- ? "fill-action"
- : "fill-[#3A3A44]"
- : "fill-[#1c1c22]"
- }`}
- viewBox="0 0 33 20"
- >
- <rect width="33" height="7" y="1" rx="3"></rect>
- <rect width="33" height="7" y="12" rx="3"></rect>
- </svg>
- </div>
- <div
- className={
- episode?.length > 0
- ? `cursor-pointer`
- : "pointer-events-none"
- }
- onClick={() => {
- setEpiView("3");
- localStorage.setItem("epiView", "3");
- }}
- >
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="33"
- height="20"
- fill="none"
- className={`${
- episode?.length > 0
- ? epiView === "3"
- ? "fill-action"
- : "fill-[#3A3A44]"
- : "fill-[#1c1c22]"
- }`}
- viewBox="0 0 33 20"
- >
- <rect width="29" height="4" x="2" y="2" rx="2"></rect>
- <rect width="29" height="4" x="2" y="8" rx="2"></rect>
- <rect width="16" height="4" x="2" y="14" rx="2"></rect>
- </svg>
- </div>
- </div>
- </div>
- </div>
- {!loading ? (
- Array.isArray(episode) ? (
- episode && (
- <div
- className={`${
- epiView === "3" &&
- "scrollbar-thin scrollbar-thumb-[#1b1c21] scrollbar-thumb-rounded-full overflow-y-scroll hover:scrollbar-thumb-[#2e2f37] h-[640px]"
- }`}
- >
- {episode?.length !== 0 && episode ? (
- <div
- className={`grid ${
- epiView === "1"
- ? "grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-5 lg:gap-8"
- : "flex flex-col gap-5"
- } pb-5 pt-2 lg:pt-0 ${
- epiView === "3" ? "" : "place-items-center"
- }`}
- >
- {epiView === "1"
- ? episode
- .slice(firstEpisodeIndex, lastEpisodeIndex)
- ?.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 (
- <Link
- key={index}
- href={`/en/anime/watch/${epi.id}/${info.id}/${prvValue}`}
- className="transition-all duration-200 ease-out lg:hover:scale-105 hover:ring-1 hover:ring-white cursor-pointer bg-secondary shrink-0 relative w-full h-[180px] sm:h-[130px] subpixel-antialiased rounded-md overflow-hidden"
- >
- <span className="absolute text-sm z-40 bottom-1 left-2 font-karla font-semibold text-white">
- Episode {epi?.number}
- </span>
- <span
- className={`absolute bottom-7 left-0 h-1 bg-red-600`}
- style={{
- width:
- progress &&
- artStorage &&
- epi?.number <= progress
- ? "100%"
- : artStorage?.[epi?.id]
- ? `${prog}%`
- : "0%",
- }}
- />
- <div className="absolute inset-0 bg-black z-30 opacity-20" />
- <Image
- src={epi?.image}
- alt="epi image"
- width={500}
- height={500}
- className="object-cover w-full h-[150px] sm:h-[100px] z-20"
- />
- </Link>
- );
- })
- : ""}
- {epiView === "2" &&
- episode
- .slice(firstEpisodeIndex, lastEpisodeIndex)
- .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 (
- <Link
- key={index}
- href={`/en/anime/watch/${epi.id}/${info.id}/${prvValue}`}
- className="flex group h-[110px] lg:h-[160px] w-full rounded-lg transition-all duration-300 ease-out bg-secondary cursor-pointer hover:scale-[1.02] ring-0 hover:ring-1 hover:shadow-lg ring-white"
- >
- <div className="w-[43%] lg:w-[30%] relative shrink-0 z-40 rounded-lg overflow-hidden shadow-[4px_0px_5px_0px_rgba(0,0,0,0.3)]">
- <div className="relative">
- <Image
- src={epi?.image}
- alt="Anime Cover"
- width={1000}
- height={1000}
- className="object-cover z-30 rounded-lg h-[110px] lg:h-[160px] brightness-[65%]"
- />
- <span
- className={`absolute bottom-0 left-0 h-[3px] bg-red-700`}
- style={{
- width:
- progress &&
- artStorage &&
- epi?.number <= progress
- ? "100%"
- : artStorage?.[epi?.id]
- ? `${prog}%`
- : "0",
- }}
- />
- <span className="absolute bottom-2 left-2 font-karla font-semibold text-sm lg:text-lg">
- Episode {epi?.number}
- </span>
- <div className="z-[9999] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 scale-[1.5]">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 20 20"
- fill="currentColor"
- className="w-5 h-5 invisible group-hover:visible"
- >
- <path d="M6.3 2.841A1.5 1.5 0 004 4.11V15.89a1.5 1.5 0 002.3 1.269l9.344-5.89a1.5 1.5 0 000-2.538L6.3 2.84z" />
- </svg>
- </div>
- </div>
- </div>
+ {/* Episodes */}
- <div
- className={`w-[70%] h-full select-none p-4 flex flex-col justify-center gap-5 ${
- epi?.id == id ? "text-[#7a7a7a]" : ""
- }`}
- >
- <h1 className="font-karla font-bold text-base lg:text-lg xl:text-xl italic line-clamp-1">
- {epi?.title}
- </h1>
- {epi?.description && (
- <p className="line-clamp-2 text-xs lg:text-md xl:text-lg italic font-outfit font-extralight">
- {epi?.description}
- </p>
- )}
- </div>
- </Link>
- );
- })}
- {epiView === "3" &&
- episode
- .slice(firstEpisodeIndex, lastEpisodeIndex)
- .map((epi, index) => {
- return (
- <div
- key={index}
- className="flex flex-col gap-3 px-2"
- >
- <Link
- href={`/en/anime/watch/${epi.id}/${info.id}/${prvValue}`}
- className={`text-start text-sm lg:text-lg ${
- progress && epi.number <= progress
- ? "text-[#5f5f5f]"
- : "text-white"
- }`}
- >
- <p>Episode {epi.number}</p>
- {epi.title && (
- <p
- className={`text-xs lg:text-sm ${
- progress && epi.number <= progress
- ? "text-[#5f5f5f]"
- : "text-[#b1b1b1]"
- } italic`}
- >
- "{epi.title}"
- </p>
- )}
- </Link>
- {index !== episode?.length - 1 && (
- <span className="h-[1px] bg-white" />
- )}
- </div>
- );
- })}
- </div>
- ) : (
- <p>No Episodes Available</p>
- )}
- </div>
- )
- ) : (
- <div className="flex flex-col">
- <pre
- className={`rounded-md overflow-hidden ${getLanguageClassName(
- "bash"
- )}`}
- >
- <code>{episode?.message}</code>
- </pre>
- </div>
- )
- ) : (
- <div className="flex justify-center">
- <div className="lds-ellipsis">
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- </div>
- </div>
- )}
- </div>
+ <AnimeEpisode info={info} progress={progress} />
</div>
{info && rec?.length !== 0 && (
<div className="w-screen lg:w-[90%] xl:w-[85%]">
@@ -1114,17 +286,3 @@ 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/en/anime/watch/[...info].js b/pages/en/anime/watch/[...info].js
index 17ec5f7..67e38c2 100644
--- a/pages/en/anime/watch/[...info].js
+++ b/pages/en/anime/watch/[...info].js
@@ -1,151 +1,82 @@
-import Image from "next/image";
-import Link from "next/link";
import Head from "next/head";
import { useEffect, useState } from "react";
-import dynamic from "next/dynamic";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../../api/auth/[...nextauth]";
-import Skeleton from "react-loading-skeleton";
-
-import { ChevronDownIcon, ForwardIcon } from "@heroicons/react/24/solid";
-import { useRouter } from "next/router";
-
-import { GET_MEDIA_USER } from "../../../../queries";
-
import dotenv from "dotenv";
import Navigasi from "../../../../components/home/staticNav";
-import DisqusComments from "../../../../components/disqus";
-
-const VideoPlayer = dynamic(() =>
- import("../../../../components/videoPlayer", { ssr: false })
-);
+import PrimarySide from "../../../../components/anime/watch/primarySide";
+import SecondarySide from "../../../../components/anime/watch/secondarySide";
+import { GET_MEDIA_USER } from "../../../../queries";
-export default function Info({ sessions, id, aniId, provider, proxy, api }) {
- const [epiData, setEpiData] = useState(null);
- const [data, setAniData] = useState(null);
- const [skip, setSkip] = useState({ op: null, ed: null });
- const [statusWatch, setStatusWatch] = useState("CURRENT");
+export default function Info({
+ sessions,
+ aniId,
+ watchId,
+ provider,
+ epiNumber,
+ dub,
+ proxy,
+ disqus,
+}) {
+ const [info, setInfo] = useState(null);
+ const [currentEpisode, setCurrentEpisode] = useState(null);
const [loading, setLoading] = useState(false);
- const [showComments, setShowComments] = useState(false);
- const [playing, setPlaying] = useState(null);
- const [playingEpisode, setPlayingEpisode] = useState(null);
- const [playingTitle, setPlayingTitle] = useState(null);
-
- const [poster, setPoster] = useState(null);
const [progress, setProgress] = useState(0);
-
- const [episodes, setEpisodes] = useState([]);
+ const [statuses, setStatuses] = useState("CURRENT");
const [artStorage, setArtStorage] = useState(null);
-
- const [url, setUrl] = useState(null);
-
- const router = useRouter();
-
- // console.log({ playing });
+ const [episodesList, setepisodesList] = useState();
+ const [onList, setOnList] = useState(false);
useEffect(() => {
- const defaultState = {
- epiData: null,
- skip: { op: null, ed: null },
- statusWatch: "CURRENT",
- playingEpisode: null,
- loading: false,
- showComments: false,
- };
-
- // Reset all state variables to their default values
- Object.keys(defaultState).forEach((key) => {
- const value = defaultState[key];
- if (Array.isArray(value)) {
- value.length
- ? eval(
- `set${
- key.charAt(0).toUpperCase() + key.slice(1)
- }(${JSON.stringify(value)})`
- )
- : eval(`set${key.charAt(0).toUpperCase() + key.slice(1)}([])`);
- } else {
- eval(
- `set${key.charAt(0).toUpperCase() + key.slice(1)}(${JSON.stringify(
- value
- )})`
- );
- }
- });
-
- const url = window.location.href;
- setUrl(url);
-
- const fetchData = async () => {
- try {
- if (provider) {
- const res = await fetch(
- `${api}/meta/anilist/watch/${id}?provider=${provider}`
- );
- const epiData = await res.json();
- setEpiData(epiData);
- } else {
- const res = await fetch(`${api}/meta/anilist/watch/${id}`);
- const epiData = await res.json();
- setEpiData(epiData);
- }
- } catch (error) {
- setTimeout(() => {
- window.location.reload();
- }, 3000);
- }
-
- let aniData = null;
- setArtStorage(JSON.parse(localStorage.getItem("artplayer_settings")));
-
- if (provider) {
- const res = await fetch(
- `${api}/meta/anilist/info/${aniId}?provider=${provider}`
- );
- aniData = await res.json();
- setEpisodes(aniData.episodes?.reverse());
- setAniData(aniData);
- } else {
- const res2 = await fetch(`${api}/meta/anilist/info/${aniId}`);
- aniData = await res2.json();
- setEpisodes(aniData.episodes?.reverse());
- setAniData(aniData);
- }
-
- let playingEpisode = aniData.episodes
- .filter((item) => item.id == id)
- .map((item) => item.number);
-
- setPlayingEpisode(playingEpisode);
-
- const playing = aniData.episodes.find((item) => item.id === id);
-
- setPoster(playing?.image);
- setPlaying(playing);
-
- const title = aniData.episodes
- .filter((item) => item.id == id)
- .find((item) => item.title !== null);
- setPlayingTitle(
- title?.title || aniData.title?.romaji || aniData.title?.english
- );
-
- const res4 = await fetch(
- `https://api.aniskip.com/v2/skip-times/${aniData.malId}/${parseInt(
- playingEpisode
- )}?types[]=ed&types[]=mixed-ed&types[]=mixed-op&types[]=op&types[]=recap&episodeLength=`
- );
- const skip = await res4.json();
-
- const op = skip.results?.find((item) => item.skipType === "op") || null;
- const ed = skip.results?.find((item) => item.skipType === "ed") || null;
-
- setSkip({ op, ed });
+ setLoading(true);
+ async function getInfo() {
+ const ress = await fetch(`https://graphql.anilist.co`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ query: `query ($id: Int) {
+ Media (id: $id) {
+ id
+ idMal
+ title {
+ romaji
+ english
+ native
+ }
+ status
+ genres
+ episodes
+ studios {
+ edges {
+ node {
+ id
+ name
+ }
+ }
+ }
+ description
+ coverImage {
+ extraLarge
+ color
+ }
+ synonyms
+
+ }
+ }
+ `,
+ variables: {
+ id: aniId,
+ },
+ }),
+ });
+ const data = await ress.json();
- if (sessions) {
+ if (sessions?.user?.name) {
const response = await fetch("https://graphql.anilist.co/", {
method: "POST",
headers: {
@@ -154,450 +85,121 @@ export default function Info({ sessions, id, aniId, provider, proxy, api }) {
body: JSON.stringify({
query: GET_MEDIA_USER,
variables: {
- username: sessions?.user.name,
+ username: sessions?.user?.name,
},
}),
});
- const dat = await response.json();
-
- const prog = dat.data.MediaListCollection;
+ 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(aniId));
+
+ if (gut) {
+ setProgress(gut.progress);
+ setOnList(true);
+ }
+
+ if (gut?.status === "COMPLETED") {
+ setStatuses("REPEATING");
+ } else if (
+ gut?.status === "REPEATING" &&
+ gut?.media?.episodes === parseInt(epiNumber)
+ ) {
+ setStatuses("COMPLETED");
+ } else if (gut?.status === "REPEATING") {
+ setStatuses("REPEATING");
+ } else if (gut?.media?.episodes === parseInt(epiNumber)) {
+ setStatuses("COMPLETED");
+ } else if (
+ gut?.media?.episodes !== null &&
+ data?.data?.Media.episodes === parseInt(epiNumber)
+ ) {
+ setStatuses("COMPLETED");
+ setLoading(false);
+ }
+ }
+ }
- const gat = prog?.lists.map((item) => item.entries);
- const git = gat?.map((item) =>
- item?.find((item) => item.media.id === parseInt(aniId))
- );
- const gut = git?.find((item) => item?.media.id === parseInt(aniId));
+ setInfo(data.data.Media);
- if (gut) {
- setProgress(gut.progress);
- }
+ const response = await fetch(
+ `/api/consumet/episode/${aniId}${dub ? `?dub=${dub}` : ""}`
+ );
+ const episodes = await response.json();
- if (gut?.status === "COMPLETED") {
- setStatusWatch("REPEATING");
- } else if (
- gut?.status === "REPEATING" &&
- gut?.media?.episodes === parseInt(playingEpisode)
- ) {
- setStatusWatch("COMPLETED");
- } else if (gut?.status === "REPEATING") {
- setStatusWatch("REPEATING");
- } else if (gut?.media?.episodes === parseInt(playingEpisode)) {
- setStatusWatch("COMPLETED");
- } else if (
- gut?.media?.episodes !== null &&
- aniData.totalEpisodes === parseInt(playingEpisode)
- ) {
- setStatusWatch("COMPLETED");
- setLoading(true);
+ if (episodes) {
+ const getProvider = episodes.data?.find(
+ (i) => i.providerId === provider
+ );
+ if (getProvider) {
+ setepisodesList(getProvider.episodes);
+ const currentEpisode = getProvider.episodes?.find(
+ (i) => i.number === parseInt(epiNumber)
+ );
+ const nextEpisode = getProvider.episodes?.find(
+ (i) => i.number === parseInt(epiNumber) + 1
+ );
+ const previousEpisode = getProvider.episodes?.find(
+ (i) => i.number === parseInt(epiNumber) - 1
+ );
+ setCurrentEpisode({
+ prev: previousEpisode,
+ playing: currentEpisode,
+ next: nextEpisode,
+ });
+ } else {
+ setLoading(false);
}
}
- setLoading(true);
- };
- fetchData();
- }, [id, aniId, provider, sessions]);
-
- useEffect(() => {
- const mediaSession = navigator.mediaSession;
- if (!mediaSession) return;
- const artwork = poster
- ? [{ src: poster, sizes: "512x512", type: "image/jpeg" }]
- : undefined;
+ setArtStorage(JSON.parse(localStorage.getItem("artplayer_settings")));
+ // setEpiData(episodes);
+ setLoading(false);
+ }
+ getInfo();
+ }, [sessions?.user?.name, epiNumber, dub]);
- mediaSession.metadata = new MediaMetadata({
- title: playingTitle,
- artist: `Moopa ${
- playingTitle === data?.title?.romaji
- ? "- Episode " + playingEpisode
- : `- ${data?.title?.romaji || data?.title?.english}`
- }`,
- artwork,
- });
- }, [poster, playingTitle, playingEpisode, data]);
+ // console.log(proxy);
return (
<>
<Head>
- <title>{playingTitle || "Loading..."}</title>
+ <title>{info?.title?.romaji || "Retrieving data..."}</title>
</Head>
- <div className="bg-primary">
- <Navigasi />
- <div className="min-h-screen mt-3 md:mt-0 flex flex-col lg:gap-0 gap-5 lg:flex-row lg:py-10 lg:px-10 justify-start w-screen">
- <div className="w-screen lg:w-[67%]">
- {loading ? (
- Array.isArray(epiData?.sources) ? (
- <div className="aspect-video z-20 bg-black">
- <VideoPlayer
- key={id}
- data={epiData}
- id={id}
- progress={parseInt(playingEpisode)}
- session={sessions}
- aniId={parseInt(data?.id)}
- stats={statusWatch}
- op={skip.op}
- ed={skip.ed}
- title={playingTitle}
- poster={poster}
- proxy={proxy}
- provider={provider}
- />
- </div>
- ) : (
- <div className="aspect-video bg-black flex-center select-none">
- <p className="lg:p-0 p-5 text-center">
- Whoops! Something went wrong. Please reload the page or try
- other sources. {`:(`}
- </p>
- </div>
- )
- ) : (
- <div className="aspect-video bg-black" />
- )}
- <div>
- {data && data?.episodes.length > 0 ? (
- data.episodes
- .filter((items) => items.id == id)
- .map((item, index) => (
- <div className="flex justify-between" key={index}>
- <div key={item.id} className="p-3 grid gap-2 w-[60%]">
- <div className="text-xl font-outfit font-semibold line-clamp-1">
- <Link
- href={`/en/anime/${data.id}`}
- className="inline hover:underline"
- >
- {item.title ||
- data.title.romaji ||
- data.title.english}
- </Link>
- </div>
- <h4 className="text-sm font-karla font-light">
- Episode {item.number}
- </h4>
- </div>
- <div className="w-[50%] flex gap-4 items-center justify-end px-4">
- <div className="relative">
- <select
- className="flex items-center gap-5 rounded-[3px] bg-secondary py-1 px-3 pr-8 font-karla appearance-none cursor-pointer"
- value={item.number}
- onChange={(e) => {
- const selectedEpisode = data.episodes.find(
- (episode) =>
- episode.number === parseInt(e.target.value)
- );
- router.push(
- `/en/anime/watch/${selectedEpisode.id}/${data.id}`
- );
- }}
- >
- {data.episodes.map((episode) => (
- <option
- key={episode.number}
- value={episode.number}
- >
- Episode {episode.number}
- </option>
- ))}
- </select>
- <ChevronDownIcon className="absolute right-2 top-1/2 transform -translate-y-1/2 w-5 h-5 pointer-events-none" />
- </div>
- <button
- className={`${
- item.number === data.episodes.length
- ? "pointer-events-none"
- : ""
- } relative group`}
- onClick={() => {
- const currentEpisodeIndex = data.episodes.findIndex(
- (episode) => episode.number === item.number
- );
- if (
- currentEpisodeIndex !== -1 &&
- currentEpisodeIndex < data.episodes.length - 1
- ) {
- const nextEpisode =
- data.episodes[currentEpisodeIndex + 1];
- router.push(
- `/en/anime/watch/${nextEpisode.id}/${data.id}`
- );
- }
- }}
- >
- <span className="absolute z-[9999] -left-11 -top-14 p-2 shadow-xl rounded-md transform transition-all whitespace-nowrap bg-secondary lg:group-hover:block group-hover:opacity-1 hidden font-karla font-bold">
- Next Episode
- </span>
- <ForwardIcon className="w-6 h-6" />
- </button>
- </div>
- </div>
- ))
- ) : (
- <div className="p-3 grid gap-2">
- <div className="text-xl font-outfit font-semibold line-clamp-2">
- <div className="inline hover:underline">
- <Skeleton width={240} />
- </div>
- </div>
- <h4 className="text-sm font-karla font-light">
- <Skeleton width={75} />
- </h4>
- </div>
- )}
- <div className="h-[1px] bg-[#3b3b3b]" />
-
- <div className="px-4 pt-7 pb-4 h-full flex">
- <div className="aspect-[9/13] h-[240px]">
- {data ? (
- <Image
- src={data.image}
- alt="Anime Cover"
- width={1000}
- height={1000}
- priority
- className="object-cover aspect-[9/13] h-[240px] rounded-md"
- />
- ) : (
- <Skeleton height={240} />
- )}
- </div>
- <div className="grid w-full px-5 gap-3 h-[240px]">
- <div className="grid grid-cols-2 gap-1 items-center">
- <h2 className="text-sm font-light font-roboto text-[#878787]">
- Studios
- </h2>
- <div className="row-start-2">
- {data ? data.studios : <Skeleton width={80} />}
- </div>
- <div className="hidden xxs:grid col-start-2 place-content-end relative">
- <div>
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- strokeWidth={1.5}
- stroke="currentColor"
- className="w-8 h-8 hover:fill-white hover:cursor-pointer"
- >
- <path
- strokeLinecap="round"
- strokeLinejoin="round"
- d="M17.593 3.322c1.1.128 1.907 1.077 1.907 2.185V21L12 17.25 4.5 21V5.507c0-1.108.806-2.057 1.907-2.185a48.507 48.507 0 0111.186 0z"
- />
- </svg>
- </div>
- </div>
- </div>
- <div className="grid gap-1 items-center">
- <h2 className="text-sm font-light font-roboto text-[#878787]">
- Status
- </h2>
- <div>{data ? data.status : <Skeleton width={75} />}</div>
- </div>
- <div className="grid gap-1 items-center overflow-y-hidden">
- <h2 className="text-sm font-light font-roboto text-[#878787]">
- Titles
- </h2>
- <div className="grid grid-flow-dense grid-cols-2 gap-2 h-full w-full">
- {data ? (
- <>
- <div className="line-clamp-3">
- {data.title.romaji || ""}
- </div>
- <div className="line-clamp-3">
- {data.title.english || ""}
- </div>
- <div className="line-clamp-3">
- {data.title.native || ""}
- </div>
- </>
- ) : (
- <Skeleton width={200} height={50} />
- )}
- </div>
- </div>
- </div>
- </div>
- <div className="flex flex-wrap gap-3 px-4 pt-3">
- {data &&
- data.genres.map((item, index) => (
- <div
- key={index}
- className="border border-action text-gray-100 py-1 px-2 rounded-md font-karla text-sm"
- >
- {item}
- </div>
- ))}
- </div>
- <div className={`bg-secondary rounded-md mt-3 mx-3`}>
- {data && (
- <p
- dangerouslySetInnerHTML={{ __html: data.description }}
- className={`p-5 text-sm font-light font-roboto text-[#e4e4e4] `}
- />
- )}
- </div>
- {!showComments && loading && (
- <div className="w-full flex justify-center py-5 font-karla px-3 lg:px-0">
- <button
- onClick={() => setShowComments(true)}
- className={
- showComments
- ? "hidden"
- : "flex-center gap-2 h-10 bg-secondary rounded w-full lg:w-[50%]"
- }
- >
- Load Disqus{" "}
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- strokeWidth="1.5"
- stroke="currentColor"
- className="w-5 h-5"
- >
- <path
- strokeLinecap="round"
- strokeLinejoin="round"
- d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155"
- />
- </svg>
- </button>
- </div>
- )}
- {showComments && (
- <div>
- {data && url && playing && (
- <div className="mt-5 px-5">
- <DisqusComments
- key={id}
- post={{
- id: id,
- title: data.title.romaji,
- url: url,
- episode: playing.number,
- }}
- />
- </div>
- )}
- </div>
- )}
- </div>
- </div>
- <div className="flex flex-col w-screen lg:w-[35%] ">
- <h1 className="text-xl font-karla pl-4 pb-5 font-semibold">
- Up Next
- </h1>
- <div className="flex flex-col gap-5 lg:pl-5 px-2 py-2 scrollbar-thin scrollbar-thumb-[#313131] scrollbar-thumb-rounded-full">
- {data && data?.episodes.length > 0 ? (
- data.episodes.some((item) => item.title && item.description) ? (
- episodes.map((item) => {
- const time = artStorage?.[item.id]?.time;
- const duration = artStorage?.[item.id]?.duration;
- let prog = (time / duration) * 100;
- if (prog > 90) prog = 100;
- return (
- <Link
- href={`/en/anime/watch/${item.id}/${data.id}${
- provider ? `/${provider}` : ""
- }`}
- key={item.id}
- className={`bg-secondary flex w-full h-[110px] rounded-lg scale-100 transition-all duration-300 ease-out ${
- item.id == id
- ? "pointer-events-none ring-1 ring-action"
- : "cursor-pointer hover:scale-[1.02] ring-0 hover:ring-1 hover:shadow-lg ring-white"
- }`}
- >
- <div className="w-[43%] lg:w-[40%] h-[110px] relative rounded-lg z-40 shrink-0 overflow-hidden shadow-[4px_0px_5px_0px_rgba(0,0,0,0.3)]">
- <div className="relative">
- <Image
- src={item.image}
- alt="Anime Cover"
- width={1000}
- height={1000}
- className={`object-cover z-30 rounded-lg h-[110px] ${
- item.id == id
- ? "brightness-[30%]"
- : "brightness-75"
- }`}
- />
- <span
- className={`absolute bottom-0 left-0 h-[3px] bg-red-700`}
- style={{
- width:
- progress &&
- artStorage &&
- item?.number <= progress
- ? "100%"
- : artStorage?.[item?.id]
- ? `${prog}%`
- : "0",
- }}
- />
- <span className="absolute bottom-2 left-2 font-karla font-bold text-sm">
- Episode {item.number}
- </span>
- {item.id == id && (
- <div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 scale-[1.5]">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 20 20"
- fill="currentColor"
- className="w-5 h-5"
- >
- <path d="M6.3 2.841A1.5 1.5 0 004 4.11V15.89a1.5 1.5 0 002.3 1.269l9.344-5.89a1.5 1.5 0 000-2.538L6.3 2.84z" />
- </svg>
- </div>
- )}
- </div>
- </div>
- <div
- className={`w-[70%] h-full select-none p-4 flex flex-col gap-2 ${
- item.id == id ? "text-[#7a7a7a]" : ""
- }`}
- >
- <h1 className="font-karla font-bold italic line-clamp-1">
- {item.title}
- </h1>
- <p className="line-clamp-2 text-xs italic font-outfit font-extralight">
- {item.description}
- </p>
- </div>
- </Link>
- );
- })
- ) : (
- data.episodes.map((item) => {
- return (
- <Link
- href={`/en/anime/watch/${item.id}/${data.id}${
- provider ? "/9anime" : ""
- }`}
- key={item.id}
- className={`bg-secondary flex-center w-full h-[50px] rounded-lg scale-100 transition-all duration-300 ease-out ${
- item.id == id
- ? "pointer-events-none ring-1 ring-action text-[#5d5d5d]"
- : "cursor-pointer hover:scale-[1.02] ring-0 hover:ring-1 hover:shadow-lg ring-white"
- }`}
- >
- Episode {item.number}
- </Link>
- );
- })
- )
- ) : (
- <>
- {[1].map((item) => (
- <Skeleton
- key={item}
- className="bg-secondary flex w-full h-[110px] rounded-lg scale-100 transition-all duration-300 ease-out"
- />
- ))}
- </>
- )}
- </div>
- </div>
+ <Navigasi />
+ <div className="w-screen flex justify-center my-3 lg:my-10">
+ <div className="lg:w-[95%] flex flex-col lg:flex-row gap-5 lg:gap-0 justify-between">
+ <PrimarySide
+ info={info}
+ navigation={currentEpisode}
+ episodeList={episodesList}
+ session={sessions}
+ epiNumber={epiNumber}
+ providerId={provider}
+ watchId={watchId}
+ status={statuses}
+ onList={onList}
+ proxy={proxy}
+ disqus={disqus}
+ setOnList={setOnList}
+ setLoading={setLoading}
+ loading={loading}
+ />
+ <SecondarySide
+ info={info}
+ providerId={provider}
+ watchId={watchId}
+ episode={episodesList}
+ progress={progress}
+ artStorage={artStorage}
+ dub={dub}
+ />
</div>
</div>
</>
@@ -607,31 +209,34 @@ export default function Info({ sessions, id, aniId, provider, proxy, api }) {
export async function getServerSideProps(context) {
dotenv.config();
- const API_URI = process.env.API_URI;
-
const session = await getServerSession(context.req, context.res, authOptions);
- const proxy = process.env.PROXY_URI;
-
- const { info } = context.query;
- if (!info) {
+ const query = context.query;
+ if (!query) {
return {
notFound: true,
};
}
- const id = info[0];
- const aniId = info[1];
- const provider = info[2] || null;
+ const proxy = process.env.PROXY_URI;
+ const disqus = process.env.DISQUS_SHORTNAME;
+
+ const aniId = query.info[0];
+ const provider = query.info[1];
+ const watchId = query.id;
+ const epiNumber = query.num;
+ const dub = query.dub;
return {
props: {
sessions: session,
- id,
- aniId,
- provider,
+ aniId: aniId || null,
+ provider: provider || null,
+ watchId: watchId || null,
+ epiNumber: epiNumber || null,
+ dub: dub || null,
proxy,
- api: API_URI,
+ disqus,
},
};
}
diff --git a/pages/en/index.js b/pages/en/index.js
index cbf96cd..35de96d 100644
--- a/pages/en/index.js
+++ b/pages/en/index.js
@@ -16,10 +16,11 @@ import SearchBar from "../../components/searchBar";
import Genres from "../../components/home/genres";
import Schedule from "../../components/home/schedule";
import getUpcomingAnime from "../../lib/anilist/getUpcomingAnime";
-import { useCountdown } from "../../lib/useCountdownSeconds";
+import { useCountdown } from "../../utils/useCountdownSeconds";
import Navigasi from "../../components/home/staticNav";
import MobileNav from "../../components/home/mobileNav";
+import axios from "axios";
// Filter schedules for each day
// const filterByCountryOfOrigin = (schedule, country) => {
@@ -58,8 +59,7 @@ export default function Home({ detail, populars, sessions, upComing }) {
useEffect(() => {
const getSchedule = async () => {
- const res = await fetch(`https://ruka.moopa.live/api/schedules`);
- const data = await res.json();
+ const { data } = await axios.get(`/api/anify/schedule`);
setSchedules(data);
};
getSchedule();
@@ -132,7 +132,6 @@ export default function Home({ detail, populars, sessions, upComing }) {
}
userData();
}, [sessions, current, plan]);
-
return (
<>
<Head>
diff --git a/pages/en/test.js b/pages/en/test.js
new file mode 100644
index 0000000..cf76827
--- /dev/null
+++ b/pages/en/test.js
@@ -0,0 +1,11 @@
+import VideoPlayer from "../../components/videoPlayer";
+
+export default function Test() {
+ return (
+ <div className="flex-center w-screen h-screen">
+ <div className="h-full aspect-video bg-black">
+ <VideoPlayer />
+ </div>
+ </div>
+ );
+}