diff options
| author | Factiven <[email protected]> | 2023-09-13 00:45:53 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-13 00:45:53 +0700 |
| commit | 7327a69b55a20b99b14ee0803d6cf5f8b88c45ef (patch) | |
| tree | cbcca777593a8cc4b0282e7d85a6fc51ba517e25 /pages/api | |
| parent | Update issue templates (diff) | |
| download | moopa-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].js | 37 | ||||
| -rw-r--r-- | pages/api/anify/page/[...params].js | 41 | ||||
| -rw-r--r-- | pages/api/auth/[...nextauth].js | 60 | ||||
| -rw-r--r-- | pages/api/consumet/episode/[id].js | 68 | ||||
| -rw-r--r-- | pages/api/consumet/source/[...params].js | 36 | ||||
| -rw-r--r-- | pages/api/og.jsx | 4 | ||||
| -rw-r--r-- | pages/api/user/profile.js | 96 | ||||
| -rw-r--r-- | pages/api/user/update/episode.js | 30 | ||||
| -rw-r--r-- | pages/api/v2/episode/[id].js | 111 | ||||
| -rw-r--r-- | pages/api/v2/etc/recent/[page].js | 26 | ||||
| -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].js | 39 | ||||
| -rw-r--r-- | pages/api/v2/source/index.js | 47 |
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); + } +} |