ChandimaPrabath commited on
Commit
25dca33
1 Parent(s): d0c3311

player test 0.1

Browse files
frontend/src/app/layout.js CHANGED
@@ -1,3 +1,4 @@
 
1
  import { Inter } from "next/font/google";
2
  import "./globals.css";
3
  import Sidebar from "@/components/Sidebar";
@@ -5,20 +6,27 @@ import { FilmProvider } from "@/context/FilmContext";
5
  import { config } from "@fortawesome/fontawesome-svg-core";
6
  import "@fortawesome/fontawesome-svg-core/styles.css";
7
  import Header from "@/components/Header";
 
 
8
  config.autoAddCss = false;
9
  const inter = Inter({ subsets: ["latin"] });
10
 
11
  export default function RootLayout({ children }) {
 
 
 
12
  return (
13
  <html lang="en">
14
  <body className={inter.className}>
15
  <div className="app-container">
16
- <header>
17
- <link rel="icon" href="/favicon.ico" sizes="any" />
18
- <Sidebar />
19
- <Header />
20
- </header>
21
- <FilmProvider>{children}</FilmProvider>
 
 
22
  </div>
23
  </body>
24
  </html>
 
1
+ 'use client';
2
  import { Inter } from "next/font/google";
3
  import "./globals.css";
4
  import Sidebar from "@/components/Sidebar";
 
6
  import { config } from "@fortawesome/fontawesome-svg-core";
7
  import "@fortawesome/fontawesome-svg-core/styles.css";
8
  import Header from "@/components/Header";
9
+ import { usePathname } from "next/navigation";
10
+
11
  config.autoAddCss = false;
12
  const inter = Inter({ subsets: ["latin"] });
13
 
14
  export default function RootLayout({ children }) {
15
+ const pathname = usePathname();
16
+ const isPlayerPage = pathname.startsWith('/player/movie') || pathname.startsWith('/player/tvshow');
17
+
18
  return (
19
  <html lang="en">
20
  <body className={inter.className}>
21
  <div className="app-container">
22
+ {!isPlayerPage && (
23
+ <header>
24
+ <link rel="icon" href="/favicon.ico" sizes="any" />
25
+ <Sidebar />
26
+ <Header />
27
+ </header>
28
+ )}
29
+ <FilmProvider>{children}</FilmProvider>
30
  </div>
31
  </body>
32
  </html>
frontend/src/app/player/movie/[title]/MoviePlayerPage.css ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ .film-player-container{
2
+ width: 100dvw;
3
+ height: 100dvh;
4
+ }
5
+
6
+ .app-container{
7
+ padding: 0;
8
+ margin: 0;
9
+ }
frontend/src/app/player/movie/[title]/page.js CHANGED
@@ -1,7 +1,8 @@
1
  "use client";
2
  import apiClient from "@/api/apiClient";
3
  import { useEffect, useState } from "react";
4
- import MoviePlayer from "@/components/moviePlayer";
 
5
 
6
  export default function FilmPlayer({ params }) {
7
  const title = decodeURIComponent(params.title);
@@ -89,7 +90,7 @@ export default function FilmPlayer({ params }) {
89
  <div className="film-player-container">
90
  {loading && <p className="text-white">Loading...</p>}
91
  {error && <p className="text-red-500">{error}</p>}
92
- {metadata && !error && (
93
  <div className="metadata">
94
  <p className="text-white">
95
  {metadata.title} ({metadata.year})
@@ -105,7 +106,7 @@ export default function FilmPlayer({ params }) {
105
  />
106
  )}
107
  </div>
108
- )}
109
  {downloadProgressUrl && downloadProgress ? (
110
  <div className="download-status">
111
  <p className="text-yellow-500">
 
1
  "use client";
2
  import apiClient from "@/api/apiClient";
3
  import { useEffect, useState } from "react";
4
+ import MoviePlayer from "@/components/MoviePlayer";
5
+ import './MoviePlayerPage.css';
6
 
7
  export default function FilmPlayer({ params }) {
8
  const title = decodeURIComponent(params.title);
 
90
  <div className="film-player-container">
91
  {loading && <p className="text-white">Loading...</p>}
92
  {error && <p className="text-red-500">{error}</p>}
93
+ {/* {metadata && !error && (
94
  <div className="metadata">
95
  <p className="text-white">
96
  {metadata.title} ({metadata.year})
 
106
  />
107
  )}
108
  </div>
109
+ )} */}
110
  {downloadProgressUrl && downloadProgress ? (
111
  <div className="download-status">
112
  <p className="text-yellow-500">
frontend/src/components/MoviePlayer.css CHANGED
@@ -1,37 +1,115 @@
1
  .video-player-container {
2
- max-width: 900px;
3
- margin: auto;
4
- background: rgba(0, 0, 0, 0.8);
5
- padding: 20px;
6
- border-radius: 12px;
7
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
8
- }
9
- .video-title {
10
- color: white;
11
- margin-bottom: 15px;
12
- font-size: 24px;
13
- }
14
- .controls {
15
- display: flex;
16
- justify-content: space-between;
17
- margin-top: 10px;
18
- }
19
- .play-pause-btn, .control-btn {
20
- padding: 10px 15px;
21
- cursor: pointer;
22
- background: #e50914;
23
- color: white;
24
- border: none;
25
- border-radius: 5px;
26
- font-size: 16px;
27
- transition: background 0.3s;
28
- }
29
- .play-pause-btn:hover, .control-btn:hover {
30
- background: #f40612;
31
- }
32
- .video-element {
33
- width: 100%;
34
- height: auto;
35
- border-radius: 8px;
36
- outline: none;
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  .video-player-container {
2
+ position: relative;
3
+ max-width: 100dvw;
4
+ height: 100%;
5
+ margin: auto;
6
+ background-color: #000;
7
+ border-radius: 8px;
8
+ overflow: hidden;
9
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
10
+ display: flex;
11
+ }
12
+
13
+ .video-title {
14
+ color: #fff;
15
+ text-align: left;
16
+ padding: 20px;
17
+ padding-bottom: 50px;
18
+ font-size: 1.5em;
19
+ font-weight: bold;
20
+ background-image: linear-gradient(#0e0f19 60%, transparent 100%);
21
+ }
22
+
23
+ .video-element {
24
+ width: 100%;
25
+ height: auto;
26
+ display: block;
27
+ }
28
+
29
+ .player-overlay {
30
+ position: absolute;
31
+ top: 0;
32
+ left: 0;
33
+ width: 100%;
34
+ height: 100%;
35
+ display: flex;
36
+ flex-direction: column;
37
+ justify-content: space-between;
38
+ background-color: rgba(0, 0, 0, 0.5);
39
+ transition: opacity 0.5s;
40
+ z-index: 100;
41
+ }
42
+
43
+ .player-overlay.hide {
44
+ opacity: 0;
45
+ pointer-events: none;
46
+ }
47
+
48
+ .player-overlay.show {
49
+ opacity: 1;
50
+ }
51
+
52
+ .player-controls-down{
53
+ display: flex;
54
+ flex-direction: row;
55
+ width: 100dvw;
56
+ justify-content: center;
57
+ align-items: center;
58
+ }
59
+
60
+ .player-controls-top{
61
+ display: flex;
62
+ flex-direction: column;
63
+ width: 100dvw;
64
+ justify-content: center;
65
+ align-items: center;
66
+ }
67
+
68
+ .controls {
69
+ display: flex;
70
+ justify-content: center;
71
+ align-items: center;
72
+ padding: 10px;
73
+ background-color: rgba(0, 0, 0, 0.7);
74
+ bottom: 0;
75
+ position: relative;
76
+ width: 100dvw;
77
+ flex-direction: column;
78
+ }
79
+
80
+ .play-pause-btn,
81
+ .control-btn {
82
+ color: #fff;
83
+ border: 1px solid #5f59d1;
84
+ border-radius: 10px;
85
+ padding: 10px 15px;
86
+ margin: 0 5px;
87
+ cursor: pointer;
88
+ font-size: 1em;
89
+ transition: background-color 0.3s;
90
+ }
91
+
92
+ .play-pause-btn:hover,
93
+ .control-btn:hover {
94
+ background-color: #5f6293;
95
+ }
96
+
97
+ .control-btn:disabled {
98
+ background-color: #232435;
99
+ cursor: not-allowed;
100
+ }
101
+
102
+ .progress-bar,
103
+ .volume-control {
104
+ margin: 0 5px;
105
+ }
106
+
107
+ .progress-bar {
108
+ width: 85%;
109
+ cursor: pointer;
110
+ }
111
+
112
+ .volume-control {
113
+ width: 100px;
114
+ cursor: pointer;
115
+ }
frontend/src/components/MoviePlayer.js CHANGED
@@ -1,35 +1,70 @@
1
  "use client";
2
  import { useEffect, useRef, useState } from "react";
3
- import './MoviePlayer.css';
 
 
 
 
 
 
 
 
 
 
4
 
5
  export default function MoviePlayer({ videoUrl, title }) {
6
  const videoRef = useRef(null);
7
  const [isPlaying, setIsPlaying] = useState(false);
 
 
 
 
 
 
8
 
9
  useEffect(() => {
10
  const videoElement = videoRef.current;
11
 
12
  const handlePlay = () => setIsPlaying(true);
13
  const handlePause = () => setIsPlaying(false);
 
 
14
 
15
  videoElement.addEventListener("play", handlePlay);
16
  videoElement.addEventListener("pause", handlePause);
 
17
 
18
  return () => {
19
  videoElement.removeEventListener("play", handlePlay);
20
  videoElement.removeEventListener("pause", handlePause);
 
21
  };
22
  }, []);
23
 
 
 
 
 
 
 
 
 
 
24
  const handleFastForward = () => {
25
  if (videoRef.current) {
26
- videoRef.current.currentTime = Math.min(videoRef.current.duration, videoRef.current.currentTime + 10);
 
 
 
27
  }
28
  };
29
 
30
  const handleRewind = () => {
31
  if (videoRef.current) {
32
- videoRef.current.currentTime = Math.max(0, videoRef.current.currentTime - 10);
 
 
 
33
  }
34
  };
35
 
@@ -41,9 +76,116 @@ export default function MoviePlayer({ videoUrl, title }) {
41
  }
42
  };
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  return (
45
- <div className="video-player-container">
46
- <h2 className="video-title">{title}</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  <video
48
  ref={videoRef}
49
  className="video-element"
@@ -54,18 +196,11 @@ export default function MoviePlayer({ videoUrl, title }) {
54
  <track
55
  kind="subtitles"
56
  label="English"
57
- srLang="en"
58
  src="path/to/your/subtitles.vtt" // Replace with actual subtitles URL
59
  />
60
  Your browser does not support the video tag.
61
  </video>
62
- <div className="controls">
63
- <button onClick={togglePlayPause} className="play-pause-btn">
64
- {isPlaying ? '❚❚ Pause' : '► Play'}
65
- </button>
66
- <button onClick={handleRewind} className="control-btn" disabled={!isPlaying}>⏪ 10s</button>
67
- <button onClick={handleFastForward} className="control-btn" disabled={!isPlaying}>⏩ 10s</button>
68
- </div>
69
  </div>
70
  );
71
  }
 
1
  "use client";
2
  import { useEffect, useRef, useState } from "react";
3
+ import "./MoviePlayer.css";
4
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5
+ import {
6
+ faFastBackward,
7
+ faFastForward,
8
+ faPause,
9
+ faPlay,
10
+ faVolumeUp,
11
+ faVolumeMute,
12
+ faExpand,
13
+ } from "@fortawesome/free-solid-svg-icons";
14
 
15
  export default function MoviePlayer({ videoUrl, title }) {
16
  const videoRef = useRef(null);
17
  const [isPlaying, setIsPlaying] = useState(false);
18
+ const [volume, setVolume] = useState(1);
19
+ const [isMuted, setIsMuted] = useState(false);
20
+ const [progress, setProgress] = useState(0);
21
+ const [isFullscreen, setIsFullscreen] = useState(false);
22
+ const [showControls, setShowControls] = useState(true);
23
+ const overlayTimeout = useRef(null);
24
 
25
  useEffect(() => {
26
  const videoElement = videoRef.current;
27
 
28
  const handlePlay = () => setIsPlaying(true);
29
  const handlePause = () => setIsPlaying(false);
30
+ const handleTimeUpdate = () =>
31
+ setProgress((videoElement.currentTime / videoElement.duration) * 100);
32
 
33
  videoElement.addEventListener("play", handlePlay);
34
  videoElement.addEventListener("pause", handlePause);
35
+ videoElement.addEventListener("timeupdate", handleTimeUpdate);
36
 
37
  return () => {
38
  videoElement.removeEventListener("play", handlePlay);
39
  videoElement.removeEventListener("pause", handlePause);
40
+ videoElement.removeEventListener("timeupdate", handleTimeUpdate);
41
  };
42
  }, []);
43
 
44
+ useEffect(() => {
45
+ if (showControls) {
46
+ if (overlayTimeout.current) {
47
+ clearTimeout(overlayTimeout.current);
48
+ }
49
+ overlayTimeout.current = setTimeout(() => setShowControls(false), 3000);
50
+ }
51
+ }, [showControls]);
52
+
53
  const handleFastForward = () => {
54
  if (videoRef.current) {
55
+ videoRef.current.currentTime = Math.min(
56
+ videoRef.current.duration,
57
+ videoRef.current.currentTime + 10
58
+ );
59
  }
60
  };
61
 
62
  const handleRewind = () => {
63
  if (videoRef.current) {
64
+ videoRef.current.currentTime = Math.max(
65
+ 0,
66
+ videoRef.current.currentTime - 10
67
+ );
68
  }
69
  };
70
 
 
76
  }
77
  };
78
 
79
+ const handleVolumeChange = (event) => {
80
+ const volumeValue = event.target.value;
81
+ setVolume(volumeValue);
82
+ videoRef.current.volume = volumeValue;
83
+ setIsMuted(volumeValue === 0);
84
+ };
85
+
86
+ const toggleMute = () => {
87
+ if (isMuted) {
88
+ videoRef.current.volume = volume;
89
+ setIsMuted(false);
90
+ } else {
91
+ videoRef.current.volume = 0;
92
+ setIsMuted(true);
93
+ }
94
+ };
95
+
96
+ const toggleFullscreen = () => {
97
+ const doc = window.document;
98
+ const docEl = doc.documentElement;
99
+
100
+ const requestFullscreen =
101
+ docEl.requestFullscreen ||
102
+ docEl.mozRequestFullScreen ||
103
+ docEl.webkitRequestFullscreen ||
104
+ docEl.msRequestFullscreen;
105
+ const exitFullscreen =
106
+ doc.exitFullscreen ||
107
+ doc.mozCancelFullScreen ||
108
+ doc.webkitExitFullscreen ||
109
+ doc.msExitFullscreen;
110
+
111
+ if (!isFullscreen) {
112
+ requestFullscreen.call(docEl);
113
+ } else {
114
+ exitFullscreen.call(doc);
115
+ }
116
+
117
+ setIsFullscreen(!isFullscreen);
118
+ };
119
+
120
+ const handleProgressChange = (event) => {
121
+ const progressValue = event.target.value;
122
+ videoRef.current.currentTime =
123
+ (progressValue / 100) * videoRef.current.duration;
124
+ setProgress(progressValue);
125
+ };
126
+
127
+ const handleMouseMove = () => {
128
+ setShowControls(true);
129
+ };
130
+
131
  return (
132
+ <div className="video-player-container" onMouseMove={handleMouseMove}>
133
+ <div className={`player-overlay ${showControls ? "show" : "hide"}`}>
134
+ <h2 className="video-title">{title}</h2>
135
+ <div className="controls">
136
+ <div className="player-controls-top">
137
+ {" "}
138
+ <input
139
+ type="range"
140
+ className="progress-bar"
141
+ value={progress}
142
+ onChange={handleProgressChange}
143
+ />
144
+ </div>
145
+ <div className="player-controls-down">
146
+ <button onClick={togglePlayPause} className="play-pause-btn">
147
+ {isPlaying ? (
148
+ <FontAwesomeIcon icon={faPause} size="xl" />
149
+ ) : (
150
+ <FontAwesomeIcon icon={faPlay} size="xl" />
151
+ )}
152
+ </button>
153
+ <button
154
+ onClick={handleRewind}
155
+ className="control-btn"
156
+ disabled={!isPlaying}
157
+ >
158
+ <FontAwesomeIcon icon={faFastBackward} size="xl" />
159
+ </button>
160
+ <button
161
+ onClick={handleFastForward}
162
+ className="control-btn"
163
+ disabled={!isPlaying}
164
+ >
165
+ <FontAwesomeIcon icon={faFastForward} size="xl" />
166
+ </button>
167
+ <button onClick={toggleMute} className="control-btn">
168
+ <FontAwesomeIcon
169
+ icon={isMuted ? faVolumeMute : faVolumeUp}
170
+ size="xl"
171
+ />
172
+ </button>
173
+ <input
174
+ type="range"
175
+ className="volume-control"
176
+ min="0"
177
+ max="1"
178
+ step="0.01"
179
+ value={volume}
180
+ onChange={handleVolumeChange}
181
+ />
182
+ <button onClick={toggleFullscreen} className="control-btn">
183
+ <FontAwesomeIcon icon={faExpand} size="xl" />
184
+ </button>
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
  <video
190
  ref={videoRef}
191
  className="video-element"
 
196
  <track
197
  kind="subtitles"
198
  label="English"
199
+ srcLang="en"
200
  src="path/to/your/subtitles.vtt" // Replace with actual subtitles URL
201
  />
202
  Your browser does not support the video tag.
203
  </video>
 
 
 
 
 
 
 
204
  </div>
205
  );
206
  }