diff options
| author | Factiven <[email protected]> | 2023-07-16 22:35:39 +0700 |
|---|---|---|
| committer | Factiven <[email protected]> | 2023-07-16 22:35:39 +0700 |
| commit | 1eee181e219dfd993d396ac3169e7aad3dd285eb (patch) | |
| tree | 23fe54e9c3f8810f3ac9ab6b29070b4f0d4b9d20 /lib | |
| parent | removed console.log (diff) | |
| download | moopa-1eee181e219dfd993d396ac3169e7aad3dd285eb.tar.xz moopa-1eee181e219dfd993d396ac3169e7aad3dd285eb.zip | |
Update v3.6.4
- Added Manga page with a working tracker for AniList user
- Added schedule component to home page
- Added disqus comment section so you can fight on each other (not recommended)
- Added /id and /en route for english and indonesian subs (id route still work in progress)
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/anilist/AniList.js (renamed from lib/AniList.js) | 0 | ||||
| -rw-r--r-- | lib/anilist/aniAdvanceSearch.js | 68 | ||||
| -rw-r--r-- | lib/anilist/getUpcomingAnime.js | 80 | ||||
| -rw-r--r-- | lib/anilist/useAnilist.js | 126 | ||||
| -rw-r--r-- | lib/apolloClient.js | 20 | ||||
| -rw-r--r-- | lib/useAnilist.js | 221 | ||||
| -rw-r--r-- | lib/useCountdownSeconds.js | 37 |
7 files changed, 311 insertions, 241 deletions
diff --git a/lib/AniList.js b/lib/anilist/AniList.js index f602dad..f602dad 100644 --- a/lib/AniList.js +++ b/lib/anilist/AniList.js diff --git a/lib/anilist/aniAdvanceSearch.js b/lib/anilist/aniAdvanceSearch.js new file mode 100644 index 0000000..bb22ead --- /dev/null +++ b/lib/anilist/aniAdvanceSearch.js @@ -0,0 +1,68 @@ +const advance = ` + query ($search: String, $type: MediaType, $status: MediaStatus, $season: MediaSeason, $seasonYear: Int, $genres: [String], $tags: [String], $sort: [MediaSort], $page: Int, $perPage: Int) { + Page (page: $page, perPage: $perPage) { + pageInfo { + total + currentPage + lastPage + hasNextPage + } + media (search: $search, type: $type, status: $status, season: $season, seasonYear: $seasonYear, genre_in: $genres, tag_in: $tags, sort: $sort, isAdult: false) { + id + title { + userPreferred + } + type + episodes + status + format + season + seasonYear + coverImage { + extraLarge + color + } + averageScore + isAdult + } + } + } +`; + +export async function aniAdvanceSearch(options = {}) { + const { + search = null, + type = "ANIME", + seasonYear = NaN, + season = undefined, + genres = null, + page = 1, + perPage = null, + sort = "POPULARITY_DESC", + } = options; + // console.log(page); + const response = await fetch("https://graphql.anilist.co/", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + query: advance, + variables: { + search: search, + type: type, + seasonYear: seasonYear, + season: season, + genres: genres, + perPage: perPage, + sort: sort, + page: page, + }, + }), + }); + + const datas = await response.json(); + // console.log(datas); + const data = datas.data.Page; + return data; +} diff --git a/lib/anilist/getUpcomingAnime.js b/lib/anilist/getUpcomingAnime.js new file mode 100644 index 0000000..fc848fd --- /dev/null +++ b/lib/anilist/getUpcomingAnime.js @@ -0,0 +1,80 @@ +const getUpcomingAnime = async () => { + // Determine the current season and year + const currentDate = new Date(); + const currentMonth = currentDate.getMonth(); + let currentSeason, currentYear; + + if (currentMonth < 3) { + currentSeason = "WINTER"; + currentYear = currentDate.getFullYear(); + } else if (currentMonth < 6) { + currentSeason = "SPRING"; + currentYear = currentDate.getFullYear(); + } else if (currentMonth < 9) { + currentSeason = "SUMMER"; + currentYear = currentDate.getFullYear(); + } else { + currentSeason = "FALL"; + currentYear = currentDate.getFullYear(); + } + + const query = ` + query ($season: MediaSeason, $seasonYear: Int) { + Page(page: 1, perPage: 20) { + media(season: $season, seasonYear: $seasonYear, sort: POPULARITY_DESC, type: ANIME) { + id + coverImage{ + large + } + bannerImage + title { + english + romaji + native + } + nextAiringEpisode { + episode + airingAt + timeUntilAiring + } + } + } + } + `; + + const variables = { + season: currentSeason, + seasonYear: currentYear, + }; + + let response = await fetch("https://graphql.anilist.co", { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify({ + query, + variables: variables ? variables : undefined, + }), + }); + + let json = await response.json(); + + let currentSeasonAnime = json.data.Page.media; + let nextAiringAnime = currentSeasonAnime.filter( + (anime) => + anime.nextAiringEpisode !== null && anime.nextAiringEpisode.episode === 1 + ); + + if (nextAiringAnime.length >= 1) { + nextAiringAnime.sort( + (a, b) => a.nextAiringEpisode.airingAt - b.nextAiringEpisode.airingAt + ); + return nextAiringAnime; // return all upcoming anime, not just the first two + } + + return null; +}; + +export default getUpcomingAnime; diff --git a/lib/anilist/useAnilist.js b/lib/anilist/useAnilist.js new file mode 100644 index 0000000..4ec55a9 --- /dev/null +++ b/lib/anilist/useAnilist.js @@ -0,0 +1,126 @@ +import { useState, useEffect } from "react"; +import { toast } from "react-toastify"; + +function useMedia(username, accessToken, status) { + const [media, setMedia] = useState([]); + + const fetchGraphQL = async (query, variables) => { + const response = await fetch("https://graphql.anilist.co/", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ query, variables }), + }); + return response.json(); + }; + + useEffect(() => { + if (!username || !accessToken) return; + const queryMedia = ` + query ($username: String, $status: MediaListStatus) { + MediaListCollection(userName: $username, type: ANIME, status: $status) { + lists { + status + name + entries { + id + mediaId + status + progress + score + media { + id + status + nextAiringEpisode { + timeUntilAiring + episode + } + title { + english + romaji + } + episodes + coverImage { + large + } + } + } + } + } + } + `; + fetchGraphQL(queryMedia, { username, status: status?.stats }).then((data) => + setMedia(data.data.MediaListCollection.lists) + ); + }, [username, accessToken, status?.stats]); + + return media; +} + +export function useAniList(session, stats) { + const accessToken = session?.user?.token; + const username = session?.user?.name; + const status = stats || null; + const media = useMedia(username, accessToken, status); + + const fetchGraphQL = async (query, variables) => { + const response = await fetch("https://graphql.anilist.co/", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: accessToken ? `Bearer ${accessToken}` : undefined, + }, + body: JSON.stringify({ query, variables }), + }); + return response.json(); + }; + + const markComplete = (mediaId) => { + if (!accessToken) return; + const completeQuery = ` + mutation($mediaId: Int ) { + SaveMediaListEntry(mediaId: $mediaId, status: COMPLETED) { + id + mediaId + status + } + } + `; + fetchGraphQL(completeQuery, { mediaId }).then((data) => + console.log({ Complete: data }) + ); + }; + + const markProgress = (mediaId, progress, stats, volumeProgress) => { + if (!accessToken) return; + const progressWatched = ` + mutation($mediaId: Int, $progress: Int, $status: MediaListStatus, $progressVolumes: Int) { + SaveMediaListEntry(mediaId: $mediaId, progress: $progress, status: $status, progressVolumes: $progressVolumes) { + id + mediaId + progress + status + } + } + `; + fetchGraphQL(progressWatched, { + mediaId, + progress, + status: stats, + progressVolumes: volumeProgress, + }).then(() => { + console.log(`Progress Updated: ${progress}`); + toast.success(`Progress Updated: ${progress}`, { + position: "bottom-right", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + draggable: true, + theme: "dark", + }); + }); + }; + + return { media, markComplete, markProgress }; +} diff --git a/lib/apolloClient.js b/lib/apolloClient.js deleted file mode 100644 index 8a25156..0000000 --- a/lib/apolloClient.js +++ /dev/null @@ -1,20 +0,0 @@ -import { ApolloClient, DefaultOptions, InMemoryCache } from "@apollo/client"; - -const defaultOptions = { - watchQuery: { - fetchPolicy: "no-cache", - errorPolicy: "ignore", - }, - query: { - fetchPolicy: "no-cache", - errorPolicy: "all", - }, -}; - -const client = new ApolloClient({ - uri: "https://graphql.anilist.co", - cache: new InMemoryCache(), - defaultOptions: defaultOptions, -}); - -export { client }; diff --git a/lib/useAnilist.js b/lib/useAnilist.js deleted file mode 100644 index fc25902..0000000 --- a/lib/useAnilist.js +++ /dev/null @@ -1,221 +0,0 @@ -import { useState, useEffect } from "react"; - -export function useAniList(session, stats) { - const [media, setMedia] = useState([]); - // const [aniAdvanceSearch, setAniAdvanceSearch] = useState([]); - - // Queries - - const queryMedia = ` - query ($username: String, $status: MediaListStatus) { - MediaListCollection(userName: $username, type: ANIME, status: $status) { - lists { - status - name - entries { - id - mediaId - status - progress - score - media { - id - nextAiringEpisode { - timeUntilAiring - episode - } - title { - english - romaji - } - episodes - coverImage { - large - } - } - } - } - } - } - `; - - const advance = ` - query ($search: String, $type: MediaType, $status: MediaStatus, $season: MediaSeason, $seasonYear: Int, $genres: [String], $tags: [String], $sort: [MediaSort], $page: Int, $perPage: Int) { - Page (page: $page, perPage: $perPage) { - pageInfo { - total - currentPage - lastPage - hasNextPage - } - media (search: $search, type: $type, status: $status, season: $season, seasonYear: $seasonYear, genre_in: $genres, tag_in: $tags, sort: $sort, isAdult: false) { - id - title { - userPreferred - } - type - episodes - status - format - season - seasonYear - coverImage { - extraLarge - color - } - averageScore - isAdult - } - } - } - `; - - // Mutations - - const completeQuery = ` - mutation($mediaId: Int ) { - SaveMediaListEntry(mediaId: $mediaId, status: COMPLETED) { - id - mediaId - status - } - } - `; - - const progressWatched = ` - mutation($mediaId: Int, $progress: Int, $status: MediaListStatus) { - SaveMediaListEntry(mediaId: $mediaId, progress: $progress, status: $status) { - id - mediaId - progress - status - } - } - `; - - const username = session?.user?.name; - const accessToken = session?.user?.token; - let statuss = stats || null; - // console.log(session); - - useEffect(() => { - async function fetchData() { - if (!username || !accessToken) return; - - const response = await fetch("https://graphql.anilist.co/", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - query: queryMedia, - variables: { - username: username, - status: statuss?.stats, - }, - }), - }); - - const data = await response.json(); - setMedia(data.data.MediaListCollection.lists); - } - - fetchData(); - }, [queryMedia, username, accessToken, statuss?.stats]); - - async function markComplete(mediaId) { - if (!accessToken) return; - const response = await fetch("https://graphql.anilist.co/", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }, - body: JSON.stringify({ - query: completeQuery, - variables: { - mediaId: mediaId, - }, - }), - }); - if (response.ok) { - const data = await response.json(); - console.log({ Complete: data }); - } else if (response.status === 401) { - console.log("Unauthorized"); - } else if (response.status === 400) { - console.log("validation error"); - } - } - - async function markProgress(mediaId, progress, stats) { - if (!accessToken) return; - const response = await fetch("https://graphql.anilist.co/", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }, - body: JSON.stringify({ - query: progressWatched, - variables: { - mediaId: mediaId, - progress: progress, - status: stats, - }, - }), - }); - if (response.ok) { - console.log(`Progress Updated: ${progress}`); - } else if (response.status === 401) { - console.log("Unauthorized"); - } else if (response.status === 400) { - console.log("validation error"); - } - } - - async function aniAdvanceSearch(options = {}) { - const { - search = null, - type = "ANIME", - seasonYear = NaN, - season = undefined, - genres = null, - page = 1, - perPage = null, - sort = "POPULARITY_DESC", - } = options; - // console.log(page); - const response = await fetch("https://graphql.anilist.co/", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - query: advance, - variables: { - search: search, - type: type, - seasonYear: seasonYear, - season: season, - genres: genres, - perPage: perPage, - sort: sort, - page: page, - }, - }), - }); - - const datas = await response.json(); - // console.log(datas); - const data = datas.data.Page; - return data; - } - - return { - media, - markComplete, - aniAdvanceSearch, - markProgress, - }; -} diff --git a/lib/useCountdownSeconds.js b/lib/useCountdownSeconds.js new file mode 100644 index 0000000..df3cb63 --- /dev/null +++ b/lib/useCountdownSeconds.js @@ -0,0 +1,37 @@ +import { useEffect, useState } from "react"; + +const useCountdown = (targetDate, update) => { + const countDownDate = new Date(targetDate).getTime(); + + const [countDown, setCountDown] = useState( + countDownDate - new Date().getTime() + ); + + useEffect(() => { + const interval = setInterval(() => { + const newCountDown = countDownDate - new Date().getTime(); + setCountDown(newCountDown); + if (newCountDown <= 0 && newCountDown > -1000) { + update(); + } + }, 1000); + + return () => clearInterval(interval); + }, [countDownDate, update]); + + return getReturnValues(countDown); +}; + +const getReturnValues = (countDown) => { + // calculate time left + const days = Math.floor(countDown / (1000 * 60 * 60 * 24)); + const hours = Math.floor( + (countDown % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60) + ); + const minutes = Math.floor((countDown % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((countDown % (1000 * 60)) / 1000); + + return [days, hours, minutes, seconds]; +}; + +export { useCountdown }; |