ChandimaPrabath commited on
Commit
04878ca
·
1 Parent(s): 18bf8cd

0.0.8 V Alpha. added Tv SHow Player.

Browse files
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.7 V Alpha",
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
- position: relative;
3
- width: 100%;
4
- height: 100vh;
5
- background: #000;
 
 
 
 
 
 
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 key={index} className="result-item">
67
- <Link
68
- to={`/film/${encodeURIComponent(film)}`}
69
- className="result-link"
70
- >
71
- {film}
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 key={index} className="result-item">
84
- <Link
85
- to={`/tvshow/${encodeURIComponent(series)}`}
86
- className="result-link"
87
- >
88
- {series}
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('Invalid season index:', index);
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
- <div className="episode-card" key={i}>
310
- <p>{episode}</p>
311
- </div>
 
 
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;