aboutsummaryrefslogtreecommitdiff
path: root/src/app/movies/components
diff options
context:
space:
mode:
authorreal-zephex <[email protected]>2024-05-25 16:58:02 +0530
committerreal-zephex <[email protected]>2024-05-25 16:58:02 +0530
commit2d0bcaeeeffef4e6ed6f445378b9729e70901f61 (patch)
tree40f63b16c4e11551b45b2989728eb659af47c6e2 /src/app/movies/components
parent✅ fix(anime): fix continue watching functionality and minor tweaks (diff)
downloaddramalama-2d0bcaeeeffef4e6ed6f445378b9729e70901f61.tar.xz
dramalama-2d0bcaeeeffef4e6ed6f445378b9729e70901f61.zip
🚀 refactor(movie): revamped movie section
Diffstat (limited to 'src/app/movies/components')
-rw-r--r--src/app/movies/components/cacher.js5
-rw-r--r--src/app/movies/components/descriptionTabs.jsx67
-rw-r--r--src/app/movies/components/faqs.jsx33
-rw-r--r--src/app/movies/components/popular.jsx49
-rw-r--r--src/app/movies/components/requestsHandler.js36
-rw-r--r--src/app/movies/components/search.jsx71
-rw-r--r--src/app/movies/components/searchFormatter.jsx51
-rw-r--r--src/app/movies/components/search_2.jsx63
-rw-r--r--src/app/movies/components/trending.jsx48
-rw-r--r--src/app/movies/components/videoPlayer.jsx17
-rw-r--r--src/app/movies/components/video_player.jsx68
11 files changed, 249 insertions, 259 deletions
diff --git a/src/app/movies/components/cacher.js b/src/app/movies/components/cacher.js
index 169508a..801fe95 100644
--- a/src/app/movies/components/cacher.js
+++ b/src/app/movies/components/cacher.js
@@ -1,10 +1,9 @@
-import { getInfoURL } from "../../../../utils/movie_urls";
+import { MovieInfoData } from "./requestsHandler";
const PreFetchMovieInfo = async (data) => {
try {
const fetchPromises = data.results.map(async (element) => {
- const link = `${getInfoURL(element.id)}`;
- await fetch(link, { next: { revalidate: 21600 } });
+ await MovieInfoData(element.id);
});
await Promise.all(fetchPromises);
diff --git a/src/app/movies/components/descriptionTabs.jsx b/src/app/movies/components/descriptionTabs.jsx
new file mode 100644
index 0000000..2f5ca91
--- /dev/null
+++ b/src/app/movies/components/descriptionTabs.jsx
@@ -0,0 +1,67 @@
+"use client";
+
+import { Tabs, Tab, Card, CardBody, Link } from "@nextui-org/react";
+import { FiThumbsUp } from "react-icons/fi";
+import { TiStarFullOutline } from "react-icons/ti";
+
+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.overview || "No description found"}
+ </CardBody>
+ </Card>
+ </Tab>
+ <Tab key="episodes" title="Details">
+ <Card>
+ <CardBody className={lexend.className}>
+ <h4>
+ <strong>Tagline</strong>:{" "}
+ <span>{data.tagline || "not sure"}</span>
+ </h4>
+ <h4>
+ <strong>Homepage</strong>:{" "}
+ <span>
+ <Link
+ color="warning"
+ isExternal
+ href={data.homepage || ""}
+ >
+ {data.homepage || "not sure"}
+ </Link>
+ </span>
+ </h4>
+ <h4>
+ <strong>Released on</strong>:{" "}
+ <span>{data.release_date || "not sure"}</span>
+ </h4>
+ <h4>
+ <strong>Status</strong>:{" "}
+ <span>{data.status || "not sure"}</span>
+ </h4>
+ <h4 className="flex items-center">
+ <strong>
+ <FiThumbsUp />
+ </strong>
+ <span className="ml-2">
+ {data.vote_count || "not sure"}
+ </span>
+ <strong className="ml-3">
+ <TiStarFullOutline />
+ </strong>
+ <span className="ml-2">
+ {data.vote_average || "not sure"}
+ </span>
+ </h4>
+ </CardBody>
+ </Card>
+ </Tab>
+ </Tabs>
+ </div>
+ );
+}
diff --git a/src/app/movies/components/faqs.jsx b/src/app/movies/components/faqs.jsx
new file mode 100644
index 0000000..4fa5043
--- /dev/null
+++ b/src/app/movies/components/faqs.jsx
@@ -0,0 +1,33 @@
+"use client";
+
+import { Accordion, AccordionItem } from "@nextui-org/react";
+
+const Questions = () => {
+ return (
+ <Accordion>
+ <AccordionItem
+ key="1"
+ aria-label="Accordion 1"
+ title="Why are there ads in the player?"
+ >
+ We do not host any media on our own servers. We simply aggregate
+ data from third-party providers. While these services are free
+ for public use, someone has to bear the costs of hosting the
+ servers and infrastructure. Therefore, the video player includes
+ advertisements to help cover these expenses.
+ </AccordionItem>
+ <AccordionItem
+ key="2"
+ aria-label="Accordion 2"
+ title="Okay but I still don't want to see ads..."
+ >
+ To avoid ads, you can utilize ad blockers such as Ghostery,
+ uBlock Origin, or any preferred ad blocker. Adjust your browser
+ settings to maximize tracking prevention or similar features for
+ enhanced protection against ads
+ </AccordionItem>
+ </Accordion>
+ );
+};
+
+export default Questions;
diff --git a/src/app/movies/components/popular.jsx b/src/app/movies/components/popular.jsx
deleted file mode 100644
index 3ef0501..0000000
--- a/src/app/movies/components/popular.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { POPULAR } from "../../../../utils/movie_urls";
-import PreFetchMovieInfo from "./cacher";
-import styles from "../styles/pop_trend.module.css";
-import Image from "next/image";
-import Link from "next/link";
-
-export default async function POPULAR_MOVIES() {
- const data = await get_popular();
- PreFetchMovieInfo(data);
-
- return (
- <main className={styles.Main}>
- <h2>Popular Movies</h2>
- <section className={styles.MovieContainer}>
- {data &&
- data.results &&
- data.results.slice(0, 16).map((item, index) => (
- <Link
- href={`/movies/${item.id}`}
- style={{
- textDecoration: "none",
- color: "white",
- }}
- key={index}
- >
- <div className={styles.MovieEntryPrev}>
- <div className={styles.MovieEntry}>
- <Image
- src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${item.poster_path}`}
- width={180}
- height={300}
- alt="Movie Poster"
- priority
- ></Image>
- <p>{item.title}</p>
- </div>
- </div>
- </Link>
- ))}
- </section>
- </main>
- );
-}
-
-const get_popular = async () => {
- const res = await fetch(POPULAR, { next: { revalidate: 21600 } });
- const data = await res.json();
- return data;
-};
diff --git a/src/app/movies/components/requestsHandler.js b/src/app/movies/components/requestsHandler.js
new file mode 100644
index 0000000..5f4db8b
--- /dev/null
+++ b/src/app/movies/components/requestsHandler.js
@@ -0,0 +1,36 @@
+"use server";
+
+import {
+ SEARCH,
+ TRENDING,
+ POPULAR,
+ getInfoURL,
+ TOP_RATED,
+ NOW_IN_THEATERS,
+ UPCOMING_MOVIES,
+} from "../../../../utils/movie_urls";
+
+export const SearchMovie = async (title) => {
+ const res = await fetch(SEARCH(title), { next: { revalidate: 21600 } });
+ const data = await res.json();
+ return data;
+};
+
+export const MovieHomepageDataFetcher = async (type) => {
+ const dataAvailable = {
+ trending: TRENDING,
+ popular: POPULAR,
+ top: TOP_RATED,
+ };
+ const res = await fetch(dataAvailable[type], {
+ next: { revalidate: 21600 },
+ });
+ const data = await res.json();
+ return data;
+};
+
+export const MovieInfoData = async (id) => {
+ const res = await fetch(getInfoURL(id), { cache: "force-cache" });
+ const data = await res.json();
+ return data;
+};
diff --git a/src/app/movies/components/search.jsx b/src/app/movies/components/search.jsx
index dca163a..35b8432 100644
--- a/src/app/movies/components/search.jsx
+++ b/src/app/movies/components/search.jsx
@@ -1,38 +1,53 @@
"use client";
import { useState } from "react";
-import styles from "../styles/search.module.css";
-import { FaSearch } from "react-icons/fa";
-import SearchResults from "./search_2";
+import { Input, Progress } from "@nextui-org/react";
-export default function SEARCH_COMPONENT() {
- const [title, setTitle] = useState("");
- const [result, setResults] = useState(null);
+import { SearchMovie } from "./requestsHandler";
+import MovieSearchFormatter from "./searchFormatter";
- const fetch_results = async (title) => {
- setResults(await SearchResults(title));
- };
+const MovieSearchBar = () => {
+ const [movieTitle, setMovieTitle] = useState("");
+ const [loading, setLoading] = useState(<></>);
+ const [movieResults, setMovieResults] = useState(<></>);
+
+ async function handleInputChange() {
+ setLoading(
+ <Progress
+ size="sm"
+ isIndeterminate
+ aria-label="Loading..."
+ className="w-full"
+ />
+ );
+ const data = await SearchMovie(movieTitle);
+ setLoading(<></>);
+ setMovieResults(await MovieSearchFormatter(data));
+ }
return (
- <main className={styles.Main}>
- <section className={styles.InputContainer}>
- <FaSearch
- color="white"
- className={styles.SearchIcon}
- size={22}
- />
- <input
- placeholder="Enter movie title here"
- onChange={(event) => setTitle(event.target.value)}
- onKeyDown={async (e) => {
- if ((e.key === "Enter" || e.code === 13) && title) {
- await fetch_results(e.target.value);
+ <section>
+ <div className="flex flex-col w-full md:flex-nowrap gap-2 lg:w-1/2">
+ <Input
+ type="text"
+ label="Search for movie"
+ placeholder="Enter movie title"
+ onChange={(event) => {
+ if (event.target.value.trim() !== "") {
+ setMovieTitle(event.target.value);
}
}}
- ></input>
- </section>
-
- <section className={styles.SearchResults}>{result}</section>
- </main>
+ onKeyDown={async (event) => {
+ if (event.key === "Enter" || event.code === "Enter") {
+ await handleInputChange();
+ }
+ }}
+ />
+ {loading}
+ </div>
+ <div className="mt-2">{movieResults}</div>
+ </section>
);
-}
+};
+
+export default MovieSearchBar;
diff --git a/src/app/movies/components/searchFormatter.jsx b/src/app/movies/components/searchFormatter.jsx
new file mode 100644
index 0000000..47b684f
--- /dev/null
+++ b/src/app/movies/components/searchFormatter.jsx
@@ -0,0 +1,51 @@
+import { Card, CardHeader, CardBody, Image, Link } from "@nextui-org/react";
+import NextImage from "next/image";
+
+import styles from "../../page.module.css";
+
+const MovieSearchFormatter = async (data) => {
+ return (
+ <section
+ className={`flex items-center overflow-auto pb-2 mb-2 ${styles.ScrollBarAdjuster}`}
+ >
+ {data &&
+ data.results.map((item, index) => {
+ if (item.poster_path) {
+ return (
+ <Link
+ key={index}
+ href={`/movies/${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={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${item.poster_path}`}
+ width={190}
+ 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.original_title}
+ </h4>
+ </CardHeader>
+ </Card>
+ </Link>
+ );
+ }
+ })}
+ </section>
+ );
+};
+
+export default MovieSearchFormatter;
diff --git a/src/app/movies/components/search_2.jsx b/src/app/movies/components/search_2.jsx
deleted file mode 100644
index cf3fc69..0000000
--- a/src/app/movies/components/search_2.jsx
+++ /dev/null
@@ -1,63 +0,0 @@
-"use server";
-
-import { SEARCH } from "../../../../utils/movie_urls";
-import PreFetchMovieInfo from "./cacher";
-import Image from "next/image";
-import Link from "next/link";
-import styles from "../styles/search.module.css";
-
-const SearchResults = async (title) => {
- const data = await get_search_results(title);
- PreFetchMovieInfo(data);
- if (data.results.length > 0) {
- return (
- <div className={styles.MovieSearchResultsContainer}>
- {data &&
- data.results &&
- data.results.map((item, index) => {
- if (item.poster_path) {
- return (
- <Link
- href={`/movies/${item.id}`}
- key={index}
- style={{
- backgroundImage: `url(https://image.tmdb.org/t/p/original${item.backdrop_path})`,
- backgroundRepeat: "no-repeat",
- backgroundSize: "cover",
- textDecoration: "none",
- color: "white",
- borderRadius: "0.5rem",
- overflow: "hidden",
- }}
- className={styles.MovieResultsPrev}
- >
- <section className={styles.MovieEntry}>
- <p>
- {item.title || item.original_title}
- </p>
- <Image
- src={`https://image.tmdb.org/t/p/original${item.poster_path}`}
- width={130}
- height={230}
- alt="Movie Poster"
- priority
- />
- </section>
- </Link>
- );
- }
- })}
- </div>
- );
- } else {
- return <p className={styles.NoResults}>No results found!</p>;
- }
-};
-
-const get_search_results = async (title) => {
- const res = await fetch(SEARCH + title, { next: { revalidate: 21600 } });
- const data = await res.json();
- return data;
-};
-
-export default SearchResults;
diff --git a/src/app/movies/components/trending.jsx b/src/app/movies/components/trending.jsx
deleted file mode 100644
index 8e20ba1..0000000
--- a/src/app/movies/components/trending.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { TRENDING } from "../../../../utils/movie_urls";
-import PreFetchMovieInfo from "./cacher";
-import styles from "../styles/pop_trend.module.css";
-import Link from "next/link";
-import Image from "next/image";
-
-export default async function TREDNING_MOVIES() {
- const data = await get_popular();
- PreFetchMovieInfo(data);
-
- return (
- <main className={styles.Main}>
- <h2>Trending Movies</h2>
- <section className={styles.MovieContainer}>
- {data &&
- data.results &&
- data.results.slice(0, 16).map((item, index) => (
- <Link
- href={`/movies/${item.id}`}
- style={{
- textDecoration: "none",
- color: "white",
- }}
- key={index}
- >
- <div className={styles.MovieEntryPrev}>
- <div className={styles.MovieEntry}>
- <Image
- src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${item.poster_path}`}
- width={180}
- height={300}
- alt="Movie Poster"
- ></Image>
- <p>{item.title}</p>
- </div>
- </div>
- </Link>
- ))}
- </section>
- </main>
- );
-}
-
-const get_popular = async () => {
- const res = await fetch(TRENDING, { next: { revalidate: 21620 } });
- const data = await res.json();
- return data;
-};
diff --git a/src/app/movies/components/videoPlayer.jsx b/src/app/movies/components/videoPlayer.jsx
new file mode 100644
index 0000000..b7cdd81
--- /dev/null
+++ b/src/app/movies/components/videoPlayer.jsx
@@ -0,0 +1,17 @@
+const MovieVideoPlayer = async ({ id: id }) => {
+ const videoFrameGenerator = (id) => {
+ return (
+ <iframe
+ src={`https://vidsrc.pro/embed/movie/${id}`}
+ allowFullScreen
+ referrerPolicy="origin"
+ height={720}
+ className="w-full h-[240px] lg:h-[720px]"
+ ></iframe>
+ );
+ };
+
+ return <section>{videoFrameGenerator(id)}</section>;
+};
+
+export default MovieVideoPlayer;
diff --git a/src/app/movies/components/video_player.jsx b/src/app/movies/components/video_player.jsx
deleted file mode 100644
index 74f6180..0000000
--- a/src/app/movies/components/video_player.jsx
+++ /dev/null
@@ -1,68 +0,0 @@
-"use client";
-
-import styles from "../styles/video_player.module.css";
-import { useState, useEffect } from "react";
-
-export default function VIDEO_PLAYER({ id: id }) {
- const [frame, setFrame] = useState(null);
-
- useEffect(() => {
- make_player(`https://vidsrc.icu/embed/movie/${id}`);
- }, []);
-
- function make_player(url) {
- setFrame(
- <iframe
- src={url}
- referrerPolicy="origin"
- allowFullScreen
- className={styles.VideoPlayer}
- ></iframe>
- );
- }
-
- return (
- <section className={styles.VideoContainer}>
- <div className={styles.sourcesButtonContainer}>
- <button
- onClick={() =>
- make_player(`https://vidsrc.pro/embed/movie/${id}`)
- }
- >
- Vidsrc.pro
- </button>
- <button
- onClick={() =>
- make_player(`https://blackvid.space/embed?tmdb=${id}`)
- }
- >
- Blackvid
- </button>
- <button
- onClick={() =>
- make_player(`https://vidsrc.to/embed/movie/${id}`)
- }
- >
- Vidsrc.to
- </button>
- <button
- onClick={() =>
- make_player(`https://vidsrc.icu/embed/movie/${id}`)
- }
- >
- Vidsrc.icu
- </button>
- <button
- onClick={() =>
- make_player(
- `https://player.autoembed.cc/embed/movie/${id}`
- )
- }
- >
- Autoembded.cc
- </button>
- </div>
- {frame}
- </section>
- );
-}