ChandimaPrabath commited on
Commit
93b25cc
·
1 Parent(s): 96b94b7

fix and improv

Browse files
frontend/src/app/globals.css CHANGED
@@ -11,24 +11,52 @@
11
  --foreground-2: #0b32a9;
12
  }
13
 
 
 
 
 
 
 
 
 
14
  body {
15
  color: var(--foreground);
16
  background: var(--background);
17
  font-family: Arial, Helvetica, sans-serif;
18
- max-width: 100vw;
19
- min-height: 100vh;
20
- max-height: 100vh;
21
  display: flex;
22
  flex-direction: column;
23
- justify-content: space-between;
24
  }
25
 
26
  footer {
27
  background-color: var(--background-secondary);
28
  }
29
 
30
- .app-container{
31
  margin-left: 10px;
32
  margin-right: 10px;
33
- height: 85vh;
34
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  --foreground-2: #0b32a9;
12
  }
13
 
14
+ html,
15
+ body {
16
+ margin: 0;
17
+ padding: 0;
18
+ height: 100%;
19
+ overflow: hidden;
20
+ }
21
+
22
  body {
23
  color: var(--foreground);
24
  background: var(--background);
25
  font-family: Arial, Helvetica, sans-serif;
 
 
 
26
  display: flex;
27
  flex-direction: column;
 
28
  }
29
 
30
  footer {
31
  background-color: var(--background-secondary);
32
  }
33
 
34
+ .app-container {
35
  margin-left: 10px;
36
  margin-right: 10px;
37
+ flex-grow: 1;
38
+ overflow-y: auto;
39
+
40
+ /* Styled scrollbar */
41
+ scrollbar-width: thin; /* Firefox */
42
+ scrollbar-color: #888 #222;
43
+ }
44
+
45
+ /* For WebKit browsers (Chrome, Edge, Safari) */
46
+ .app-container::-webkit-scrollbar {
47
+ width: 8px; /* Width of the scrollbar */
48
+ }
49
+
50
+ .app-container::-webkit-scrollbar-track {
51
+ background: #222; /* Track color */
52
+ border-radius: 4px;
53
+ }
54
+
55
+ .app-container::-webkit-scrollbar-thumb {
56
+ background-color: #888; /* Scrollbar thumb color */
57
+ border-radius: 4px;
58
+ }
59
+
60
+ .app-container::-webkit-scrollbar-thumb:hover {
61
+ background-color: #555; /* Thumb color on hover */
62
+ }
frontend/src/components/CategoriesSection.css CHANGED
@@ -21,4 +21,5 @@
21
  font-size: 1rem;
22
  text-transform: capitalize;
23
  font-weight: 600;
 
24
  }
 
21
  font-size: 1rem;
22
  text-transform: capitalize;
23
  font-weight: 600;
24
+ cursor: pointer;
25
  }
frontend/src/components/MusicPlayer.css CHANGED
@@ -4,9 +4,10 @@
4
  }
5
 
6
  .player-minimized video {
 
7
  height: 10vh;
8
- width: 25vh;
9
- background-color: black;
10
  }
11
 
12
  .music-title {
@@ -18,9 +19,11 @@
18
  white-space: normal; /* Allows wrapping but limits line count */
19
  line-height: 1.2em; /* Optional: Adjust line spacing */
20
  max-height: 1.2em; /* Optional: Adjust to fit one line */
 
21
  }
22
 
23
- .music-title.mini{
 
24
  }
25
 
26
  .player-minimized {
@@ -40,9 +43,14 @@
40
  align-items: center;
41
  }
42
 
43
- .player-mini-top {
44
  display: flex;
45
  }
 
 
 
 
 
46
 
47
  .player-controls {
48
  position: absolute;
@@ -117,6 +125,8 @@
117
  width: 100%;
118
  justify-content: center;
119
  align-items: center;
 
 
120
  }
121
 
122
  .player-controls-left {
@@ -153,6 +163,12 @@
153
  border-radius: 10px;
154
  }
155
 
 
 
 
 
 
 
156
  .buffer-bar {
157
  position: absolute;
158
  top: 0;
@@ -192,10 +208,16 @@
192
 
193
  .player-mini-control-bottom {
194
  display: flex;
195
- padding-left: 5px;
196
- padding-right: 5px;
197
  padding-bottom: 10px;
198
  gap: 5px;
 
 
 
 
 
 
199
  }
200
 
201
  /********** Range Input Styles **********/
 
4
  }
5
 
