aboutsummaryrefslogtreecommitdiff
path: root/pages/lib
diff options
context:
space:
mode:
authorFactiven <[email protected]>2023-04-14 00:07:02 +0700
committerFactiven <[email protected]>2023-04-14 00:07:02 +0700
commit482b1c8db5cfeaa20d75ce92fcb10f3ca8433633 (patch)
treef0c12d3acb6bd8ce43e63e01527c97a62dba7e9c /pages/lib
parentUpdate index.js (diff)
downloadmoopa-482b1c8db5cfeaa20d75ce92fcb10f3ca8433633.tar.xz
moopa-482b1c8db5cfeaa20d75ce92fcb10f3ca8433633.zip
Update 5th
Diffstat (limited to 'pages/lib')
-rw-r--r--pages/lib/AniList.js54
-rw-r--r--pages/lib/Artplayer.js54
-rw-r--r--pages/lib/apolloClient.js20
-rw-r--r--pages/lib/mongodb.js30
-rw-r--r--pages/lib/useAnilist.js208
-rw-r--r--pages/lib/useNotify.js41
6 files changed, 407 insertions, 0 deletions
diff --git a/pages/lib/AniList.js b/pages/lib/AniList.js
new file mode 100644
index 0000000..f602dad
--- /dev/null
+++ b/pages/lib/AniList.js
@@ -0,0 +1,54 @@
+export async function aniListData({ sort, page = 1 }) {
+ const resAnilist = await fetch(`https://graphql.anilist.co`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ query: `
+ query (
+ $id: Int
+ $page: Int
+ $perPage: Int
+ $search: String
+ $sort: [MediaSort]
+ ) {
+ Page(page: $page, perPage: $perPage) {
+ pageInfo {
+ total
+ currentPage
+ lastPage
+ hasNextPage
+ perPage
+ }
+ media(id: $id, search: $search, sort: $sort type: ANIME) {
+ id
+ idMal
+ title {
+ romaji
+ english
+ }
+ coverImage {
+ extraLarge
+ }
+ description
+ }
+ }
+ }
+ `,
+ variables: {
+ page: page,
+ perPage: 15,
+ sort,
+ },
+ }),
+ });
+ const anilistData = await resAnilist.json();
+ const data = anilistData.data.Page.media;
+ // console.log(resAnilist);
+ return {
+ props: {
+ data,
+ },
+ };
+}
diff --git a/pages/lib/Artplayer.js b/pages/lib/Artplayer.js
new file mode 100644
index 0000000..49806ed
--- /dev/null
+++ b/pages/lib/Artplayer.js
@@ -0,0 +1,54 @@
+import { useEffect, useRef } from "react";
+import Artplayer from "artplayer";
+import Hls from "hls.js";
+
+export default function Player({ option, getInstance, ...rest }) {
+ const artRef = useRef();
+ function playM3u8(video, url, art) {
+ if (Hls.isSupported()) {
+ const hls = new Hls();
+ hls.loadSource(url);
+ hls.attachMedia(video);
+
+ // optional
+ art.hls = hls;
+ art.once("url", () => hls.destroy());
+ art.once("destroy", () => hls.destroy());
+ } else if (video.canPlayType("application/vnd.apple.mpegurl")) {
+ video.src = url;
+ } else {
+ art.notice.show = "Unsupported playback format: m3u8";
+ }
+ }
+
+ useEffect(() => {
+ const art = new Artplayer({
+ ...option,
+ container: artRef.current,
+ customType: {
+ m3u8: playM3u8,
+ },
+ fullscreen: true,
+ fullscreenWeb: true,
+ hotkey: true,
+ lock: true,
+ autoOrientation: true,
+ theme: "#f97316",
+ icons: {
+ state: "</>",
+ },
+ });
+
+ if (getInstance && typeof getInstance === "function") {
+ getInstance(art);
+ }
+
+ return () => {
+ if (art && art.destroy) {
+ art.destroy(false);
+ }
+ };
+ }, []);
+
+ return <div ref={artRef} {...rest}></div>;
+}
diff --git a/pages/lib/apolloClient.js b/pages/lib/apolloClient.js
new file mode 100644
index 0000000..8a25156
--- /dev/null
+++ b/pages/lib/apolloClient.js
@@ -0,0 +1,20 @@
+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/pages/lib/mongodb.js b/pages/lib/mongodb.js
new file mode 100644
index 0000000..dbbf0dc
--- /dev/null
+++ b/pages/lib/mongodb.js
@@ -0,0 +1,30 @@
+// This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
+import { MongoClient } from "mongodb";
+
+if (!process.env.MONGODB_URI) {
+ throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
+}
+
+const uri = process.env.MONGODB_URI;
+const options = {};
+
+let client;
+let clientPromise;
+
+if (process.env.NODE_ENV === "development") {
+ // In development mode, use a global variable so that the value
+ // is preserved across module reloads caused by HMR (Hot Module Replacement).
+ if (!global._mongoClientPromise) {
+ client = new MongoClient(uri, options);
+ global._mongoClientPromise = client.connect();
+ }
+ clientPromise = global._mongoClientPromise;
+} else {
+ // In production mode, it's best to not use a global variable.
+ client = new MongoClient(uri, options);
+ clientPromise = client.connect();
+}
+
+// Export a module-scoped MongoClient promise. By doing this in a
+// separate module, the client can be shared across functions.
+export default clientPromise;
diff --git a/pages/lib/useAnilist.js b/pages/lib/useAnilist.js
new file mode 100644
index 0000000..12317f8
--- /dev/null
+++ b/pages/lib/useAnilist.js
@@ -0,0 +1,208 @@
+import { useState, useEffect } from "react";
+
+export function useAniList(session) {
+ const [media, setMedia] = useState([]);
+ // const [aniAdvanceSearch, setAniAdvanceSearch] = useState([]);
+
+ // Queries
+
+ const queryMedia = `
+ query ($username: String) {
+ MediaListCollection(userName: $username, type: ANIME) {
+ lists {
+ status
+ name
+ entries {
+ id
+ mediaId
+ status
+ progress
+ score
+ media {
+ id
+ title {
+ english
+ romaji
+ }
+ episodes
+ coverImage {
+ large
+ }
+ }
+ }
+ }
+ }
+ }
+ `;
+
+ const advance = `
+ query ($search: String, $type: MediaType, $status: MediaStatus, $season: MediaSeason, $year: 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: $year, genre_in: $genres, tag_in: $tags, sort: $sort) {
+ id
+ title {
+ userPreferred
+ }
+ type
+ episodes
+ status
+ format
+ 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) {
+ SaveMediaListEntry(mediaId: $mediaId, progress: $progress) {
+ id
+ mediaId
+ progress
+ status
+ }
+ }
+ `;
+
+ const username = session?.user?.name;
+ const accessToken = session?.user?.token;
+
+ 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,
+ },
+ }),
+ });
+
+ const data = await response.json();
+ setMedia(data.data.MediaListCollection.lists);
+ }
+
+ fetchData();
+ }, [queryMedia, username, accessToken]);
+
+ 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) {
+ 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,
+ },
+ }),
+ });
+ if (response.ok) {
+ console.log("Progress Updated");
+ } else if (response.status === 401) {
+ console.log("Unauthorized");
+ } else if (response.status === 400) {
+ console.log("validation error");
+ }
+ }
+
+ async function aniAdvanceSearch(
+ search,
+ type,
+ seasonYear,
+ season,
+ genres,
+ perPage,
+ sort
+ ) {
+ 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: 1,
+ },
+ }),
+ });
+
+ const datas = await response.json();
+ // console.log(search);
+ const data = datas.data.Page;
+ return data;
+ }
+
+ return {
+ media,
+ markComplete,
+ aniAdvanceSearch,
+ markProgress,
+ };
+}
diff --git a/pages/lib/useNotify.js b/pages/lib/useNotify.js
new file mode 100644
index 0000000..e6ba7e6
--- /dev/null
+++ b/pages/lib/useNotify.js
@@ -0,0 +1,41 @@
+import { useState, useCallback } from "react";
+import { motion as m, AnimatePresence } from "framer-motion";
+
+export const useNotification = () => {
+ const [showNotification, setShowNotification] = useState(false);
+ const [notificationMessage, setNotificationMessage] = useState("");
+
+ const show = useCallback(
+ (message) => {
+ setNotificationMessage(message);
+ setShowNotification(true);
+ setTimeout(() => {
+ setShowNotification(false);
+ }, 5000);
+ },
+ [setNotificationMessage, setShowNotification]
+ );
+
+ const NotificationComponent = () => {
+ return (
+ <AnimatePresence>
+ {showNotification && (
+ <m.div
+ key="teasa"
+ transition={{ duration: 0.5 }}
+ initial={{ opacity: 0, y: 100 }}
+ animate={{ opacity: 1, y: 0 }}
+ exit={{ opacity: 0, y: 100 }}
+ className="z-50 fixed bottom-10 w-screen flex justify-center text-center"
+ >
+ <div className="bg-green-600 text-white px-2 py-2 font-bold rounded-[30px]">
+ {notificationMessage}
+ </div>
+ </m.div>
+ )}
+ </AnimatePresence>
+ );
+ };
+
+ return { Notification: NotificationComponent, show };
+};