diff options
| author | Factiven <[email protected]> | 2023-09-25 00:44:40 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-25 00:44:40 +0700 |
| commit | 1a85c2571690ba592ac5183d5eadaf9846fe532b (patch) | |
| tree | 3f3552c00cd49c0eeab5275275cf5cf5666e5027 /pages/api | |
| parent | Delete .github/workflows/deploy.yml (diff) | |
| download | moopa-4.1.0.tar.xz moopa-4.1.0.zip | |
Update v4.1.0 (#79)v4.1.0
* Update v4.1.0
* Update pages/_app.js
Diffstat (limited to 'pages/api')
| -rw-r--r-- | pages/api/user/profile.js | 103 | ||||
| -rw-r--r-- | pages/api/user/update/episode.js | 2 | ||||
| -rw-r--r-- | pages/api/v2/admin/broadcast/index.js | 40 | ||||
| -rw-r--r-- | pages/api/v2/admin/bug-report/index.js | 49 | ||||
| -rw-r--r-- | pages/api/v2/admin/meta/index.js | 47 | ||||
| -rw-r--r-- | pages/api/v2/episode/[id].js | 121 | ||||
| -rw-r--r-- | pages/api/v2/etc/recent/[page].js | 12 | ||||
| -rw-r--r-- | pages/api/v2/etc/schedule/index.js | 14 | ||||
| -rw-r--r-- | pages/api/v2/info/[id].js | 10 | ||||
| -rw-r--r-- | pages/api/v2/source/index.js | 12 |
10 files changed, 327 insertions, 83 deletions
diff --git a/pages/api/user/profile.js b/pages/api/user/profile.js index 89a23d5..5ca6b75 100644 --- a/pages/api/user/profile.js +++ b/pages/api/user/profile.js @@ -1,71 +1,66 @@ import { getServerSession } from "next-auth"; import { authOptions } from "../auth/[...nextauth]"; -import { - createUser, - deleteUser, - getUser, - updateUser, -} from "../../../prisma/user"; +import { createUser, deleteUser, getUser, updateUser } 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 } = 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, 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); + 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 "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 "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 "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); + 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); + } + } + } + default: { + return res.status(405).json({ message: "Method not allowed" }); + } } - default: { - return res.status(405).json({ message: "Method not allowed" }); - } + } catch (error) { + console.log(error); + return res.status(500).json({ message: "Internal server error" }); } - } catch (error) { - console.log(error); - return res.status(500).json({ message: "Internal server error" }); + } else { + // Not Signed in + res.status(401); } - // } else { - // // Not Signed in - // res.status(401); - // } - // res.end(); + res.end(); } diff --git a/pages/api/user/update/episode.js b/pages/api/user/update/episode.js index 3ee345d..bee98ab 100644 --- a/pages/api/user/update/episode.js +++ b/pages/api/user/update/episode.js @@ -7,7 +7,7 @@ import { deleteList, getEpisode, updateUserEpisode, -} from "../../../../prisma/user"; +} from "@/prisma/user"; export default async function handler(req, res) { const session = await getServerSession(req, res, authOptions); diff --git a/pages/api/v2/admin/broadcast/index.js b/pages/api/v2/admin/broadcast/index.js new file mode 100644 index 0000000..d3d3af0 --- /dev/null +++ b/pages/api/v2/admin/broadcast/index.js @@ -0,0 +1,40 @@ +import { rateLimitStrict, redis } from "@/lib/redis"; +// import { getServerSession } from "next-auth"; +// import { authOptions } from "pages/api/auth/[...nextauth]"; + +export default async function handler(req, res) { + // Check if the custom header "X-Your-Custom-Header" is present and has a specific value + const customHeaderValue = req.headers["x-broadcast-key"]; + + if (customHeaderValue !== "get-broadcast") { + return res.status(401).json({ message: "Unauthorized" }); + } + + try { + if (redis) { + try { + const ipAddress = req.socket.remoteAddress; + await rateLimitStrict.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } + + const getId = await redis.get(`broadcast`); + if (getId) { + const broadcast = JSON.parse(getId); + return res + .status(200) + .json({ message: broadcast.message, startAt: broadcast.startAt }); + } else { + return res.status(200).json({ message: "No broadcast" }); + } + } + + return res.status(200).json({ message: "redis is not defined" }); + } catch (err) { + console.error(err); + res.status(500).json({ error: err.message }); + } +} diff --git a/pages/api/v2/admin/bug-report/index.js b/pages/api/v2/admin/bug-report/index.js new file mode 100644 index 0000000..fc5ee77 --- /dev/null +++ b/pages/api/v2/admin/bug-report/index.js @@ -0,0 +1,49 @@ +import { rateLimitStrict, redis } from "@/lib/redis"; +// import { getServerSession } from "next-auth"; +// import { authOptions } from "pages/api/auth/[...nextauth]"; + +export default async function handler(req, res) { + // const session = await getServerSession(req, res, authOptions); + // const admin = session?.user?.name === process.env.ADMIN_USERNAME; + // create random id each time the endpoint is called + const id = Math.random().toString(36).substr(2, 9); + + // if (!admin) { + // return res.status(401).json({ message: "Unauthorized" }); + // } + const { data } = req.body; + + // if method is not POST return message "Method not allowed" + if (req.method !== "POST") { + return res.status(405).json({ message: "Method not allowed" }); + } + + try { + if (redis) { + try { + const ipAddress = req.socket.remoteAddress; + await rateLimitStrict.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } + + const getId = await redis.get(`report:${id}`); + if (getId) { + return res + .status(200) + .json({ message: `Data already exist for id: ${id}` }); + } + await redis.set(`report:${id}`, JSON.stringify(data)); + return res + .status(200) + .json({ message: `Report has successfully sent, with Id of ${id}` }); + } + + return res.status(200).json({ message: "redis is not defined" }); + } catch (err) { + console.error(err); + res.status(500).json({ error: err.message }); + } +} diff --git a/pages/api/v2/admin/meta/index.js b/pages/api/v2/admin/meta/index.js new file mode 100644 index 0000000..5f51b7f --- /dev/null +++ b/pages/api/v2/admin/meta/index.js @@ -0,0 +1,47 @@ +import { rateLimitStrict, redis } from "@/lib/redis"; +import { getServerSession } from "next-auth"; +import { authOptions } from "pages/api/auth/[...nextauth]"; + +export default async function handler(req, res) { + const session = await getServerSession(req, res, authOptions); + const admin = session?.user?.name === process.env.ADMIN_USERNAME; + + if (!admin) { + return res.status(401).json({ message: "Unauthorized" }); + } + const { id, data } = req.body; + + // if method is not POST return message "Method not allowed" + if (req.method !== "POST") { + return res.status(405).json({ message: "Method not allowed" }); + } + + try { + if (redis) { + try { + const ipAddress = req.socket.remoteAddress; + await rateLimitStrict.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } + + const getId = await redis.get(`meta:${id}`); + if (getId) { + return res + .status(200) + .json({ message: `Data already exist for id: ${id}` }); + } + await redis.set(`meta:${id}`, JSON.stringify(data)); + return res + .status(200) + .json({ message: `Data stored successfully for id: ${id}` }); + } + + return res.status(200).json({ message: "redis is not defined" }); + } catch (err) { + console.error(err); + res.status(500).json({ error: err.message }); + } +} diff --git a/pages/api/v2/episode/[id].js b/pages/api/v2/episode/[id].js index c5d98f5..ab2d321 100644 --- a/pages/api/v2/episode/[id].js +++ b/pages/api/v2/episode/[id].js @@ -1,5 +1,7 @@ import axios from "axios"; -import redis from "../../../../lib/redis"; +import { rateLimitStrict, rateLimiterRedis, redis } from "@/lib/redis"; +import appendImagesToEpisodes from "@/utils/combineImages"; +import appendMetaToEpisodes from "@/utils/appendMetaToEpisodes"; const CONSUMET_URI = process.env.API_URI; const API_KEY = process.env.API_KEY; @@ -23,15 +25,27 @@ async function fetchConsumet(id, dub) { `${CONSUMET_URI}/meta/anilist/episodes/${id}` ); - if (data?.message === "Anime not found") { + if (data?.message === "Anime not found" || data?.length < 1) { return []; } + const reformatted = data.map((item) => ({ + id: item?.id || null, + title: item?.title || null, + img: item?.image || null, + number: item?.number || null, + createdAt: item?.createdAt || null, + description: item?.description || null, + url: item?.url || null, + })); + const array = [ { map: true, providerId: "gogoanime", - episodes: isAscending(data) ? data : data.reverse(), + episodes: isAscending(reformatted) + ? reformatted + : reformatted.reverse(), }, ]; @@ -74,20 +88,60 @@ async function fetchAnify(id) { } } +async function fetchCoverImage(id) { + try { + if (!process.env.API_KEY) { + return []; + } + + const { data } = await axios.get( + `https://api.anify.tv/episode-covers/${id}?apikey=${API_KEY}` + ); + + if (!data) { + return []; + } + + return data; + } catch (error) { + console.error("Error fetching and processing data:", error.message); + return []; + } +} + export default async function handler(req, res) { - const { id, releasing = "false", dub = false } = req.query; + const { id, releasing = "false", dub = false, refresh = null } = req.query; // if releasing is true then cache for 10 minutes, if it false cache for 1 month; const cacheTime = releasing === "true" ? 60 * 10 : 60 * 60 * 24 * 30; let cached; + let meta; if (redis) { - cached = await redis.get(id); - console.log("using redis"); + try { + const ipAddress = req.socket.remoteAddress; + refresh + ? await rateLimitStrict.consume(ipAddress) + : await rateLimiterRedis.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } + + if (refresh) { + await redis.del(id); + console.log("deleted cache"); + } else { + cached = await redis.get(id); + console.log("using redis"); + } + + meta = await redis.get(`meta:${id}`); } - if (cached) { + if (cached && !refresh) { if (dub) { const filtered = JSON.parse(cached).filter((item) => item.episodes.some((epi) => epi.hasDub === true) @@ -96,27 +150,46 @@ export default async function handler(req, res) { } else { return res.status(200).json(JSON.parse(cached)); } - } + } else { + const [consumet, anify, cover] = await Promise.all([ + fetchConsumet(id, dub), + fetchAnify(id), + fetchCoverImage(id), + ]); + + const hasImage = consumet.map((i) => + i.episodes.some( + (e) => e.img !== null || !e.img.includes("https://s4.anilist.co/") + ) + ); - const [consumet, anify] = await Promise.all([ - fetchConsumet(id, dub), - fetchAnify(id), - ]); + const rawData = [...consumet, ...anify]; - const data = [...consumet, ...anify]; + let data = rawData; - if (redis && cacheTime !== null) { - await redis.set(id, JSON.stringify(data), "EX", cacheTime); - } + if (meta) { + data = await appendMetaToEpisodes(rawData, JSON.parse(meta)); + } else if (cover && cover?.length > 0 && !hasImage.includes(true)) + data = await appendImagesToEpisodes(rawData, cover); - if (dub) { - const filtered = data.filter((item) => - item.episodes.some((epi) => epi.hasDub === true) - ); - return res.status(200).json(filtered); - } + if (redis && cacheTime !== null) { + await redis.set( + id, + JSON.stringify(data.filter((i) => i.episodes.length > 0)), + "EX", + cacheTime + ); + } - console.log("fresh data"); + if (dub) { + const filtered = data.filter((item) => + item.episodes.some((epi) => epi.hasDub === true) + ); + return res.status(200).json(filtered); + } - return res.status(200).json(data); + console.log("fresh data"); + + return res.status(200).json(data.filter((i) => i.episodes.length > 0)); + } } diff --git a/pages/api/v2/etc/recent/[page].js b/pages/api/v2/etc/recent/[page].js index 19495c1..6727787 100644 --- a/pages/api/v2/etc/recent/[page].js +++ b/pages/api/v2/etc/recent/[page].js @@ -1,7 +1,19 @@ +import { rateLimiterRedis, redis } from "@/lib/redis"; + const API_URL = process.env.API_URI; export default async function handler(req, res) { try { + if (redis) { + try { + const ipAddress = req.socket.remoteAddress; + await rateLimiterRedis.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } + } const page = req.query.page || 1; var hasNextPage = true; diff --git a/pages/api/v2/etc/schedule/index.js b/pages/api/v2/etc/schedule/index.js index 7a13fff..9b8f43d 100644 --- a/pages/api/v2/etc/schedule/index.js +++ b/pages/api/v2/etc/schedule/index.js @@ -1,6 +1,6 @@ import axios from "axios"; import cron from "cron"; -import redis from "../../../../../lib/redis"; +import { rateLimiterRedis, redis } from "@/lib/redis"; const API_KEY = process.env.API_KEY; @@ -43,6 +43,14 @@ export default async function handler(req, res) { try { let cached; if (redis) { + try { + const ipAddress = req.socket.remoteAddress; + await rateLimiterRedis.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } cached = await redis.get("schedule"); } if (cached) { @@ -60,9 +68,9 @@ export default async function handler(req, res) { 60 * 60 * 24 * 7 ); } - res.status(200).json(data); + return res.status(200).json(data); } else { - res.status(404).json({ message: "Schedule not found" }); + return res.status(404).json({ message: "Schedule not found" }); } } } catch (error) { diff --git a/pages/api/v2/info/[id].js b/pages/api/v2/info/[id].js index 41daa6e..243756c 100644 --- a/pages/api/v2/info/[id].js +++ b/pages/api/v2/info/[id].js @@ -1,5 +1,5 @@ import axios from "axios"; -import redis from "../../../../lib/redis"; +import { rateLimiterRedis, redis } from "@/lib/redis"; const API_KEY = process.env.API_KEY; @@ -19,6 +19,14 @@ export default async function handler(req, res) { const id = req.query.id; let cached; if (redis) { + try { + const ipAddress = req.socket.remoteAddress; + await rateLimiterRedis.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } cached = await redis.get(id); } if (cached) { diff --git a/pages/api/v2/source/index.js b/pages/api/v2/source/index.js index 51ac5ec..74a63cb 100644 --- a/pages/api/v2/source/index.js +++ b/pages/api/v2/source/index.js @@ -1,3 +1,4 @@ +import { rateLimiterRedis, redis } from "@/lib/redis"; import axios from "axios"; const CONSUMET_URI = process.env.API_URI; @@ -33,6 +34,17 @@ export default async function handler(req, res) { return res.status(405).json({ message: "Method not allowed" }); } + if (redis) { + try { + const ipAddress = req.socket.remoteAddress; + await rateLimiterRedis.consume(ipAddress); + } catch (error) { + return res.status(429).json({ + error: `Too Many Requests, retry after ${error.msBeforeNext / 1000}`, + }); + } + } + const { source, providerId, watchId, episode, id, sub = "sub" } = req.body; if (source === "anify") { |