aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorreal-zephex <[email protected]>2024-05-19 08:00:13 +0530
committerreal-zephex <[email protected]>2024-05-19 08:00:13 +0530
commit6ef5bd54d5cdea80adc6972dbcb662908b3e39dd (patch)
tree55c1c4ca2823ba62f2184d2de0ac29c4535117a5
parentminor changes to the manga page (diff)
downloaddramalama-6ef5bd54d5cdea80adc6972dbcb662908b3e39dd.tar.xz
dramalama-6ef5bd54d5cdea80adc6972dbcb662908b3e39dd.zip
added series support
-rw-r--r--src/app/anime/components/popularAnimes.jsx2
-rw-r--r--src/app/components/header/header.jsx1
-rw-r--r--src/app/page.jsx9
-rw-r--r--src/app/web-series/[id]/page.jsx111
-rw-r--r--src/app/web-series/components/HomePageModules.jsx56
-rw-r--r--src/app/web-series/components/cacher.js19
-rw-r--r--src/app/web-series/components/data-fetch.js87
-rw-r--r--src/app/web-series/components/searchBar.jsx49
-rw-r--r--src/app/web-series/components/searchResults.jsx35
-rw-r--r--src/app/web-series/components/videoPlayer.jsx71
-rw-r--r--src/app/web-series/page.jsx28
-rw-r--r--src/app/web-series/styles/info.module.css171
-rw-r--r--src/app/web-series/styles/pages.module.css46
-rw-r--r--src/app/web-series/styles/search.module.css78
-rw-r--r--src/app/web-series/styles/videoPlayer.module.css76
-rw-r--r--src/app/web-series/styles/web-series.module.css4
-rw-r--r--utils/movie_urls.js2
-rw-r--r--utils/series_urls.js28
18 files changed, 871 insertions, 2 deletions
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() {
<Link href="/kdrama">Kdrama</Link>
<Link href="/manga">Manga</Link>
<Link href="/movies">Movies</Link>
+ <Link href="/web-series">Web Series</Link>
</div>
</div>
</main>
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() {
<p>Your one stop for all your movie needs</p>
</div>
</Link>
+ <Link
+ href={"/web-series"}
+ title="Click here to get redirected to the kdrama webpage"
+ >
+ <div className={styles.movies}>
+ <h2>Web Series</h2>
+ <p>Your one stop for all your web-series needs</p>
+ </div>
+ </Link>
</div>
</div>
</main>
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 (
+ <main
+ style={{
+ // backgroundImage: `url(https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${data.backdrop_path})`,
+ background: `linear-gradient(to bottom, rgba(0, 0, 0, 0) 70%, rgba(0, 0, 0, 1) 100%),
+ url(https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${data.backdrop_path}) no-repeat center center fixed`,
+ backgroundSize: "cover",
+ }}
+ className={styles.Main}
+ >
+ <div className={styles.AnimeInfo}>
+ <section className={styles.AnimeInfoContainer}>
+ <div className={styles.TitleContainer}>
+ <Image
+ src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${data.poster_path}`}
+ width={190}
+ height={290}
+ alt="Series Poster"
+ priority
+ />
+ <section className={styles.SideTitleContainer}>
+ <h2 className={styles.title}>{data.name}</h2>
+ <p className={styles.secondTitle}>
+ {data.original_name}
+ </p>
+ <p className={styles.tagline}>
+ <span>{data.tagline || "not found"}</span>
+ </p>
+ <p className={styles.description}>
+ {" "}
+ {data.overview}
+ </p>
+ <hr />
+ <p className={styles.genres}>
+ Genres:{" "}
+ {data.genres.map((item, index) => (
+ <span key={index}>
+ {item.name}
+ {index !== data.genres.length - 1 &&
+ ", "}
+ </span>
+ ))}
+ </p>
+ <p className={styles.epiInfo}>
+ Seasons: <span>{data.number_of_seasons}</span>
+ </p>
+ <p className={styles.epiInfo}>
+ Episodes: <span>{data.number_of_episodes}</span>
+ </p>
+ <div className={styles.votes}>
+ <section className={styles.vote}>
+ <BiSolidUpvote color="var(--nord-green)" />{" "}
+ <p>{data.vote_count}</p>
+ </section>
+ <section className={styles.vote}>
+ <LiaStarSolid color="var(--nord-green)" />{" "}
+ <p>{data.vote_average}</p>
+ </section>
+ </div>
+ </section>
+ </div>
+ <section className={styles.CrewContainer}>
+ <h2>Crew</h2>
+ <div className={styles.CrewEntry}>
+ {crew_data &&
+ crew_data.cast.map((item, index) => (
+ <div
+ key={index}
+ className={styles.CastEntry}
+ >
+ <Image
+ src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${item.profile_path}`}
+ width={140}
+ height={190}
+ alt="Crew Poster"
+ />
+ <p>{item.name}</p>
+ <p style={{ fontSize: 11 }}>
+ {item.character}
+ </p>
+ </div>
+ ))}
+ </div>
+ </section>
+
+ <section className={styles.VideoContainer}>
+ <SeriesPlayer id={data.id} />
+ </section>
+ </section>
+ </div>
+ </main>
+ );
+};
+
+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 (
+ <main className={styles.main}>
+ <h2>{type} series</h2>
+ <section className={styles.SeriesContainer}>
+ {data &&
+ data.results.length > 0 &&
+ data.results.map((item, index) => (
+ <Link
+ key={index}
+ href={`/web-series/${item.id}`}
+ style={{ textDecoration: "none", color: "white" }}
+ title={item.name}
+ >
+ <section className={styles.SeriesEntry}>
+ <Image
+ src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${item.poster_path}`}
+ width={167}
+ height={267}
+ alt="Series Poster"
+ priority
+ />
+ <p>{item.name || "Not sure"}</p>
+ </section>
+ </Link>
+ ))}
+ </section>
+ </main>
+ );
+};
+
+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 (
+ <main className={styles.Main}>
+ <section className={styles.InputContainer}>
+ <FaSearch
+ color="white"
+ className={styles.SearchIcon}
+ size={17}
+ />
+ <input
+ placeholder="Enter series 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);
+ }
+ }}
+ ></input>
+ </section>
+
+ {loading && (
+ <p style={{ color: "white", textAlign: "center" }}>
+ Please wait while we crunch up all the data
+ </p>
+ )}
+ <section className={styles.SearchResults}>{result}</section>
+ </main>
+ );
+};
+
+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 (
+ <div className={styles.SearchedSeriesContainer}>
+ {data &&
+ data.results.map((item, index) => (
+ <Link
+ key={index}
+ style={{ color: "white", textDecoration: "none" }}
+ href={`/web-series/${item.id}`}
+ title={item.name}
+ >
+ <div className={styles.SearchedSeriesEntry}>
+ <Image
+ src={`https://sup-proxy.zephex0-f6c.workers.dev/api-content?url=https://image.tmdb.org/t/p/original${item.poster_path}`}
+ width={160}
+ height={247}
+ alt="Searched Series Poster"
+ />
+ <p>{item.name}</p>
+ </div>
+ </Link>
+ ))}
+ </div>
+ );
+};
+
+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 (
+ <main className={styles.Main}>
+ <div className={styles.EpisodeSeasonInput}>
+ <input
+ name="Season"
+ type="number"
+ placeholder="Season Number"
+ onChange={(e) => {
+ if (Number(e.target.value) > 0) {
+ setSeason(e.target.value);
+ }
+ }}
+ ></input>
+ <input
+ name="Episode"
+ type="number"
+ placeholder="Episode Number"
+ onChange={(e) => {
+ if (Number(e.target.value) > 0) {
+ setEpisode(e.target.value);
+ }
+ }}
+ ></input>
+
+ <button onClick={() => VideoPlayerInitialize(id)}>
+ Search
+ </button>
+ </div>
+
+ <div className={styles.VideoPlayer}>
+ {iframe}
+ <p id="video-player">
+ 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.
+ </p>
+ </div>
+ </main>
+ );
+};
+
+const iframeGenerator = async (id, seasonNumber, episodeNumber) => {
+ return (
+ <iframe
+ src={`https://vidsrc.pro/embed/tv/${id}/${seasonNumber}/${episodeNumber}`}
+ allowFullScreen
+ referrerPolicy="origin"
+ ></iframe>
+ );
+};
+
+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 (
+ <main className={styles.main}>
+ <SearchBar />
+ <Pages type={"popular"} />
+ <hr
+ style={{
+ borderColor: "grey",
+ marginTop: 15,
+ marginBottom: -15,
+ }}
+ />
+ <Pages type={"trending"} />
+ <hr
+ style={{
+ borderColor: "grey",
+ marginTop: 15,
+ marginBottom: -15,
+ }}
+ />
+ <Pages type={"top"} />
+ </main>
+ );
+}
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
diff --git a/utils/movie_urls.js b/utils/movie_urls.js
index dd39bb6..066041d 100644
--- a/utils/movie_urls.js
+++ b/utils/movie_urls.js
@@ -1,4 +1,4 @@
-const API_KEY = "171fe27dbfecc58e2a18fbced644cda9";
+export const API_KEY = "171fe27dbfecc58e2a18fbced644cda9";
export const PROXY = "https://sup-proxy.zephex0-f6c.workers.dev/api-json?url=";
// MOVIES
diff --git a/utils/series_urls.js b/utils/series_urls.js
new file mode 100644
index 0000000..26d83bf
--- /dev/null
+++ b/utils/series_urls.js
@@ -0,0 +1,28 @@
+import { API_KEY, PROXY } from "./movie_urls";
+
+// Popular TV shows
+export const popular_tv_shows = () =>
+ `${PROXY}https://api.themoviedb.org/3/tv/popular?api_key=${API_KEY}`;
+
+// Trending show either for the week or the day
+export const trending_tv_shows = (duration = "day") =>
+ `${PROXY}https://api.themoviedb.org/3/trending/tv/${duration}?api_key=${API_KEY}`;
+
+// Top Rated TV Shows
+export const top_rated_shows = () =>
+ `${PROXY}https://api.themoviedb.org/3/tv/top_rated?api_key=${API_KEY}`;
+
+// Recommendations based on a particular show
+export const recommended_shows = (id) =>
+ `https://api.themoviedb.org/3/tv/${id}/recommendations?api_key=${API_KEY}`;
+
+// Crew Details
+export const crew_details = (id) =>
+ `https://api.themoviedb.org/3/tv/${id}/credits?api_key=${API_KEY}`;
+
+// TV Info
+export const tv_info = (id) =>
+ `https://api.themoviedb.org/3/tv/${id}?api_key=${API_KEY}`;
+
+// Search shows
+export const search_tv = (query) => `https://api.themoviedb.org/3/search/tv?api_key=${API_KEY}&query=${query}` \ No newline at end of file