aboutsummaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorFactiven <[email protected]>2023-08-12 22:54:26 +0700
committerGitHub <[email protected]>2023-08-12 22:54:26 +0700
commit3e78826658c7d2a4e9b3c1d73e63dacc1d39c361 (patch)
treed580d03670692c6c5d361ec8559e7a2352354f3a /components
parentUpdate v3.9.1 - Merged Beta to Main (#44) (diff)
downloadmoopa-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.js1
-rw-r--r--components/anime/infoDetails.js5
-rw-r--r--components/anime/viewMode/listMode.js18
-rw-r--r--components/anime/viewMode/thumbnailDetail.js4
-rw-r--r--components/anime/viewMode/thumbnailOnly.js4
-rw-r--r--components/anime/watch/primary/details.js18
-rw-r--r--components/anime/watch/primarySide.js20
-rw-r--r--components/anime/watch/secondarySide.js4
-rw-r--r--components/home/content.js126
-rw-r--r--components/home/schedule.js4
-rw-r--r--components/manga/info/topSection.js2
-rw-r--r--components/manga/rightBar.js1
-rw-r--r--components/videoPlayer.js23
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);