From 6ef5bd54d5cdea80adc6972dbcb662908b3e39dd Mon Sep 17 00:00:00 2001 From: real-zephex Date: Sun, 19 May 2024 08:00:13 +0530 Subject: added series support --- src/app/anime/components/popularAnimes.jsx | 2 +- src/app/components/header/header.jsx | 1 + src/app/page.jsx | 9 ++ src/app/web-series/[id]/page.jsx | 111 ++++++++++++++ src/app/web-series/components/HomePageModules.jsx | 56 +++++++ src/app/web-series/components/cacher.js | 19 +++ src/app/web-series/components/data-fetch.js | 87 +++++++++++ src/app/web-series/components/searchBar.jsx | 49 +++++++ src/app/web-series/components/searchResults.jsx | 35 +++++ src/app/web-series/components/videoPlayer.jsx | 71 +++++++++ src/app/web-series/page.jsx | 28 ++++ src/app/web-series/styles/info.module.css | 171 ++++++++++++++++++++++ src/app/web-series/styles/pages.module.css | 46 ++++++ src/app/web-series/styles/search.module.css | 78 ++++++++++ src/app/web-series/styles/videoPlayer.module.css | 76 ++++++++++ src/app/web-series/styles/web-series.module.css | 4 + 16 files changed, 842 insertions(+), 1 deletion(-) create mode 100644 src/app/web-series/[id]/page.jsx create mode 100644 src/app/web-series/components/HomePageModules.jsx create mode 100644 src/app/web-series/components/cacher.js create mode 100644 src/app/web-series/components/data-fetch.js create mode 100644 src/app/web-series/components/searchBar.jsx create mode 100644 src/app/web-series/components/searchResults.jsx create mode 100644 src/app/web-series/components/videoPlayer.jsx create mode 100644 src/app/web-series/page.jsx create mode 100644 src/app/web-series/styles/info.module.css create mode 100644 src/app/web-series/styles/pages.module.css create mode 100644 src/app/web-series/styles/search.module.css create mode 100644 src/app/web-series/styles/videoPlayer.module.css create mode 100644 src/app/web-series/styles/web-series.module.css (limited to 'src') diff --git a/src/app/anime/components/popularAnimes.jsx b/src/app/anime/components/popularAnimes.jsx index 2259a42..5bf8904 100644 --- a/src/app/anime/components/popularAnimes.jsx +++ b/src/app/anime/components/popularAnimes.jsx @@ -4,7 +4,7 @@ import { Atkinson_Hyperlegible } from "next/font/google"; import styles from "../styles/pop_recent_top.module.css"; import { popular, anime_info } from "../data-fetch/request"; -import { preFetchAnimeInfo, preFetchVideoLinks } from "./cacher"; +import { preFetchAnimeInfo } from "./cacher"; const atkinson = Atkinson_Hyperlegible({ subsets: ["latin"], weight: "400" }); diff --git a/src/app/components/header/header.jsx b/src/app/components/header/header.jsx index c1fbc2d..ba9ff86 100644 --- a/src/app/components/header/header.jsx +++ b/src/app/components/header/header.jsx @@ -18,6 +18,7 @@ export default async function Header() { Kdrama Manga Movies + Web Series diff --git a/src/app/page.jsx b/src/app/page.jsx index 4f9eda2..91f9551 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -42,6 +42,15 @@ export default async function Home() {

Your one stop for all your movie needs

+ +
+

Web Series

+

Your one stop for all your web-series needs

+
+ diff --git a/src/app/web-series/[id]/page.jsx b/src/app/web-series/[id]/page.jsx new file mode 100644 index 0000000..63fcc3a --- /dev/null +++ b/src/app/web-series/[id]/page.jsx @@ -0,0 +1,111 @@ +import Image from "next/image"; +import { SERIES_INFO, CREW_DETAILS } from "../components/data-fetch"; +import styles from "../styles/info.module.css"; +import { BiSolidUpvote } from "react-icons/bi"; +import { LiaStarSolid } from "react-icons/lia"; +import SeriesPlayer from "../components/videoPlayer"; + +const SeriesInfoPage = async ({ params }) => { + const id = params.id; + const data = await FetchSeriesInfo(id); + const crew_data = await CREW_DETAILS(id); + return ( +
+
+
+
+ Series Poster +
+

{data.name}

+

+ {data.original_name} +

+

+ {data.tagline || "not found"} +

+

+ {" "} + {data.overview} +

+
+

+ Genres:{" "} + {data.genres.map((item, index) => ( + + {item.name} + {index !== data.genres.length - 1 && + ", "} + + ))} +

+

+ Seasons: {data.number_of_seasons} +

+

+ Episodes: {data.number_of_episodes} +

+
+
+ {" "} +

{data.vote_count}

+
+
+ {" "} +

{data.vote_average}

+
+
+
+
+
+

Crew

+
+ {crew_data && + crew_data.cast.map((item, index) => ( +
+ Crew Poster +

{item.name}

+

+ {item.character} +

+
+ ))} +
+
+ +
+ +
+
+
+
+ ); +}; + +const FetchSeriesInfo = async (id) => { + const data = SERIES_INFO(id); + return data; +}; + +export default SeriesInfoPage; diff --git a/src/app/web-series/components/HomePageModules.jsx b/src/app/web-series/components/HomePageModules.jsx new file mode 100644 index 0000000..90af2f8 --- /dev/null +++ b/src/app/web-series/components/HomePageModules.jsx @@ -0,0 +1,56 @@ +import { POPULAR_SHOWS, TRENDING_SHOWS, TOP_SHOWS } from "./data-fetch"; +import styles from "../styles/pages.module.css"; +import Image from "next/image"; +import Link from "next/link"; +import PreFecthSeriesInfo from "./cacher"; + +const HomepageUtils = async (type) => { + const fetchFunctions = { + popular: POPULAR_SHOWS, + trending: TRENDING_SHOWS, + top: TOP_SHOWS, + }; + + const fetchData = fetchFunctions[type]; + + if (fetchData) { + return await fetchData(); + } else { + return; + } +}; + +const Pages = async ({ type: type }) => { + const data = await HomepageUtils(type); + PreFecthSeriesInfo(data); + return ( +
+

{type} series

+
+ {data && + data.results.length > 0 && + data.results.map((item, index) => ( + +
+ Series Poster +

{item.name || "Not sure"}

+
+ + ))} +
+
+ ); +}; + +export default Pages; diff --git a/src/app/web-series/components/cacher.js b/src/app/web-series/components/cacher.js new file mode 100644 index 0000000..3e2a197 --- /dev/null +++ b/src/app/web-series/components/cacher.js @@ -0,0 +1,19 @@ +import { SERIES_INFO } from "./data-fetch"; + +const PreFecthSeriesInfo = async (data) => { + try { + const fetchPromises = data.results.map(async (element) => { + await SERIES_INFO(element.id); + }); + + await Promise.all(fetchPromises); + console.log("Series info pre-fetched successfully!"); + } catch (error) { + console.error( + "Error occurred while pre-fetching series info page:", + error + ); + } +}; + +export default PreFecthSeriesInfo; diff --git a/src/app/web-series/components/data-fetch.js b/src/app/web-series/components/data-fetch.js new file mode 100644 index 0000000..e0feca5 --- /dev/null +++ b/src/app/web-series/components/data-fetch.js @@ -0,0 +1,87 @@ +"use server"; + +import { + popular_tv_shows, + trending_tv_shows, + top_rated_shows, + recommended_shows, + crew_details, + tv_info, + search_tv, +} from "../../../../utils/series_urls"; + +export const POPULAR_SHOWS = async () => { + try { + const res = await fetch(popular_tv_shows(), { + next: { + revalidate: 21600, + }, + }); + const data = await res.json(); + return data; + } catch (error) { + throw new Error(error.message); + } +}; + +export const TRENDING_SHOWS = async () => { + try { + const res = await fetch(trending_tv_shows(), { + next: { + revalidate: 21600, + }, + }); + const data = await res.json(); + return data; + } catch (error) { + throw new Error(error.message); + } +}; + +export const TOP_SHOWS = async () => { + try { + const res = await fetch(top_rated_shows(), { + next: { + revalidate: 21600, + }, + }); + const data = await res.json(); + return data; + } catch (error) { + throw new Error(error.message); + } +}; + +export const SERIES_INFO = async (id) => { + try { + const res = await fetch(tv_info(id), { next: { revalidate: 21600 } }); + const data = await res.json(); + return data; + } catch (error) { + throw new Error(error.message); + } +}; + +export const CREW_DETAILS = async (id) => { + try { + const res = await fetch(crew_details(id), { + next: { revalidate: 21600 }, + }); + const data = await res.json(); + return data; + } catch (error) { + throw new Error(error.message); + } +}; + +export const SEARCH_TV = async (title) => { + try { + const res = await fetch(search_tv(title), { + next: { revalidate: 21600 }, + }); + const data = await res.json(); + return data; + } catch (error) { + throw new Error(error.message); + } +}; diff --git a/src/app/web-series/components/searchBar.jsx b/src/app/web-series/components/searchBar.jsx new file mode 100644 index 0000000..81dd25f --- /dev/null +++ b/src/app/web-series/components/searchBar.jsx @@ -0,0 +1,49 @@ +"use client"; +import styles from "../styles/search.module.css"; +import { FaSearch } from "react-icons/fa"; +import { useState } from "react"; + +import { SEARCH_TV } from "./data-fetch"; +import SearchResults from "./searchResults"; + +const SearchBar = () => { + const [title, setTitle] = useState(""); + const [result, setResults] = useState(null); + const [loading, setloading] = useState(false); + + const fetch_results = async (title) => { + setloading(true); + setResults(await SearchResults(await SEARCH_TV(title))); + setloading(false); + }; + + return ( +
+
+ + setTitle(event.target.value)} + onKeyDown={async (e) => { + if ((e.key === "Enter" || e.code === 13) && title) { + await fetch_results(e.target.value); + } + }} + > +
+ + {loading && ( +

+ Please wait while we crunch up all the data +

+ )} +
{result}
+
+ ); +}; + +export default SearchBar; diff --git a/src/app/web-series/components/searchResults.jsx b/src/app/web-series/components/searchResults.jsx new file mode 100644 index 0000000..d1564e0 --- /dev/null +++ b/src/app/web-series/components/searchResults.jsx @@ -0,0 +1,35 @@ +"use server"; + +import Link from "next/link"; +import Image from "next/image"; +import styles from "../styles/search.module.css"; +import PreFecthSeriesInfo from "./cacher"; + +const SearchResults = async (data) => { + PreFecthSeriesInfo(data); + return ( +
+ {data && + data.results.map((item, index) => ( + +
+ Searched Series Poster +

{item.name}

+
+ + ))} +
+ ); +}; + +export default SearchResults; diff --git a/src/app/web-series/components/videoPlayer.jsx b/src/app/web-series/components/videoPlayer.jsx new file mode 100644 index 0000000..0e6b603 --- /dev/null +++ b/src/app/web-series/components/videoPlayer.jsx @@ -0,0 +1,71 @@ +"use client"; + +import { useState } from "react"; +import styles from "../styles/videoPlayer.module.css"; + +const SeriesPlayer = ({ id: id }) => { + const [iframe, iframeContent] = useState(null); + const [episode, setEpisode] = useState(""); + const [season, setSeason] = useState(""); + + async function VideoPlayerInitialize() { + if (!episode || !season) { + alert("Please provide the required episode and season number."); + return; + } + iframeContent(await iframeGenerator(id, season, episode)); + document.getElementById("video-player").style.display = "none"; + } + + return ( +
+
+ { + if (Number(e.target.value) > 0) { + setSeason(e.target.value); + } + }} + > + { + if (Number(e.target.value) > 0) { + setEpisode(e.target.value); + } + }} + > + + +
+ +
+ {iframe} +

+ Please use adblockers to prevent ads and redirects. We have + no control over the amount of ads or the type of ads which + you might encounter. +

+
+
+ ); +}; + +const iframeGenerator = async (id, seasonNumber, episodeNumber) => { + return ( + + ); +}; + +export default SeriesPlayer; diff --git a/src/app/web-series/page.jsx b/src/app/web-series/page.jsx new file mode 100644 index 0000000..63fcd05 --- /dev/null +++ b/src/app/web-series/page.jsx @@ -0,0 +1,28 @@ +import styles from "./styles/web-series.module.css"; +import Pages from "./components/HomePageModules"; +import SearchBar from "./components/searchBar"; + +export default async function SeriesHomepage() { + return ( +
+ + +
+ +
+ +
+ ); +} diff --git a/src/app/web-series/styles/info.module.css b/src/app/web-series/styles/info.module.css new file mode 100644 index 0000000..8873b41 --- /dev/null +++ b/src/app/web-series/styles/info.module.css @@ -0,0 +1,171 @@ +.Main { + min-height: 100vh; + margin-top: 60px; + +} + +.Main::-webkit-scrollbar { + width: 0; +} + +.AnimeInfo { + backdrop-filter: blur(10px); + background-color: #1f1f1fcb; + +} + +.AnimeInfoContainer { + width: 50%; + height: 100vh; + margin: 0px auto; +} + +.TitleContainer { + display: flex; + align-items: center; +} + +.TitleContainer img { + border-radius: 0.8rem; + padding: 0.5rem; +} + +.SideTitleContainer { + margin: 0.4rem; + color: white; +} + +.title { + margin: 0; +} + +.secondTitle { + margin: 0; + font-size: small; +} + +.tagline { + margin: 0; +} + +.tagline span { + background-color: #121212b7; + padding: 0.2rem; + border-radius: 0.5rem; + font-size: 12px; +} + +.description { + margin: 0.2rem 0 0 0; + height: auto; + max-height: 100px; + overflow: auto; +} + +.description::-webkit-scrollbar { + width: 3px; +} + +.description::-webkit-scrollbar-thumb { + background-color: var(--neon-yellow); + border-radius: 1rem; +} + + +.genres { + margin: 0; + color: var(--nord-yellow); +} + +.genres span { + color: white; +} + +.epiInfo { + margin: 0; + color: var(--nord-yellow); +} + +.epiInfo span { + color: white; +} + +.votes { + display: flex; +} + +.votes p { + margin: 0 0 0 0; +} + +.vote { + display: flex; + align-items: center; + margin: 0 0.2rem 0 0; +} + +.CrewContainer { + color: white; + margin-top: -1rem; +} + +.CrewEntry { + display: flex; + align-items: center; + overflow: auto; +} + +.CrewEntry h2 { + margin: 0; + color: white; +} + +.CastEntry { + display: flex; + flex-direction: column; + align-items: center; + margin: 0 0 0 0.4rem; +} + +.CastEntry img { + border-radius: 0.5rem; +} + +.CastEntry p { + margin: 0; + width: 140px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + text-align: center; +} + +.CrewEntry::-webkit-scrollbar { + height: 3px; +} + +.CrewEntry::-webkit-scrollbar-thumb { + background-color: var(--neon-yellow); + border-radius: 1rem; +} + + +@media screen and (max-width: 1024px) { + .AnimeInfoContainer { + width: 100%; + } + + .title { + font-size: 20px; + } + + .description { + font-size: 14px; + max-height: 100px; + overflow: auto; + } + + .SideTitleContainer { + font-size: 14px; + } +} \ No newline at end of file diff --git a/src/app/web-series/styles/pages.module.css b/src/app/web-series/styles/pages.module.css new file mode 100644 index 0000000..631f7db --- /dev/null +++ b/src/app/web-series/styles/pages.module.css @@ -0,0 +1,46 @@ +.main h2 { + color: white; +} + +.SeriesContainer { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); + grid-gap: 0.5rem; + align-items: center; + margin: -1rem 0 0 0; +} + +.SeriesEntry { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: #1f1f1fce; + border-radius: 0.5rem; + padding: 0.4rem; + color: white; + cursor: pointer; +} + +.SeriesEntry p { + width: 160px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + text-align: center; + margin: 0.3rem 0 0 0; + font-family: "Atkinson Hyperlegible", serif; +} + +.SeriesEntry img { + border-radius: 0.5rem; +} + +@media screen and (max-width: 768px) { + .SeriesContainer { + display: flex; + align-items: center; + overflow-x: auto; + overflow-y: hidden; + } +} \ No newline at end of file diff --git a/src/app/web-series/styles/search.module.css b/src/app/web-series/styles/search.module.css new file mode 100644 index 0000000..145a2aa --- /dev/null +++ b/src/app/web-series/styles/search.module.css @@ -0,0 +1,78 @@ +.InputContainer { + display: flex; + align-items: center; + background-color: #121212; + width: 40vw; + border-radius: 0.5rem; +} + +.SearchIcon { + margin-left: 0.4rem; +} + +.InputContainer input { + background-color: transparent; + outline: none; + border: none; + padding: 0.4rem; + font-family: "Lexend Deca", serif; + margin-left: 0.2rem; + font-size: large; + color: white; + width: 100%; +} + +.SearchedSeriesContainer { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); + grid-gap: 0.7rem; + align-items: center; + margin-top: 0.8rem; +} + +.SearchedSeriesEntry { + display: flex; + align-items: center; + flex-direction: column; + background-color: #1f1f1f; + border-radius: 0.5rem; + padding: 0.2rem; + transition: opacity 200ms ease; + +} + +.SearchedSeriesContainer:hover .SearchedSeriesEntry { + opacity: 0.5; +} + +.SearchedSeriesContainer .SearchedSeriesEntry:hover { + opacity: 1; +} + +.SearchedSeriesEntry p { + width: 150px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + text-align: center; + margin: 0.2rem 0 0.2rem 0; +} + +.SearchedSeriesEntry img { + border-radius: 0.5rem; + padding: 0.2rem 0.2rem 0 0.2rem; +} + +@media screen and (max-width: 768px) { + + .InputContainer { + width: 100%; + } + + .SearchedSeriesContainer { + display: flex; + overflow: auto; + } + + +} \ No newline at end of file diff --git a/src/app/web-series/styles/videoPlayer.module.css b/src/app/web-series/styles/videoPlayer.module.css new file mode 100644 index 0000000..f44776f --- /dev/null +++ b/src/app/web-series/styles/videoPlayer.module.css @@ -0,0 +1,76 @@ +.Main { + margin: 1.5rem 0 0 0; +} + +.EpisodeSeasonInput { + display: flex; + align-items: center; + justify-content: center; +} + +.EpisodeSeasonInput input { + padding: 0.6rem; + margin: 0 0.2rem 0 0.2rem; + border: none; + outline: none; + background-color: #121212a6; + border-radius: 0.5rem; + font-family: "Lexend Deca", serif; + color: white; +} + +.EpisodeSeasonInput button { + padding: 0.5rem; + border: none; + outline: none; + border-radius: 0.5rem; + background-color: #121212a6; + color: white; + cursor: pointer; + font-family: "Atkinson Hyperlegible", serif; +} + + +.EpisodeSeasonInput input::placeholder { + color: gray; +} + +.VideoPlayer iframe { + margin: 1rem 0 2.5rem 0; + width: 100%; + height: 400px; + border-radius: 0.5rem; + border: none; + outline: none; +} + +.VideoPlayer p { + color: white; + margin: 0.5rem 0 0 0; + text-align: center; + font-size: 12px; +} + +@media screen and (max-width: 768px) { + + .EpisodeSeasonInput { + width: 80%; + margin: 0px auto; + } + + .VideoPlayer iframe { + width: 100%; + height: 300px; + margin-bottom: 50px; + } + + .EpisodeSeasonInput input { + padding: 0.4rem; + } + + .EpisodeSeasonInput button { + padding: 0.3rem 0.4rem 0.3rem 0.4rem; + font-size: 14px; + } + +} \ No newline at end of file diff --git a/src/app/web-series/styles/web-series.module.css b/src/app/web-series/styles/web-series.module.css new file mode 100644 index 0000000..849fed9 --- /dev/null +++ b/src/app/web-series/styles/web-series.module.css @@ -0,0 +1,4 @@ +.main { + margin: 65px auto; + width: 99%; +} \ No newline at end of file -- cgit v1.2.3 From 6e83d0f37cb00785d142f9ddefddeff17535e77b Mon Sep 17 00:00:00 2001 From: real-zephex Date: Sun, 19 May 2024 08:05:01 +0530 Subject: added series support --- src/app/web-series/components/videoPlayer.jsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/app/web-series/components/videoPlayer.jsx b/src/app/web-series/components/videoPlayer.jsx index 0e6b603..cc8feb3 100644 --- a/src/app/web-series/components/videoPlayer.jsx +++ b/src/app/web-series/components/videoPlayer.jsx @@ -59,13 +59,8 @@ const SeriesPlayer = ({ id: id }) => { }; const iframeGenerator = async (id, seasonNumber, episodeNumber) => { - return ( - - ); + const url = `https://vidsrc.pro/embed/tv/${id}/${seasonNumber}/${episodeNumber}`; + return ; }; export default SeriesPlayer; -- cgit v1.2.3