javascriptyoutubeyoutube-api

Youtube API's getDuration() function keeps returning 0 or "undefined"


I'm currently a beginner in JavaScript and I want to make a YouTube player for my personal website. I want the user to be able to click a button on the player and skip forward to the next or previous song. I also want the user to see the complete duration of the song, along with other details about it.

I tried using the player.getDuration() function which comes with YouTube's embed API, and assigning the value to the videoLength variable but no matter what I do, the value it returns is undefined or 0, which is it's initial value in my code. I believe the problem is that the player gets the video by using the loadVideoByUrl() function, instead of me passing the video id in the onYouTubeIframeAPIReady(). I would like to be able to have the video urls and other info about the songs in the object array so I can keep adding songs without the need of making a playlist on YouTube.

Here is the JavaScript code. It's not done, but I would like o figure this out before moving on.

/*Playlist defined as an array of objects*/
let songs = [
    {
        "title": "Dollz Doll - Sasha Solo",
        "artist": "Bratz",
        "album": "Dollz Doll",
        "year": 2025,
        "url": "https://www.youtube-nocookie.com/embed/5mmSXIg6Ig4?si=hdDWCzDytQ-186Y3"
    },

    {
        "title": "Think About It",
        "artist": "Bratz",
        "album": "Think About It",
        "year": 2025,
        "url": "https://www.youtube-nocookie.com/embed/lfYl_f8zo9Y?si=5aMcKkeIqR8TCciP"
    },

    {
        "title": "Speed Drive",
        "artist": "Charli XCX",
        "album": "Barbie The Album",
        "year": 2023,
        "url": "https://www.youtube-nocookie.com/embed/TxZwCpgxttQ?si=Ymw_FXTfHlbODIkR"
    }
]

let songsLength = songs.length;
let i = 0;
 
/*Selecting the elements*/
let songTitle = document.querySelector('h1');
let songArtist = document.getElementById('artist');
let songAlbum = document.getElementById('album');
let songYear = document.getElementById('release_year');

let btnToggle = document.getElementById('toggle');
let btnNext = document.getElementById('next');
let btnPrev = document.getElementById('previous');
let btnVolume = document.getElementById('volume_button');
let volumeBar = document.getElementById('volume_bar');

/*YT-api*/
let tag = document.createElement('script');

tag.src = "https://www.youtube.com/iframe_api";
let firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

let player;
function onYouTubeIframeAPIReady() {
    player = new YT.Player('yt_video', {
        origin: 'https://dorianbay.neocities.org/',
        playerVars: {
            'playsinline': 1,
            'controls': 0
        },
        events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
        }
    });
}

function onPlayerReady(event) {
    setSongInfo(i);
}

function onPlayerStateChange() {
//work-in-progress
}

function setSongInfo(i) {
    player.loadVideoByUrl(songs[i].url);
    songTitle.textContent = songs[i].title;
    songArtist.textContent = 'Artist: ' + songs[i].artist;
    songAlbum.textContent = 'Album: ' + songs[i].album;
    songYear.textContent = 'Year of release: ' + songs[i].year;

    //videoLength is currently 0
    let videoLength = player.getDuration();
    document.getElementById('song_finish').innerHTML = videoLength;
}

function previousSong() {
    i--;
    if(i < 0) {
        i = songsLength - 1;
    }
    setSongInfo(i);
}

function nextSong() {
    i++;
        if (i >= songsLength) {
        i = 0;
    }
    setSongInfo(i);
    
}

songTitle.textContent = songs[0].title;
songArtist.textContent = 'Artist: ' + songs[0].artist;
songAlbum.textContent = 'Album: ' + songs[0].album;
songYear.textContent = 'Year of release: ' + songs[0].year;

btnPrev.addEventListener('click', previousSong);
btnNext.addEventListener('click', nextSong);

And here is the HTML and CSS code:

<!DOCTYPE html>
<html lang="eng">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>YouTube Player</title>

    <link href="../css/style.css" rel="stylesheet" type="text/css" media="all">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&family=VT323&display=swap" rel="stylesheet">

    <style>

      #mp3_purple, h1, button {

        color: var(--dark_purple);

      }

      #mp3_purple {

        display: grid;
        grid-template-columns: 1fr 1fr;
        background-color: var(--white);
        width: 850px;
        height: 350px;
        border: 0.3em solid var(--dark_purple);
        padding-left: 1em;

      }

      section:nth-child(2) {
        
        display: flex;
        flex-flow: column wrap;
        justify-content: center;
        align-items: center;
        gap: 0.5em;

      }

      #yt_video {

        width: 100%;
        height: 65%;

      }

      #info span {

        display: block;
        text-align: center;

      }

      h1 {

        
        margin-left: 0;
        text-shadow: none;
        -webkit-text-stroke: 0;
        text-align: left;

      }
      
      #listened {

        width: 80%;


      }

      #time_indic {

        display: flex;
        flex-flow: row nowrap;
        justify-content: space-between;

      }


      #listened progress {

        width: 100%;
        
      }

      progress {

        height: 5px;
        border-radius: 0;

      }

      button {

        background: none;
        border: none;
        
      }
      
      h1, button {
        
        font-size: 2em;
        
      }

      #volume {

      align-self: flex-start;
      padding-left: 2em;
      display: flex;
      flex-flow: row nowrap;
      align-items: center;

      }

      #volume button, #volume_bar {

        font-size: 0.6em;

      }
      
    </style>

  </head>
  <body>
    
    <div id="mp3_purple">
      <section>
        <h1>Song title</h1>
        <div id="yt_video"></div>
      </section>
      <section>
        <div id="info">
          <span id="artist">Artist:</span>
          <span id="album">Album:</span>
          <span id="release_year">Year of release:</span>
        </div>
        <div id="listened">
          <progress max="100" value="50"></progress>
          <div id="time_indic">
            <span id="song_start">00:00</span>
            <span id="song_finish">00:00</span>
          </div>
        </div>
        <div>
          <button id="previous">⏮</button>
          <button id="toggle">▶</button>
          <button id="next">⏭</button>
        </div>
        <div id="volume">
          <button id="volume_button">🔈</button>
          <progress id="volume_bar" max="100" value="50" style="display: none;"></progress>
        </div>
      </section>
    </div>

    <script src="playlist.js"></script>
  </body>
</html>

Solution

  • Set in your onPlayerStateChange function the code for convert the seconds obtained from the getDuration() function as follows:

    function onPlayerStateChange() {
      //work-in-progress
      
      // New variable to store the duration obtained.
      var duration_obtained = 0;
      duration_obtained = player.getDuration();
    
      // Convert the seconds (obtained from the getDuration() function):
      // Source: https://stackoverflow.com/a/25279399/4092887
      var date = new Date(0);
      date.setSeconds(duration_obtained); // specify value for SECONDS here
      
      // Version # 1: 
      duration_obtained = date.toISOString().substring(11, 19);
    
      // Version # 2:
      duration_obtained = addZero(date.getMinutes()) + ':' + addZero(date.getSeconds());
    
      // Set the duration converted to time here: 
      document.getElementById('song_finish').innerHTML = duration_obtained;
    }
    
    // Add zeros and colons to display the time
    // Source: https://www.w3schools.com/jsref/jsref_getseconds.asp
    function addZero(i) {
      if (i < 10) {
        i = '0' + i;
      }
      return i;
    }
    
    

    Here is the working jsfiddle.