diff options
| author | real-zephex <[email protected]> | 2024-05-25 16:58:02 +0530 |
|---|---|---|
| committer | real-zephex <[email protected]> | 2024-05-25 16:58:02 +0530 |
| commit | 2d0bcaeeeffef4e6ed6f445378b9729e70901f61 (patch) | |
| tree | 40f63b16c4e11551b45b2989728eb659af47c6e2 /src/app/movies/components | |
| parent | ✅ fix(anime): fix continue watching functionality and minor tweaks (diff) | |
| download | dramalama-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.js | 5 | ||||
| -rw-r--r-- | src/app/movies/components/descriptionTabs.jsx | 67 | ||||
| -rw-r--r-- | src/app/movies/components/faqs.jsx | 33 | ||||
| -rw-r--r-- | src/app/movies/components/popular.jsx | 49 | ||||
| -rw-r--r-- | src/app/movies/components/requestsHandler.js | 36 | ||||
| -rw-r--r-- | src/app/movies/components/search.jsx | 71 | ||||
| -rw-r--r-- | src/app/movies/components/searchFormatter.jsx | 51 | ||||
| -rw-r--r-- | src/app/movies/components/search_2.jsx | 63 | ||||
| -rw-r--r-- | src/app/movies/components/trending.jsx | 48 | ||||
| -rw-r--r-- | src/app/movies/components/videoPlayer.jsx | 17 | ||||
| -rw-r--r-- | src/app/movies/components/video_player.jsx | 68 |
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> - ); -} |