aboutsummaryrefslogtreecommitdiff
path: root/pages
diff options
context:
space:
mode:
authorFactiven <[email protected]>2023-05-25 22:56:21 +0700
committerGitHub <[email protected]>2023-05-25 22:56:21 +0700
commit8dcb5cb96819547e574d4ca619c54c6f902b8860 (patch)
tree492e9147c106d7ddb7706c7ba2127f6d04ac49ce /pages
parentUpdate videoPlayer.js (diff)
downloadmoopa-8dcb5cb96819547e574d4ca619c54c6f902b8860.tar.xz
moopa-8dcb5cb96819547e574d4ca619c54c6f902b8860.zip
Update v3.6.1
> Added Thumbnail to info page > Temporarily removed Manga from website until the page is finished
Diffstat (limited to 'pages')
-rw-r--r--pages/anime/[...id].js604
-rw-r--r--pages/anime/watch/[...info].js355
-rw-r--r--pages/manga/chapter/[chapter].js460
-rw-r--r--pages/manga/detail/id.js267
4 files changed, 531 insertions, 1155 deletions
diff --git a/pages/anime/[...id].js b/pages/anime/[...id].js
index 867e429..200a7f4 100644
--- a/pages/anime/[...id].js
+++ b/pages/anime/[...id].js
@@ -21,124 +21,11 @@ import { signIn, useSession } from "next-auth/react";
import AniList from "../../components/media/aniList";
import ListEditor from "../../components/listEditor";
-const query = `
- query ($username: String, $status: MediaListStatus) {
- MediaListCollection(userName: $username, type: ANIME, status: $status, sort: SCORE_DESC) {
- user {
- id
- name
- about (asHtml: true)
- createdAt
- avatar {
- large
- }
- statistics {
- anime {
- count
- episodesWatched
- meanScore
- minutesWatched
- }
- }
- bannerImage
- mediaListOptions {
- animeList {
- sectionOrder
- }
- }
- }
- lists {
- status
- name
- entries {
- id
- mediaId
- status
- progress
- score
- media {
- id
- status
- title {
- english
- romaji
- }
- episodes
- coverImage {
- large
- }
- }
- }
- }
- }
- }
- `;
-
-const infoQuery = `query ($id: Int) {
- Media(id: $id) {
- id
- type
- title {
- romaji
- english
- native
- }
- coverImage {
- extraLarge
- large
- color
- }
- bannerImage
- description
- episodes
- nextAiringEpisode {
- episode
- airingAt
- }
- averageScore
- popularity
- status
- startDate {
- year
- }
- duration
- genres
- relations {
- edges {
- relationType
- node {
- id
- type
- status
- title {
- romaji
- english
- userPreferred
- }
- coverImage {
- extraLarge
- large
- color
- }
- }
- }
- }
- recommendations {
- nodes {
- mediaRecommendation {
- id
- title {
- romaji
- }
- coverImage {
- extraLarge
- large
- }
- }
- }
- }
- }
-}`;
+import { GET_MEDIA_USER } from "../../queries";
+import { GET_MEDIA_INFO } from "../../queries";
+
+// import { aniInfo } from "../../components/devComp/data";
+// console.log(GET_MEDIA_USER);
export default function Info({ info, color }) {
const { data: session } = useSession();
@@ -147,99 +34,119 @@ export default function Info({ info, color }) {
const [progress, setProgress] = useState(0);
const [statuses, setStatuses] = useState(null);
const [domainUrl, setDomainUrl] = useState("");
-
const [showAll, setShowAll] = useState(false);
const [open, setOpen] = useState(false);
-
const [time, setTime] = useState(0);
const { id } = useRouter().query;
- const rec = info?.recommendations?.nodes.map(
+ const [epiView, setEpiView] = useState("3");
+
+ const [artStorage, setArtStorage] = useState(null);
+
+ const rec = info?.recommendations?.nodes?.map(
(data) => data.mediaRecommendation
);
useEffect(() => {
- const { protocol, host } = window.location;
- const url = `${protocol}//${host}`;
- setDomainUrl(url);
-
+ handleClose();
async function fetchData() {
setLoading(true);
if (id) {
try {
- setEpisode(null)
- const res = await fetch(`https://api.moopa.my.id/meta/anilist/info/${info.id}`)
- const data = await res.json();
+ const { protocol, host } = window.location;
+ const url = `${protocol}//${host}`;
- if (res.status === 500) {
- setEpisode([]);
- } else if (res.status === 404) {
- window.location.href("/404");
- } else if (!data || data?.episodes?.length === 0) {
+ const view = localStorage.getItem("epiView");
+
+ setDomainUrl(url);
+
+ setArtStorage(JSON.parse(localStorage.getItem("artplayer_settings")));
+
+ setEpisode(null);
+ 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 {
- setEpisode(data.episodes?.reverse());
- }
+ const data = await res.json();
+ // 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");
+ }
+ 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: query,
- variables: {
- username: session?.user?.name,
+ if (session?.user?.name) {
+ const response = await fetch("https://graphql.anilist.co/", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
},
- }),
- });
-
- const dat = await response.json();
-
- const prog = dat.data.MediaListCollection;
-
- const gat = prog.lists.map((item) => item.entries);
- const git = gat.map((item) =>
- item.find((item) => item.mediaId === parseInt(id[0]))
- );
- const gut = git?.find((item) => item?.mediaId === parseInt(id[0]));
-
- if (gut) {
- setProgress(gut?.progress);
- if (gut.status === "CURRENT") {
- setStatuses({ name: "Watching", value: "CURRENT" });
- } else if (gut.status === "PLANNING") {
- setStatuses({ name: "Plan to watch", value: "PLANNING" });
- } else if (gut.status === "COMPLETED") {
- setStatuses({ name: "Completed", value: "COMPLETED" });
- } else if (gut.status === "DROPPED") {
- setStatuses({ name: "Dropped", value: "DROPPED" });
- } else if (gut.status === "PAUSED") {
- setStatuses({ name: "Paused", value: "PAUSED" });
- } else if (gut.status === "REPEATING") {
- setStatuses({ name: "Rewatching", value: "REPEATING" });
+ 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)
+ );
+ }
}
-
- setLoading(false);
} catch (error) {
- console.log(error);
+ console.error(error);
setTimeout(() => {
window.location.reload();
}, 1000);
+ } finally {
+ setLoading(false);
}
}
}
fetchData();
- }, [id, session?.user?.name, info]);
+ }, [id, info, session?.user?.name]);
+
+ // console.log();
function handleOpen() {
setOpen(true);
@@ -601,71 +508,294 @@ export default function Info({ info, color }) {
)}
</div>
</div>
- <div className="z-20 flex flex-col gap-10 p-3 lg:p-0">
- <div className="flex items-center lg:gap-10 gap-7">
- {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-5 rounded-sm font-karla font-bold bg-white text-black"
- >
- {time}
+ <div className="flex flex-col gap-5 lg:gap-10 p-3 lg:p-0">
+ <div className="flex sm:flex-row flex-col gap-5 md:gap-0 justify-between ">
+ <div className="flex items-center lg:gap-10 gap-7">
+ {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 className="h-6 w-6">
- <ClockIcon />
- </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>
{!loading ? (
episode && (
- <div className="flex h-[640px] flex-col gap-5 scrollbar-thin scrollbar-thumb-[#1b1c21] scrollbar-thumb-rounded-full overflow-y-scroll hover:scrollbar-thumb-[#2e2f37]">
- {
- episode?.length !== 0 && episode ? (
- episode?.map((epi, index) => {
- return (
- <div
- key={index}
- className="flex flex-col gap-3 px-2"
- >
+ <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-auto-fit gap-5 lg:gap-8"
+ : "flex flex-col gap-5"
+ } pb-5 ${
+ epiView === "3" ? "" : "place-items-center"
+ }`}
+ >
+ {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 (
+ <Link
+ key={index}
+ href={`/anime/watch/${epi.id}/${info.id}`}
+ 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?.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={`/anime/watch/${epi.id}/${info.id}`}
- className={`text-start text-sm lg:text-lg ${
- progress && epi.number <= progress
- ? "text-[#5f5f5f]"
- : "text-white"
- }`}
+ 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"
>
- <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>
- )}
+ <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>
+
+ <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>
- {index !== episode?.length - 1 && (
- <span className="h-[1px] bg-white" />
- )}
- </div>
- );
- })
- ) : (
- <p>No Episodes Available</p>
- )
- }
+ );
+ })}
+ {epiView === "3" &&
+ episode?.map((epi, index) => {
+ return (
+ <div
+ key={index}
+ className="flex flex-col gap-3 px-2"
+ >
+ <Link
+ href={`/anime/watch/${epi.id}/${info.id}`}
+ 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>
)
) : (
@@ -705,7 +835,7 @@ export async function getServerSideProps(context) {
"Content-Type": "application/json",
},
body: JSON.stringify({
- query: infoQuery,
+ query: GET_MEDIA_INFO,
variables: {
id: id?.[0],
},
diff --git a/pages/anime/watch/[...info].js b/pages/anime/watch/[...info].js
index 1350ce8..b3d02cf 100644
--- a/pages/anime/watch/[...info].js
+++ b/pages/anime/watch/[...info].js
@@ -14,7 +14,10 @@ import { Navigasi } from "../..";
import { ChevronDownIcon, ForwardIcon } from "@heroicons/react/24/solid";
import { useRouter } from "next/router";
+import { GET_MEDIA_USER } from "../../../queries";
+
import dotenv from "dotenv";
+import Footer from "../../../components/footer";
const VideoPlayer = dynamic(() =>
import("../../../components/videoPlayer", { ssr: false })
@@ -29,8 +32,10 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
const [loading, setLoading] = useState(false);
const [playingTitle, setPlayingTitle] = useState(null);
const [poster, setPoster] = useState(null);
+ const [progress, setProgress] = useState(0);
const [episodes, setEpisodes] = useState([]);
+ const [artStorage, setArtStorage] = useState(null);
const router = useRouter();
@@ -64,7 +69,6 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
});
const fetchData = async () => {
-
try {
if (provider) {
const res = await fetch(
@@ -86,6 +90,7 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
}
let aniData = null;
+ setArtStorage(JSON.parse(localStorage.getItem("artplayer_settings")));
if (provider) {
const res = await fetch(
@@ -138,58 +143,7 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
"Content-Type": "application/json",
},
body: JSON.stringify({
- query: `
- query ($username: String, $status: MediaListStatus) {
- MediaListCollection(userName: $username, type: ANIME, status: $status, sort: SCORE_DESC) {
- user {
- id
- name
- about (asHtml: true)
- createdAt
- avatar {
- large
- }
- statistics {
- anime {
- count
- episodesWatched
- meanScore
- minutesWatched
- }
- }
- bannerImage
- mediaListOptions {
- animeList {
- sectionOrder
- }
- }
- }
- lists {
- status
- name
- entries {
- id
- mediaId
- status
- progress
- score
- media {
- id
- status
- title {
- english
- romaji
- }
- episodes
- coverImage {
- large
- }
- }
- }
- }
- }
- }
- `,
+ query: GET_MEDIA_USER,
variables: {
username: sessions?.user.name,
},
@@ -206,6 +160,10 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
);
const gut = git?.find((item) => item?.media.id === parseInt(aniId));
+ if (gut) {
+ setProgress(gut.progress);
+ }
+
if (gut?.status === "COMPLETED") {
setStatusWatch("REPEATING");
} else if (
@@ -282,85 +240,83 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
<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={`/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>
+ {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={`/anime/${data.id}`}
+ className="inline hover:underline"
+ >
+ {item.title ||
+ data.title.romaji ||
+ data.title.english}
+ </Link>
</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(
- `/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(
- `/anime/watch/${nextEpisode.id}/${data.id}`
- );
- }
+ <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(
+ `/anime/watch/${selectedEpisode.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>
+ {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(
+ `/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">
@@ -473,38 +429,53 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
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) => {
- return (
- <Link
- href={`/anime/watch/${item.id}/${data.id}${
- provider ? "/9anime" : ""
- }`}
- 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-[40%] h-[110px] relative ">
- <div className="">
- <Image
- src={item.image}
- alt="Anime Cover"
- width={1000}
- height={1000}
- className={`object-cover rounded-lg w-[240px] h-[110px] shadow-[4px_0px_5px_0px_rgba(0,0,0,0.3)] ${
- item.id == id
- ? "brightness-[30%]"
- : "brightness-75"
- }`}
- />
- </div>
+ {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={`/anime/watch/${item.id}/${data.id}${
+ provider ? "/9anime" : ""
+ }`}
+ 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-light text-sm">
Episode {item.number}
</span>
@@ -521,40 +492,41 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
</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={`/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"
+ </div>
+ <div
+ className={`w-[70%] h-full select-none p-4 flex flex-col gap-2 ${
+ item.id == id ? "text-[#7a7a7a]" : ""
}`}
>
- Episode {item.number}
- </Link>
- );
- })
- )
+ <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={`/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) => (
@@ -568,6 +540,7 @@ export default function Info({ sessions, id, aniId, provider, proxy }) {
</div>
</div>
</div>
+ <Footer />
</div>
</SkeletonTheme>
</>
diff --git a/pages/manga/chapter/[chapter].js b/pages/manga/chapter/[chapter].js
deleted file mode 100644
index 14f04ca..0000000
--- a/pages/manga/chapter/[chapter].js
+++ /dev/null
@@ -1,460 +0,0 @@
-import axios from "axios";
-import Head from "next/head";
-import { useEffect, useState } from "react";
-import Navbar from "../../../components/navbar";
-import Footer from "../../../components/footer";
-import ScrollTracker from "../../../components/scrollTracker";
-
-export default function Test({ title, id, aniId, data, provider }) {
- const [isLoading, setIsLoading] = useState(true);
- const [datas, setData] = useState(data);
- const [currentChapter, setCurrentChapter] = useState(null);
- const [nextChapter, setNextChapter] = useState(null);
- const [prevChapter, setPrevChapter] = useState(null);
-
- useEffect(() => {
- function storedData() {
- const nowChap = localStorage.getItem("currentChapterId");
- const chapt = localStorage.getItem("chapters");
- const chapters = JSON.parse(chapt);
- const currentChapter = chapters.find((chapter) => chapter.id === nowChap);
- const currentIndex = chapters.findIndex(
- (chapter) => chapter.id === nowChap
- );
-
- const nextIndex = currentIndex + 1;
-
- const nextChapter = chapters[nextIndex];
- const prevIndex = currentIndex - 1;
-
- setNextChapter(nextChapter);
- setCurrentChapter(currentChapter);
- setPrevChapter(chapters[prevIndex]);
- setIsLoading(false);
- }
- storedData();
- }, []);
-
- function getNextChapter() {
- window.scrollTo(0, 0);
- setIsLoading(true);
- const currentId = localStorage.getItem("currentChapterId");
- const scrollData = JSON.parse(localStorage.getItem("watchedManga")) || [];
- const scroll = localStorage.getItem("scrollPercentage");
- if (scroll >= 5) {
- const existingDataIndex = scrollData.findIndex(
- (data) => data.id === currentId
- );
- if (existingDataIndex !== -1) {
- // Update existing data
- scrollData[existingDataIndex].timestamp = Date.now();
- scrollData[existingDataIndex].percentage = parseFloat(
- localStorage.getItem("scrollPercentage")
- );
- } else {
- // Add new data
- scrollData.push({
- timestamp: Date.now(),
- percentage: parseFloat(localStorage.getItem("scrollPercentage")),
- id: currentId,
- });
- }
-
- localStorage.setItem("watchedManga", JSON.stringify(scrollData));
-
- const chapt = localStorage.getItem("chapters");
- const chapters = JSON.parse(chapt);
-
- const currentIndex = chapters.findIndex(
- (chapter) => chapter.id === currentId
- );
-
- const nextIndex = currentIndex + 1;
-
- const nextChapter = chapters[nextIndex];
- const nexttChapter = chapters[nextIndex + 1];
- const prevChapter = chapters[nextIndex - 1];
-
- setNextChapter(nexttChapter);
- setCurrentChapter(nextChapter);
- setPrevChapter(prevChapter);
-
- if (!nextChapter) {
- return;
- }
-
- fetch(
- `https://api.moopa.my.id/meta/anilist-manga/read?chapterId=${nextChapter.id}&provider=${provider}`
- )
- .then((response) => response.json())
- .then((data) => {
- if (provider === "mangakakalot") {
- const datas = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${item.img}&referer={Referer:'https://mangakakalot.com/'}`,
- page: item.page,
- title: item.title,
- }));
- // console.log(datas);
- setData(datas);
- } else {
- const dat = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${encodeURIComponent(
- item.img
- )}&referer=${encodeURIComponent(item.headerForImage.Referer)}`,
- page: item.page,
- title: item.title || null,
- }));
- setData(dat);
- }
- })
- .finally(() => {
- setIsLoading(false);
- });
-
- // Update the current chapter id in local storage
- localStorage.setItem("currentChapterId", nextChapter.id);
- }
-
- const chapt = localStorage.getItem("chapters");
- const chapters = JSON.parse(chapt);
-
- const currentIndex = chapters.findIndex(
- (chapter) => chapter.id === currentId
- );
-
- const nextIndex = currentIndex + 1;
-
- const nextChapter = chapters[nextIndex];
- const nexttChapter = chapters[nextIndex + 1];
- const prevChapter = chapters[nextIndex - 1];
-
- setNextChapter(nexttChapter);
- setCurrentChapter(nextChapter);
- setPrevChapter(prevChapter);
-
- if (!nextChapter) {
- return;
- }
-
- fetch(
- `https://api.moopa.my.id/meta/anilist-manga/read?chapterId=${nextChapter.id}&provider=${provider}`
- )
- .then((response) => response.json())
- .then((data) => {
- if (provider === "mangakakalot") {
- const datas = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${item.img}&referer={Referer:'https://mangakakalot.com/'}`,
- page: item.page,
- title: item.title,
- }));
- // console.log(datas);
- setData(datas);
- } else {
- const dat = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${encodeURIComponent(
- item.img
- )}&referer=${encodeURIComponent(item.headerForImage.Referer)}`,
- page: item.page,
- title: item.title || null,
- }));
- setData(dat);
- }
- })
- .finally(() => {
- setIsLoading(false);
- });
-
- // Update the current chapter id in local storage
- localStorage.setItem("currentChapterId", nextChapter.id);
- }
- // console.log(data);
-
- function getPrevChapter() {
- // Get the current id
- window.scrollTo(0, 0);
- setIsLoading(true);
-
- const currentId = localStorage.getItem("currentChapterId");
- const scrollData = JSON.parse(localStorage.getItem("watchedManga")) || [];
- const scroll = localStorage.getItem("scrollPercentage");
- if (scroll >= 5) {
- const existingDataIndex = scrollData.findIndex(
- (data) => data.id === currentId
- );
- if (existingDataIndex !== -1) {
- // Update existing data
- scrollData[existingDataIndex].timestamp = Date.now();
- scrollData[existingDataIndex].percentage = parseFloat(
- localStorage.getItem("scrollPercentage")
- );
- } else {
- // Add new data
- scrollData.push({
- timestamp: Date.now(),
- percentage: parseFloat(localStorage.getItem("scrollPercentage")),
- id: currentId,
- });
- }
-
- localStorage.setItem("watchedManga", JSON.stringify(scrollData));
-
- const chapt = localStorage.getItem("chapters");
- const chapters = JSON.parse(chapt);
-
- const currentIndex = chapters.findIndex(
- (chapter) => chapter.id === currentId
- );
-
- const nextIndex = currentIndex + 1;
-
- const nextChapter = chapters[nextIndex];
- const nexttChapter = chapters[nextIndex + 1];
- const prevChapter = chapters[nextIndex - 1];
-
- setNextChapter(nexttChapter);
- setCurrentChapter(nextChapter);
- setPrevChapter(prevChapter);
-
- if (!nextChapter) {
- return;
- }
-
- fetch(
- `https://api.moopa.my.id/meta/anilist-manga/read?chapterId=${nextChapter.id}&provider=${provider}`
- )
- .then((response) => response.json())
- .then((data) => {
- if (provider === "mangakakalot") {
- const datas = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${item.img}&referer={Referer:'https://mangakakalot.com/'}`,
- page: item.page,
- title: item.title,
- }));
- // console.log(datas);
- setData(datas);
- } else {
- const dat = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${encodeURIComponent(
- item.img
- )}&referer=${encodeURIComponent(item.headerForImage.Referer)}`,
- page: item.page,
- title: item.title || null,
- }));
- setData(dat);
- }
- })
- .finally(() => {
- setIsLoading(false);
- });
-
- // Update the current chapter id in local storage
- localStorage.setItem("currentChapterId", nextChapter.id);
- }
-
- const chapt = localStorage.getItem("chapters");
- const chapters = JSON.parse(chapt);
-
- const currentIndex = chapters.findIndex(
- (chapter) => chapter.id === currentId
- );
-
- const prevIndex = currentIndex - 1;
-
- const prevChapter = chapters[prevIndex];
- const nextChapter = chapters[prevIndex + 1];
- const prevvChapter = chapters[prevIndex - 1];
- setCurrentChapter(prevChapter);
- setNextChapter(nextChapter);
- setPrevChapter(prevvChapter);
-
- fetch(
- `https://api.moopa.my.id/meta/anilist-manga/read?chapterId=${prevChapter.id}&provider=${provider}`
- )
- .then((response) => response.json())
- .then((data) => {
- // console.log(data);
- if (provider === "mangakakalot") {
- const datas = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${item.img}&referer={Referer:'https://mangakakalot.com/'}`,
- page: item.page,
- title: item.title,
- }));
- // console.log(datas);
- setData(datas);
- } else {
- const dat = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${encodeURIComponent(
- item.img
- )}&referer=${encodeURIComponent(item.headerForImage.Referer)}`,
- page: item.page,
- title: item.title || null,
- }));
- setData(dat);
- }
- })
- .finally(() => {
- setIsLoading(false);
- });
-
- // Update the current chapter id in local storage
- localStorage.setItem("currentChapterId", prevChapter.id);
- }
- // console.log({ PREV_CHAPTER: prevChapter });
- // console.log({ CURRENT_CHAPTER: currentChapter });
- // console.log({ NEXT_CHAPTER: nextChapter });
-
- return (
- <>
- <Head>
- <title>{title}</title>
- <meta name="info" content="More detailed info about the Manga" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <link rel="icon" href="/c.svg" />
- </Head>
- <Navbar />
- <ScrollTracker data={currentChapter} id={aniId} />
-
- <div className="flex h-full min-h-screen w-screen flex-col items-center text-white">
- <div className="lg:pt-nav pt-5 text-3xl font-semibold">
- {isLoading ? (
- <div />
- ) : currentChapter && currentChapter.chapter ? (
- <p>Chapter {currentChapter.chapter}</p>
- ) : (
- <p>{currentChapter.title}</p>
- )}
- </div>
-
- {isLoading ? (
- <p className="pt-nav">Loading...</p>
- ) : (
- <div className="pointer-events-none z-10 flex min-h-screen w-screen flex-col items-center pt-nav">
- {datas.length > 0 &&
- datas.map((item, index) => (
- <img
- draggable={false}
- key={index}
- src={item.img}
- alt={`Page ${item.page}`}
- />
- ))}
- </div>
- )}
- {isLoading ? (
- <div />
- ) : (
- <>
- <div className="sticky bottom-9 z-40 my-5 mr-[20rem] flex gap-6 lg:mr-0 lg:gap-10">
- <div
- className={`cursor-pointer rounded-md bg-[#121212] p-2 text-center text-xl hover:bg-[#2d303a] ${
- prevChapter ? `` : `pointer-events-none`
- }`}
- onClick={getPrevChapter}
- >
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- strokeWidth="1.5"
- stroke={`${prevChapter ? `currentColor` : `#919191`}`}
- className="h-6 w-6"
- >
- <path
- strokeLinecap="round"
- strokeLinejoin="round"
- d="M15.75 19.5L8.25 12l7.5-7.5"
- />
- </svg>
- </div>
- <div
- className={`cursor-pointer ${
- nextChapter ? `` : `pointer-events-none`
- } rounded-md bg-[#121212] p-2 text-center text-xl hover:bg-[#2d303a]`}
- onClick={getNextChapter}
- >
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 24 24"
- fill="none"
- strokeWidth="1.5"
- stroke={`${nextChapter ? `currentColor` : `#919191`}`}
- className={`h-6 w-6`}
- >
- <path
- strokeLinecap="round"
- strokeLinejoin="round"
- d="M8.25 4.5l7.5 7.5-7.5 7.5"
- />
- </svg>
- </div>
- </div>
-
- <div className="z-30 w-screen bg-[#1e2023] px-5 py-[3px] text-xl lg:w-[30%] lg:bg-transparent lg:text-center">
- {nextChapter ? (
- nextChapter.chapter ? (
- <p>Next Chapter {nextChapter.chapter}</p>
- ) : (
- <p>Next Chapter {nextChapter.title}</p>
- )
- ) : (
- <p>End of Chapter</p>
- )}
- </div>
- </>
- )}
- </div>
- <Footer />
- </>
- );
-}
-
-export async function getServerSideProps(context) {
- const { id, title, provider, aniId } = context.query;
- const urls = [
- `https://api.moopa.my.id/meta/anilist-manga/read?chapterId=${id}&provider=${provider}`,
- ];
- const results = await axios.get(urls);
-
- if (provider === "mangakakalot") {
- const data = results.data;
- const datas = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${item.img}&referer={Referer:'https://mangakakalot.com/'}`,
- page: item.page,
- title: item.title,
- }));
- return {
- props: {
- aniId,
- id,
- title,
- data: datas,
- provider,
- },
- };
- }
-
- if (!results.data) {
- return {
- notFound: true,
- };
- }
-
- const data = results.data;
- const dat = data.map((item) => ({
- img: `https://api.consumet.org/utils/image-proxy?url=${encodeURIComponent(
- item.img
- )}&referer=${encodeURIComponent(item.headerForImage.Referer)}`,
- page: item.page,
- title: item.title || null,
- }));
-
- return {
- props: {
- aniId,
- id,
- title,
- data: dat,
- provider,
- },
- };
-}
diff --git a/pages/manga/detail/id.js b/pages/manga/detail/id.js
deleted file mode 100644
index 29cacb1..0000000
--- a/pages/manga/detail/id.js
+++ /dev/null
@@ -1,267 +0,0 @@
-import axios from "axios";
-import Head from "next/head";
-import Image from "next/image";
-import Link from "next/link";
-import { useEffect, useState } from "react";
-import Layout from "../../../components/layout";
-
-// { `Don't touch this` }
-
-// import { useUser } from "@auth0/nextjs-auth0/client";
-// import {
-// arrayRemove,
-// arrayUnion,
-// collection,
-// doc,
-// getDoc,
-// getDocs,
-// setDoc,
-// updateDoc,
-// } from "firebase/firestore";
-// import db from "../../../lib/firebase";
-
-const options = [
- "mangadex",
- "mangahere",
- "mangakakalot",
- "mangapark",
- "mangapill",
- "mangareader",
- "mangasee123",
-];
-
-export default function MangaDetail({ data, manga, aniId, provider }) {
- const [selectOption, setSelectedOption] = useState(options[0]);
- const [recentWatch, setRecentWatch] = useState();
-
- const [load, setLoad] = useState(true);
-
- useEffect(() => {
- function getRecent() {
- const recentWatch = JSON.parse(localStorage.getItem("watchedManga"))?.map(
- (data) => data.id
- );
- setRecentWatch(recentWatch);
- }
- getRecent();
- }, []);
-
- function handleLoad() {
- setLoad(false);
- }
-
- const relation = data?.relations.filter(
- (relation) => relation.malId !== null
- );
-
- const mangan = JSON.stringify(manga);
-
- async function clickDeez(props) {
- localStorage.setItem("chapters", mangan);
- localStorage.setItem("currentChapterId", props);
- }
-
- return (
- <>
- <Head>
- <title>{data.title?.english || data.title.romaji}</title>
- <meta name="info" content="More detailed info about the Manga" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <link rel="icon" href="/c.svg" />
- </Head>
- <div className="w-screen">
- <Layout>
- <div className="flex w-screen justify-center pt-[10rem] ">
- {data ? (
- <div className="flex w-[85%] flex-col gap-10 ">
- <div className="flex gap-10">
- <div className="relative h-[358px] w-[230px]">
- <Image
- src={data.image}
- alt="CoverImage"
- fill
- className="object-cover"
- />
- </div>
- <div className="flex w-[77%] flex-col gap-10">
- <h1 className="font-karla text-3xl font-bold">
- {data.title?.english}
- </h1>
- <p dangerouslySetInnerHTML={{ __html: data.description }} />
- </div>
- </div>
- {relation?.length > 0 ? (
- <div className="p-3 lg:p-0">
- <h1 className="items-start py-5 text-2xl font-bold">
- Relations
- </h1>
- <div
- className={`grid grid-cols-1 justify-items-center py-5 px-5 lg:grid-cols-3 ${
- load ? "h-[290px] overflow-y-clip" : ""
- }`}
- >
- {relation &&
- relation.map((relation, index) => {
- return (
- <div key={index} className="w-full gap-6 p-5 ">
- <Link
- href={
- relation.type === "MANGA" ||
- relation.type === "NOVEL"
- ? `/manga/detail/id?aniId=${relation.id}`
- : `/anime/${relation.id}`
- }
- className={`flex w-full justify-between rounded-md bg-[#282828] p-2 shadow-lg duration-300 ease-out hover:scale-105 ${
- relation.type === "TV" ||
- relation.type === "OVA" ||
- relation.type === "MOVIE" ||
- relation.type === "SPECIAL" ||
- relation.type === "ONA" ||
- relation.type === "MANGA" ||
- relation.type === "TV_SHORT"
- ? ``
- : "pointer-events-none"
- }`}
- >
- <div className="flex flex-col justify-between">
- <div className="font-bold text-[#FF7F57]">
- {relation.relationType}
- </div>
- <div className="text-lg font-bold text-white">
- {relation.title.romaji ||
- relation.title.english ||
- relation.title.userPreferred}
- </div>
- <div className="flex">
- <p className="dynamic-text rounded-lg p-1 font-outfit text-sm font-semibold">
- {relation.type}
- </p>
- </div>
- </div>
- <div className="relative h-[200px] w-[140px] shrink-0">
- <Image
- fill
- src={relation.image}
- alt={`Cover Image for ${relation.title}`}
- className=" bg-slate-400 object-cover"
- />
- </div>
- </Link>
- </div>
- );
- })}
- </div>
- {relation.length > 3 && (
- <button
- type="button"
- className="w-full"
- onClick={handleLoad}
- >
- {load ? "Load More" : ""}
- </button>
- )}
- </div>
- ) : (
- <p>No Relations</p>
- )}
- <div className="flex flex-col gap-10">
- <h1 className="text-3xl font-bold">Chapters</h1>
- <div className="flex h-[640px] flex-col gap-10 overflow-y-scroll scrollbar-thin scrollbar-thumb-slate-800 scrollbar-thumb-rounded-full hover:scrollbar-thumb-slate-600">
- {manga?.map((chapter, index) => {
- return (
- <div
- key={index}
- onClick={() => clickDeez(chapter.id)}
- className={`${
- recentWatch?.includes(chapter.id)
- ? "text-gray-400"
- : ""
- }`}
- >
- <Link
- // href="#"
- href={`/manga/chapter/[chapter]`}
- as={`/manga/chapter/read?id=${chapter.id}&title=${
- data.title?.english || data.title?.romaji
- }&provider=${provider}&aniId=${aniId}`}
- >
- {typeof chapter.title === "string" &&
- !isNaN(Number(chapter.title)) ? (
- <div>Chapter {Number(chapter.title)}</div>
- ) : (
- <div>
- {chapter.chapter ? (
- <p>Chapter {chapter.chapter}</p>
- ) : (
- <p>{chapter.title}</p>
- )}
- </div>
- )}
- </Link>
- </div>
- );
- })}
- </div>
- </div>
- </div>
- ) : (
- <p>Oops no data found :(</p>
- )}
- </div>
- </Layout>
- </div>
- </>
- );
-}
-
-export const getServerSideProps = async (context) => {
- context.res.setHeader("Cache-Control", "public, max-age=3600");
- const { aniId, aniTitle } = context.query;
- const prv = "mangahere";
-
- try {
- const info = await axios.get(
- `https://api.moopa.my.id/meta/anilist-manga/info/${aniId}?provider=${prv}`
- );
- const result = info.data;
- const manga = result.chapters;
-
- return {
- props: {
- data: result,
- aniId: aniId,
- provider: prv,
- manga,
- },
- };
- } catch (error) {
- if (error.response && error.response.status === 404) {
- try {
- const prv = "mangakakalot";
- const manga = await axios.get(
- `https://api.moopa.my.id/meta/anilist-manga/info/${aniId}?provider=${prv}`
- );
- const results = manga.data;
-
- return {
- props: {
- data: results,
- aniId: aniId,
- manga: results.chapters,
- provider: prv,
- },
- };
- } catch (error) {
- console.error(error);
- return {
- notFound: true,
- };
- }
- } else {
- console.error(error);
- return {
- notFound: true,
- };
- }
- }
-};