Switch between songs in the audio Player

Viewed 90

I am trying to switch between songs in next js using the use effect hook but everything works perfectly when I click the button the song start automatically and the song switch but the color behind the progress bar does match the current time because it getting the progress of the first song that is loaded in the browser how can I fix this using the use Effect or other method?

if you noticed is does not load properly at the first time when you click the button to switch the song but when you click the play / pause button it fixed I don't know why.

Also it give me the last value not the actual value I mean I need for example the 140 but it always gave me the 247 value the prev Value

post: is the part // ! useEffect to change the audio

import React, { useState, useRef, useEffect } from "react";
import styles from "../styles/AudioPlayer.module.css";
import { BiLeftArrowAlt } from "react-icons/bi";
import { BiRightArrowAlt } from "react-icons/bi";
import { FaPlay } from "react-icons/fa";
import { FaPause } from "react-icons/fa";

const AudioPlayer = () => {
  // ! state
  const [isPlaying, setIsPlaying] = useState(false);
  const [duration, setDuration] = useState(0);
  const [currentTime, setCurrentTime] = useState(0);
  const [audio, setAudio] = useState(null);

  const chapters = [
    {
      // start: 0,
      // end: 40,
      start: 0,
      end: 8,
    },
    {
      start: 135,
      end: 140,
      // start: 100,
      // end: 140,
    },
  ];

  const Elvis = "../audios/AudioElvis.mp3";
  const GetLucky = "../audios/GetLucky.mp3";

  // ! refs

  const audioPlayer = useRef(); // ? reference to the audio component
  const progressBar = useRef(); // ? reference to the progress bar
  const animationRef = useRef(); // ? reference to the animation

  // ! useEffect to handle the audio player

  useEffect(() => {
    const seconds = Math.floor(audioPlayer.current.duration);
    setDuration(seconds);

    // ! current is a reference to the current item
    // ? max is the reference given by the progress bar

    progressBar.current.max = seconds;
  }, [audioPlayer?.current?.loadedmetadata, audioPlayer?.current?.readyState]);

  // ! useEffect to handle the end of the audio

  useEffect(() => {
    if (currentTime == duration && isPlaying) {
      togglePlayPause();
      timeTravel(0);
    }
  }, [currentTime]);

  // ! useEffect to change the audio

  useEffect(() => {
    if (audio && !isPlaying) {
      if (audio === Elvis) {
        setDuration(140);
      } else if (audio === GetLucky) {
        setDuration(247);
      }

      console.log("audio", audio);
      console.log("duration", duration);
      setDuration(audioPlayer.current.duration);
      audioPlayer.current.src = audio;
      audioPlayer.current.load(); // ? load the audio
      togglePlayPause();
      timeTravel(0);
    } else if (audio && isPlaying) {
      if (audio === Elvis) {
        setDuration(140);
      } else if (audio === GetLucky) {
        setDuration(247);
      }

      console.log("audio", audio);
      console.log(audio === Elvis);
      console.log(audio === GetLucky);
      console.log("duration", duration);
      audioPlayer.current.src = audio;
      audioPlayer.current.load(); // ? load the audio
      audioPlayer.current.play();
      timeTravel(0);
    }
  }, [audio]);

  // ! FUNCTIONS

  const calculateTime = (secs) => {
    const minutes = Math.floor(secs / 60);
    const returnedMinutes = minutes < 10 ? `0${minutes}` : minutes;
    const seconds = Math.floor(secs % 60);
    const returnedSeconds = seconds < 10 ? `0${seconds}` : seconds;
    return `${returnedMinutes}:${returnedSeconds}`;
  };

  const togglePlayPause = () => {
    const prevValue = isPlaying;
    setIsPlaying(!prevValue);

    if (!prevValue) {
      audioPlayer.current.play();

      // ? requestAnimationFrame is a function that allows us to run a function
      // ? every frame of the animation

      animationRef.current = requestAnimationFrame(whilePlaying);
    } else {
      audioPlayer.current.pause();
      cancelAnimationFrame(animationRef.current);
    }
  };

  // ! Creating our animation function => whilePlaying

  const whilePlaying = () => {
    progressBar.current.value = audioPlayer.current.currentTime;

    changePlayerCurrentTime();

    animationRef.current = requestAnimationFrame(whilePlaying);
  };

  // ! Changing the range of the progress bar FUNCTION

  const changeRange = () => {
    // ! Setting our audio current time to the value of the progress bar
    audioPlayer.current.currentTime = progressBar.current.value;

    changePlayerCurrentTime();
  };

  const changePlayerCurrentTime = () => {
    // ! Updating the progress bar in CSS

    // ? progressBar.current.style.setProperty => takes two arguments
    // ? first is the property name
    // ? second is the value of the property

    // console.log("bar", progressBar.current.value);
    // console.log("duration", duration);

    progressBar.current.style.setProperty(
      "--seek-before-width",
      `${(progressBar.current.value / duration) * 100}%`
    );
    setCurrentTime(progressBar.current.value);
  };

  const backThirty = () => {
    progressBar.current.value = Number(progressBar.current.value) - 30;
    changeRange();
  };

  const forwardThirty = () => {
    progressBar.current.value = Number(progressBar.current.value) + 30;
    changeRange();
  };

  const timeTravel = (newTime) => {
    progressBar.current.value = newTime;
    changeRange();
  };

  // // ! Changing the audio source

  // const changeSong = (song) => {
  //   setAudio(song);
  //   setIsPlaying(false);
  //   timeTravel(0);
  // };

  return (
    <div className={styles.audioPlayer}>
      {/* Audio Player Reference */}

      <audio
        ref={audioPlayer}
        // src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"
        src={Elvis}
        preload="metadata"
      ></audio>

      {/* End of the Audio Player Reference */}

      {/* Current Time */}
      <div className={styles.currentTime}>{calculateTime(currentTime)}</div>

      {/* Progress Bar */}

      <div className={styles.progressBarWrapper}>
        <input
          type="range"
          className={styles.progressBar}
          defaultValue="0"
          ref={progressBar}
          onChange={changeRange}
          step="0.05"
        />

        {/* Chapters Video 2 */}

        {chapters.map((chapter, i) => {
          const leftStyle = (chapter.start / duration) * 100;

          const widthStyle = ((chapter.end - chapter.start) / duration) * 100;

          return (
            <div
              key={i}
              className={`${styles.chapter} ${
                chapter.start === 0 && styles.start
              } ${chapter.end === duration && styles.end}`}
              style={{
                "--left": `${leftStyle}%`,
                "--width": `${widthStyle}%`,
              }}
            ></div>
          );
        })}
      </div>

      {/* Duration */}

      <div className={styles.duration}>
        {duration && !isNaN(duration) ? calculateTime(duration) : "0:00"}
      </div>

      {/* Controls */}

      <div className={styles.controls}>
        <button className={styles.forwardBackward} onClick={backThirty}>
          <BiLeftArrowAlt /> 30
        </button>
        <button onClick={togglePlayPause} className={styles.playPause}>
          {isPlaying ? <FaPause /> : <FaPlay className={styles.play} />}
        </button>
        <button className={styles.forwardBackward} onClick={forwardThirty}>
          30 <BiRightArrowAlt />
        </button>
      </div>

      <div>
        <button onClick={() => setAudio(Elvis)}>Elvis Song</button>
        <button onClick={() => setAudio(GetLucky)}>Get Lucky Song</button>
      </div>
    </div>
  );
};

export { AudioPlayer };
// ! the {} means that this is a named export
0 Answers
Related