Nexora-Music / frontend /src /context /MusicPlayerContext.js
ChandimaPrabath's picture
playqueue button controll
b615593
import React, {
createContext,
useContext,
useRef,
useState,
useEffect,
} from "react";
const MusicPlayerContext = createContext();
export const MusicPlayerProvider = ({ children }) => {
const videoRef = useRef(null);
const [src, setSrc] = useState("");
const [title, setTitle] = useState("");
const [nowPlaying, setNowPlaying] = useState("");
const [isPlayerVisible, setIsPlayerVisible] = useState(false);
const [isPlayerMaximized, setIsPlayerMaximized] = useState(false);
const [loadingProgress, setLoadingProgress] = useState(null);
const [abortController, setAbortController] = useState(null);
const [didDestroy, setDidDestroy] = useState(false);
// Playqueue and index
const [playqueue, setPlayqueue] = useState([]);
const [isPlayEueOpen, setIsPlayEueOpen] = useState(false);
const [currentIndex, setCurrentIndex] = useState(0);
const canPlayPrevious = currentIndex > 0;
const canPlayNext = currentIndex < playqueue.length - 1;
const initializePlayer = async (source, title) => {
// Check if song already exists in playqueue
const songIndex = playqueue.findIndex((song) => song.source === source);
if (songIndex !== -1) {
setCurrentIndex(songIndex); // Set to existing song index
} else {
// Add new song and set to that new index
const newSong = { source, title };
setPlayqueue((prev) => [...prev, newSong]);
setCurrentIndex(playqueue.length); // Set index to the end (new song position)
}
if (abortController) {
abortController.abort();
}
const newAbortController = new AbortController();
setAbortController(newAbortController);
const extractedFileName = source.split("/").pop();
setTitle(title);
if (videoRef.current) {
videoRef.current.pause();
}
try {
const response = await fetch(
`/api/get/music/${encodeURIComponent(extractedFileName)}`,
{
signal: newAbortController.signal,
}
);
const data = await response.json();
if (data.status === "Download started") {
const progressUrl = data.progress_url;
checkProgress(progressUrl, extractedFileName, newAbortController);
} else {
startPlayer(data.url);
}
} catch (error) {
if (error.name !== "AbortError") {
console.error("Error initializing player:", error);
}
}
};
const checkProgress = (progressUrl, fileName, abortController) => {
const intervalId = setInterval(async () => {
try {
const response = await fetch(progressUrl, {
signal: abortController.signal,
});
const progressData = await response.json();
setLoadingProgress(progressData.progress);
if (progressData.progress.status === "Completed") {
clearInterval(intervalId);
fetchFinalUrl(fileName, abortController);
}
} catch (error) {
if (error.name === "AbortError") {
clearInterval(intervalId);
} else {
console.error("Error fetching progress:", error);
}
}
}, 1000);
};
const fetchFinalUrl = async (fileName, abortController, attempt = 1) => {
try {
const response = await fetch(
`/api/get/music/${encodeURIComponent(fileName)}`,
{
signal: abortController.signal,
}
);
const data = await response.json();
if (data.url) {
startPlayer(data.url);
} else {
retryFetchFinalUrl(fileName, abortController, attempt);
}
} catch (error) {
if (error.name !== "AbortError") {
console.error("Error fetching final URL:", error);
retryFetchFinalUrl(fileName, abortController, attempt);
}
}
};
const retryFetchFinalUrl = (fileName, abortController, attempt) => {
const retryDelay = 2000;
setTimeout(() => {
console.log(`Retry attempt ${attempt} for ${fileName}`);
fetchFinalUrl(fileName, abortController, attempt + 1);
}, retryDelay);
};
const startPlayer = (source) => {
setDidDestroy(false);
setSrc(source);
setIsPlayerVisible(true);
if (videoRef.current) {
videoRef.current.src = source;
videoRef.current.load();
}
};
const togglePlayerSize = () => setIsPlayerMaximized(!isPlayerMaximized);
const addToPlayqueue = (song) => {
const songIndex = playqueue.findIndex(
(track) => track.source === song.source
);
if (songIndex === -1) {
setPlayqueue((prev) => [...prev, song]);
}
};
const removeFromPlayqueue = (source) => {
setPlayqueue((prev) => prev.filter((track) => track.source !== source));
if (currentIndex >= playqueue.length) {
setCurrentIndex(playqueue.length - 1);
}
};
const playNext = () => {
if (canPlayNext) {
const nextIndex = currentIndex + 1;
setCurrentIndex(nextIndex);
const { source, title } = playqueue[nextIndex];
initializePlayer(source, title);
}
};
const playPrevious = () => {
if (canPlayPrevious) {
const prevIndex = currentIndex - 1;
setCurrentIndex(prevIndex);
const { source, title } = playqueue[prevIndex];
initializePlayer(source, title);
}
};
const playAtIndex = (index) => {
if (index >= 0 && index < playqueue.length) {
setCurrentIndex(index);
const { source, title } = playqueue[index];
initializePlayer(source, title);
}
};
useEffect(() => {
const handleEnded = () => playNext();
if (videoRef.current) {
videoRef.current.addEventListener("ended", handleEnded);
}
return () => {
if (videoRef.current) {
videoRef.current.removeEventListener("ended", handleEnded);
}
};
}, [currentIndex, playqueue]);
return (
<MusicPlayerContext.Provider
value={{
videoRef,
initializePlayer,
isPlayerVisible,
src,
title,
isPlayerMaximized,
togglePlayerSize,
setIsPlayerVisible,
loadingProgress,
nowPlaying,
setNowPlaying,
didDestroy,
setDidDestroy,
playqueue,
setPlayqueue,
addToPlayqueue,
removeFromPlayqueue,
playNext,
playPrevious,
playAtIndex,
currentIndex,
canPlayPrevious,
canPlayNext,
isPlayEueOpen,
setIsPlayEueOpen,
}}
>
{children}
</MusicPlayerContext.Provider>
);
};
export const useMusicPlayer = () => {
return useContext(MusicPlayerContext);
};