diff options
| author | Factiven <[email protected]> | 2023-09-26 23:35:35 +0700 |
|---|---|---|
| committer | Factiven <[email protected]> | 2023-09-26 23:35:35 +0700 |
| commit | 20b8a7267827e3a07c1eef668c3b9c22fda43765 (patch) | |
| tree | 2fec9006dfac5737d8b227bf5ccce73880800cc2 /pages | |
| parent | Update release.md (diff) | |
| download | moopa-20b8a7267827e3a07c1eef668c3b9c22fda43765.tar.xz moopa-20b8a7267827e3a07c1eef668c3b9c22fda43765.zip | |
Update v4.1.2v4.1.2
Diffstat (limited to 'pages')
| -rw-r--r-- | pages/_app.js | 4 | ||||
| -rw-r--r-- | pages/admin/index.js | 261 | ||||
| -rw-r--r-- | pages/api/v2/admin/meta/index.js | 6 | ||||
| -rw-r--r-- | pages/en/anime/[...id].js | 4 | ||||
| -rw-r--r-- | pages/en/anime/watch/[...info].js | 38 |
5 files changed, 80 insertions, 233 deletions
diff --git a/pages/_app.js b/pages/_app.js index 9e07d22..f553a98 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -7,9 +7,9 @@ import "react-toastify/dist/ReactToastify.css"; import "react-loading-skeleton/dist/skeleton.css"; import { SkeletonTheme } from "react-loading-skeleton"; import SearchPalette from "@/components/searchPalette"; -import { SearchProvider } from "@/lib/hooks/isOpenState"; +import { SearchProvider } from "@/lib/context/isOpenState"; import Head from "next/head"; -import { WatchPageProvider } from "@/lib/hooks/watchPageProvider"; +import { WatchPageProvider } from "@/lib/context/watchPageProvider"; import { ToastContainer, toast } from "react-toastify"; import { useEffect } from "react"; import { unixTimestampToRelativeTime } from "@/utils/getTimes"; diff --git a/pages/admin/index.js b/pages/admin/index.js index 4fdc8c2..cbb5086 100644 --- a/pages/admin/index.js +++ b/pages/admin/index.js @@ -1,19 +1,14 @@ +import AdminDashboard from "@/components/admin/dashboard"; +import AdminLayout from "@/components/admin/layout"; +import AppendMeta from "@/components/admin/meta/AppendMeta"; +import { + countKeysWithPrefix, + countNumericKeys, + getValuesWithPrefix, +} from "@/utils/getRedisWithPrefix"; import { getServerSession } from "next-auth"; import { authOptions } from "pages/api/auth/[...nextauth]"; -import { useState } from "react"; -import { toast } from "react-toastify"; - -// Define a function to convert the data -function convertData(episodes) { - const convertedData = episodes.map((episode) => ({ - episode: episode.episode, - title: episode?.title, - description: episode?.description || null, - img: episode?.img?.hd || episode?.img?.mobile || null, // Use hd if available, otherwise use mobile - })); - - return convertedData; -} +import React, { useState } from "react"; export async function getServerSideProps(context) { const sessions = await getServerSession( @@ -43,221 +38,49 @@ export async function getServerSideProps(context) { }; } + const [anime, info, meta, report] = await Promise.all([ + countNumericKeys(), + countKeysWithPrefix("anime:"), + countKeysWithPrefix("meta:"), + getValuesWithPrefix("report:"), + ]); + return { props: { session: sessions, + animeCount: anime || 0, + infoCount: info || 0, + metaCount: meta || 0, + report: report || [], api, }, }; } -export default function Admin({ api }) { - const [id, setId] = useState(); - const [resultData, setResultData] = useState(null); - - const [query, setQuery] = useState(""); - const [tmdbId, setTmdbId] = useState(); - const [hasilQuery, setHasilQuery] = useState([]); - const [season, setSeason] = useState(); - - const [override, setOverride] = useState(); - - const [loading, setLoading] = useState(false); - - const handleSearch = async () => { - try { - setLoading(true); - setResultData(null); - const res = await fetch(`${api}/meta/tmdb/${query}`); - const json = await res.json(); - const data = json.results; - setHasilQuery(data); - setLoading(false); - } catch (err) { - console.log(err); - } - }; - - const handleDetail = async () => { - try { - setLoading(true); - const res = await fetch(`${api}/meta/tmdb/info/${tmdbId}?type=TV%20Series -`); - const json = await res.json(); - const data = json.seasons; - setHasilQuery(data); - setLoading(false); - } catch (err) { - console.log(err); - } - }; - - const handleStore = async () => { - try { - setLoading(true); - if (!resultData && !id) { - console.log("No data to store"); - setLoading(false); - return; - } - const data = await fetch("/api/v2/admin/meta", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - id: id, - data: resultData, - }), - }); - if (data.status === 200) { - const json = await data.json(); - toast.success(json.message); - setLoading(false); - } - } catch (err) { - console.log(err); - } - }; - - const handleOverride = async () => { - setResultData(JSON.parse(override)); - }; +export default function Admin({ + animeCount, + infoCount, + metaCount, + report, + api, +}) { + const [page, setPage] = useState(1); return ( - <> - <div className="container mx-auto p-4"> - <h1 className="text-3xl font-semibold mb-4">Append Data Page</h1> - <div> - <div className="space-y-3 mb-4"> - <label>Search Anime:</label> - <input - type="text" - className="w-full px-3 py-2 border rounded-md text-black" - value={query} - onChange={(e) => setQuery(e.target.value)} - /> - <button - type="button" - className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600" - onClick={handleSearch} - > - Find Anime{" "} - {loading && <span className="animate-spin ml-2">🔄</span>} - </button> - </div> - <div className="space-y-3 mb-4"> - <label>Get Episodes:</label> - <input - type="number" - className="w-full px-3 py-2 border rounded-md text-black" - value={tmdbId} - onChange={(e) => setTmdbId(e.target.value)} - /> - <button - type="button" - className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600" - onClick={handleDetail} - > - Get Details{" "} - {loading && <span className="animate-spin ml-2">🔄</span>} - </button> - </div> - - <div className="space-y-3 mb-4"> - <label>Override Result:</label> - <textarea - rows="5" - className="w-full px-3 py-2 border rounded-md text-black" - value={override} - onChange={(e) => setOverride(e.target.value)} - /> - <button - type="button" - className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600" - onClick={handleOverride} - > - Override{" "} - {loading && <span className="animate-spin ml-2">🔄</span>} - </button> - </div> - - <div className="space-y-3 mb-4"> - <label className="block text-sm font-medium text-gray-300"> - Anime ID: - </label> - <input - type="number" - className="w-full px-3 py-2 border rounded-md text-black" - value={id} - onChange={(e) => setId(e.target.value)} - /> - </div> - <div className="mb-4"> - <button - className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600" - onClick={handleStore} - > - Store Data {season && `Season ${season}`} - </button> - </div> - - {hasilQuery?.some((i) => i?.season) && ( - <div className="border rounded-md p-4 mt-4"> - <h2 className="text-lg font-semibold mb-2"> - Which season do you want to format? - </h2> - <div className="w-full flex gap-2"> - {hasilQuery?.map((season, index) => ( - <button - type="button" - className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600" - key={index} - onClick={() => { - setLoading(true); - const data = hasilQuery[index].episodes; - const convertedData = convertData(data); - setSeason(index + 1); - setResultData(convertedData); - console.log(convertedData); - setLoading(false); - }} - > - <p> - {season.season}{" "} - {loading && <span className="animate-spin ml-2">🔄</span>} - </p> - </button> - ))} - </div> - </div> - )} - - {resultData && ( - <div className="border rounded-md p-4 mt-4"> - <h2 className="text-lg font-semibold mb-2">Season {season}</h2> - <pre>{JSON.stringify(resultData, null, 2)}</pre> - </div> - )} - {hasilQuery && ( - <div className="border rounded-md p-4 mt-4"> - <h2 className="text-lg font-semibold mb-2"> - Result Data,{" "} - {hasilQuery.length > 0 && `${hasilQuery.length} Seasons`}: - </h2> - <pre>{JSON.stringify(hasilQuery, null, 2)}</pre> - </div> - )} - </div> - <div> - {/* {resultData && ( - <div className="border rounded-md p-4 mt-4"> - <h2 className="text-lg font-semibold mb-2">Result Data:</h2> - <pre>{JSON.stringify(resultData, null, 2)}</pre> - </div> - )} */} - </div> + <AdminLayout page={page} setPage={setPage}> + <div className="h-full"> + {page == 1 && ( + <AdminDashboard + animeCount={animeCount} + infoCount={infoCount} + metaCount={metaCount} + report={report} + /> + )} + {page == 2 && <AppendMeta api={api} />} + {page == 3 && <p className="flex-center h-full">Coming Soon!</p>} + {page == 4 && <p className="flex-center h-full">Coming Soon!</p>} </div> - </> + </AdminLayout> ); } diff --git a/pages/api/v2/admin/meta/index.js b/pages/api/v2/admin/meta/index.js index 5f51b7f..600a3ef 100644 --- a/pages/api/v2/admin/meta/index.js +++ b/pages/api/v2/admin/meta/index.js @@ -27,12 +27,6 @@ export default async function handler(req, res) { }); } - 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) diff --git a/pages/en/anime/[...id].js b/pages/en/anime/[...id].js index 4809ce5..910bbc6 100644 --- a/pages/en/anime/[...id].js +++ b/pages/en/anime/[...id].js @@ -152,7 +152,7 @@ export default function Info({ info, color }) { <MobileNav sessions={session} hideProfile={true} /> <main className="w-screen min-h-screen relative flex flex-col items-center bg-primary gap-5"> <div className="w-screen absolute"> - <div className="bg-gradient-to-t from-primary from-10% to-transparent absolute h-[280px] w-screen z-10 inset-0 backdrop-blur-[2px]" /> + <div className="bg-gradient-to-t from-primary from-10% to-transparent absolute h-[280px] w-screen z-10 inset-0" /> {info?.bannerImage && ( <Image src={info?.bannerImage} @@ -160,7 +160,7 @@ export default function Info({ info, color }) { height={1000} width={1000} blurDataURL={info?.bannerImage} - className="object-cover bg-image w-screen absolute top-0 left-0 h-[250px] brightness-[55%] z-0" + className="object-cover bg-image blur-[2px] w-screen absolute top-0 left-0 h-[250px] brightness-[55%] z-0" /> )} </div> diff --git a/pages/en/anime/watch/[...info].js b/pages/en/anime/watch/[...info].js index f5b4fce..b74a3f2 100644 --- a/pages/en/anime/watch/[...info].js +++ b/pages/en/anime/watch/[...info].js @@ -4,7 +4,7 @@ import { FlagIcon, ShareIcon } from "@heroicons/react/24/solid"; import Details from "@/components/watch/primary/details"; import EpisodeLists from "@/components/watch/secondary/episodeLists"; import { getServerSession } from "next-auth"; -import { useWatchProvider } from "@/lib/hooks/watchPageProvider"; +import { useWatchProvider } from "@/lib/context/watchPageProvider"; import { authOptions } from "../../../api/auth/[...nextauth]"; import { createList, createUser, getEpisode } from "@/prisma/user"; import Link from "next/link"; @@ -289,6 +289,29 @@ export default function Watch({ }; }, [provider, watchId, info?.id]); + useEffect(() => { + const mediaSession = navigator.mediaSession; + if (!mediaSession) return; + + const now = episodeNavigation?.playing; + const poster = now?.img || info?.bannerImage; + const title = now?.title || info?.title?.romaji; + + const artwork = poster + ? [{ src: poster, sizes: "512x512", type: "image/jpeg" }] + : undefined; + + mediaSession.metadata = new MediaMetadata({ + title: title, + artist: `Moopa ${ + title === info?.title?.romaji + ? "- Episode " + epiNumber + : `- ${info?.title?.romaji || info?.title?.english}` + }`, + artwork, + }); + }, [episodeNavigation, info, epiNumber]); + const handleShareClick = async () => { try { if (navigator.share) { @@ -338,7 +361,6 @@ export default function Watch({ <meta name="robots" content="index, follow" /> <meta property="og:type" content="website" /> - <meta property="og:url" content="https://moopa.live/" /> <meta property="og:title" content={`Watch - ${ @@ -347,12 +369,19 @@ export default function Watch({ /> <meta property="og:description" - content="Discover your new favorite anime or manga title! Moopa offers a vast library of high-quality content, accessible on multiple devices and without any interruptions. Start using Moopa today!" + content={episodeNavigation?.playing?.description || info?.description} + /> + <meta + property="og:image" + content={episodeNavigation?.playing?.img || info?.bannerImage} /> - <meta property="og:image" content="/preview.png" /> <meta property="og:site_name" content="Moopa" /> <meta name="twitter:card" content="summary_large_image" /> <meta + name="twitter:image" + content={episodeNavigation?.playing?.img || info?.bannerImage} + /> + <meta name="twitter:title" content={`Watch - ${ episodeNavigation?.playing?.title || info?.title?.english @@ -499,6 +528,7 @@ export default function Watch({ > <EpisodeLists info={info} + session={sessions} map={mapEpisode} providerId={provider} watchId={watchId} |