aboutsummaryrefslogtreecommitdiff
path: root/src/app/kdrama/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/kdrama/components')
-rw-r--r--src/app/kdrama/components/cacher.js17
-rw-r--r--src/app/kdrama/components/episodesContainer.jsx83
-rw-r--r--src/app/kdrama/components/infoTabs.jsx51
-rw-r--r--src/app/kdrama/components/popular.jsx47
-rw-r--r--src/app/kdrama/components/recent.jsx46
-rw-r--r--src/app/kdrama/components/requests.js44
-rw-r--r--src/app/kdrama/components/search.jsx65
-rw-r--r--src/app/kdrama/components/searchBar.jsx57
-rw-r--r--src/app/kdrama/components/searchFormatter.jsx46
-rw-r--r--src/app/kdrama/components/searchQuery.js10
-rw-r--r--src/app/kdrama/components/videoLink.js11
11 files changed, 282 insertions, 195 deletions
diff --git a/src/app/kdrama/components/cacher.js b/src/app/kdrama/components/cacher.js
index 860cdca..fdfa272 100644
--- a/src/app/kdrama/components/cacher.js
+++ b/src/app/kdrama/components/cacher.js
@@ -1,21 +1,6 @@
-// This function pre-fetches all the video links for a drama in the background
"use server";
-export async function PreFetchVideoLinks(data, dramaId) {
- try {
- const fetchPromises = data.map(async (element) => {
- const link = `https://consumet-jade.vercel.app/movies/dramacool/watch?episodeId=${element.id}&mediaId=${dramaId}`;
- await fetch(link, { cache: "force-cache" });
- });
-
- await Promise.all(fetchPromises);
- console.log("Video links pre-fetched successfully!");
- } catch (error) {
- console.error("Error occurred while pre-fetching video links:", error);
- }
-}
-
-export async function PreFetchAnimeInfo(data) {
+export async function PreFetchKdramaInfo(data) {
try {
const fetchPromises = data.results.map(async (element) => {
const link = `https://consumet-jade.vercel.app/movies/dramacool/info?id=${element.id}`;
diff --git a/src/app/kdrama/components/episodesContainer.jsx b/src/app/kdrama/components/episodesContainer.jsx
new file mode 100644
index 0000000..984ece5
--- /dev/null
+++ b/src/app/kdrama/components/episodesContainer.jsx
@@ -0,0 +1,83 @@
+"use client";
+
+import { MediaPlayer, MediaProvider } from "@vidstack/react";
+import "@vidstack/react/player/styles/default/theme.css";
+import "@vidstack/react/player/styles/default/layouts/video.css";
+import {
+ defaultLayoutIcons,
+ DefaultVideoLayout,
+} from "@vidstack/react/player/layouts/default";
+import { Select, SelectItem, Button, Skeleton } from "@nextui-org/react";
+import { useState, useEffect } from "react";
+
+import { lexend } from "../../../../config/fonts";
+import { videoLink } from "./requests";
+
+const EpisodesContainer = ({ data: data }) => {
+ const [videolink, setVideoLink] = useState("");
+ const [loading, setLoading] = useState(<></>);
+
+ async function handleSelectChange(episodeId) {
+ setVideoLink("");
+ setLoading(
+ <div className="w-full flex items-center gap-3">
+ <div className="w-full flex flex-col gap-2">
+ <Skeleton className="h-44 rounded-lg lg:h-96" />
+ </div>
+ </div>
+ );
+ const videoURL = await videoLink(episodeId, data.id);
+ setLoading(<></>);
+ setVideoLink(videoURL);
+ }
+
+ return (
+ <section>
+ <div className="flex w-full flex-wrap md:flex-nowrap gap-4 my-2">
+ <Select
+ label="Select Episode"
+ className={`${lexend.className} max-w-xs`}
+ >
+ {data.episodes && data.episodes.length > 0 ? (
+ data.episodes.map((item, index) => (
+ <SelectItem
+ key={index}
+ textValue={item.episode}
+ onClick={async () =>
+ await handleSelectChange(item.id)
+ }
+ className={lexend.className}
+ >
+ {item.episode}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem disabled className={lexend.className}>
+ No episodes available right now
+ </SelectItem>
+ )}
+ </Select>
+ </div>
+
+ {loading}
+ {videolink && (
+ <div>
+ <MediaPlayer
+ title={data.title}
+ src={videolink}
+ aspectRatio="16/9"
+ load="eager"
+ playsInline
+ volume={0.8}
+ autoPlay
+ >
+ <MediaProvider />
+ <DefaultVideoLayout icons={defaultLayoutIcons} />
+ </MediaPlayer>
+ </div>
+ )}
+ </section>
+ );
+};
+
+export default EpisodesContainer;
diff --git a/src/app/kdrama/components/infoTabs.jsx b/src/app/kdrama/components/infoTabs.jsx
new file mode 100644
index 0000000..54c05ba
--- /dev/null
+++ b/src/app/kdrama/components/infoTabs.jsx
@@ -0,0 +1,51 @@
+"use client";
+
+import { Tabs, Tab, Card, CardBody } from "@nextui-org/react";
+
+import { lexend, atkinson } from "../../../../config/fonts";
+
+export default function DescriptionTabs({ data: data }) {
+ return (
+ <div className="flex w-full flex-col">
+ <Tabs aria-label="Options" className={lexend.className}>
+ <Tab key="description" title="Description">
+ <Card>
+ <CardBody className={atkinson.className}>
+ {data.description || "No description found"}
+ </CardBody>
+ </Card>
+ </Tab>
+ <Tab key="episodes" title="Details">
+ <Card>
+ <CardBody className={atkinson.className}>
+ <h4>
+ <strong>Episodes</strong>:{" "}
+ <span>{data.episodes.length}</span>
+ </h4>
+ <h4>
+ <strong>Duration</strong>:{" "}
+ <span>{data.duration || "not found"}</span>
+ </h4>
+ <h4>
+ <strong>Release Year</strong>:{" "}
+ <span>{data.releaseDate}</span>
+ </h4>
+ <h4>
+ <strong>Other Names</strong>:{" "}
+ {data.otherNames &&
+ data.otherNames.map((item, index) => (
+ <span key={index}>
+ {item}
+ {index <
+ data.otherNames.length - 1 &&
+ ", "}
+ </span>
+ ))}
+ </h4>
+ </CardBody>
+ </Card>
+ </Tab>
+ </Tabs>
+ </div>
+ );
+}
diff --git a/src/app/kdrama/components/popular.jsx b/src/app/kdrama/components/popular.jsx
deleted file mode 100644
index 21d8cc3..0000000
--- a/src/app/kdrama/components/popular.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import styles from "../styles/popular.module.css";
-import Image from "next/image";
-import Link from "next/link";
-import { PreFetchAnimeInfo } from "./cacher";
-
-export default async function PopularDramas() {
- const popular = await getPopular();
- PreFetchAnimeInfo(popular);
-
- return (
- <div className={styles.Main}>
- <h2 className={styles.popDramasText}>Trending Dramas</h2>
-
- <div className={styles.AnimeContainer}>
- {popular &&
- popular.results.slice(0, 24).map((item, index) => (
- <Link
- href={`/kdrama/${encodeURIComponent(item.id)}`}
- key={index}
- style={{ textDecoration: "none" }}
- >
- <div
- className={styles.AnimeEntry}
- title={item.title}
- >
- <Image
- src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=${item.image}`}
- width={167}
- height={267}
- alt="Drama Poster"
- />
- <p>{item.title}</p>
- </div>
- </Link>
- ))}
- </div>
- </div>
- );
-}
-
-async function getPopular() {
- const res = await fetch("https://dramacool-scraper.vercel.app/popular", {
- next: { revalidate: 21600 },
- });
- const data = await res.json();
- return data;
-}
diff --git a/src/app/kdrama/components/recent.jsx b/src/app/kdrama/components/recent.jsx
deleted file mode 100644
index 2b883d6..0000000
--- a/src/app/kdrama/components/recent.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import styles from "../styles/popular.module.css";
-import Image from "next/image";
-import Link from "next/link";
-import { PreFetchAnimeInfo } from "./cacher";
-
-export default async function RecentDramas() {
- const popular = await getPopular();
- PreFetchAnimeInfo(popular);
- return (
- <div className={styles.Main}>
- <h2 className={styles.popDramasText}>Recent Releases</h2>
-
- <div className={styles.AnimeContainer}>
- {popular &&
- popular.results.slice(0, 24).map((item, index) => (
- <Link
- href={`/kdrama/${encodeURIComponent(item.id)}`}
- key={index}
- style={{ textDecoration: "none" }}
- >
- <div
- className={styles.AnimeEntry}
- title={item.title}
- >
- <Image
- src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=${item.image}`}
- width={167}
- height={267}
- alt="Drama Poster"
- />
- <p>{item.title}</p>
- </div>
- </Link>
- ))}
- </div>
- </div>
- );
-}
-
-async function getPopular() {
- const res = await fetch("https://dramacool-scraper.vercel.app/recent", {
- next: { revalidate: 21600 },
- });
- const data = await res.json();
- return data;
-}
diff --git a/src/app/kdrama/components/requests.js b/src/app/kdrama/components/requests.js
new file mode 100644
index 0000000..5609d79
--- /dev/null
+++ b/src/app/kdrama/components/requests.js
@@ -0,0 +1,44 @@
+"use server";
+
+import {
+ popular_dramas_url,
+ recent_drama_url,
+ search_drama_url,
+ drama_info_url,
+ videoURL,
+} from "../../../../utils/kdrama_urls";
+
+export const DramaDataFetcher = async (type) => {
+ const options = {
+ popular: popular_dramas_url,
+ recent: recent_drama_url,
+ };
+ const res = await fetch(options[type], { next: { revalidate: 21600 } });
+ const data = await res.json();
+ return data;
+};
+
+export const SearchedDramaData = async (title) => {
+ const res = await fetch(search_drama_url(title), {
+ next: { revalidate: 21600 },
+ });
+ const data = await res.json();
+ return data;
+};
+
+export const dramaInfo = async (id) => {
+ const res = await fetch(drama_info_url(id), {
+ next: { revalidate: 21600 },
+ });
+ const data = await res.json();
+ return data;
+};
+
+export const videoLink = async (epiId, mediaId) => {
+ const res = await fetch(videoURL(epiId, mediaId), {
+ next: { revalidate: 21600 },
+ });
+ const data = await res.json();
+ const videoLink = data.sources[0].url;
+ return videoLink;
+};
diff --git a/src/app/kdrama/components/search.jsx b/src/app/kdrama/components/search.jsx
deleted file mode 100644
index f44e4bb..0000000
--- a/src/app/kdrama/components/search.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-"use client";
-
-import styles from "../styles/search.module.css";
-import { useState } from "react";
-import { FaSearch } from "react-icons/fa";
-import FetchSearchTitle from "./searchQuery";
-import Image from "next/image";
-import Link from "next/link";
-import { PreFetchAnimeInfo } from "./cacher";
-
-export default function DramaSearch() {
- const [title, setTitle] = useState("");
- const [infoTitle, setInfoTitle] = useState(null);
- const [loadingText, setLoadingText] = useState(null);
-
- const handleSearch = async (title) => {
- setLoadingText(true);
- const data = await FetchSearchTitle(title);
- PreFetchAnimeInfo(data);
- setLoadingText(false);
- setInfoTitle(data);
- };
-
- return (
- <div className={styles.SearchContainer}>
- <div className={styles.Search}>
- <FaSearch color="white" size={16} />
- <input
- placeholder="Search for drama"
- onChange={(event) => setTitle(event.target.value)}
- onKeyDown={async (e) => {
- if ((e.key === "Enter" || e.code === 13) && title) {
- await handleSearch(e.target.value);
- }
- }}
- ></input>
- </div>
-
- {loadingText && (
- <p className={styles.LoadingText}>Wait a moment...</p>
- )}
-
- <div className={styles.SearchResults}>
- {infoTitle &&
- infoTitle.results.map((item, index) => (
- <Link
- href={`/kdrama/${encodeURIComponent(item.id)}`}
- style={{ textDecoration: "none" }}
- key={index}
- >
- <div className={styles.SearchEntry}>
- <p>{item.title}</p>
- <Image
- src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=${item.image}`}
- width={140}
- height={210}
- alt="Drama Poster"
- />
- </div>
- </Link>
- ))}
- </div>
- </div>
- );
-}
diff --git a/src/app/kdrama/components/searchBar.jsx b/src/app/kdrama/components/searchBar.jsx
new file mode 100644
index 0000000..5f5d89e
--- /dev/null
+++ b/src/app/kdrama/components/searchBar.jsx
@@ -0,0 +1,57 @@
+"use client";
+
+import React from "react";
+import { useState } from "react";
+import { Input, Progress } from "@nextui-org/react";
+
+import { SearchedDramaData } from "./requests";
+import SearchedDataFormatter from "./searchFormatter";
+import { PreFetchKdramaInfo } from "./cacher";
+
+export const Searchbar = () => {
+ const [loading, setLoading] = useState(<></>);
+ const [searchData, setSearchData] = useState(null);
+ const [searchTitle, setSearchTitle] = useState("");
+
+ async function handleSearchInput() {
+ setSearchData(null);
+ setLoading(
+ <Progress
+ size="sm"
+ isIndeterminate
+ aria-label="Loading..."
+ className="w-full"
+ />
+ );
+ const data = await SearchedDramaData(searchTitle);
+ PreFetchKdramaInfo(data);
+ const format = await SearchedDataFormatter(data);
+ setSearchData(format);
+ setLoading(<></>);
+ }
+
+ return (
+ <div>
+ <div className="flex w-full flex-wrap flex-col mt-2 md:flex-nowrap md:mx-2 gap-4 lg:w-1/2 lg:mx-2">
+ <Input
+ type="text"
+ label="Search for k-dramas here"
+ placeholder="Enter k-drama title"
+ color="default"
+ onChange={(event) => {
+ if (event.target.value.trim() !== "") {
+ setSearchTitle(event.target.value);
+ }
+ }}
+ onKeyDown={async (event) => {
+ if (event.key === "Enter" || event.code === "Enter") {
+ await handleSearchInput();
+ }
+ }}
+ />
+ {loading}
+ </div>
+ <div className="w-full mt-2">{searchData}</div>
+ </div>
+ );
+};
diff --git a/src/app/kdrama/components/searchFormatter.jsx b/src/app/kdrama/components/searchFormatter.jsx
new file mode 100644
index 0000000..bac2549
--- /dev/null
+++ b/src/app/kdrama/components/searchFormatter.jsx
@@ -0,0 +1,46 @@
+import { Card, CardHeader, CardBody, Image, Link } from "@nextui-org/react";
+import NextImage from "next/image";
+
+import styles from "../../page.module.css";
+
+const SearchedDataFormatter = async (data) => {
+ return (
+ <section
+ className={`flex items-center overflow-auto pb-2 ${styles.ScrollBarAdjuster}`}
+ >
+ {data &&
+ data.results.length > 0 &&
+ data.results.map((item, index) => (
+ <Link
+ key={index}
+ href={`/kdrama/${encodeURIComponent(item.id)}`}
+ aria-label="anime redirection links"
+ className="flex flex-col items-center mx-1"
+ >
+ <Card className="overflow-hidden" isPressable>
+ <CardBody>
+ <Image
+ as={NextImage}
+ isBlurred
+ alt="Anime Poster"
+ src={item.image}
+ width={185}
+ height={120}
+ shadow="lg"
+ className="h-64"
+ priority
+ />
+ </CardBody>
+ <CardHeader>
+ <h4 className="antialiased text-small text-center uppercase w-44 overflow-hidden whitespace-nowrap text-ellipsis ">
+ {item.title}
+ </h4>
+ </CardHeader>
+ </Card>
+ </Link>
+ ))}
+ </section>
+ );
+};
+
+export default SearchedDataFormatter;
diff --git a/src/app/kdrama/components/searchQuery.js b/src/app/kdrama/components/searchQuery.js
deleted file mode 100644
index 18c06a9..0000000
--- a/src/app/kdrama/components/searchQuery.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use server";
-
-export default async function FetchSearchTitle(title) {
- const res = await fetch(
- `https://consumet-jade.vercel.app/movies/dramacool/${title}`,
- { cache: "force-cache" }
- );
- const data = await res.json();
- return data;
-}
diff --git a/src/app/kdrama/components/videoLink.js b/src/app/kdrama/components/videoLink.js
deleted file mode 100644
index e49ca18..0000000
--- a/src/app/kdrama/components/videoLink.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use server";
-export default async function getVideoLink(epiId, mediaId) {
- let videoLink;
- const res = await fetch(
- `https://consumet-jade.vercel.app/movies/dramacool/watch?episodeId=${epiId}&mediaId=${mediaId}`,
- { cache: "force-cache" }
- );
- const data = await res.json();
- videoLink = data.sources[0].url;
- return videoLink;
-}