import React, { useState, useEffect, useRef } from "react"; import "./MusicPlayer.css"; import MusicComponent from "./MusicComponent"; import Switch from "react-switch"; export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLogin, queue, setModal }) { const [currentTime, setCurrentTime] = useState(0); const [trackLength, setTrackLength] = useState(0); const [viewing, setViewing] = useState(false); // State for expansion const [expanded, setExpanded] = useState(false); // State for expansion const [songName, setSongName] = useState(""); const [debouncedSongName, setDebouncedSongName] = useState(songName); const [currentSong, setCurrentSong] = useState([]); const [songs, setSongs] = useState([]); const [paused, setPaused] = useState([]); const [getRecommendedMusic, setGetRecommendedMusic] = useState(false); const [lyrics, setLyrics] = useState([]); const [currentLines, setCurrentLines] = useState({ past: [], present: [], future: [], }); const [lyric_progress_ms, setLyricProgressMs] = useState(0); const [subtitleColor, setSubtitleColor] = useState("black"); const [subtitleBG, setSubtitleBG] = useState("white"); const [backgroundImage, setBackgroundImage] = useState(""); const [clicked, setClicked] = useState(false); const [canvaz, setCanvaz] = useState(''); const [videoSrc, setVideoSrc] = useState(''); const videoRef = useRef(null); const inputRef = useRef(null); // Create a ref to the input field useEffect(() => { // const getDominantColor = async (imageSrc) => { // return new Promise((resolve, reject) => { // const img = new Image(); // img.crossOrigin = "Anonymous"; // img.src = imageSrc; // img.onload = () => { // const canvas = document.createElement("canvas"); // const ctx = canvas.getContext("2d"); // canvas.width = img.width; // canvas.height = img.height; // ctx.drawImage(img, 0, 0); // const imageData = ctx.getImageData( // 0, // 0, // canvas.width, // canvas.height, // ).data; // const length = imageData.length; // let totalR = 0, // totalG = 0, // totalB = 0; // for (let i = 0; i < length; i += 4) { // totalR += imageData[i]; // totalG += imageData[i + 1]; // totalB += imageData[i + 2]; // } // const averageR = Math.round(totalR / (length / 4)); // const averageG = Math.round(totalG / (length / 4)); // const averageB = Math.round(totalB / (length / 4)); // resolve({ r: averageR, g: averageG, b: averageB }); // }; // img.onerror = (error) => { // reject(error); // }; // }); // }; const modifyUrl = (url) => { return url.replace(/w\d+-h\d+/, "w255-h255"); }; const fetchColor = async () => { if ( currentSong && currentSong[0]?.image ) { const imageUrl = currentSong[0]?.trackId != 'kCGs5_oCtBE' && currentSong[0]?.trackId != 'O8eYd7oAZtA' ? currentSong[0].image : ''; try { // const dominantColor = await getDominantColor(imageUrl); // // Calculate luminance (YIQ color space) to determine if subtitle should be black or white // const luminance = // (0.299 * dominantColor.r + // 0.587 * dominantColor.g + // 0.114 * dominantColor.b) / // 255; // if (luminance > 0.5) { // setSubtitleColor("black"); // setSubtitleBG("white"); // } else { // setSubtitleColor("white"); // setSubtitleBG("black"); // } const proxiedUrl = `https://api.kedaimaster.com/image?url=${encodeURIComponent(modifyUrl(imageUrl))}`; // Use your proxy to fetch the image setBackgroundImage(proxiedUrl); } catch (error) { console.error("Error fetching or processing image:", error); } } }; fetchColor(); }, [currentSong]); const convertToMilliseconds = (timeStr) => { const [minutes, seconds] = timeStr.split(':').map(Number); return (minutes * 60 + seconds) * 1000; }; useEffect(() => { if (!socket) return; socket.on("requestResponse", (response) => { if(response.success) setModal("message", { captMessage: 'Berhasil menambahkan lagu' }, null, null); else setModal("message", { captMessage: 'Gagal menambahkan lagu', descMessage: response.alasan }, null, null); }); socket.on("searchResponse", (response) => { console.log(response); setSongs(response); }); socket.on("updateCurrentSong", (response) => { console.log(response) setCurrentSong(response); // setCurrentTime(response.progress_ms / 1000); // Convert milliseconds to seconds // setLyricProgressMs(response.progress_ms); // setTrackLength(convertToMilliseconds(response.item.length)); }); socket.on("updatePlayer", (response) => { setPaused(response.decision); }); socket.on("updateLyrics", (response) => { setLyrics(response); console.log(response); setCurrentLines({ past: [], present: [], future: [], }); }); socket.on("updateQueue", ({ getRecommendedMusic }) => { if (getRecommendedMusic == undefined) return; setGetRecommendedMusic(getRecommendedMusic); // Only set the queue if it's a valid non-empty array console.log("Updated config:", getRecommendedMusic); // Log the valid queue }); return () => { socket.off("searchResponse"); }; }, [socket]); // useEffect for setting up the socket listener useEffect(() => { const handleUpdateCanvas = (response) => { if (response && response !== canvaz) { console.log(response); console.log(canvaz); setCanvaz(response); fetch(response) .then((response) => response.blob()) .then((blob) => { const blobUrl = URL.createObjectURL(blob); setVideoSrc(blobUrl); if (videoRef.current) { videoRef.current.load(); // Reload the video element } }) .catch((error) => console.error('Error loading video:', error)); } else if (!response) { // Clear the video source if response is empty setVideoSrc(''); if (videoRef.current) { videoRef.current.load(); // Reload the video element } } }; // Listen for the "updateCanvas" event socket.on("updateCanvas", handleUpdateCanvas); socket.on("claimPlayerRes", (response) => { if (response.error) { console.log('Error:', response.error); // Handle error } else { window.open(response.url); } }); socket.on("unClaimPlayerRes", (response) => { if (response.error) { console.log('Error:', response.error); // Handle error } else { console.log('Player token:', response.token); // Handle success and use the player token } }); // Clean up the socket listener when the component is unmounted return () => { socket.off("updateCanvas", handleUpdateCanvas); }; }, [socket, canvaz]); useEffect(() => { // Simulate progress every 100ms const interval = setInterval(() => { setLyricProgressMs((prevProgress) => prevProgress + 100); }, 100); return () => clearInterval(interval); // Clean up interval on component unmount }, []); useEffect(() => { if (lyrics == null) return; const pastLines = lyrics.filter( (line) => line.startTimeMs < lyric_progress_ms, ); const presentLines = lyrics.filter( (line) => line.startTimeMs > lyric_progress_ms, ); const futureLines = lyrics.filter( (line) => line.startTimeMs > lyric_progress_ms, ); setCurrentLines({ past: pastLines.slice(-2, 1), // Get the last past line present: pastLines.slice(-1), future: futureLines.slice(0, 1), // Get the first future line }); }, [lyrics, lyric_progress_ms]); useEffect(() => { const handler = setTimeout(() => { setDebouncedSongName(songName); }, 300); // Cleanup function to clear the timeout if songName changes return () => { clearTimeout(handler); }; }, [songName]); const changeIsGetRecommendedMusic = () => { const isGetRecommendedMusic = !getRecommendedMusic; setGetRecommendedMusic(isGetRecommendedMusic) const token = localStorage.getItem("auth"); if (socket != null && token) { socket.emit("configPlayer", { token, shopId, getRecommendedMusic: isGetRecommendedMusic }); } } useEffect(() => { if (socket != null && debouncedSongName) { socket.emit("searchRequest", { shopId, songName: debouncedSongName }); } }, [debouncedSongName, shopId, socket]); const handleInputChange = (event) => { setSongName(event.target.value); }; const onRequest = (track) => { const token = localStorage.getItem("auth"); if (socket != null && token) { setModal('loading') socket.emit("songRequest", { token, shopId, track }); setSongName(""); console.log(track) } }; const onDecision = (trackId, vote) => { const token = localStorage.getItem("auth"); if (socket != null && token) socket.emit("songVote", { token, shopId, trackId, vote }); }; const handlePauseOrResume = (trackId, vote) => { const token = localStorage.getItem("auth"); if (socket != null && token) { socket.emit("playOrPause", { token, shopId, action: paused ? "pause" : "resume", }); console.log(paused); setPaused(!paused); } }; const handleSetPlayer = () => { const token = localStorage.getItem("auth"); socket.emit("claimPlayer", { token, shopId, }); if (isSpotifyNeedLogin) { } else { // socket.emit("unClaimPlayer", { // token, // shopId, // }); } }; useEffect(() => { const interval = setInterval(() => { setCurrentTime((prevTime) => prevTime < trackLength ? prevTime + 1 : prevTime, ); }, 1000); return () => clearInterval(interval); }, [trackLength]); const formatTime = (timeInSeconds) => { const minutes = Math.floor(timeInSeconds / 60); const seconds = Math.floor(timeInSeconds % 60); // Ensure seconds and milliseconds are always displayed with two and three digits respectively const formattedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`; return `${minutes}:${formattedSeconds}`; }; const toggleView = () => { setViewing(!viewing); }; const toggleExpand = () => { setExpanded(!expanded); }; const expandableContainerRef = useRef(null); useEffect(() => { if (expanded && expandableContainerRef.current) { expandableContainerRef.current.scrollTo({ top: 0, behavior: "smooth" }); } }, [expanded]); const [text, setText] = useState("Menunggu musik favoritmu"); const textIndex = useRef(0); const [messages, setMessages] = useState(["Menunggu musik favoritmu", "Klik untuk putar musik favoritmu"]); useEffect(() => { // Update the messages based on currentSong const newMessages = [ currentSong != null && currentSong[0]?.trackId != 'kCGs5_oCtBE' && currentSong[0]?.trackId != 'O8eYd7oAZtA' && currentSong[0]?.name != undefined ? `${currentSong[0]?.name} - ${currentSong[0]?.artist}` : "Menunggu musik favoritmu", "Klik untuk putar musik favoritmu" ]; setMessages(newMessages); setText(newMessages[0]); // Update the text state to the first message const element = document.querySelector('.animated-text'); // Check if the element exists before adding the event listener if (element) { const handleAnimationIteration = () => { // Toggle between the two text values based on the current index textIndex.current = (textIndex.current + 1) % messages.length; setText(messages[textIndex.current]); }; element.addEventListener('animationiteration', handleAnimationIteration); return () => { element.removeEventListener('animationiteration', handleAnimationIteration); }; } }, [currentSong]); // Run effect when currentSong changes const handleButtonClick = () => { setClicked(true); if (inputRef.current) { inputRef.current.focus(); // Focus the input when the button is clicked } // After 1 second, remove the "clicked" class to let the color gradually return to the original setTimeout(() => { setClicked(false); }, 1000); // 1 second timeout (same as the CSS transition duration) }; const handleFocus = () => { console.log(user) if(user.length == 0) setModal("message", { captMessage: 'Silahkan lakukan transaksi' }, null, null); }; return (
{line.words}
{line.words}