6
  .player-minimized video {
7
+ max-width: 18vh;
8
  height: 10vh;
9
+ min-width: 18vh;
10
+ background-color: #000;
11
  }
12
 
13
  .music-title {
 
19
  white-space: normal; /* Allows wrapping but limits line count */
20
  line-height: 1.2em; /* Optional: Adjust line spacing */
21
  max-height: 1.2em; /* Optional: Adjust to fit one line */
22
+ width: 100%;
23
  }
24
 
25
+ .music-title.player-mini{
26
+ font-size: .85rem;
27
  }
28
 
29
  .player-minimized {
 
43
  align-items: center;
44
  }
45
 
46
+ .player-top {
47
  display: flex;
48
  }
49
+ .name-container{
50
+ display: flex;
51
+ align-items: center;
52
+ width: 100%;
53
+ }
54
 
55
  .player-controls {
56
  position: absolute;
 
125
  width: 100%;
126
  justify-content: center;
127
  align-items: center;
128
+ padding-left: 5px;
129
+ padding-right: 5px;
130
  }
131
 
132
  .player-controls-left {
 
163
  border-radius: 10px;
164
  }
165
 
166
+ .progress-bar-container.player-mini {
167
+ width: 100%;
168
+ height: 6px;
169
+ margin: 7px 0;
170
+ }
171
+
172
  .buffer-bar {
173
  position: absolute;
174
  top: 0;
 
208
 
209
  .player-mini-control-bottom {
210
  display: flex;
211
+ padding-left: 10px;
212
+ padding-right: 10px;
213
  padding-bottom: 10px;
214
  gap: 5px;
215
+ font-size: .8rem;
216
+ }
217
+
218
+ .player-mini-volume{
219
+ display: flex;
220
+ gap: 5px;
221
  }
222
 
223
  /********** Range Input Styles **********/
frontend/src/components/MusicPlayer.js CHANGED
@@ -64,15 +64,15 @@ export default function MusicPlayer() {
64
  };
65
 
66
  const handleProgress = () => {
67
- const videoElement = videoRef.current;
68
- if (videoElement.buffered.length > 0) {
69
- const bufferEnd = videoElement.buffered.end(
70
- videoElement.buffered.length - 1
71
- );
72
- const bufferValue = (bufferEnd / videoElement.duration) * 100;
73
- setBufferProgress(bufferValue);
74
- }
75
- };
76
 
77
  const handlePlay = () => setIsPlaying(true);
78
  const handlePause = () => setIsPlaying(false);
@@ -179,7 +179,8 @@ export default function MusicPlayer() {
179
 
180
  const destroyPlayer = () => {
181
  if (videoRef.current) {
182
- initializePlayer("");
 
183
  }
184
  };
185
 
@@ -228,10 +229,12 @@ export default function MusicPlayer() {
228
  {isPlayerMaximized && (
229
  <div className={`player-controls ${showControls ? "show" : "hide"}`}>
230
  <div className="player-controls-top">
231
- <label className="music-title">{fileName}</label>
232
- <button className="player-max-button" onClick={togglePlayerSize}>
233
- <IoIosArrowDown />
234
- </button>
 
 
235
  </div>
236
  <div className="player-controls-center">
237
  <button className="player-max-button" onClick={handleRewind}>
@@ -263,70 +266,80 @@ export default function MusicPlayer() {
263
  <label className="duration">{formatTime(duration)}</label>
264
  </div>
265
  <div className="player-controls-down">
266
- <div className="player-controls-left">
267
- <button
268
- onClick={toggleMute}
269
- className="player-min-button volumn-btn"
270
- >
271
- {isMuted ? <TbVolumeOff /> : <TbVolume />}
272
- </button>
273
- <input
274
- type="range"
275
- className="volume-control"
276
- min="0"
277
- max="1"
278
- step="0.01"
279
- value={volume}
280
- onChange={handleVolumeChange}
281
- />
282
- <button
283
- onClick={handleRewind}
284
- className="previous-btn player-min-button"
285
- >
286
- <TbPlayerSkipBack />
287
- </button>
288
 
289
- <button
290
- onClick={handleFastForward}
291
- className="next-btn player-min-button"
292
- >
293
- <TbPlayerSkipForward />
294
- </button>
295
- {isPlaying ? (
296
- <button className="playlist-btn player-min-button">
297
- <TbPlaylist />
298
  </button>
299
- ) : (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  <button
301
- className="playlist-btn player-min-button"
302
- disabled={true}
303
  >
304
- <TbPlaylistOff />
 
 
 
 
305
  </button>
306
- )}
307
- </div>
308
- <div className="player-controls-right">
309
- <button onClick={toggleFullscreen} className="player-min-button">
310
- {isFullscreen ? <RiFullscreenExitLine /> : <RiFullscreenLine />}
311
- </button>
312
  </div>
313
  </div>
314
- </div>
315
-
316
  </div>
317
  )}
318
- <div className="player-mini-top">
319
  <video
320
  ref={videoRef}
321
  src={currentSrc}
322
  preload="metadata"
323
  className="video-element"
324
  autoPlay
 
325
  />
326
  {!isPlayerMaximized && (
327
  <div className="player-controls-mini">
328
  <div className="player-mini-control-top">
329
- <label className="music-title mini">{fileName}</label>
330
  <button className="player-min-button" onClick={togglePlayerSize}>
331
  <IoIosArrowUp />
332
  </button>
@@ -344,6 +357,8 @@ export default function MusicPlayer() {
344
  <button className="player-min-button" onClick={destroyPlayer}>
345
  <TbPlayerStop />
346
  </button>
 
 
347
  <button
348
  onClick={toggleMute}
349
  className="player-min-button volumn-btn"
@@ -366,7 +381,10 @@ export default function MusicPlayer() {
366
  {!isPlayerMaximized && (
367
  <div className="player-mini-control-bottom">
368
  <label className="current-time">{formatTime(currentTime)}</label>
369
- <div className="progress-bar-container" onClick={handleProgressClick}>
 
 
 
370
  <div
371
  className="buffer-bar"
372
  style={{ width: `${bufferProgress}%` }}
 
64
  };
65
 
66
  const handleProgress = () => {
67
+ const videoElement = videoRef.current;
68
+ if (videoElement.buffered.length > 0) {
69
+ const bufferEnd = videoElement.buffered.end(
70
+ videoElement.buffered.length - 1
71
+ );
72
+ const bufferValue = (bufferEnd / videoElement.duration) * 100;
73
+ setBufferProgress(bufferValue);
74
+ }
75
+ };
76
 
77
  const handlePlay = () => setIsPlaying(true);
78
  const handlePause = () => setIsPlaying(false);
 
179
 
180
  const destroyPlayer = () => {
181
  if (videoRef.current) {
182
+ videoRef.current.src = "";
183
+ setIsPlayerVisible(false);
184
  }
185
  };
186
 
 
229
  {isPlayerMaximized && (
230
  <div className={`player-controls ${showControls ? "show" : "hide"}`}>
231
  <div className="player-controls-top">
232
+ <div className="name-container">
233
+ <label className="music-title">{fileName}</label>
234
+ <button className="player-max-button" onClick={togglePlayerSize}>
235
+ <IoIosArrowDown />
236
+ </button>
237
+ </div>
238
  </div>
239
  <div className="player-controls-center">
240
  <button className="player-max-button" onClick={handleRewind}>
 
266
  <label className="duration">{formatTime(duration)}</label>
267
  </div>
268
  <div className="player-controls-down">
269
+ <div className="player-controls-left">
270
+ <button
271
+ onClick={toggleMute}
272
+ className="player-min-button volumn-btn"
273
+ >
274
+ {isMuted ? <TbVolumeOff /> : <TbVolume />}
275
+ </button>
276
+ <input
277
+ type="range"
278
+ className="volume-control"
279
+ min="0"
280
+ max="1"
281
+ step="0.01"
282
+ value={volume}
283
+ onChange={handleVolumeChange}
284
+ />
285
+ <button
286
+ onClick={handleRewind}
287
+ className="previous-btn player-min-button"
288
+ >
289
+ <TbPlayerSkipBack />
290
+ </button>
291
 
292
+ <button
293
+ onClick={handleFastForward}
294
+ className="next-btn player-min-button"
295
+ >
296
+ <TbPlayerSkipForward />
 
 
 
 
297
  </button>
298
+ <button className="player-min-button" onClick={destroyPlayer}>
299
+ <TbPlayerStop />
300
+ </button>
301
+ {isPlaying ? (
302
+ <button className="playlist-btn player-min-button">
303
+ <TbPlaylist />
304
+ </button>
305
+ ) : (
306
+ <button
307
+ className="playlist-btn player-min-button"
308
+ disabled={true}
309
+ >
310
+ <TbPlaylistOff />
311
+ </button>
312
+ )}
313
+ </div>
314
+ <div className="player-controls-right">
315
  <button
316
+ onClick={toggleFullscreen}
317
+ className="player-min-button"
318
  >
319
+ {isFullscreen ? (
320
+ <RiFullscreenExitLine />
321
+ ) : (
322
+ <RiFullscreenLine />
323
+ )}
324
  </button>
325
+ </div>
 
 
 
 
 
326
  </div>
327
  </div>
 
 
328
  </div>
329
  )}
330
+ <div className="player-top">
331
  <video
332
  ref={videoRef}
333
  src={currentSrc}
334
  preload="metadata"
335
  className="video-element"
336
  autoPlay
337
+ onClick={isPlayerMaximized ? null : togglePlayerSize}
338
  />
339
  {!isPlayerMaximized && (
340
  <div className="player-controls-mini">
341
  <div className="player-mini-control-top">
342
+ <label className="music-title player-mini">{fileName}</label>
343
  <button className="player-min-button" onClick={togglePlayerSize}>
344
  <IoIosArrowUp />
345
  </button>
 
357
  <button className="player-min-button" onClick={destroyPlayer}>
358
  <TbPlayerStop />
359
  </button>
360
+ </div>
361
+ <div className="player-mini-volume">
362
  <button
363
  onClick={toggleMute}
364
  className="player-min-button volumn-btn"
 
381
  {!isPlayerMaximized && (
382
  <div className="player-mini-control-bottom">
383
  <label className="current-time">{formatTime(currentTime)}</label>
384
+ <div
385
+ className="progress-bar-container player-mini"
386
+ onClick={handleProgressClick}
387
+ >
388
  <div
389
  className="buffer-bar"
390
  style={{ width: `${bufferProgress}%` }}
frontend/src/context/MusicPlayerContext.js CHANGED
@@ -7,69 +7,89 @@ const MusicPlayerContext = createContext();
7
  export const MusicPlayerProvider = ({ children }) => {
8
  const videoRef = useRef(null);
9
  const [src, setSrc] = useState("");
10
- const [fileName, setFileName] = useState(""); // New state for the file name
11
  const [isPlayerVisible, setIsPlayerVisible] = useState(false);
12
  const [isPlayerMaximized, setIsPlayerMaximized] = useState(false);
13
- const [loadingProgress, setLoadingProgress] = useState(null); // New state for loading progress
 
14
 
15
  const initializePlayer = async (source) => {
 
 
 
 
 
 
 
 
 
 
16
  const extractedFileName = source.split('/').pop();
17
- setFileName(extractedFileName); // Set the file name state
 
18
 
19
  try {
20
- // Call the API to get the music file or start the download
21
- const response = await fetch(`/api/get/music/${encodeURIComponent(extractedFileName)}`);
 
 
22
  const data = await response.json();
23
 
24
- // If the file is being downloaded, get the progress URL
25
  if (data.status === "Download started") {
26
  const progressUrl = data.progress_url;
27
- checkProgress(progressUrl, extractedFileName);
28
  } else {
29
- // If the music file is available, initialize the player
30
- startPlayer(data.url);
31
  }
32
  } catch (error) {
33
- console.error("Error initializing player:", error);
 
 
34
  }
35
  };
36
 
37
- const checkProgress = (progressUrl, fileName) => {
38
  const intervalId = setInterval(async () => {
39
  try {
40
- const response = await fetch(progressUrl);
41
  const progressData = await response.json();
42
 
43
- setLoadingProgress(progressData.progress); // Update loading progress state
44
 
45
- // Check if the download is complete
46
  if (progressData.progress.status === "Completed") {
47
- clearInterval(intervalId); // Stop checking progress
48
- fetchFinalUrl(fileName); // Fetch the final URL
49
  }
50
  } catch (error) {
51
- console.error("Error fetching progress:", error);
 
 
 
 
52
  }
53
- }, 1000); // Check progress every second
54
  };
55
 
56
- const fetchFinalUrl = async (fileName, attempt = 1) => {
57
  try {
58
- const response = await fetch(`/api/get/music/${encodeURIComponent(fileName)}`);
 
 
59
  const data = await response.json();
60
 
61
  if (data.url) {
62
- // Start the player with the final URL if available
63
  startPlayer(data.url);
64
  } else {
65
- // If URL is not yet available, retry with exponential backoff
66
- const retryDelay = Math.min(2000 * attempt, 10000); // Increase delay with each attempt, maxing at 10 seconds
67
- setTimeout(() => fetchFinalUrl(fileName, attempt + 1), retryDelay);
68
  }
69
  } catch (error) {
70
- console.error("Error fetching final URL:", error);
71
- const retryDelay = Math.min(2000 * attempt, 10000); // Retry after delay in case of error
72
- setTimeout(() => fetchFinalUrl(fileName, attempt + 1), retryDelay);
 
 
73
  }
74
  };
75
 
@@ -91,7 +111,7 @@ export const MusicPlayerProvider = ({ children }) => {
91
  initializePlayer,
92
  isPlayerVisible,
93
  src,
94
- fileName, // Export the file name
95
  isPlayerMaximized,
96
  togglePlayerSize,
97
  setIsPlayerVisible,
 
7
  export const MusicPlayerProvider = ({ children }) => {
8
  const videoRef = useRef(null);
9
  const [src, setSrc] = useState("");
10
+ const [fileName, setFileName] = useState("");
11
  const [isPlayerVisible, setIsPlayerVisible] = useState(false);
12
  const [isPlayerMaximized, setIsPlayerMaximized] = useState(false);
13
+ const [loadingProgress, setLoadingProgress] = useState(null);
14
+ const [abortController, setAbortController] = useState(null); // AbortController for stopping
15
 
16
  const initializePlayer = async (source) => {
17
+ // Stop any ongoing initializePlayer process if called again
18
+ if (abortController) {
19
+ abortController.abort(); // Cancel the previous request
20
+ }
21
+
22
+ // Set up a new AbortController
23
+ const newAbortController = new AbortController();
24
+ setAbortController(newAbortController);
25
+
26
+ // Extract the file name and start the player
27
  const extractedFileName = source.split('/').pop();
28
+ setFileName(extractedFileName);
29
+ startPlayer(extractedFileName);
30
 
31
  try {
32
+ // Call the API with the signal to allow aborting
33
+ const response = await fetch(`/api/get/music/${encodeURIComponent(extractedFileName)}`, {
34
+ signal: newAbortController.signal,
35
+ });
36
  const data = await response.json();
37
 
38
+ // If the file is being downloaded, check progress
39
  if (data.status === "Download started") {
40
  const progressUrl = data.progress_url;
41
+ checkProgress(progressUrl, extractedFileName, newAbortController);
42
  } else {
43
+ startPlayer(data.url); // Start the player with the final URL if available
 
44
  }
45
  } catch (error) {
46
+ if (error.name !== 'AbortError') {
47
+ console.error("Error initializing player:", error); // Log only non-abort errors
48
+ }
49
  }
50
  };
51
 
52
+ const checkProgress = (progressUrl, fileName, abortController) => {
53
  const intervalId = setInterval(async () => {
54
  try {
55
+ const response = await fetch(progressUrl, { signal: abortController.signal });
56
  const progressData = await response.json();
57
 
58
+ setLoadingProgress(progressData.progress);
59
 
 
60
  if (progressData.progress.status === "Completed") {
61
+ clearInterval(intervalId);
62
+ fetchFinalUrl(fileName, abortController);
63
  }
64
  } catch (error) {
65
+ if (error.name === 'AbortError') {
66
+ clearInterval(intervalId); // Stop checking progress if aborted
67
+ } else {
68
+ console.error("Error fetching progress:", error);
69
+ }
70
  }
71
+ }, 1000);
72
  };
73
 
74
+ const fetchFinalUrl = async (fileName, abortController, attempt = 1) => {
75
  try {
76
+ const response = await fetch(`/api/get/music/${encodeURIComponent(fileName)}`, {
77
+ signal: abortController.signal,
78
+ });
79
  const data = await response.json();
80
 
81
  if (data.url) {
 
82
  startPlayer(data.url);
83
  } else {
84
+ const retryDelay = 2000;
85
+ setTimeout(() => fetchFinalUrl(fileName, abortController, attempt + 1), retryDelay);
 
86
  }
87
  } catch (error) {
88
+ if (error.name !== 'AbortError') {
89
+ console.error("Error fetching final URL:", error);
90
+ const retryDelay = 2000;
91
+ setTimeout(() => fetchFinalUrl(fileName, abortController, attempt + 1), retryDelay);
92
+ }
93
  }
94
  };
95
 
 
111
  initializePlayer,
112
  isPlayerVisible,
113
  src,
114
+ fileName,
115
  isPlayerMaximized,
116
  togglePlayerSize,
117
  setIsPlayerVisible,