aboutsummaryrefslogtreecommitdiff
path: root/pages
diff options
context:
space:
mode:
Diffstat (limited to 'pages')
-rw-r--r--pages/_document.js6
-rw-r--r--pages/api/anify/info/[id].js37
-rw-r--r--pages/api/anify/page/[...params].js41
-rw-r--r--pages/api/consumet/episode/[id].js12
-rw-r--r--pages/api/user/profile.js52
-rw-r--r--pages/api/user/update/episode.js68
-rw-r--r--pages/en/anime/[...id].js1
-rw-r--r--pages/en/anime/popular.js15
-rw-r--r--pages/en/anime/recently-watched.js159
-rw-r--r--pages/en/anime/trending.js15
-rw-r--r--pages/en/anime/watch/[...info].js29
-rw-r--r--pages/en/index.js159
-rw-r--r--pages/en/manga/[id].js24
-rw-r--r--pages/en/manga/read/[...params].js15
-rw-r--r--pages/en/search/[param].js7
15 files changed, 556 insertions, 84 deletions
diff --git a/pages/_document.js b/pages/_document.js
index effc121..d79f31f 100644
--- a/pages/_document.js
+++ b/pages/_document.js
@@ -1,11 +1,15 @@
import { Html, Head, Main, NextScript } from "next/document";
+// import { randomBytes } from "crypto";
export default function Document() {
+ // const nonce = randomBytes(128).toString("base64");
+ // const csp = `object-src 'none'; base-uri 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline' https: http: 'nonce-${nonce}' 'strict-dynamic'`;
+
return (
<Html lang="en">
<Head>
<link rel="manifest" href="/manifest.json" />
- <link rel="apple-touch-icon" href="/icon.png"></link>
+ <link rel="apple-touch-icon" href="/icon.png" />
<meta name="theme-color" content="#141519" />
<link
rel="stylesheet"
diff --git a/pages/api/anify/info/[id].js b/pages/api/anify/info/[id].js
new file mode 100644
index 0000000..c33d158
--- /dev/null
+++ b/pages/api/anify/info/[id].js
@@ -0,0 +1,37 @@
+import axios from "axios";
+import cacheData from "memory-cache";
+
+const API_KEY = process.env.API_KEY;
+
+// Function to fetch new data
+export async function fetchInfo(id) {
+ try {
+ const { data } = await axios.get(
+ `https://api.anify.tv/info/${id}?apikey=${API_KEY}`
+ );
+ return data;
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ return null;
+ }
+}
+
+export default async function handler(req, res) {
+ try {
+ const id = req.query.id;
+ const cached = cacheData.get(id);
+ if (cached) {
+ return res.status(200).json(cached);
+ } else {
+ const data = await fetchInfo(id);
+ if (data) {
+ res.status(200).json(data);
+ cacheData.put(id, data, 1000 * 60 * 10);
+ } else {
+ res.status(404).json({ message: "Schedule not found" });
+ }
+ }
+ } catch (error) {
+ res.status(500).json({ error });
+ }
+}
diff --git a/pages/api/anify/page/[...params].js b/pages/api/anify/page/[...params].js
new file mode 100644
index 0000000..80dda6c
--- /dev/null
+++ b/pages/api/anify/page/[...params].js
@@ -0,0 +1,41 @@
+import axios from "axios";
+import cacheData from "memory-cache";
+
+const API_KEY = process.env.API_KEY;
+
+// Function to fetch new data
+async function fetchData(id, providerId, chapterId) {
+ try {
+ const res = await fetch(
+ `https://api.anify.tv/pages?id=${id}&providerId=${providerId}&readId=${chapterId}&apikey=${API_KEY}`
+ );
+ const data = await res.json();
+ return data;
+ // return { id, providerId, chapterId };
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ return null;
+ }
+}
+
+export default async function handler(req, res) {
+ try {
+ const id = req.query.params;
+ const chapter = req.query.chapter;
+ // res.status(200).json({ id, chapter });
+ const cached = cacheData.get(chapter);
+ if (cached) {
+ return res.status(200).json(cached);
+ } else {
+ const data = await fetchData(id[0], id[1], chapter);
+ if (data) {
+ res.status(200).json(data);
+ cacheData.put(id[2], data, 1000 * 60 * 10);
+ } else {
+ res.status(404).json({ message: "Manga/Novel not found :(" });
+ }
+ }
+ } catch (error) {
+ res.status(500).json({ error });
+ }
+}
diff --git a/pages/api/consumet/episode/[id].js b/pages/api/consumet/episode/[id].js
index 737292f..e6f40ce 100644
--- a/pages/api/consumet/episode/[id].js
+++ b/pages/api/consumet/episode/[id].js
@@ -7,12 +7,18 @@ export default async function handler(req, res) {
try {
const id = req.query.id;
const dub = req.query.dub || false;
+ const refresh = req.query.refresh || false;
const providers = ["enime", "gogoanime"];
const datas = [];
const cached = cacheData.get(id + dub);
- if (cached) {
+
+ if (refresh) {
+ cacheData.del(id + dub);
+ }
+
+ if (!refresh && cached) {
return res.status(200).json(cached);
} else {
async function fetchData(provider) {
@@ -31,7 +37,7 @@ export default async function handler(req, res) {
}
return res.json();
});
- if (data.episodes?.length > 0) {
+ if (data.episodes.length > 0) {
datas.push({
providerId: provider,
episodes: dub ? data.episodes : data.episodes.reverse(),
@@ -53,7 +59,7 @@ export default async function handler(req, res) {
if (datas.length === 0) {
return res.status(404).json({ message: "Anime not found" });
} else {
- cacheData.put(id + dub, { data: datas }, 1000 * 60 * 60 * 15); // 15 minutes
+ cacheData.put(id + dub, { data: datas }, 1000 * 60 * 60 * 10);
res.status(200).json({ data: datas });
}
}
diff --git a/pages/api/user/profile.js b/pages/api/user/profile.js
new file mode 100644
index 0000000..2b44ae2
--- /dev/null
+++ b/pages/api/user/profile.js
@@ -0,0 +1,52 @@
+import {
+ createUser,
+ deleteUser,
+ getUser,
+ updateUser,
+} from "../../../prisma/user";
+
+export default async function handler(req, res) {
+ try {
+ switch (req.method) {
+ case "POST": {
+ const { name, setting } = req.body;
+ const new_user = await createUser(name, setting);
+ if (!new_user) {
+ return res.status(200).json({ message: "User is already created" });
+ } else {
+ return res.status(201).json(new_user);
+ }
+ }
+ case "PUT": {
+ const { name, anime } = req.body;
+ const user = await updateUser(name, anime);
+ if (!user) {
+ return res.status(200).json({ message: "Title is already there" });
+ } else {
+ return res.status(200).json(user);
+ }
+ }
+ case "GET": {
+ const { name } = req.query;
+ const user = await getUser(name);
+ if (!user) {
+ return res.status(404).json({ message: "User not found" });
+ } else {
+ return res.status(200).json(user);
+ }
+ }
+ case "DELETE": {
+ const { name } = req.body;
+ const user = await deleteUser(name);
+ if (!user) {
+ return res.status(404).json({ message: "User not found" });
+ } else {
+ return res.status(200).json(user);
+ }
+ }
+ }
+ } catch (error) {
+ console.log(error);
+ return res.status(500).json({ message: "Internal server error" });
+ }
+}
diff --git a/pages/api/user/update/episode.js b/pages/api/user/update/episode.js
new file mode 100644
index 0000000..f69bb78
--- /dev/null
+++ b/pages/api/user/update/episode.js
@@ -0,0 +1,68 @@
+import {
+ createList,
+ getEpisode,
+ updateUserEpisode,
+} from "../../../../prisma/user";
+
+export default async function handler(req, res) {
+ try {
+ switch (req.method) {
+ case "POST": {
+ const { name, id } = JSON.parse(req.body);
+
+ const episode = await createList(name, id);
+ if (!episode) {
+ return res
+ .status(200)
+ .json({ message: "Episode is already created" });
+ } else {
+ return res.status(201).json(episode);
+ }
+ }
+ case "PUT": {
+ const {
+ name,
+ id,
+ watchId,
+ title,
+ image,
+ number,
+ duration,
+ timeWatched,
+ aniTitle,
+ provider,
+ } = JSON.parse(req.body);
+ const episode = await updateUserEpisode({
+ name,
+ id,
+ watchId,
+ title,
+ image,
+ number,
+ duration,
+ timeWatched,
+ aniTitle,
+ provider,
+ });
+ if (!episode) {
+ return res.status(200).json({ message: "Episode is already there" });
+ } else {
+ return res.status(200).json(episode);
+ }
+ }
+ case "GET": {
+ const { name, id } = req.query;
+ // console.log(req.query);
+ const episode = await getEpisode(name, id);
+ if (!episode) {
+ return res.status(404).json({ message: "Episode not found" });
+ } else {
+ return res.status(200).json(episode);
+ }
+ }
+ }
+ } catch (error) {
+ console.log(error);
+ return res.status(500).json({ message: "Internal server error" });
+ }
+}
diff --git a/pages/en/anime/[...id].js b/pages/en/anime/[...id].js
index 6c78955..5e4aed8 100644
--- a/pages/en/anime/[...id].js
+++ b/pages/en/anime/[...id].js
@@ -154,6 +154,7 @@ export default function Info({ info, color }) {
prg={progress}
max={info?.episodes}
image={info}
+ close={handleClose}
/>
)}
</div>
diff --git a/pages/en/anime/popular.js b/pages/en/anime/popular.js
index b8b19ba..8cbbeab 100644
--- a/pages/en/anime/popular.js
+++ b/pages/en/anime/popular.js
@@ -3,7 +3,6 @@ import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import Skeleton from "react-loading-skeleton";
-import Navbar from "../../../components/navbar";
import Footer from "../../../components/footer";
import { getServerSession } from "next-auth";
import { authOptions } from "../../api/auth/[...nextauth]";
@@ -98,7 +97,7 @@ export default function PopularAnime({ sessions }) {
<>
<MobileNav sessions={sessions} />
<div className="flex flex-col gap-2 items-center min-h-screen w-screen px-2 relative pb-10">
- <div className="z-50 bg-primary pt-5 pb-3 shadow-md shadow-primary w-full fixed left-3">
+ <div className="z-50 bg-primary pt-5 pb-3 shadow-md shadow-primary w-full fixed px-3">
<Link href="/en" className="flex gap-2 items-center font-karla">
<ChevronLeftIcon className="w-5 h-5" />
<h1 className="text-xl">Popular Anime</h1>
@@ -110,7 +109,11 @@ export default function PopularAnime({ sessions }) {
key={index}
className="flex flex-col items-center w-[150px] lg:w-[180px]"
>
- <Link href={`/en/anime/${i.id}`} className="p-2">
+ <Link
+ href={`/en/anime/${i.id}`}
+ className="p-2"
+ title={i.title.romaji}
+ >
<Image
src={i.coverImage.large}
alt={i.title.romaji}
@@ -119,7 +122,11 @@ export default function PopularAnime({ sessions }) {
className="w-[140px] h-[190px] lg:w-[170px] lg:h-[230px] object-cover rounded hover:scale-105 scale-100 transition-all duration-200 ease-out"
/>
</Link>
- <Link href={`/en/anime/${i.id}`} className="w-full px-2">
+ <Link
+ href={`/en/anime/${i.id}`}
+ className="w-full px-2"
+ title={i.title.romaji}
+ >
<h1 className="font-karla font-bold xl:text-base text-[15px] line-clamp-2">
{i.status === "RELEASING" ? (
<span className="dots bg-green-500" />
diff --git a/pages/en/anime/recently-watched.js b/pages/en/anime/recently-watched.js
new file mode 100644
index 0000000..0a7fbae
--- /dev/null
+++ b/pages/en/anime/recently-watched.js
@@ -0,0 +1,159 @@
+import { ChevronLeftIcon, PlayIcon } from "@heroicons/react/24/solid";
+import Image from "next/image";
+import Link from "next/link";
+import { useEffect, useState } from "react";
+import Skeleton from "react-loading-skeleton";
+import Footer from "../../../components/footer";
+import { getServerSession } from "next-auth";
+import { authOptions } from "../../api/auth/[...nextauth]";
+import MobileNav from "../../../components/home/mobileNav";
+
+export default function PopularAnime({ sessions }) {
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ setLoading(true);
+ const fetchData = async () => {
+ let data;
+ if (sessions?.user?.name) {
+ data = await fetch(
+ `/api/user/profile?name=${sessions?.user?.name}`
+ ).then((res) => {
+ if (!res.ok) {
+ switch (res.status) {
+ case 404: {
+ return console.log("user not found");
+ }
+ case 500: {
+ return console.log("server error");
+ }
+ }
+ }
+ return res.json();
+ });
+ }
+ if (!data) {
+ const dat = JSON.parse(localStorage.getItem("artplayer_settings"));
+ if (dat) {
+ const arr = Object.keys(dat).map((key) => dat[key]);
+ setData(arr);
+ setLoading(false);
+ }
+ } else {
+ setData(data?.WatchListEpisode);
+ setLoading(false);
+ }
+ };
+ fetchData();
+ }, []);
+
+ return (
+ <>
+ <MobileNav sessions={sessions} />
+ <div className="flex flex-col gap-2 items-center min-h-screen w-screen px-2 relative pb-10">
+ <div className="z-50 bg-primary pt-5 pb-3 shadow-md shadow-primary w-full fixed left-0 px-3">
+ <Link href="/en" className="flex gap-2 items-center font-karla">
+ <ChevronLeftIcon className="w-5 h-5" />
+ <h1 className="text-xl">Recently Watched</h1>
+ </Link>
+ </div>
+ <div className="grid grid-cols-1 xs:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4 gap-3 md:gap-7 pt-16">
+ {data
+ ?.filter((i) => i.title !== null)
+ .map((i) => {
+ const time = i.timeWatched;
+ const duration = i.duration;
+ let prog = (time / duration) * 100;
+ if (prog > 90) prog = 100;
+
+ return (
+ <Link
+ key={i.watchId}
+ className="flex flex-col gap-2 shrink-0 cursor-pointer"
+ href={`/en/anime/watch/${i.aniId}/${
+ i.provider
+ }?id=${encodeURIComponent(i.watchId)}&num=${i.episode}`}
+ >
+ <div className="relative md:w-[320px] aspect-video rounded-md overflow-hidden group">
+ <div className="w-full h-full bg-gradient-to-t from-black/70 from-20% to-transparent group-hover:to-black/40 transition-all duration-300 ease-out absolute z-30" />
+ <div className="absolute bottom-3 left-0 mx-2 text-white flex gap-2 items-center w-[80%] z-30">
+ <PlayIcon className="w-5 h-5 shrink-0" />
+ <h1
+ className="font-semibold text-sm md:text-base font-karla line-clamp-1"
+ title={i?.title || i.anititle}
+ >
+ {i?.title || i.anititle}
+ </h1>
+ </div>
+ <span
+ className={`absolute bottom-0 left-0 h-[2px] bg-red-600 z-30`}
+ style={{
+ width: `${prog}%`,
+ }}
+ />
+ {i?.image && (
+ <Image
+ src={i?.image}
+ width={200}
+ height={200}
+ alt="Episode Thumbnail"
+ className="w-fit group-hover:scale-[1.02] duration-300 ease-out z-10"
+ />
+ )}
+ </div>
+ <div className="flex flex-col font-karla w-full">
+ {/* <h1 className="font-semibold">{i.title}</h1> */}
+ <p className="flex items-center gap-1 text-sm text-gray-400 md:w-[320px]">
+ <span
+ className="text-white max-w-[150px] md:max-w-[220px]"
+ style={{
+ display: "inline-block",
+ overflow: "hidden",
+ textOverflow: "ellipsis",
+ whiteSpace: "nowrap",
+ }}
+ title={i.aniTitle}
+ >
+ {i.aniTitle}
+ </span>{" "}
+ | Episode {i.episode}
+ </p>
+ </div>
+ </Link>
+ );
+ })}
+
+ {loading && (
+ <>
+ {[1, 2, 4, 5, 6, 7, 8].map((item) => (
+ <div
+ key={item}
+ className="flex flex-col gap-2 items-center md:w-[320px] rounded-md overflow-hidden"
+ >
+ <div className="w-full">
+ <Skeleton className="w-fit aspect-video rounded" />
+ </div>
+ <div className="w-full">
+ <Skeleton width={80} height={20} />
+ </div>
+ </div>
+ ))}
+ </>
+ )}
+ </div>
+ </div>
+ <Footer />
+ </>
+ );
+}
+
+export async function getServerSideProps(context) {
+ const session = await getServerSession(context.req, context.res, authOptions);
+
+ return {
+ props: {
+ sessions: session,
+ },
+ };
+}
diff --git a/pages/en/anime/trending.js b/pages/en/anime/trending.js
index cbc30ab..9f8a187 100644
--- a/pages/en/anime/trending.js
+++ b/pages/en/anime/trending.js
@@ -3,7 +3,6 @@ import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import Skeleton from "react-loading-skeleton";
-import Navbar from "../../../components/navbar";
import Footer from "../../../components/footer";
import { getServerSession } from "next-auth";
import { authOptions } from "../../api/auth/[...nextauth]";
@@ -98,7 +97,7 @@ export default function TrendingAnime({ sessions }) {
<>
<MobileNav sessions={sessions} />
<div className="flex flex-col gap-2 items-center min-h-screen w-screen px-2 relative pb-10">
- <div className="z-50 bg-primary pt-5 pb-3 shadow-md shadow-primary w-full fixed left-3">
+ <div className="z-50 bg-primary pt-5 pb-3 shadow-md shadow-primary w-full fixed px-3">
<Link href="/en" className="flex gap-2 items-center font-karla">
<ChevronLeftIcon className="w-5 h-5" />
<h1 className="text-xl">Trending Now</h1>
@@ -110,7 +109,11 @@ export default function TrendingAnime({ sessions }) {
key={index}
className="flex flex-col items-center w-[150px] lg:w-[180px]"
>
- <Link href={`/en/anime/${i.id}`} className="p-2">
+ <Link
+ href={`/en/anime/${i.id}`}
+ className="p-2"
+ title={i.title.romaji}
+ >
<Image
src={i.coverImage.large}
alt={i.title.romaji}
@@ -119,7 +122,11 @@ export default function TrendingAnime({ sessions }) {
className="w-[140px] h-[190px] lg:w-[170px] lg:h-[230px] object-cover rounded hover:scale-105 scale-100 transition-all duration-200 ease-out"
/>
</Link>
- <Link href={`/en/anime/${i.id}`} className="w-full px-2">
+ <Link
+ href={`/en/anime/${i.id}`}
+ className="w-full px-2"
+ title={i.title.romaji}
+ >
<h1 className="font-karla font-bold xl:text-base text-[15px] line-clamp-2">
{i.status === "RELEASING" ? (
<span className="dots bg-green-500" />
diff --git a/pages/en/anime/watch/[...info].js b/pages/en/anime/watch/[...info].js
index 67e38c2..bc8851b 100644
--- a/pages/en/anime/watch/[...info].js
+++ b/pages/en/anime/watch/[...info].js
@@ -9,6 +9,8 @@ import Navigasi from "../../../../components/home/staticNav";
import PrimarySide from "../../../../components/anime/watch/primarySide";
import SecondarySide from "../../../../components/anime/watch/secondarySide";
import { GET_MEDIA_USER } from "../../../../queries";
+import { createList, createUser, getEpisode } from "../../../../prisma/user";
+// import { updateUser } from "../../../../prisma/user";
export default function Info({
sessions,
@@ -17,6 +19,7 @@ export default function Info({
provider,
epiNumber,
dub,
+ userData,
proxy,
disqus,
}) {
@@ -124,7 +127,7 @@ export default function Info({
}
}
}
-
+
setInfo(data.data.Media);
const response = await fetch(
@@ -156,12 +159,16 @@ export default function Info({
setLoading(false);
}
}
-
+
setArtStorage(JSON.parse(localStorage.getItem("artplayer_settings")));
// setEpiData(episodes);
setLoading(false);
}
getInfo();
+
+ return () => {
+ setCurrentEpisode(null);
+ };
}, [sessions?.user?.name, epiNumber, dub]);
// console.log(proxy);
@@ -190,6 +197,7 @@ export default function Info({
setOnList={setOnList}
setLoading={setLoading}
loading={loading}
+ timeWatched={userData?.timeWatched}
/>
<SecondarySide
info={info}
@@ -227,6 +235,22 @@ export async function getServerSideProps(context) {
const epiNumber = query.num;
const dub = query.dub;
+ let userData = null;
+
+ if (session) {
+ await createUser(session.user.name);
+ await createList(session.user.name, watchId);
+ const data = await getEpisode(session.user.name, watchId);
+ userData = JSON.parse(
+ JSON.stringify(data, (key, value) => {
+ if (key === "createdDate") {
+ return String(value);
+ }
+ return value;
+ })
+ );
+ }
+
return {
props: {
sessions: session,
@@ -235,6 +259,7 @@ export async function getServerSideProps(context) {
watchId: watchId || null,
epiNumber: epiNumber || null,
dub: dub || null,
+ userData: userData?.[0] || null,
proxy,
disqus,
},
diff --git a/pages/en/index.js b/pages/en/index.js
index 35de96d..c3a98fc 100644
--- a/pages/en/index.js
+++ b/pages/en/index.js
@@ -21,17 +21,40 @@ import { useCountdown } from "../../utils/useCountdownSeconds";
import Navigasi from "../../components/home/staticNav";
import MobileNav from "../../components/home/mobileNav";
import axios from "axios";
+import { createUser } from "../../prisma/user";
-// Filter schedules for each day
-// const filterByCountryOfOrigin = (schedule, country) => {
-// const filteredSchedule = {};
-// for (const day in schedule) {
-// filteredSchedule[day] = schedule[day].filter(
-// (anime) => anime.countryOfOrigin === country
-// );
-// }
-// return filteredSchedule;
-// };
+import { checkAdBlock } from "adblock-checker";
+import { ToastContainer, toast } from "react-toastify";
+
+export async function getServerSideProps(context) {
+ const session = await getServerSession(context.req, context.res, authOptions);
+
+ if (session) {
+ await createUser(session.user.name);
+ }
+
+ const trendingDetail = await aniListData({
+ sort: "TRENDING_DESC",
+ page: 1,
+ });
+ const popularDetail = await aniListData({
+ sort: "POPULARITY_DESC",
+ page: 1,
+ });
+ const genreDetail = await aniListData({ sort: "TYPE", page: 1 });
+
+ const upComing = await getUpcomingAnime();
+
+ return {
+ props: {
+ genre: genreDetail.props,
+ detail: trendingDetail.props,
+ populars: popularDetail.props,
+ sessions: session,
+ upComing,
+ },
+ };
+}
export default function Home({ detail, populars, sessions, upComing }) {
const { media: current } = useAniList(sessions, { stats: "CURRENT" });
@@ -42,6 +65,27 @@ export default function Home({ detail, populars, sessions, upComing }) {
const [anime, setAnime] = useState([]);
+ useEffect(() => {
+ async function adBlock() {
+ const ad = await checkAdBlock();
+ if (ad) {
+ toast.dark(
+ "Please disable your adblock for better experience, we don't have any ads on our site.",
+ {
+ position: "top-center",
+ autoClose: false,
+ hideProgressBar: true,
+ closeOnClick: true,
+ pauseOnHover: true,
+ draggable: true,
+ theme: "dark",
+ }
+ );
+ }
+ }
+ adBlock();
+ }, []);
+
const update = () => {
setAnime((prevAnime) => prevAnime.slice(1));
};
@@ -89,6 +133,9 @@ export default function Home({ detail, populars, sessions, upComing }) {
const [list, setList] = useState(null);
const [planned, setPlanned] = useState(null);
const [greeting, setGreeting] = useState("");
+ const [user, setUser] = useState(null);
+
+ // console.log({ user });
const [prog, setProg] = useState(null);
@@ -96,6 +143,43 @@ export default function Home({ detail, populars, sessions, upComing }) {
const data = detail.data[0];
useEffect(() => {
+ async function userData() {
+ let data;
+ if (sessions?.user?.name) {
+ data = await fetch(
+ `/api/user/profile?name=${sessions?.user?.name}`
+ ).then((res) => {
+ if (!res.ok) {
+ switch (res.status) {
+ case 404: {
+ return console.log("user not found");
+ }
+ case 500: {
+ return console.log("server error");
+ }
+ }
+ }
+ return res.json();
+ });
+ }
+ if (!data) {
+ const dat = JSON.parse(localStorage.getItem("artplayer_settings"));
+ if (dat) {
+ const arr = Object.keys(dat).map((key) => dat[key]);
+ const newFirst = arr?.sort((a, b) => {
+ return new Date(b?.createdAt) - new Date(a?.createdAt);
+ });
+ setUser(newFirst);
+ }
+ } else {
+ setUser(data?.WatchListEpisode);
+ }
+ // const data = await res.json();
+ }
+ userData();
+ }, [sessions?.user?.name]);
+
+ useEffect(() => {
const time = new Date().getHours();
let greeting = "";
@@ -112,7 +196,8 @@ export default function Home({ detail, populars, sessions, upComing }) {
setGreeting(greeting);
async function userData() {
- if (!sessions) return;
+ if (!sessions?.user?.name) return;
+
const getMedia =
current.filter((item) => item.status === "CURRENT")[0] || null;
const list = getMedia?.entries
@@ -131,7 +216,8 @@ export default function Home({ detail, populars, sessions, upComing }) {
}
}
userData();
- }, [sessions, current, plan]);
+ }, [sessions?.user?.name, current, plan]);
+
return (
<>
<Head>
@@ -158,6 +244,13 @@ export default function Home({ detail, populars, sessions, upComing }) {
<div className="h-auto w-screen bg-[#141519] text-[#dbdcdd] ">
<Navigasi />
<SearchBar />
+ <ToastContainer
+ pauseOnFocusLoss={false}
+ style={{
+ width: "400px",
+ }}
+ />
+
{/* PC / TABLET */}
<div className=" hidden justify-center lg:flex my-16">
<div className="relative grid grid-rows-2 items-center lg:flex lg:h-[467px] lg:w-[80%] lg:justify-between">
@@ -228,6 +321,22 @@ export default function Home({ detail, populars, sessions, upComing }) {
animate={{ opacity: 1 }}
transition={{ duration: 0.5, staggerChildren: 0.2 }} // Add staggerChildren prop
>
+ {user?.length > 0 && (
+ <motion.div // Add motion.div to each child component
+ key="recentlyWatched"
+ initial={{ y: 20, opacity: 0 }}
+ whileInView={{ y: 0, opacity: 1 }}
+ transition={{ duration: 0.5 }}
+ viewport={{ once: true }}
+ >
+ <Content
+ ids="recentlyWatched"
+ section="Recently Watched"
+ userData={user}
+ />
+ </motion.div>
+ )}
+
{sessions && releaseData?.length > 0 && (
<motion.div // Add motion.div to each child component
key="onGoing"
@@ -354,29 +463,3 @@ export default function Home({ detail, populars, sessions, upComing }) {
</>
);
}
-
-export async function getServerSideProps(context) {
- const session = await getServerSession(context.req, context.res, authOptions);
-
- const trendingDetail = await aniListData({
- sort: "TRENDING_DESC",
- page: 1,
- });
- const popularDetail = await aniListData({
- sort: "POPULARITY_DESC",
- page: 1,
- });
- const genreDetail = await aniListData({ sort: "TYPE", page: 1 });
-
- const upComing = await getUpcomingAnime();
-
- return {
- props: {
- genre: genreDetail.props,
- detail: trendingDetail.props,
- populars: popularDetail.props,
- sessions: session,
- upComing,
- },
- };
-}
diff --git a/pages/en/manga/[id].js b/pages/en/manga/[id].js
index eb53a93..bb3cbc2 100644
--- a/pages/en/manga/[id].js
+++ b/pages/en/manga/[id].js
@@ -9,12 +9,12 @@ import { useEffect, useState } from "react";
import { setCookie } from "nookies";
import { getServerSession } from "next-auth";
import { authOptions } from "../../api/auth/[...nextauth]";
+import getAnifyInfo from "../../../lib/anify/info";
export default function Manga({ info, userManga, chapters }) {
const [domainUrl, setDomainUrl] = useState("");
const [firstEp, setFirstEp] = useState();
- const chaptersData =
- info.chapters.data.length === 0 ? chapters : info.chapters.data;
+ const chaptersData = info.chapters.data;
useEffect(() => {
setDomainUrl(window.location.origin);
@@ -84,8 +84,7 @@ export async function getServerSideProps(context) {
const { id } = context.query;
const key = process.env.API_KEY;
- const res = await fetch(`https://api.anify.tv/info/${id}?apikey=${key}`);
- const data = await res.json();
+ const data = await getAnifyInfo(id, key);
let userManga = null;
@@ -152,27 +151,10 @@ export async function getServerSideProps(context) {
};
}
- let chapter = null;
-
- if (data?.chapters?.data.length === 0) {
- const res2 = await fetch(
- `https://api.anify.tv/chapters/${id}?apikey=${key}`
- );
- const data2 = await res2.json();
- if (data2.error) {
- return {
- notFound: true
- }
- } else {
- chapter = data2;
- }
- }
-
return {
props: {
info: data,
userManga,
- chapters: chapter || null,
},
};
}
diff --git a/pages/en/manga/read/[...params].js b/pages/en/manga/read/[...params].js
index dbabb3d..e608d16 100644
--- a/pages/en/manga/read/[...params].js
+++ b/pages/en/manga/read/[...params].js
@@ -15,6 +15,7 @@ import Head from "next/head";
import nookies from "nookies";
import ShortCutModal from "../../../../components/manga/modals/shortcutModal";
import ChapterModal from "../../../../components/manga/modals/chapterModal";
+import getAnifyPage from "../../../../lib/anify/page";
export default function Read({ data, currentId, sessions }) {
const [info, setInfo] = useState();
@@ -228,6 +229,8 @@ export async function getServerSideProps(context) {
const cookies = nookies.get(context);
+ const key = process.env.API_KEY;
+
const query = context.query;
const providerId = query.params[0];
const chapterId = query.chapterId;
@@ -243,18 +246,12 @@ export async function getServerSideProps(context) {
const session = await getServerSession(context.req, context.res, authOptions);
- const key = process.env.API_KEY;
- const res = await fetch(
- `https://api.anify.tv/pages?providerId=${providerId}&readId=${encodeURIComponent(
- chapterId
- )}&apikey=${key}`
- );
+ const data = await getAnifyPage(mediaId, providerId, chapterId, key);
- const data = await res.json();
if (data.error) {
return {
- notFound: true
- }
+ notFound: true,
+ };
}
return {
diff --git a/pages/en/search/[param].js b/pages/en/search/[param].js
index cacc2b8..abd4f04 100644
--- a/pages/en/search/[param].js
+++ b/pages/en/search/[param].js
@@ -429,7 +429,7 @@ export default function Card() {
? `/en/manga/${anime.id}`
: `/en/anime/${anime.id}`
}
- className=""
+ title={anime.title.userPreferred}
>
<Image
className="object-cover bg-[#3B3C41] w-[146px] h-[208px] xxs:w-[115px] xxs:h-[163px] xs:w-[135px] xs:h-[192px] xl:w-[185px] xl:h-[265px] hover:scale-105 scale-100 transition-all cursor-pointer duration-200 ease-out rounded-[10px]"
@@ -439,7 +439,10 @@ export default function Card() {
height={500}
/>
</Link>
- <Link href={`/en/anime/${anime.id}`}>
+ <Link
+ href={`/en/anime/${anime.id}`}
+ title={anime.title.userPreferred}
+ >
<h1 className="font-outfit font-bold xl:text-base text-[15px] pt-4 line-clamp-2">
{anime.status === "RELEASING" ? (
<span className="dots bg-green-500" />