aboutsummaryrefslogtreecommitdiff
path: root/pages/api
diff options
context:
space:
mode:
authorFactiven <[email protected]>2023-09-13 00:45:53 +0700
committerGitHub <[email protected]>2023-09-13 00:45:53 +0700
commit7327a69b55a20b99b14ee0803d6cf5f8b88c45ef (patch)
treecbcca777593a8cc4b0282e7d85a6fc51ba517e25 /pages/api
parentUpdate issue templates (diff)
downloadmoopa-7327a69b55a20b99b14ee0803d6cf5f8b88c45ef.tar.xz
moopa-7327a69b55a20b99b14ee0803d6cf5f8b88c45ef.zip
Update v4 - Merge pre-push to main (#71)
* Create build-test.yml * initial v4 commit * update: github workflow * update: push on branch * Update .github/ISSUE_TEMPLATE/bug_report.md * configuring next.config.js file
Diffstat (limited to 'pages/api')
-rw-r--r--pages/api/anify/info/[id].js37
-rw-r--r--pages/api/anify/page/[...params].js41
-rw-r--r--pages/api/auth/[...nextauth].js60
-rw-r--r--pages/api/consumet/episode/[id].js68
-rw-r--r--pages/api/consumet/source/[...params].js36
-rw-r--r--pages/api/og.jsx4
-rw-r--r--pages/api/user/profile.js96
-rw-r--r--pages/api/user/update/episode.js30
-rw-r--r--pages/api/v2/episode/[id].js111
-rw-r--r--pages/api/v2/etc/recent/[page].js26
-rw-r--r--pages/api/v2/etc/schedule/index.js (renamed from pages/api/anify/schedule.js)28
-rw-r--r--pages/api/v2/info/[id].js39
-rw-r--r--pages/api/v2/source/index.js47
13 files changed, 376 insertions, 247 deletions
diff --git a/pages/api/anify/info/[id].js b/pages/api/anify/info/[id].js
deleted file mode 100644
index c33d158..0000000
--- a/pages/api/anify/info/[id].js
+++ /dev/null
@@ -1,37 +0,0 @@
-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
deleted file mode 100644
index 80dda6c..0000000
--- a/pages/api/anify/page/[...params].js
+++ /dev/null
@@ -1,41 +0,0 @@
-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/auth/[...nextauth].js b/pages/api/auth/[...nextauth].js
index f270e7a..da78d07 100644
--- a/pages/api/auth/[...nextauth].js
+++ b/pages/api/auth/[...nextauth].js
@@ -1,6 +1,5 @@
import NextAuth from "next-auth";
-import { GET_CURRENT_USER } from "../../../queries";
-import { ApolloClient, InMemoryCache } from "@apollo/client";
+import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
const defaultOptions = {
watchQuery: {
@@ -40,7 +39,24 @@ export const authOptions = {
url: process.env.GRAPHQL_ENDPOINT,
async request(context) {
const { data } = await client.query({
- query: GET_CURRENT_USER,
+ query: gql`
+ query {
+ Viewer {
+ id
+ name
+ avatar {
+ large
+ medium
+ }
+ bannerImage
+ mediaListOptions {
+ animeList {
+ customLists
+ }
+ }
+ }
+ }
+ `,
context: {
headers: {
Authorization: "Bearer " + context.tokens.access_token,
@@ -48,11 +64,47 @@ export const authOptions = {
},
});
+ const userLists = data.Viewer.mediaListOptions.animeList.customLists;
+
+ let custLists = userLists || [];
+
+ if (!userLists?.includes("Watched using Moopa")) {
+ custLists.push("Watched using Moopa");
+ const fetchGraphQL = async (query, variables) => {
+ const response = await fetch("https://graphql.anilist.co/", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: context.tokens.access_token
+ ? `Bearer ${context.tokens.access_token}`
+ : undefined,
+ },
+ body: JSON.stringify({ query, variables }),
+ });
+ return response.json();
+ };
+
+ const customLists = async (lists) => {
+ const setList = `
+ mutation($lists: [String]){
+ UpdateUser(animeListOptions: { customLists: $lists }){
+ id
+ }
+ }
+ `;
+ const data = await fetchGraphQL(setList, { lists });
+ return data;
+ };
+
+ await customLists(custLists);
+ }
+
return {
token: context.tokens.access_token,
name: data.Viewer.name,
sub: data.Viewer.id,
image: data.Viewer.avatar,
+ list: data.Viewer.mediaListOptions.animeList.customLists,
};
},
},
@@ -64,6 +116,8 @@ export const authOptions = {
id: profile.sub,
name: profile?.name,
image: profile.image,
+ list: profile?.list,
+ version: "1.0.1",
};
},
},
diff --git a/pages/api/consumet/episode/[id].js b/pages/api/consumet/episode/[id].js
deleted file mode 100644
index 6e7f318..0000000
--- a/pages/api/consumet/episode/[id].js
+++ /dev/null
@@ -1,68 +0,0 @@
-import cacheData from "memory-cache";
-
-const API_URL = process.env.API_URI;
-
-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", "zoro"];
- const datas = [];
-
- const cached = cacheData.get(id + dub);
-
- if (refresh) {
- cacheData.del(id + dub);
- }
-
- if (!refresh && cached) {
- return res.status(200).json(cached);
- } else {
- async function fetchData(provider) {
- try {
- const data = await fetch(
- dub && provider === "gogoanime"
- ? `${API_URL}/meta/anilist/info/${id}?dub=true`
- : `${API_URL}/meta/anilist/info/${id}?provider=${provider}`
- ).then((res) => {
- if (!res.ok) {
- switch (res.status) {
- case 404: {
- return null;
- }
- }
- }
- return res.json();
- });
- if (data.episodes.length > 0) {
- datas.push({
- providerId: provider,
- episodes: dub ? data.episodes : data.episodes.reverse(),
- });
- }
- } catch (error) {
- console.error(
- `Error fetching data for provider '${provider}':`,
- error
- );
- }
- }
- if (dub === false) {
- await Promise.all(providers.map((provider) => fetchData(provider)));
- } else {
- await fetchData("gogoanime");
- }
-
- if (datas.length === 0) {
- return res.status(404).json({ message: "Anime not found" });
- } else {
- cacheData.put(id + dub, { data: datas }, 1000 * 60 * 60 * 10);
- res.status(200).json({ data: datas });
- }
- }
- } catch (error) {
- res.status(500).json({ error });
- }
-}
diff --git a/pages/api/consumet/source/[...params].js b/pages/api/consumet/source/[...params].js
deleted file mode 100644
index e589d4a..0000000
--- a/pages/api/consumet/source/[...params].js
+++ /dev/null
@@ -1,36 +0,0 @@
-import axios from "axios";
-import cacheData from "memory-cache";
-
-const API_URL = process.env.API_URI;
-
-export default async function handler(req, res) {
- const query = req.query.params;
- try {
- const provider = query[0];
- const id = query[1];
-
- const cached = cacheData.get(id);
- if (cached) {
- return res.status(200).json(cached);
- } else {
- let datas;
-
- const { data } = await axios.get(
- `${API_URL}/meta/anilist/watch/${id}?provider=${provider}`
- );
-
- if (data) {
- datas = data;
- cacheData.put(id, data, 1000 * 60 * 5);
- }
-
- if (!datas) {
- return res.status(404).json({ message: "Source not found" });
- }
-
- res.status(200).json(datas);
- }
- } catch (error) {
- res.status(500).json({ error });
- }
-}
diff --git a/pages/api/og.jsx b/pages/api/og.jsx
index b1cf238..d52f90e 100644
--- a/pages/api/og.jsx
+++ b/pages/api/og.jsx
@@ -35,7 +35,7 @@ export default async function handler(request) {
<div
style={{
display: "flex",
- fontSize: 60,
+ fontSize: "60px",
color: "black",
background: "#f6f6f6",
width: "100%",
@@ -63,7 +63,7 @@ export default async function handler(request) {
position: "absolute",
top: 10,
left: 25,
- fontSize: "40",
+ fontSize: "40px",
color: "#FF7F57",
fontFamily: "Outfit",
filter: "brightness(100%)",
diff --git a/pages/api/user/profile.js b/pages/api/user/profile.js
index e20aaca..89a23d5 100644
--- a/pages/api/user/profile.js
+++ b/pages/api/user/profile.js
@@ -9,63 +9,63 @@ import {
} from "../../../prisma/user";
export default async function handler(req, res) {
- const session = await getServerSession(req, res, authOptions);
- if (session) {
- // Signed in
- 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);
- }
+ // const session = await getServerSession(req, res, authOptions);
+ // if (session) {
+ // Signed in
+ try {
+ switch (req.method) {
+ case "POST": {
+ const { name } = req.body;
+ const new_user = await createUser(name);
+ 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 "PUT": {
+ const { name, settings } = req.body;
+ const user = await updateUser(name, settings);
+ if (!user) {
+ return res.status(200).json({ message: "Can't update settings" });
+ } else {
+ return res.status(200).json(user);
}
- case "GET": {
- const { name } = req.query;
- const user = await getUser(name);
+ }
+ 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;
+ // return res.status(200).json({ name });
+ if (session.user.name !== name) {
+ return res.status(401).json({ message: "Unauthorized" });
+ } else {
+ const user = await deleteUser(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;
- // return res.status(200).json({ name });
- if (session.user.name !== name) {
- return res.status(401).json({ message: "Unauthorized" });
- } else {
- const user = await deleteUser(name);
- if (!user) {
- return res.status(404).json({ message: "User not found" });
- } else {
- return res.status(200).json(user);
- }
- }
- }
- default: {
- return res.status(405).json({ message: "Method not allowed" });
- }
}
- } catch (error) {
- console.log(error);
- return res.status(500).json({ message: "Internal server error" });
+ default: {
+ return res.status(405).json({ message: "Method not allowed" });
+ }
}
- } else {
- // Not Signed in
- res.status(401);
+ } catch (error) {
+ console.log(error);
+ return res.status(500).json({ message: "Internal server error" });
}
- res.end();
+ // } else {
+ // // Not Signed in
+ // res.status(401);
+ // }
+ // res.end();
}
diff --git a/pages/api/user/update/episode.js b/pages/api/user/update/episode.js
index 52c9494..3ee345d 100644
--- a/pages/api/user/update/episode.js
+++ b/pages/api/user/update/episode.js
@@ -4,6 +4,7 @@ import { authOptions } from "../../auth/[...nextauth]";
import {
createList,
deleteEpisode,
+ deleteList,
getEpisode,
updateUserEpisode,
} from "../../../../prisma/user";
@@ -42,6 +43,9 @@ export default async function handler(req, res) {
timeWatched,
aniTitle,
provider,
+ nextId,
+ nextNumber,
+ dub,
} = JSON.parse(req.body);
const episode = await updateUserEpisode({
name,
@@ -54,6 +58,9 @@ export default async function handler(req, res) {
timeWatched,
aniTitle,
provider,
+ nextId,
+ nextNumber,
+ dub,
});
if (!episode) {
return res
@@ -74,15 +81,24 @@ export default async function handler(req, res) {
}
}
case "DELETE": {
- const { name, id } = req.body;
+ const { name, id, aniId } = req.body;
if (session.user.name !== name) {
return res.status(401).json({ message: "Unauthorized" });
} else {
- const episode = await deleteEpisode(name, id);
- if (!episode) {
- return res.status(404).json({ message: "Episode not found" });
- } else {
- return res.status(200).json({ message: "Episode deleted" });
+ if (id) {
+ const episode = await deleteEpisode(name, id);
+ if (!episode) {
+ return res.status(404).json({ message: "Episode not found" });
+ } else {
+ return res.status(200).json({ message: "Episode deleted" });
+ }
+ } else if (aniId) {
+ const episode = await deleteList(name, aniId);
+ if (!episode) {
+ return res.status(404).json({ message: "Episode not found" });
+ } else {
+ return res.status(200).json({ message: "Episode deleted" });
+ }
}
}
}
@@ -93,7 +109,7 @@ export default async function handler(req, res) {
}
} else {
// Not Signed in
- res.status(401);
+ res.status(401).json({ message: "Unauthorized" });
}
res.end();
}
diff --git a/pages/api/v2/episode/[id].js b/pages/api/v2/episode/[id].js
new file mode 100644
index 0000000..1d328f6
--- /dev/null
+++ b/pages/api/v2/episode/[id].js
@@ -0,0 +1,111 @@
+import axios from "axios";
+import redis from "../../../../lib/redis";
+
+const CONSUMET_URI = process.env.API_URI;
+const API_KEY = process.env.API_KEY;
+
+async function fetchConsumet(id, dub) {
+ try {
+ if (dub) {
+ return [];
+ }
+
+ const { data } = await axios.get(`${CONSUMET_URI}/meta/anilist/info/${id}`);
+
+ if (!data?.episodes?.length > 0) {
+ return [];
+ }
+
+ const array = [
+ {
+ map: true,
+ providerId: "gogoanime",
+ episodes: data.episodes.reverse(),
+ },
+ ];
+
+ return array;
+ } catch (error) {
+ console.error(error);
+ return [];
+ }
+}
+
+async function fetchAnify(id) {
+ try {
+ if (!process.env.API_KEY) {
+ return [];
+ }
+
+ const { data } = await axios.get(
+ `https://api.anify.tv/episodes/${id}?apikey=${API_KEY}`
+ );
+
+ if (!data) {
+ return [];
+ }
+
+ const filtered = data.filter(
+ (item) => item.providerId !== "animepahe" && item.providerId !== "kass"
+ );
+ const modifiedData = filtered.map((provider) => {
+ if (provider.providerId === "gogoanime") {
+ const reversedEpisodes = [...provider.episodes].reverse();
+ return { ...provider, episodes: reversedEpisodes };
+ }
+ return provider;
+ });
+
+ return modifiedData;
+ } catch (error) {
+ console.error(error);
+ return [];
+ }
+}
+
+export default async function handler(req, res) {
+ const { id, releasing = "false", dub = false } = req.query;
+
+ // if releasing is true then cache for 10 minutes, if it false cache for 1 week;
+ const cacheTime = releasing === "true" ? 60 * 10 : 60 * 60 * 24 * 7;
+
+ let cached;
+
+ if (redis) {
+ cached = await redis.get(id);
+ console.log("using redis");
+ }
+
+ if (cached) {
+ if (dub) {
+ const filtered = JSON.parse(cached).filter((item) =>
+ item.episodes.some((epi) => epi.hasDub === true)
+ );
+ return res.status(200).json(filtered);
+ } else {
+ return res.status(200).json(JSON.parse(cached));
+ }
+ }
+
+ const [consumet, anify] = await Promise.all([
+ fetchConsumet(id, dub),
+ fetchAnify(id),
+ ]);
+
+ const data = [...consumet, ...anify];
+
+ if (redis && cacheTime !== null) {
+ await redis.set(id, JSON.stringify(data), "EX", cacheTime);
+ }
+
+ if (dub) {
+ const filtered = data.filter((item) =>
+ item.episodes.some((epi) => epi.hasDub === true)
+ );
+ return res.status(200).json(filtered);
+ }
+
+ console.log("fresh data");
+
+ return res.status(200).json(data);
+}
diff --git a/pages/api/v2/etc/recent/[page].js b/pages/api/v2/etc/recent/[page].js
new file mode 100644
index 0000000..19495c1
--- /dev/null
+++ b/pages/api/v2/etc/recent/[page].js
@@ -0,0 +1,26 @@
+const API_URL = process.env.API_URI;
+
+export default async function handler(req, res) {
+ try {
+ const page = req.query.page || 1;
+
+ var hasNextPage = true;
+ var datas = [];
+
+ async function fetchData(page) {
+ const data = await fetch(
+ `${API_URL}/meta/anilist/recent-episodes?page=${page}&perPage=30&provider=gogoanime`
+ ).then((res) => res.json());
+
+ const filtered = data?.results?.filter((i) => i.type !== "ONA");
+ hasNextPage = data?.hasNextPage;
+ datas = filtered;
+ }
+
+ await fetchData(page);
+
+ return res.status(200).json({ hasNextPage, results: datas });
+ } catch (error) {
+ res.status(500).json({ error });
+ }
+}
diff --git a/pages/api/anify/schedule.js b/pages/api/v2/etc/schedule/index.js
index 99f10d6..7a13fff 100644
--- a/pages/api/anify/schedule.js
+++ b/pages/api/v2/etc/schedule/index.js
@@ -1,6 +1,6 @@
import axios from "axios";
-import cacheData from "memory-cache";
import cron from "cron";
+import redis from "../../../../../lib/redis";
const API_KEY = process.env.API_KEY;
@@ -21,7 +21,14 @@ async function fetchData() {
async function refreshCache() {
const newData = await fetchData();
if (newData) {
- cacheData.put("schedule", newData, 1000 * 60 * 15);
+ if (redis) {
+ await redis.set(
+ "schedule",
+ JSON.stringify(newData),
+ "EX",
+ 60 * 60 * 24 * 7
+ );
+ }
console.log("Cache refreshed successfully.");
}
}
@@ -34,15 +41,26 @@ job.start();
export default async function handler(req, res) {
try {
- const cached = cacheData.get("schedule");
+ let cached;
+ if (redis) {
+ cached = await redis.get("schedule");
+ }
if (cached) {
- return res.status(200).json(cached);
+ return res.status(200).json(JSON.parse(cached));
} else {
const data = await fetchData();
if (data) {
+ // cacheData.put("schedule", data, 1000 * 60 * 60 * 24 * 7);
+ if (redis) {
+ await redis.set(
+ "schedule",
+ JSON.stringify(data),
+ "EX",
+ 60 * 60 * 24 * 7
+ );
+ }
res.status(200).json(data);
- cacheData.put("schedule", data, 1000 * 60 * 60 * 24 * 7);
} else {
res.status(404).json({ message: "Schedule not found" });
}
diff --git a/pages/api/v2/info/[id].js b/pages/api/v2/info/[id].js
new file mode 100644
index 0000000..41daa6e
--- /dev/null
+++ b/pages/api/v2/info/[id].js
@@ -0,0 +1,39 @@
+import axios from "axios";
+import redis from "../../../../lib/redis";
+
+const API_KEY = process.env.API_KEY;
+
+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) {
+ const id = req.query.id;
+ let cached;
+ if (redis) {
+ cached = await redis.get(id);
+ }
+ if (cached) {
+ // console.log("Using cached data");
+ return res.status(200).json(JSON.parse(cached));
+ } else {
+ const data = await fetchInfo(id);
+ if (data) {
+ // console.log("Setting cache");
+ if (redis) {
+ await redis.set(id, JSON.stringify(data), "EX", 60 * 10);
+ }
+ return res.status(200).json(data);
+ } else {
+ return res.status(404).json({ message: "Schedule not found" });
+ }
+ }
+}
diff --git a/pages/api/v2/source/index.js b/pages/api/v2/source/index.js
new file mode 100644
index 0000000..51ac5ec
--- /dev/null
+++ b/pages/api/v2/source/index.js
@@ -0,0 +1,47 @@
+import axios from "axios";
+
+const CONSUMET_URI = process.env.API_URI;
+const API_KEY = process.env.API_KEY;
+
+async function consumetSource(id) {
+ try {
+ const { data } = await axios.get(
+ `${CONSUMET_URI}/meta/anilist/watch/${id}`
+ );
+ return data;
+ } catch (error) {
+ console.error(error);
+ return null;
+ }
+}
+
+async function anifySource(providerId, watchId, episode, id, sub) {
+ try {
+ const { data } = await axios.get(
+ `https://api.anify.tv/sources?providerId=${providerId}&watchId=${encodeURIComponent(
+ watchId
+ )}&episode=${episode}&id=${id}&subType=${sub}&apikey=${API_KEY}`
+ );
+ return data;
+ } catch (error) {
+ return null;
+ }
+}
+
+export default async function handler(req, res) {
+ if (req.method !== "POST") {
+ return res.status(405).json({ message: "Method not allowed" });
+ }
+
+ const { source, providerId, watchId, episode, id, sub = "sub" } = req.body;
+
+ if (source === "anify") {
+ const data = await anifySource(providerId, watchId, episode, id, sub);
+ return res.status(200).json(data);
+ }
+
+ if (source === "consumet") {
+ const data = await consumetSource(watchId);
+ return res.status(200).json(data);
+ }
+}