diff --git a/components/home/content.tsx b/components/home/content.tsx index b193381..e1886b6 100644 --- a/components/home/content.tsx +++ b/components/home/content.tsx @@ -321,7 +321,7 @@ export default function Content({ ? `/en/anime/watch/${ anime.id }/gogoanime?id=${encodeURIComponent( - anime?.slug + anime?.slug?.replace('/', '') )}&num=${anime.currentEpisode}` : `/en/${type}/${anime.id}` : `/en/${type}/${anime.id}` diff --git a/components/shared/changelogs.tsx b/components/shared/changelogs.tsx index 2a8a843..b39eeac 100644 --- a/components/shared/changelogs.tsx +++ b/components/shared/changelogs.tsx @@ -3,22 +3,37 @@ import Link from "next/link"; import { Fragment, useEffect, useRef, useState } from "react"; const web = { - version: "v4.4.0", + version: "v4.4.1" }; const logs = [ { - version: "v4.4.0", + version: "v4.4.1", pre: false, notes: null, highlights: true, changes: [ + "New player layout for mobile devices", + "Added seek buttons in the player", + "Added previous and next episode buttons in the player", "Added rate modal when user finished watching the whole series", "Fix: only half of the episodes has episodes thumbnail", "Fix: pressing back button in anime info page redirects user to the wrong page", - "Progressively migrate codebase to typescript", - ], - }, + "Progressively migrate codebase to typescript" + ] + } + // { + // version: "v4.4.0", + // pre: false, + // notes: null, + // highlights: false, + // changes: [ + // "Added rate modal when user finished watching the whole series", + // "Fix: only half of the episodes has episodes thumbnail", + // "Fix: pressing back button in anime info page redirects user to the wrong page", + // "Progressively migrate codebase to typescript" + // ] + // } // { // version: "v4.3.1", // pre: true, @@ -221,7 +236,7 @@ export function ChangelogsVersions({ pre, notes, highlights, - children, + children }: ChangelogsVersionsProps) { return ( <> diff --git a/components/watch/new-player/components/buttons.tsx b/components/watch/new-player/components/buttons.tsx index b8b5b57..eaa23aa 100644 --- a/components/watch/new-player/components/buttons.tsx +++ b/components/watch/new-player/components/buttons.tsx @@ -11,6 +11,7 @@ import { type TooltipPlacement, useMediaRemote, useMediaStore, + SeekButton } from "@vidstack/react"; import { ClosedCaptionsIcon, @@ -29,23 +30,26 @@ import { VolumeHighIcon, VolumeLowIcon, PreviousIcon, + SeekForward10Icon, + SeekBackward10Icon } from "@vidstack/react/icons"; import { useRouter } from "next/router"; import { Navigation } from "../player"; export interface MediaButtonProps { tooltipPlacement: TooltipPlacement; + offset?: number | undefined; navigation?: Navigation; host?: boolean; } export const buttonClass = - "group ring-media-focus relative inline-flex h-10 w-10 cursor-pointer items-center justify-center rounded-md outline-none ring-inset hover:bg-white/20 data-[focus]:ring-4"; + "group ring-media-focus relative inline-flex h-10 w-10 cursor-pointer items-center justify-center rounded-md outline-none ring-inset sm:hover:bg-white/20 data-[focus]:ring-4 z-30"; export const tooltipClass = "animate-out fade-out slide-out-to-bottom-2 data-[visible]:animate-in data-[visible]:fade-in data-[visible]:slide-in-from-bottom-4 z-10 rounded-sm bg-black/90 px-2 py-0.5 text-sm font-medium text-white parent-data-[open]:hidden"; -export function Play({ tooltipPlacement }: MediaButtonProps) { +export function Play({ tooltipPlacement, offset }: MediaButtonProps) { const isPaused = useMediaState("paused"), ended = useMediaState("ended"), tooltipText = isPaused ? "Play" : "Pause", @@ -57,39 +61,95 @@ export function Play({ tooltipPlacement }: MediaButtonProps) { - + {tooltipText} ); } +export function SeekForwardButton({ + tooltipPlacement, + offset +}: MediaButtonProps) { + return ( + + + + + + + + Forward 10 Seconds + + + ); +} + +export function SeekBackwardButton({ + tooltipPlacement, + offset +}: MediaButtonProps) { + return ( + + + + + + + + Backward 10 Seconds + + + ); +} + export function NextEpisode({ tooltipPlacement, - navigation, + offset, + navigation }: MediaButtonProps) { const router = useRouter(); const { dataMedia, track } = useWatchProvider(); + function handleNext() { + router.push( + `/en/anime/watch/${dataMedia.id}/${track?.provider}?id=${ + navigation?.next?.id + }&num=${navigation?.next?.number}${ + track?.isDub ? `&dub=${track?.isDub}` : "" + }` + ); + } + return ( navigation?.next && ( - { - router.push( - `/en/anime/watch/${dataMedia.id}/${track?.provider}?id=${ - navigation?.next?.id - }&num=${navigation?.next?.number}${ - track?.isDub ? `&dub=${track?.isDub}` : "" - }` - ); - }} + - - + + - + Next Episode @@ -99,30 +159,38 @@ export function NextEpisode({ export function PreviousEpisode({ tooltipPlacement, - navigation, + offset, + navigation }: MediaButtonProps) { const router = useRouter(); const { dataMedia, track } = useWatchProvider(); + function handlePrev() { + router.push( + `/en/anime/watch/${dataMedia.id}/${track?.provider}?id=${ + navigation?.prev?.id + }&num=${navigation?.prev?.number}${ + track?.isDub ? `&dub=${track?.isDub}` : "" + }` + ); + } + return ( navigation?.prev && ( - - { - router.push( - `/en/anime/watch/${dataMedia.id}/${track?.provider}?id=${ - navigation?.prev?.id - }&num=${navigation?.prev?.number}${ - track?.isDub ? `&dub=${track?.isDub}` : "" - }` - ); - }} + + - - + + - + Previous Episode @@ -135,27 +203,17 @@ export function MobilePlayButton({ tooltipPlacement, host }: MediaButtonProps) { ended = useMediaState("ended"), Icon = ended ? ReplayIcon : isPaused ? PlayIcon : PauseIcon; return ( - - - - - - - {/* - {tooltipText} - */} - + + + ); } -export function Mute({ tooltipPlacement }: MediaButtonProps) { +export function Mute({ tooltipPlacement, offset }: MediaButtonProps) { const volume = useMediaState("volume"), isMuted = useMediaState("muted"); return ( @@ -171,14 +229,18 @@ export function Mute({ tooltipPlacement }: MediaButtonProps) { )} - + {isMuted ? "Unmute" : "Mute"} ); } -export function Caption({ tooltipPlacement }: MediaButtonProps) { +export function Caption({ tooltipPlacement, offset }: MediaButtonProps) { const track = useMediaState("textTrack"), isOn = track && isTrackCaptionKind(track); return ( @@ -192,14 +254,18 @@ export function Caption({ tooltipPlacement }: MediaButtonProps) { )} - + {isOn ? "Closed-Captions On" : "Closed-Captions Off"} ); } -export function TheaterButton({ tooltipPlacement }: MediaButtonProps) { +export function TheaterButton({ tooltipPlacement, offset }: MediaButtonProps) { const playerState = useMediaState("currentTime"), isPlaying = useMediaState("playing"); @@ -215,7 +281,7 @@ export function TheaterButton({ tooltipPlacement }: MediaButtonProps) { setPlayerState((prev: any) => ({ ...prev, currentTime: playerState, - isPlaying: isPlaying, + isPlaying: isPlaying })); setTheaterMode((prev: any) => !prev); }} @@ -227,14 +293,18 @@ export function TheaterButton({ tooltipPlacement }: MediaButtonProps) { )} - + Theatre Mode ); } -export function PIP({ tooltipPlacement }: MediaButtonProps) { +export function PIP({ tooltipPlacement, offset }: MediaButtonProps) { const isActive = useMediaState("pictureInPicture"); return ( @@ -247,7 +317,11 @@ export function PIP({ tooltipPlacement }: MediaButtonProps) { )} - + {isActive ? "Exit PIP" : "Enter PIP"} @@ -256,7 +330,7 @@ export function PIP({ tooltipPlacement }: MediaButtonProps) { export function PlayNextButton({ tooltipPlacement, - navigation, + navigation }: MediaButtonProps) { // const remote = useMediaRemote(); const router = useRouter(); @@ -276,14 +350,14 @@ export function PlayNextButton({ ); } }} - className="next-button hidden" + className="next-button text-sm hidden" > Next Episode ); } -export function SkipOpButton({ tooltipPlacement }: MediaButtonProps) { +export function SkipOpButton({ tooltipPlacement, offset }: MediaButtonProps) { const remote = useMediaRemote(); const { track } = useWatchProvider(); const op = track?.skip?.find((item: any) => item.text === "Opening"); @@ -294,14 +368,14 @@ export function SkipOpButton({ tooltipPlacement }: MediaButtonProps) { onClick={() => { remote.seek(op?.endTime); }} - className="op-button hidden hover:bg-white/80 bg-white px-4 py-2 text-primary font-karla font-semibold rounded-md" + className="op-button hidden text-sm hover:bg-white/80 bg-white px-4 py-2 text-primary font-karla font-semibold rounded-md" > Skip Opening ); } -export function SkipEdButton({ tooltipPlacement }: MediaButtonProps) { +export function SkipEdButton({ tooltipPlacement, offset }: MediaButtonProps) { const remote = useMediaRemote(); const { duration } = useMediaStore(); const { track } = useWatchProvider(); @@ -317,14 +391,14 @@ export function SkipEdButton({ tooltipPlacement }: MediaButtonProps) { title="ed-button" type="button" onClick={() => remote.seek(endTime)} - className="ed-button hidden cursor-pointer hover:bg-white/80 bg-white px-4 py-2 text-primary font-karla font-semibold rounded-md" + className="ed-button hidden text-sm cursor-pointer hover:bg-white/80 bg-white px-4 py-2 text-primary font-karla font-semibold rounded-md" > Skip Ending ); } -export function Fullscreen({ tooltipPlacement }: MediaButtonProps) { +export function Fullscreen({ tooltipPlacement, offset }: MediaButtonProps) { const isActive = useMediaState("fullscreen"); return ( @@ -337,7 +411,11 @@ export function Fullscreen({ tooltipPlacement }: MediaButtonProps) { )} - + {isActive ? "Exit Fullscreen" : "Enter Fullscreen"} diff --git a/components/watch/new-player/components/layouts/video-layout.tsx b/components/watch/new-player/components/layouts/video-layout.tsx index 8d4ec01..d16dc9c 100644 --- a/components/watch/new-player/components/layouts/video-layout.tsx +++ b/components/watch/new-player/components/layouts/video-layout.tsx @@ -6,7 +6,8 @@ import { Controls, Gesture, Spinner, - useMediaState, + Time, + useMediaState } from "@vidstack/react"; import * as Buttons from "../buttons"; @@ -41,7 +42,7 @@ export function VideoLayout({ thumbnails, navigation, host = true, - session, + session }: VideoLayoutProps) { const [isMobile, setIsMobile] = useState(false); @@ -56,7 +57,7 @@ export function VideoLayout({ setRatingModalState((prev: any) => { return { ...prev, - isFullscreen: isFullscreen, + isFullscreen: isFullscreen }; }); }, [isFullscreen]); @@ -65,7 +66,7 @@ export function VideoLayout({ <> {ratingModalState.isFullscreen && ( )} + + {/* TOP CONTROLS */} + - {/* */} + + {!!track?.subtitles?.length && ( + + )} + + + + - {/* {isPaused && ( */} - {/* )} */} + {/* MOBILE CENTER */} + + + + + + + + + {/* LOADING */} - {/* */} @@ -118,15 +145,16 @@ export function VideoLayout({ )} - + {/* DESKTOP CONTROLS */} + - + - + @@ -136,6 +164,8 @@ export function VideoLayout({ {!!track?.subtitles?.length && ( )} + + {!isMobile && !isFullscreen && ( @@ -143,6 +173,32 @@ export function VideoLayout({ + + {/* MOBILE CONTROLS */} + + + + + + + + + + + + + + + + > ); diff --git a/components/watch/new-player/components/menus.tsx b/components/watch/new-player/components/menus.tsx index de2b302..7a28eec 100644 --- a/components/watch/new-player/components/menus.tsx +++ b/components/watch/new-player/components/menus.tsx @@ -12,7 +12,7 @@ import { type TooltipPlacement, useVideoQualityOptions, useMediaState, - usePlaybackRateOptions, + usePlaybackRateOptions } from "@vidstack/react"; import { ChevronLeftIcon, @@ -25,7 +25,7 @@ import { // EpisodesIcon, SettingsSwitchIcon, // PlaybackSpeedCircleIcon, - OdometerIcon, + OdometerIcon } from "@vidstack/react/icons"; import { buttonClass, tooltipClass } from "./buttons"; @@ -34,6 +34,7 @@ import React from "react"; export interface SettingsProps { placement: MenuPlacement; + offset?: number; tooltipPlacement: TooltipPlacement; } @@ -44,10 +45,15 @@ export const submenuClass = "hidden w-full flex-col items-start justify-center outline-none data-[keyboard]:mt-[3px] data-[open]:inline-block"; export const contentMenuClass = - "flex cust-scroll h-[var(--menu-height)] max-h-[180px] lg:max-h-[400px] min-w-[260px] flex-col overflow-y-auto overscroll-y-contain rounded-md border border-white/10 bg-secondary p-2 font-sans text-[15px] font-medium outline-none backdrop-blur-sm transition-[height] duration-300 will-change-[height] data-[resizing]:overflow-hidden"; + "flex cust-scroll h-[var(--menu-height)] max-h-[180px] lg:max-h-[400px] min-w-[260px] flex-col overflow-y-auto overscroll-y-contain rounded-md border border-white/10 bg-secondary p-1 font-sans text-[15px] font-medium outline-none backdrop-blur-sm transition-[height] duration-300 will-change-[height] data-[resizing]:overflow-hidden"; -export function Settings({ placement, tooltipPlacement }: SettingsProps) { +export function Settings({ + placement, + offset, + tooltipPlacement +}: SettingsProps) { const { track } = useWatchProvider(); + const isFullscreen = useMediaState("fullscreen"); const isSubtitleAvailable = track?.epiData?.subtitles?.length > 0; return ( @@ -58,21 +64,33 @@ export function Settings({ placement, tooltipPlacement }: SettingsProps) { - + Settings - {/* - {isSubtitleAvailable && } - - */} - - - - - {isSubtitleAvailable && } - - + {!isFullscreen ? ( + + + + + + {isSubtitleAvailable && } + + + + ) : ( + + + + + {isSubtitleAvailable && } + + + )} ); } @@ -194,13 +212,13 @@ function AutoPlay() { { label: "On", value: "on", - selected: false, + selected: false }, { label: "Off", value: "off", - selected: true, - }, + selected: true + } ]); const { autoplay, setAutoPlay } = useWatchProvider(); @@ -254,13 +272,13 @@ function AutoNext() { { label: "On", value: "on", - selected: false, + selected: false }, { label: "Off", value: "off", - selected: true, - }, + selected: true + } ]); const { autoNext, setAutoNext } = useWatchProvider(); @@ -368,7 +386,7 @@ function SubmenuButton({ label, hint, icon: Icon, - disabled, + disabled }: SubmenuButtonProps) { return ( {(cues, forwardRef) => @@ -39,7 +39,7 @@ export function Time({ thumbnails, host }: TimeSliderProps) { key={cue.startTime} ref={forwardRef} > - + diff --git a/components/watch/new-player/player.module.css b/components/watch/new-player/player.module.css index f2f5b39..4b4743e 100644 --- a/components/watch/new-player/player.module.css +++ b/components/watch/new-player/player.module.css @@ -11,7 +11,7 @@ color: #f5f5f5; contain: layout; font-family: sans-serif; - overflow: hidden; + /* overflow: hidden; */ } .player[data-focus]:not([data-playing]) { diff --git a/components/watch/new-player/player.tsx b/components/watch/new-player/player.tsx index f2d11f7..5e25a61 100644 --- a/components/watch/new-player/player.tsx +++ b/components/watch/new-player/player.tsx @@ -11,7 +11,7 @@ import { useMediaRemote, type MediaPlayerInstance, Track, - MediaTimeUpdateEventDetail, + MediaTimeUpdateEventDetail } from "@vidstack/react"; import { VideoLayout } from "./components/layouts/video-layout"; import { useWatchProvider } from "@/lib/context/watchPageProvider"; @@ -86,7 +86,7 @@ export default function VidStack({ id, navigation, userData, - sessions, + sessions }: VidStackProps) { let player = useRef(null); @@ -97,7 +97,7 @@ export default function VidStack({ playerState, dataMedia, autoNext, - setRatingModalState, + setRatingModalState } = useWatchProvider(); const { qualities, duration } = useMediaStore(player); @@ -193,8 +193,8 @@ export default function VidStack({ provider: track?.provider, nextId: navigation?.next?.id, nextNumber: Number(navigation?.next?.number), - dub: track?.isDub ? true : false, - }), + dub: track?.isDub ? true : false + }) }); } @@ -214,7 +214,7 @@ export default function VidStack({ nextId: navigation?.next?.id, nextNumber: navigation?.next?.number, dub: track?.isDub ? true : false, - createdAt: new Date().toISOString(), + createdAt: new Date().toISOString() }); // console.log("update"); }, 5000); @@ -256,58 +256,49 @@ export default function VidStack({ }, [playerState?.currentTime, playerState?.isPlaying]); useEffect(() => { - const chapter = track?.skip, - videoDuration = Math.round(duration); + const chapter = track?.skip; + const videoDuration = Math.round(duration); + + if (!chapter || chapter.length === 0 || !player.current) { + // Handle cases where there's no chapter data or player is not ready + setChapters(""); + return; + } let vtt = "WEBVTT\n\n"; - let lastEndTime = 0; - - if (chapter && chapter?.length > 0) { - chapter.forEach((item: SkipData) => { - let startMinutes = Math.floor(item.startTime / 60); - let startSeconds = item.startTime % 60; - let endMinutes = Math.floor(item.endTime / 60); - let endSeconds = item.endTime % 60; - - let start = `${startMinutes.toString().padStart(2, "0")}:${startSeconds - .toString() - .padStart(2, "0")}`; - let end = `${endMinutes.toString().padStart(2, "0")}:${endSeconds - .toString() - .padStart(2, "0")}`; - - vtt += `${start} --> ${end}\n${item.text}\n\n`; - if (item.endTime > lastEndTime) { - lastEndTime = item.endTime; - } - }); - - if (lastEndTime < videoDuration) { - let startMinutes = Math.floor(lastEndTime / 60); - let startSeconds = lastEndTime % 60; - let endMinutes = Math.floor(videoDuration / 60); - let endSeconds = videoDuration % 60; - - let start = `${startMinutes.toString().padStart(2, "0")}:${startSeconds - .toString() - .padStart(2, "0")}`; - let end = `${endMinutes.toString().padStart(2, "0")}:${endSeconds - .toString() - .padStart(2, "0")}`; - - vtt += `${start} --> ${end}\n\n\n`; + chapter.forEach((item: { endTime: any; startTime: any; text: any }) => { + if (!item.endTime) { + // Handle missing endTime gracefully + console.warn("Skipping item with missing endTime:", item); + return; } - const vttBlob = new Blob([vtt], { type: "text/vtt" }); - const vttUrl = URL.createObjectURL(vttBlob); + const [startMinutes, startSeconds] = formatTime(item.startTime); + const [endMinutes, endSeconds] = formatTime(item.endTime); + + vtt += `${startMinutes}:${startSeconds} --> ${endMinutes}:${endSeconds}\n${item.text}\n\n`; + }); - setChapters(vttUrl); + if (chapter[chapter.length - 1].endTime < videoDuration) { + // Add a final chapter if needed + const [startMinutes, startSeconds] = formatTime( + chapter[chapter.length - 1].endTime + ); + const [endMinutes, endSeconds] = formatTime(videoDuration); + vtt += `${startMinutes}:${startSeconds} --> ${endMinutes}:${endSeconds}\n\n\n`; } + + const vttBlob = new Blob([vtt], { type: "text/vtt" }); + const vttUrl = URL.createObjectURL(vttBlob); + + setChapters(vttUrl); + return () => { setChapters(""); + URL.revokeObjectURL(vttUrl); // Clean up VTT URL }; - }, [track?.skip, duration]); + }, [track?.skip, duration, player.current]); useEffect(() => { return () => { @@ -315,7 +306,7 @@ export default function VidStack({ player.current.destroy(); } }; - }, []); + }, [id]); function onEnded() { if (!navigation?.next?.id) return; @@ -382,14 +373,14 @@ export default function VidStack({ // @ts-ignore Fix when convert useAnilist to typescript markProgress({ mediaId: dataMedia.id, - progress: navigation.playing.number, + progress: navigation.playing.number }); if (dataMedia.episodes === +navigation.playing?.number) { setRatingModalState((prev: any) => { return { ...prev, - isOpen: true, + isOpen: true }; }); } @@ -447,7 +438,7 @@ export default function VidStack({ crossorigin="anonymous" src={{ src: defaultQuality?.url, - type: "application/vnd.apple.mpegurl", + type: "application/vnd.apple.mpegurl" }} onTimeUpdate={onTimeUpdate} playsinline @@ -486,3 +477,12 @@ export function calculateAspectRatio(width: number, height: number) { const aspectRatio = `${width / divisor}/${height / divisor}`; return aspectRatio; } + +function formatTime(timeInSeconds: number) { + const minutes = Math.floor(timeInSeconds / 60); + const seconds = Math.floor(timeInSeconds % 60); + return [ + minutes.toString().padStart(2, "0"), + seconds.toString().padStart(2, "0") + ]; +} diff --git a/components/watch/primary/details.tsx b/components/watch/primary/details.tsx index dd739f2..4ff1be5 100644 --- a/components/watch/primary/details.tsx +++ b/components/watch/primary/details.tsx @@ -28,7 +28,7 @@ export default function Details({ onList, setOnList, handleOpen, - disqus, + disqus }: DetailsProps) { const [showComments, setShowComments] = useState(false); const { markPlanning } = useAniList(session); @@ -65,7 +65,7 @@ export default function Details({ {info ? ( 420 ? truncatedDesc - : description, + : description }} className={`p-5 text-sm font-light font-roboto text-[#e4e4e4] `} /> @@ -224,7 +224,7 @@ export default function Details({ title: info.title.romaji, url: window.location.href, episode: epiNumber, - name: disqus, + name: disqus }} /> diff --git a/package-lock.json b/package-lock.json index 6c651cc..3447d17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@heroicons/react": "^2.0.17", "@prisma/client": "^5.3.1", "@vercel/og": "^0.5.4", - "@vidstack/react": "^1.8.3", + "@vidstack/react": "^1.9.8", "axios": "^1.4.0", "cookies": "^0.8.0", "cron": "^2.4.0", @@ -2682,9 +2682,9 @@ } }, "node_modules/@vidstack/react": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@vidstack/react/-/react-1.8.3.tgz", - "integrity": "sha512-QCyHy6e3LpzfajtjrhJPXzGYbBrBCUE5qYAatKXX+nxWqRvspa0fJPlnGeWb+tg6DlDsgwDLFjGNWj8qUeUVXQ==", + "version": "1.9.8", + "resolved": "https://registry.npmjs.org/@vidstack/react/-/react-1.9.8.tgz", + "integrity": "sha512-1gGlCXpmGriKZ+sgP1WLgm4tpkU2buXeAIPFoh8t7V4X3jV1l15oZS4whfPswCY6/9jAwVKq0jQBLryAuBYZww==", "dependencies": { "media-captions": "^1.0.1" }, @@ -5178,9 +5178,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", diff --git a/package.json b/package.json index 6f77d24..59e73cb 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "moopa", - "version": "4.4.0", + "version": "4.4.1", "private": true, "founder": "Factiven", "scripts": { "dev": "next dev", - "build": "next build", + "build": "npx prisma migrate deploy && npx prisma generate && next build", "export": "next build && next export", "start": "next start", "type-check": "tsc", @@ -16,7 +16,7 @@ "@heroicons/react": "^2.0.17", "@prisma/client": "^5.3.1", "@vercel/og": "^0.5.4", - "@vidstack/react": "^1.8.3", + "@vidstack/react": "^1.9.8", "axios": "^1.4.0", "cookies": "^0.8.0", "cron": "^2.4.0", diff --git a/pages/en/anime/watch/[...info].js b/pages/en/anime/watch/[...info].js index 0f8dff9..445d220 100644 --- a/pages/en/anime/watch/[...info].js +++ b/pages/en/anime/watch/[...info].js @@ -29,7 +29,7 @@ export async function getServerSideProps(context) { const query = context?.query; if (!query) { return { - notFound: true, + notFound: true }; } @@ -53,8 +53,8 @@ export async function getServerSideProps(context) { return { redirect: { destination: "/en/removed", - permanent: false, - }, + permanent: false + } }; } @@ -62,7 +62,7 @@ export async function getServerSideProps(context) { method: "POST", headers: { "Content-Type": "application/json", - ...(accessToken && { Authorization: `Bearer ${accessToken}` }), + ...(accessToken && { Authorization: `Bearer ${accessToken}` }) }, body: JSON.stringify({ query: `query ($id: Int) { @@ -103,9 +103,9 @@ export async function getServerSideProps(context) { } `, variables: { - id: aniId, - }, - }), + id: aniId + } + }) }); const data = await ress.json(); // const variables = { id: aniId }; @@ -139,8 +139,8 @@ export async function getServerSideProps(context) { userData: userData?.[0] || null, info: data?.data?.Media || null, proxy, - disqus, - }, + disqus + } }; } @@ -153,7 +153,7 @@ export default function Watch({ userData, sessions, provider, - epiNumber, + epiNumber }) { const [artStorage, setArtStorage] = useState(null); @@ -178,7 +178,7 @@ export default function Watch({ setMarked, setTrack, aspectRatio, - setDataMedia, + setDataMedia } = useWatchProvider(); useEffect(() => { @@ -238,9 +238,9 @@ export default function Watch({ title: playingData?.title || info?.title?.romaji, description: playingData?.description, img: playingData?.img || playingData?.image, - number: currentEpisode.number, + number: currentEpisode.number }, - next: nextEpisode, + next: nextEpisode }; setEpisodeNavigation(vidNav); } @@ -272,7 +272,7 @@ export default function Watch({ const anify = await fetch("/api/v2/source", { method: "POST", headers: { - "Content-Type": "application/json", + "Content-Type": "application/json" }, body: JSON.stringify({ source: @@ -283,8 +283,8 @@ export default function Watch({ watchId: watchId, episode: epiNumber, id: info.id, - sub: dub ? "dub" : "sub", - }), + sub: dub ? "dub" : "sub" + }) }).then((res) => res.json()); if (!anify?.sources?.length > 0) { @@ -317,14 +317,14 @@ export default function Watch({ anify?.intro?.start ?? Math.round(getOp?.interval.startTime), endTime: anify?.intro?.end ?? Math.round(getOp?.interval.endTime), - text: "Opening", + text: "Opening" } : null, ed = { startTime: anify?.outro?.start ?? Math.round(getEd?.interval.startTime), endTime: anify?.outro?.end ?? Math.round(getEd?.interval.endTime), - text: "Ending", + text: "Ending" }; const skipData = [op, ed].filter((i) => i !== null); @@ -338,7 +338,7 @@ export default function Watch({ src: proxy + "/" + i.url, label: i.lang, kind: i.lang === "Thumbnails" ? "thumbnails" : "subtitles", - ...(i.lang === "English" && { default: true }), + ...(i.lang === "English" && { default: true }) }; }); @@ -358,12 +358,12 @@ export default function Watch({ url: `${proxy}/proxy/m3u8/${encodeURIComponent( String(quality?.url) )}/${encodeURIComponent(JSON.stringify(anify?.headers))}`, - headers: anify?.headers, + headers: anify?.headers }, subtitles: subtitles, thumbnails: thumbnails?.src, epiData: anify, - skip: skipData, + skip: skipData }; setTrack(episode); @@ -374,7 +374,7 @@ export default function Watch({ return () => { setPlayerState({ currentTime: 0, - isPlaying: false, + isPlaying: false }); setMarked(0); setTrack(null); @@ -402,7 +402,7 @@ export default function Watch({ ? "- Episode " + epiNumber : `- ${info?.title?.romaji || info?.title?.english}` }`, - artwork, + artwork }); }, [episodeNavigation, info, epiNumber]); @@ -412,7 +412,7 @@ export default function Watch({ await navigator.share({ title: `Watch Now - ${info?.title?.english || info.title.romaji}`, // text: `Watch [${info?.title?.romaji}] and more on Moopa. Join us for endless anime entertainment"`, - url: window.location.href, + url: window.location.href }); } else { // Web Share API is not supported, provide a fallback or show a message