Spaces:
Build error
Build error
Commit ·
04878ca
1
Parent(s): 18bf8cd
0.0.8 V Alpha. added Tv SHow Player.
Browse files- frontend/src/App.js +3 -0
- frontend/src/components/tv/backArrow.js +14 -0
- frontend/src/config.js +1 -1
- frontend/src/pages/filmPlayer.css +24 -5
- frontend/src/pages/searchPage.js +19 -15
- frontend/src/pages/tvshowDetailsPage.js +8 -5
- frontend/src/pages/tvshowPlayer.css +100 -0
- frontend/src/pages/tvshowPlayer.js +82 -0
frontend/src/App.js
CHANGED
|
@@ -29,10 +29,12 @@ import { TvShowsProvider } from "./context/TvShowsContext";
|
|
| 29 |
import "./App.css";
|
| 30 |
import MenueModal from "./components/modals/menueModal";
|
| 31 |
import FilmPlayer from "./pages/filmPlayer";
|
|
|
|
| 32 |
import TvShowDetailsPage from "./pages/tvshowDetailsPage";
|
| 33 |
import AdminPage from "./pages/Admin/adminPage";
|
| 34 |
import SearchPage from "./pages/searchPage";
|
| 35 |
|
|
|
|
| 36 |
library.add(
|
| 37 |
faEllipsisVertical,
|
| 38 |
faPlay,
|
|
@@ -182,6 +184,7 @@ function AppContent() {
|
|
| 182 |
<Route path="/tvshows" element={<TvShowsPage />} />
|
| 183 |
<Route path="/film/:title" element={<FilmDetailsPage />} />
|
| 184 |
<Route path="/player/film/:videoUrl" element={<FilmPlayer />} />
|
|
|
|
| 185 |
<Route path="/tvshow/:title" element={<TvShowDetailsPage />} />
|
| 186 |
<Route path="/admin" element={<AdminPage />} />
|
| 187 |
</Routes>
|
|
|
|
| 29 |
import "./App.css";
|
| 30 |
import MenueModal from "./components/modals/menueModal";
|
| 31 |
import FilmPlayer from "./pages/filmPlayer";
|
| 32 |
+
import TvshowPlayer from "./pages/tvshowPlayer";
|
| 33 |
import TvShowDetailsPage from "./pages/tvshowDetailsPage";
|
| 34 |
import AdminPage from "./pages/Admin/adminPage";
|
| 35 |
import SearchPage from "./pages/searchPage";
|
| 36 |
|
| 37 |
+
|
| 38 |
library.add(
|
| 39 |
faEllipsisVertical,
|
| 40 |
faPlay,
|
|
|
|
| 184 |
<Route path="/tvshows" element={<TvShowsPage />} />
|
| 185 |
<Route path="/film/:title" element={<FilmDetailsPage />} />
|
| 186 |
<Route path="/player/film/:videoUrl" element={<FilmPlayer />} />
|
| 187 |
+
<Route path="/player/tvshow/:title/:season/:episode" element={<TvshowPlayer />} />
|
| 188 |
<Route path="/tvshow/:title" element={<TvShowDetailsPage />} />
|
| 189 |
<Route path="/admin" element={<AdminPage />} />
|
| 190 |
</Routes>
|
frontend/src/components/tv/backArrow.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React from "react";
|
| 2 |
+
import { useNavigate } from "react-router-dom";
|
| 3 |
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
| 4 |
+
|
| 5 |
+
const BackArrow = () => {
|
| 6 |
+
const navigate = useNavigate();
|
| 7 |
+
return (
|
| 8 |
+
<div className="back-arrow" onClick={() => navigate("/")}>
|
| 9 |
+
<FontAwesomeIcon icon="fa-solid fa-chevron-left" />
|
| 10 |
+
</div>
|
| 11 |
+
);
|
| 12 |
+
};
|
| 13 |
+
|
| 14 |
+
export default BackArrow;
|
frontend/src/config.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
const config = {
|
| 3 |
apiBaseUrl: 'https://unicone-studio-load-balancer.hf.space',
|
| 4 |
searchUrl: 'https://unicone-studio-search.hf.space/api/search',
|
| 5 |
-
version: "0.0.
|
| 6 |
};
|
| 7 |
|
| 8 |
export default config;
|
|
|
|
| 2 |
const config = {
|
| 3 |
apiBaseUrl: 'https://unicone-studio-load-balancer.hf.space',
|
| 4 |
searchUrl: 'https://unicone-studio-search.hf.space/api/search',
|
| 5 |
+
version: "0.0.8 V Alpha",
|
| 6 |
};
|
| 7 |
|
| 8 |
export default config;
|
frontend/src/pages/filmPlayer.css
CHANGED
|
@@ -1,8 +1,14 @@
|
|
| 1 |
.film-player-container {
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
}
|
| 7 |
|
| 8 |
.film-player-container .plyr {
|
|
@@ -38,7 +44,20 @@
|
|
| 38 |
opacity: 1;
|
| 39 |
}
|
| 40 |
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
/* Handle animations on page load */
|
| 43 |
@keyframes pageLoad {
|
| 44 |
from {
|
|
|
|
| 1 |
.film-player-container {
|
| 2 |
+
background-color: #121212; /* Dark background */
|
| 3 |
+
color: #e0e0e0; /* Light text color for readability */
|
| 4 |
+
padding: 0; /* Remove padding to avoid unnecessary scrolling */
|
| 5 |
+
position: relative;
|
| 6 |
+
height: 100vh;
|
| 7 |
+
display: flex;
|
| 8 |
+
flex-direction: column;
|
| 9 |
+
justify-content: center;
|
| 10 |
+
align-items: center;
|
| 11 |
+
overflow: hidden; /* Prevent any overflow causing scroll */
|
| 12 |
}
|
| 13 |
|
| 14 |
.film-player-container .plyr {
|
|
|
|
| 44 |
opacity: 1;
|
| 45 |
}
|
| 46 |
|
| 47 |
+
.plyr {
|
| 48 |
+
width: 100%;
|
| 49 |
+
max-width: 100%;
|
| 50 |
+
height: 100%;
|
| 51 |
+
max-height: 100vh;
|
| 52 |
+
object-fit: contain;
|
| 53 |
+
--plyr-color-main: #ff5722; /* Orange */
|
| 54 |
+
--plyr-color-controls: #e0e0e0; /* Light controls */
|
| 55 |
+
--plyr-color-progress: #ff5722; /* Orange progress bar */
|
| 56 |
+
--plyr-color-buffer: #333; /* Dark buffer bar */
|
| 57 |
+
--plyr-color-volume: #ff5722; /* Orange volume control */
|
| 58 |
+
--plyr-color-time: #e0e0e0; /* Light time controls */
|
| 59 |
+
--plyr-color-fullscreen: #ff5722; /* Orange fullscreen button */
|
| 60 |
+
}
|
| 61 |
/* Handle animations on page load */
|
| 62 |
@keyframes pageLoad {
|
| 63 |
from {
|
frontend/src/pages/searchPage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import React, { useState, useEffect } from "react";
|
|
|
|
| 2 |
import { search } from "../api/searchApi";
|
| 3 |
-
import { Link } from "react-router-dom";
|
| 4 |
import "./searchPage.css";
|
| 5 |
|
| 6 |
const SearchPage = () => {
|
|
@@ -10,6 +10,8 @@ const SearchPage = () => {
|
|
| 10 |
const [error, setError] = useState(null);
|
| 11 |
const [debouncedQuery, setDebouncedQuery] = useState("");
|
| 12 |
|
|
|
|
|
|
|
| 13 |
useEffect(() => {
|
| 14 |
const handler = setTimeout(() => {
|
| 15 |
if (debouncedQuery) {
|
|
@@ -40,6 +42,10 @@ const SearchPage = () => {
|
|
| 40 |
setDebouncedQuery(e.target.value);
|
| 41 |
};
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
return (
|
| 44 |
<div className="search-page">
|
| 45 |
<div className="search-container">
|
|
@@ -63,13 +69,12 @@ const SearchPage = () => {
|
|
| 63 |
<h2>Films</h2>
|
| 64 |
<ul className="results-list">
|
| 65 |
{results.films.map((film, index) => (
|
| 66 |
-
<li
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
</Link>
|
| 73 |
</li>
|
| 74 |
))}
|
| 75 |
</ul>
|
|
@@ -80,13 +85,12 @@ const SearchPage = () => {
|
|
| 80 |
<h2>TV Series</h2>
|
| 81 |
<ul className="results-list">
|
| 82 |
{results.tv_series.map((series, index) => (
|
| 83 |
-
<li
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
</Link>
|
| 90 |
</li>
|
| 91 |
))}
|
| 92 |
</ul>
|
|
|
|
| 1 |
import React, { useState, useEffect } from "react";
|
| 2 |
+
import { useNavigate } from "react-router-dom";
|
| 3 |
import { search } from "../api/searchApi";
|
|
|
|
| 4 |
import "./searchPage.css";
|
| 5 |
|
| 6 |
const SearchPage = () => {
|
|
|
|
| 10 |
const [error, setError] = useState(null);
|
| 11 |
const [debouncedQuery, setDebouncedQuery] = useState("");
|
| 12 |
|
| 13 |
+
const navigate = useNavigate();
|
| 14 |
+
|
| 15 |
useEffect(() => {
|
| 16 |
const handler = setTimeout(() => {
|
| 17 |
if (debouncedQuery) {
|
|
|
|
| 42 |
setDebouncedQuery(e.target.value);
|
| 43 |
};
|
| 44 |
|
| 45 |
+
const handleItemClick = (path) => {
|
| 46 |
+
navigate(path);
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
return (
|
| 50 |
<div className="search-page">
|
| 51 |
<div className="search-container">
|
|
|
|
| 69 |
<h2>Films</h2>
|
| 70 |
<ul className="results-list">
|
| 71 |
{results.films.map((film, index) => (
|
| 72 |
+
<li
|
| 73 |
+
key={index}
|
| 74 |
+
className="result-item"
|
| 75 |
+
onClick={() => handleItemClick(`/film/${encodeURIComponent(film)}`)}
|
| 76 |
+
>
|
| 77 |
+
{film}
|
|
|
|
| 78 |
</li>
|
| 79 |
))}
|
| 80 |
</ul>
|
|
|
|
| 85 |
<h2>TV Series</h2>
|
| 86 |
<ul className="results-list">
|
| 87 |
{results.tv_series.map((series, index) => (
|
| 88 |
+
<li
|
| 89 |
+
key={index}
|
| 90 |
+
className="result-item"
|
| 91 |
+
onClick={() => handleItemClick(`/tvshow/${encodeURIComponent(series)}`)}
|
| 92 |
+
>
|
| 93 |
+
{series}
|
|
|
|
| 94 |
</li>
|
| 95 |
))}
|
| 96 |
</ul>
|
frontend/src/pages/tvshowDetailsPage.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import React, { useEffect, useState, useCallback } from "react";
|
|
|
|
| 2 |
import { useParams } from "react-router-dom";
|
| 3 |
import apiClient from "../api/apiClient";
|
| 4 |
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
@@ -162,11 +163,11 @@ function TvShowDetailsPage() {
|
|
| 162 |
if (index >= 0 && index < tvshowFiles.length) {
|
| 163 |
setSeasonIndex(index);
|
| 164 |
setSelectedSeason(tvshowFiles[index]);
|
|
|
|
| 165 |
} else {
|
| 166 |
-
console.error(
|
| 167 |
}
|
| 168 |
};
|
| 169 |
-
|
| 170 |
|
| 171 |
if (loading) {
|
| 172 |
return <div className="loading">Loading...</div>;
|
|
@@ -306,9 +307,11 @@ function TvShowDetailsPage() {
|
|
| 306 |
<h3>{selectedSeason.season}</h3>
|
| 307 |
<div className="episode-cards">
|
| 308 |
{selectedSeason.episodes.map((episode, i) => (
|
| 309 |
-
<
|
| 310 |
-
<
|
| 311 |
-
|
|
|
|
|
|
|
| 312 |
))}
|
| 313 |
</div>
|
| 314 |
</div>
|
|
|
|
| 1 |
import React, { useEffect, useState, useCallback } from "react";
|
| 2 |
+
import { Link } from "react-router-dom";
|
| 3 |
import { useParams } from "react-router-dom";
|
| 4 |
import apiClient from "../api/apiClient";
|
| 5 |
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
|
| 163 |
if (index >= 0 && index < tvshowFiles.length) {
|
| 164 |
setSeasonIndex(index);
|
| 165 |
setSelectedSeason(tvshowFiles[index]);
|
| 166 |
+
console.log(selectedSeason);
|
| 167 |
} else {
|
| 168 |
+
console.error("Invalid season index:", index);
|
| 169 |
}
|
| 170 |
};
|
|
|
|
| 171 |
|
| 172 |
if (loading) {
|
| 173 |
return <div className="loading">Loading...</div>;
|
|
|
|
| 307 |
<h3>{selectedSeason.season}</h3>
|
| 308 |
<div className="episode-cards">
|
| 309 |
{selectedSeason.episodes.map((episode, i) => (
|
| 310 |
+
<Link to={`/player/tvshow/${encodeURIComponent(title)}/${encodeURIComponent(selectedSeason.season)}/${encodeURIComponent(episode)}`}>
|
| 311 |
+
<div className="episode-card" key={episode}>
|
| 312 |
+
<p>{episode}</p>
|
| 313 |
+
</div>
|
| 314 |
+
</Link>
|
| 315 |
))}
|
| 316 |
</div>
|
| 317 |
</div>
|
frontend/src/pages/tvshowPlayer.css
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* TvshowPlayer.css */
|
| 2 |
+
.tvshow-player-container {
|
| 3 |
+
background-color: #121212; /* Dark background */
|
| 4 |
+
color: #e0e0e0; /* Light text color for readability */
|
| 5 |
+
padding: 0; /* Remove padding to avoid unnecessary scrolling */
|
| 6 |
+
position: relative;
|
| 7 |
+
height: 100vh;
|
| 8 |
+
display: flex;
|
| 9 |
+
flex-direction: column;
|
| 10 |
+
justify-content: center;
|
| 11 |
+
align-items: center;
|
| 12 |
+
overflow: hidden; /* Prevent any overflow causing scroll */
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
/* Ensure the player controls don't affect the video aspect ratio */
|
| 16 |
+
.plyr__video-embed {
|
| 17 |
+
position: relative;
|
| 18 |
+
padding-bottom: 56.25%; /* 16:9 aspect ratio */
|
| 19 |
+
height: 0;
|
| 20 |
+
overflow: hidden;
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
background: black;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
.plyr__video-embed iframe {
|
| 26 |
+
position: absolute;
|
| 27 |
+
top: 0;
|
| 28 |
+
left: 0;
|
| 29 |
+
width: 100%;
|
| 30 |
+
height: 100%;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
.plyr {
|
| 34 |
+
width: 100%;
|
| 35 |
+
max-width: 100%;
|
| 36 |
+
height: 100%;
|
| 37 |
+
max-height: 100vh;
|
| 38 |
+
object-fit: contain;
|
| 39 |
+
--plyr-color-main: #ff5722; /* Orange */
|
| 40 |
+
--plyr-color-controls: #e0e0e0; /* Light controls */
|
| 41 |
+
--plyr-color-progress: #ff5722; /* Orange progress bar */
|
| 42 |
+
--plyr-color-buffer: #333; /* Dark buffer bar */
|
| 43 |
+
--plyr-color-volume: #ff5722; /* Orange volume control */
|
| 44 |
+
--plyr-color-time: #e0e0e0; /* Light time controls */
|
| 45 |
+
--plyr-color-fullscreen: #ff5722; /* Orange fullscreen button */
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
.plyr__controls {
|
| 49 |
+
background: #0e5bbf; /* Deep blue background for controls */
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
.back-arrow {
|
| 53 |
+
position: absolute;
|
| 54 |
+
top: 20px;
|
| 55 |
+
left: 20px;
|
| 56 |
+
padding: 10px;
|
| 57 |
+
cursor: pointer;
|
| 58 |
+
transition: transform .2s ease;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
.back-arrow:hover {
|
| 62 |
+
transform: scale(1.2);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
/* Progress Circle */
|
| 66 |
+
.progress-container {
|
| 67 |
+
position: absolute;
|
| 68 |
+
top: 50%;
|
| 69 |
+
left: 50%;
|
| 70 |
+
transform: translate(-50%, -50%);
|
| 71 |
+
display: flex;
|
| 72 |
+
align-items: center;
|
| 73 |
+
justify-content: center;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
.progress-circle {
|
| 77 |
+
border: 8px solid rgba(255, 255, 255, 0.1);
|
| 78 |
+
border-radius: 50%;
|
| 79 |
+
border-top: 8px solid #ff5722;
|
| 80 |
+
width: 60px;
|
| 81 |
+
height: 60px;
|
| 82 |
+
animation: spin 1.5s linear infinite;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
/* Keyframes for spinning animation */
|
| 86 |
+
@keyframes spin {
|
| 87 |
+
0% { transform: rotate(0deg); }
|
| 88 |
+
100% { transform: rotate(360deg); }
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
@media (max-width: 768px) {
|
| 92 |
+
.tvshow-player-container {
|
| 93 |
+
padding: 10px;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
.plyr {
|
| 97 |
+
max-width: 100%;
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
frontend/src/pages/tvshowPlayer.js
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { useState, useEffect, useCallback } from "react";
|
| 2 |
+
import { useParams } from "react-router-dom";
|
| 3 |
+
import apiClient from "../api/apiClient";
|
| 4 |
+
import Plyr from "plyr-react";
|
| 5 |
+
import "plyr-react/plyr.css";
|
| 6 |
+
import "./tvshowPlayer.css";
|
| 7 |
+
import BackArrow from "../components/tv/backArrow";
|
| 8 |
+
|
| 9 |
+
const TvshowPlayer = React.memo(() => {
|
| 10 |
+
const { title, season, episode } = useParams();
|
| 11 |
+
const [videoUrl, setVideoUrl] = useState(null);
|
| 12 |
+
const [progress, setProgress] = useState(null);
|
| 13 |
+
const [error, setError] = useState(null);
|
| 14 |
+
|
| 15 |
+
const fetchProgress = useCallback(async (progressUrl) => {
|
| 16 |
+
try {
|
| 17 |
+
const response = await fetch(progressUrl);
|
| 18 |
+
const data = await response.json();
|
| 19 |
+
if (data.progress.status === "Completed") {
|
| 20 |
+
setTimeout(async () => {
|
| 21 |
+
const videoResponse = await apiClient.getTVEpisode(title, season, episode);
|
| 22 |
+
if (videoResponse.url) {
|
| 23 |
+
setVideoUrl(videoResponse.url);
|
| 24 |
+
} else {
|
| 25 |
+
setError("Error fetching video URL.");
|
| 26 |
+
}
|
| 27 |
+
}, 5000);
|
| 28 |
+
} else {
|
| 29 |
+
setProgress(data.progress);
|
| 30 |
+
setTimeout(() => fetchProgress(progressUrl), 2000);
|
| 31 |
+
}
|
| 32 |
+
} catch {
|
| 33 |
+
setError("Error fetching progress.");
|
| 34 |
+
}
|
| 35 |
+
}, [title, season, episode]);
|
| 36 |
+
|
| 37 |
+
useEffect(() => {
|
| 38 |
+
const getEpisode = async () => {
|
| 39 |
+
try {
|
| 40 |
+
const response = await apiClient.getTVEpisode(title, season, episode);
|
| 41 |
+
if (response.url) {
|
| 42 |
+
setVideoUrl(response.url);
|
| 43 |
+
} else if (response.status === "Download started") {
|
| 44 |
+
fetchProgress(response.progress_url);
|
| 45 |
+
} else if (response.error) {
|
| 46 |
+
setError(response.error);
|
| 47 |
+
}
|
| 48 |
+
} catch {
|
| 49 |
+
setError("Error fetching episode.");
|
| 50 |
+
}
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
getEpisode();
|
| 54 |
+
}, [title, season, episode, fetchProgress]);
|
| 55 |
+
|
| 56 |
+
if (error) {
|
| 57 |
+
return <div>Error: {error}</div>;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
return (
|
| 61 |
+
<div className="tvshow-player-container">
|
| 62 |
+
<BackArrow />
|
| 63 |
+
{videoUrl ? (
|
| 64 |
+
<Plyr
|
| 65 |
+
source={{
|
| 66 |
+
type: 'video',
|
| 67 |
+
sources: [{ src: videoUrl, type: 'video/mp4' }],
|
| 68 |
+
}}
|
| 69 |
+
options={{
|
| 70 |
+
controls: ['play', 'progress', 'current-time', 'mute', 'volume', 'fullscreen'],
|
| 71 |
+
}}
|
| 72 |
+
/>
|
| 73 |
+
) : (
|
| 74 |
+
<div className="progress-container">
|
| 75 |
+
<div className="progress-circle"></div>
|
| 76 |
+
</div>
|
| 77 |
+
)}
|
| 78 |
+
</div>
|
| 79 |
+
);
|
| 80 |
+
});
|
| 81 |
+
|
| 82 |
+
export default TvshowPlayer;
|