diff options
| author | Factiven <[email protected]> | 2023-08-12 22:54:26 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-08-12 22:54:26 +0700 |
| commit | 3e78826658c7d2a4e9b3c1d73e63dacc1d39c361 (patch) | |
| tree | d580d03670692c6c5d361ec8559e7a2352354f3a /components | |
| parent | Update v3.9.1 - Merged Beta to Main (#44) (diff) | |
| download | moopa-3e78826658c7d2a4e9b3c1d73e63dacc1d39c361.tar.xz moopa-3e78826658c7d2a4e9b3c1d73e63dacc1d39c361.zip | |
Update v3.9.3 - Merged Beta to Main (#51)v3.9.3
* commit
* update db
* Update v3.9.1-beta-v3.1
* Update v3.9.1
* Fix watched progress not showing
* Secure headers
* Fix recently watched image
* Update v3.9.2
> Added custom lists for AniList
> Fixed episode listMode progress
* Update db route
* Fixed AniList
* Fix next button on dub anime
> video is playing sub anime instead dub
* small adjusment for premid
* fix eslint
* small updates
> added ability to remove episode from recently watched
* Update v3.9.3
Diffstat (limited to 'components')
| -rw-r--r-- | components/anime/episode.js | 1 | ||||
| -rw-r--r-- | components/anime/infoDetails.js | 5 | ||||
| -rw-r--r-- | components/anime/viewMode/listMode.js | 18 | ||||
| -rw-r--r-- | components/anime/viewMode/thumbnailDetail.js | 4 | ||||
| -rw-r--r-- | components/anime/viewMode/thumbnailOnly.js | 4 | ||||
| -rw-r--r-- | components/anime/watch/primary/details.js | 18 | ||||
| -rw-r--r-- | components/anime/watch/primarySide.js | 20 | ||||
| -rw-r--r-- | components/anime/watch/secondarySide.js | 4 | ||||
| -rw-r--r-- | components/home/content.js | 126 | ||||
| -rw-r--r-- | components/home/schedule.js | 4 | ||||
| -rw-r--r-- | components/manga/info/topSection.js | 2 | ||||
| -rw-r--r-- | components/manga/rightBar.js | 1 | ||||
| -rw-r--r-- | components/videoPlayer.js | 23 |
13 files changed, 174 insertions, 56 deletions
diff --git a/components/anime/episode.js b/components/anime/episode.js index c889c25..5d3451b 100644 --- a/components/anime/episode.js +++ b/components/anime/episode.js @@ -246,6 +246,7 @@ export default function AnimeEpisode({ info, progress }) { info={info} episode={episode} index={index} + artStorage={artStorage} providerId={providerId} progress={progress} dub={isDub} diff --git a/components/anime/infoDetails.js b/components/anime/infoDetails.js index 0cf233c..814e49b 100644 --- a/components/anime/infoDetails.js +++ b/components/anime/infoDetails.js @@ -45,7 +45,10 @@ export default function DesktopDetails({ <div className="hidden lg:flex w-full flex-col gap-5 h-[250px]"> <div className="flex flex-col gap-2"> - <h1 className=" font-inter font-bold text-[36px] text-white line-clamp-1"> + <h1 + className="title font-inter font-bold text-[36px] text-white line-clamp-1" + title={info?.title?.romaji || info?.title?.english} + > {info ? ( info?.title?.romaji || info?.title?.english ) : ( diff --git a/components/anime/viewMode/listMode.js b/components/anime/viewMode/listMode.js index 2016262..f3bcf05 100644 --- a/components/anime/viewMode/listMode.js +++ b/components/anime/viewMode/listMode.js @@ -4,10 +4,16 @@ export default function ListMode({ info, episode, index, + artStorage, providerId, progress, dub, }) { + const time = artStorage?.[episode?.id]?.timeWatched; + const duration = artStorage?.[episode?.id]?.duration; + let prog = (time / duration) * 100; + if (prog > 90) prog = 100; + return ( <div key={episode.number} className="flex flex-col gap-3 px-2"> <Link @@ -15,7 +21,11 @@ export default function ListMode({ episode.id )}&num=${episode.number}${dub ? `&dub=${dub}` : ""}`} className={`text-start text-sm lg:text-lg ${ - progress && episode.number <= progress + progress + ? progress && episode.number <= progress + ? "text-[#5f5f5f]" + : "text-white" + : prog === 100 ? "text-[#5f5f5f]" : "text-white" }`} @@ -24,7 +34,11 @@ export default function ListMode({ {episode.title && ( <p className={`text-xs lg:text-sm ${ - progress && episode.number <= progress + progress + ? progress && episode.number <= progress + ? "text-[#5f5f5f]" + : "text-[#b1b1b1]" + : prog === 100 ? "text-[#5f5f5f]" : "text-[#b1b1b1]" } italic`} diff --git a/components/anime/viewMode/thumbnailDetail.js b/components/anime/viewMode/thumbnailDetail.js index a085bc7..6efeb77 100644 --- a/components/anime/viewMode/thumbnailDetail.js +++ b/components/anime/viewMode/thumbnailDetail.js @@ -10,7 +10,7 @@ export default function ThumbnailDetail({ progress, dub, }) { - const time = artStorage?.[epi?.id]?.time; + const time = artStorage?.[epi?.id]?.timeWatched; const duration = artStorage?.[epi?.id]?.duration; let prog = (time / duration) * 100; if (prog > 90) prog = 100; @@ -33,7 +33,7 @@ export default function ThumbnailDetail({ className="object-cover z-30 rounded-lg h-[110px] lg:h-[160px] brightness-[65%]" /> <span - className={`absolute bottom-0 left-0 h-[3px] bg-red-700`} + className={`absolute bottom-0 left-0 h-[2px] bg-red-700`} style={{ width: progress && artStorage && epi?.number <= progress diff --git a/components/anime/viewMode/thumbnailOnly.js b/components/anime/viewMode/thumbnailOnly.js index 6063dfc..99f02bd 100644 --- a/components/anime/viewMode/thumbnailOnly.js +++ b/components/anime/viewMode/thumbnailOnly.js @@ -9,7 +9,7 @@ export default function ThumbnailOnly({ progress, dub, }) { - const time = artStorage?.[episode?.id]?.time; + const time = artStorage?.[episode?.id]?.timeWatched; const duration = artStorage?.[episode?.id]?.duration; let prog = (time / duration) * 100; if (prog > 90) prog = 100; @@ -25,7 +25,7 @@ export default function ThumbnailOnly({ Episode {episode?.number} </span> <span - className={`absolute bottom-7 left-0 h-1 bg-red-600`} + className={`absolute bottom-7 left-0 h-[2px] bg-red-600`} style={{ width: progress && artStorage && episode?.number <= progress diff --git a/components/anime/watch/primary/details.js b/components/anime/watch/primary/details.js index 94c3360..f092879 100644 --- a/components/anime/watch/primary/details.js +++ b/components/anime/watch/primary/details.js @@ -8,6 +8,7 @@ export default function Details({ info, session, epiNumber, + description, id, onList, setOnList, @@ -48,7 +49,10 @@ export default function Details({ <Skeleton height={240} /> )} </div> - <div className="grid w-full pl-5 gap-3 h-[240px]"> + <div + className="grid w-full pl-5 gap-3 h-[240px]" + data-episode={info?.episodes || "0"} + > <div className="grid grid-cols-2 gap-1 items-center"> <h2 className="text-sm font-light font-roboto text-[#878787]"> Studios @@ -93,11 +97,15 @@ export default function Details({ <div className="grid grid-flow-dense grid-cols-2 gap-2 h-full w-full"> {info ? ( <> - <div className="line-clamp-3">{info.title?.romaji || ""}</div> - <div className="line-clamp-3"> + <div className="title-rm line-clamp-3"> + {info.title?.romaji || ""} + </div> + <div className="title-en line-clamp-3"> {info.title?.english || ""} </div> - <div className="line-clamp-3">{info.title?.native || ""}</div> + <div className="title-nt line-clamp-3"> + {info.title?.native || ""} + </div> </> ) : ( <Skeleton width={200} height={50} /> @@ -120,7 +128,7 @@ export default function Details({ <div className={`bg-secondary rounded-md mt-3 mx-3`}> {info && ( <p - dangerouslySetInnerHTML={{ __html: info?.description }} + dangerouslySetInnerHTML={{ __html: description }} className={`p-5 text-sm font-light font-roboto text-[#e4e4e4] `} /> )} diff --git a/components/anime/watch/primarySide.js b/components/anime/watch/primarySide.js index c601795..b032fd6 100644 --- a/components/anime/watch/primarySide.js +++ b/components/anime/watch/primarySide.js @@ -27,6 +27,7 @@ export default function PrimarySide({ setOnList, episodeList, timeWatched, + dub, }) { const [episodeData, setEpisodeData] = useState(); const [open, setOpen] = useState(false); @@ -148,6 +149,7 @@ export default function PrimarySide({ aniTitle={info.title?.romaji || info.title?.english} track={navigation} timeWatched={timeWatched} + dub={dub} /> ) ) : ( @@ -162,13 +164,14 @@ export default function PrimarySide({ <Link href={`/en/anime/${info.id}`} className="hover:underline" + title={navigation?.playing?.title || info.title?.romaji} > {navigation?.playing?.title || info.title?.romaji} </Link> </h1> - <h1 className="text-sm font-karla font-light"> + <h3 className="text-sm font-karla font-light"> Episode {epiNumber} - </h1> + </h3> </div> <div className="flex gap-4 items-center justify-end"> <div className="relative"> @@ -180,7 +183,11 @@ export default function PrimarySide({ (episode) => episode.number === parseInt(e.target.value) ); router.push( - `/en/anime/watch/${info.id}/${providerId}?id=${selectedEpisode.id}&num=${selectedEpisode.number}` + `/en/anime/watch/${info.id}/${providerId}?id=${ + selectedEpisode.id + }&num=${selectedEpisode.number}${ + dub ? `&dub=${dub}` : "" + }` ); }} > @@ -199,7 +206,11 @@ export default function PrimarySide({ }relative group`} onClick={() => { router.push( - `/en/anime/watch/${info.id}/${providerId}?id=${navigation?.next.id}&num=${navigation?.next.number}` + `/en/anime/watch/${info.id}/${providerId}?id=${ + navigation?.next.id + }&num=${navigation?.next.number}${ + dub ? `&dub=${dub}` : "" + }` ); }} > @@ -229,6 +240,7 @@ export default function PrimarySide({ <Details info={info} session={session} + description={navigation?.playing?.description || info?.description} epiNumber={epiNumber} id={watchId} onList={onList} diff --git a/components/anime/watch/secondarySide.js b/components/anime/watch/secondarySide.js index e3f0224..5d9b8f9 100644 --- a/components/anime/watch/secondarySide.js +++ b/components/anime/watch/secondarySide.js @@ -18,7 +18,7 @@ export default function SecondarySide({ {episode && episode.length > 0 ? ( episode.some((item) => item.title && item.description) > 0 ? ( episode.map((item) => { - const time = artStorage?.[item.id]?.time; + const time = artStorage?.[item.id]?.timeWatched; const duration = artStorage?.[item.id]?.duration; let prog = (time / duration) * 100; if (prog > 90) prog = 100; @@ -50,7 +50,7 @@ export default function SecondarySide({ }`} /> <span - className={`absolute bottom-0 left-0 h-[3px] bg-red-700`} + className={`absolute bottom-0 left-0 h-[2px] bg-red-700`} style={{ width: progress && artStorage && item?.number <= progress diff --git a/components/home/content.js b/components/home/content.js index f13c7a8..70f0e3f 100644 --- a/components/home/content.js +++ b/components/home/content.js @@ -5,6 +5,7 @@ import { MdChevronRight } from "react-icons/md"; import { ChevronRightIcon, ArrowRightCircleIcon, + XMarkIcon, } from "@heroicons/react/24/outline"; import { parseCookies } from "nookies"; @@ -12,6 +13,7 @@ import { parseCookies } from "nookies"; import { ChevronLeftIcon } from "@heroicons/react/20/solid"; import { ExclamationCircleIcon, PlayIcon } from "@heroicons/react/24/solid"; import { useRouter } from "next/router"; +import { toast } from "react-toastify"; export default function Content({ ids, @@ -20,6 +22,7 @@ export default function Content({ userData, og, userName, + setRemoved, }) { const router = useRouter(); @@ -139,10 +142,64 @@ export default function Content({ } }; + const removeItem = async (id) => { + if (userName) { + // remove from database + const res = await fetch(`/api/user/update/episode`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: userName, + id: id, + }), + }); + const data = await res.json(); + + // remove from local storage + const artplayerSettings = + JSON.parse(localStorage.getItem("artplayer_settings")) || {}; + if (artplayerSettings[id]) { + delete artplayerSettings[id]; + localStorage.setItem( + "artplayer_settings", + JSON.stringify(artplayerSettings) + ); + } + + // update client + setRemoved(id); + + if (data?.message === "Episode deleted") { + toast.success("Episode removed from history", { + position: "bottom-right", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + draggable: true, + theme: "dark", + }); + } + } else { + const artplayerSettings = + JSON.parse(localStorage.getItem("artplayer_settings")) || {}; + if (artplayerSettings[id]) { + delete artplayerSettings[id]; + localStorage.setItem( + "artplayer_settings", + JSON.stringify(artplayerSettings) + ); + } + + setRemoved(id); + } + }; + return ( <div> <div - className={`flex items-center justify-between lg:justify-normal lg:gap-3 px-5 ${ + className={`flex items-center justify-between lg:justify-normal lg:gap-3 px-5 z-40 ${ section === "Recommendations" ? "" : "cursor-pointer" }`} onClick={goToPage} @@ -169,7 +226,6 @@ export default function Content({ onClick={handleClick} ref={containerRef} > - {ids !== "recentlyWatched" ? slicedData?.map((anime) => { const progress = og?.find((i) => i.mediaId === anime.id); @@ -273,14 +329,27 @@ export default function Content({ if (prog > 90) prog = 100; return ( - <Link + <div key={i.watchId} - className="flex flex-col gap-2 shrink-0 cursor-pointer" - href={`/en/anime/watch/${i.aniId}/${ - i.provider - }?id=${encodeURIComponent(i.watchId)}&num=${i.episode}`} + className="flex flex-col gap-2 shrink-0 cursor-pointer relative group/item" > - <div className="relative w-[320px] aspect-video rounded-md overflow-hidden group"> + <div className="absolute z-40 top-1 right-1 group-hover/item:visible invisible hover:text-action"> + <div + className="flex flex-col items-center group/delete" + onClick={() => removeItem(i.watchId)} + > + <XMarkIcon className="w-6 h-6 shrink-0 bg-primary p-1 rounded-full" /> + <span className="absolute font-karla bg-secondary shadow-black shadow-2xl py-1 px-2 whitespace-nowrap text-white text-sm rounded-md right-7 -bottom-[2px] z-40 duration-300 transition-all ease-out group-hover/delete:visible group-hover/delete:scale-100 group-hover/delete:translate-x-0 group-hover/delete:opacity-100 opacity-0 translate-x-10 scale-50 invisible"> + Remove from history + </span> + </div> + </div> + <Link + className="relative w-[320px] aspect-video rounded-md overflow-hidden group" + href={`/en/anime/watch/${i.aniId}/${ + i.provider + }?id=${encodeURIComponent(i.watchId)}&num=${i.episode}`} + > <div className="w-full h-full bg-gradient-to-t from-black/70 from-20% to-transparent group-hover:to-black/40 transition-all duration-300 ease-out absolute z-30" /> <div className="absolute bottom-3 left-0 mx-2 text-white flex gap-2 items-center w-[80%] z-30"> <PlayIcon className="w-5 h-5 shrink-0" /> @@ -299,6 +368,7 @@ export default function Content({ width: `${prog}%`, }} /> + {i?.image && ( <Image src={i?.image} @@ -308,9 +378,14 @@ export default function Content({ className="w-fit group-hover:scale-[1.02] duration-300 ease-out z-10" /> )} - </div> + </Link> - <div className="flex flex-col font-karla w-full"> + <Link + className="flex flex-col font-karla w-full" + href={`/en/anime/watch/${i.aniId}/${ + i.provider + }?id=${encodeURIComponent(i.watchId)}&num=${i.episode}`} + > {/* <h1 className="font-semibold">{i.title}</h1> */} <p className="flex items-center gap-1 text-sm text-gray-400 w-[320px]"> <span @@ -328,24 +403,25 @@ export default function Content({ </span>{" "} | Episode {i.episode} </p> - </div> - </Link> + </Link> + </div> ); })} - {userData?.length >= 10 && section !== "Recommendations" && ( - <div - key={section} - className="flex cursor-pointer" - onClick={goToPage} - > - <div className="w-[320px] aspect-video overflow-hidden object-cover rounded-md border-secondary border-2 flex flex-col gap-2 items-center text-center justify-center text-[#6a6a6a] hover:text-[#9f9f9f] hover:border-[#757575] transition-colors duration-200"> - <h1 className="whitespace-pre-wrap text-sm"> - More on {section} - </h1> - <ArrowRightCircleIcon className="w-5 h-5" /> + {userData?.filter((i) => i.aniId !== null)?.length >= 10 && + section !== "Recommendations" && ( + <div + key={section} + className="flex cursor-pointer" + onClick={goToPage} + > + <div className="w-[320px] aspect-video overflow-hidden object-cover rounded-md border-secondary border-2 flex flex-col gap-2 items-center text-center justify-center text-[#6a6a6a] hover:text-[#9f9f9f] hover:border-[#757575] transition-colors duration-200"> + <h1 className="whitespace-pre-wrap text-sm"> + More on {section} + </h1> + <ArrowRightCircleIcon className="w-5 h-5" /> + </div> </div> - </div> - )} + )} {filteredData?.length >= 10 && section !== "Recommendations" && ( <div key={section} diff --git a/components/home/schedule.js b/components/home/schedule.js index 73c63f0..4043c5e 100644 --- a/components/home/schedule.js +++ b/components/home/schedule.js @@ -117,10 +117,10 @@ export default function Schedule({ data, scheduleData, time }) { > <div className="flex flex-col gap-2 px-2 pt-2"> {scheduleData[days[currentPage]] - .filter((show, index, self) => { + ?.filter((show, index, self) => { return index === self.findIndex((s) => s.id === show.id); }) - .map((i, index) => { + ?.map((i, index) => { const currentTime = Date.now(); const hasAired = i.airingAt < currentTime; diff --git a/components/manga/info/topSection.js b/components/manga/info/topSection.js index 14dc5e5..40b5a37 100644 --- a/components/manga/info/topSection.js +++ b/components/manga/info/topSection.js @@ -66,7 +66,7 @@ export default function TopSection({ info, firstEp, setCookie }) { </div> <div className="w-full flex flex-col justify-start z-40"> <div className="md:h-1/2 py-2 md:py-5 flex flex-col md:gap-2 justify-end"> - <h1 className="text-xl md:text-2xl xl:text-3xl text-white font-semibold font-karla line-clamp-1 text-start"> + <h1 className="title text-xl md:text-2xl xl:text-3xl text-white font-semibold font-karla line-clamp-1 text-start"> {info.title?.romaji || info.title?.english || info.title?.native} </h1> <span className="flex flex-wrap text-xs lg:text-sm md:text-[#747478]"> diff --git a/components/manga/rightBar.js b/components/manga/rightBar.js index 6d37e4a..18c5e55 100644 --- a/components/manga/rightBar.js +++ b/components/manga/rightBar.js @@ -151,6 +151,7 @@ export default function RightBar({ Chapter Progress </label> <input + id="chapter-progress" type="number" placeholder="0" min={0} diff --git a/components/videoPlayer.js b/components/videoPlayer.js index 46129ab..dcde703 100644 --- a/components/videoPlayer.js +++ b/components/videoPlayer.js @@ -35,6 +35,7 @@ export default function VideoPlayer({ track, aniTitle, timeWatched, + dub, }) { const [url, setUrl] = useState(""); const [source, setSource] = useState([]); @@ -226,10 +227,7 @@ export default function VideoPlayer({ watchId: id, title: track?.playing?.title || aniTitle, aniTitle: aniTitle, - image: - track?.playing?.image || - info?.bannerImage || - info?.coverImage?.extraLarge, + image: track?.playing?.image || info?.coverImage?.extraLarge, number: Number(progress), duration: art.duration, timeWatched: art.currentTime, @@ -260,10 +258,7 @@ export default function VideoPlayer({ watchId: id, title: track?.playing?.title || aniTitle, aniTitle: aniTitle, - image: - track?.playing?.image || - info?.bannerImage || - info?.coverImage?.extraLarge, + image: track?.playing?.image || info?.coverImage?.extraLarge, episode: Number(progress), duration: art.duration, timeWatched: art.currentTime, @@ -285,6 +280,12 @@ export default function VideoPlayer({ }); }); + art.on("resize", () => { + art.subtitle.style({ + fontSize: art.height * 0.05 + "px", + }); + }); + art.on("video:timeupdate", async () => { if (!session) return; @@ -313,7 +314,9 @@ export default function VideoPlayer({ router.push( `/en/anime/watch/${aniId}/${provider}?id=${encodeURIComponent( track?.next?.id - )}&num=${track?.next?.number}` + )}&num=${track?.next?.number}${ + dub ? `&dub=${dub}` : "" + }` ); } }, @@ -332,7 +335,7 @@ export default function VideoPlayer({ router.push( `/en/anime/watch/${aniId}/${provider}?id=${encodeURIComponent( track?.next?.id - )}&num=${track?.next?.number}` + )}&num=${track?.next?.number}${dub ? `&dub=${dub}` : ""}` ); } }, 7000); |