Jillian Hoenig
Jillian Hoenig

Reputation: 257

Playlist index messed up when adding video to playlist queue (youtube iframe api)

I'm using youtube iframe api in my web app, but there's a weird behavior when adding a video to the playlist. Whenever a video is added to an existing playlist, and playlist index becomes a non-integer number - which messes up the NextVideo and PreviousVideo functions, both of which work properly otherwise.

_mediaplayer.html.erb (template partial with the media player html)

<div id="media-player" class="playing">
    <marquee>Now playing: <span id="track-title"></span></marquee>
    <div class="controls"> 
    <button aria-label="play" id="play" class="play">Play</button> 
    <button aria-label="stop" id="stop" class="stop">Stop</button>
    <button aria-label="previous track" id="prev" class="prev">Prev</button>
    <button aria-label="next track" id="next" class="next">Next</button>
    <div class="current-time-container">
        <span id="curr-main" class="current-time"></span>
    </div>
    </div>
    <div class="range-container">
    <input id="dur-main" type="range" name="rng" min="0" value="0" max="252.029388">
    </div>
</div>

<div controls data-autoplay="0" data-loop="1" id="youtube-player">Youtube Player</div>

youtubePlayer.js

// initialize youtube player
const player = new YT.Player('youtube-player', {
    width: 300,
    height: 200,
});

document.addEventListener('turbo:load', youtube_player, false);
document.addEventListener('turbo:frame-load', youtube_player, false);

function youtube_player () {

        let playlist = document.getElementById('cuePlaylist').dataset.playlist.split(',');
        // define media player controls
        const playAll = document.getElementById("playPlaylist"),
            cue  = document.getElementById("cuePlaylist"),
            play = document.getElementById("play"),
            stop = document.getElementById("stop"),
            prev = document.getElementById("prev"),
            next = document.getElementById("next");

        cue.addEventListener("click", function(e){
            e.preventDefault();
            if (player.getPlaylist()) {
                const new_playlist = player.getPlaylist().concat(playlist);
                if (player.getPlayerState() == YT.PlayerState.PLAYING) {
                    player.loadPlaylist(new_playlist, player.getCurrentTime(), player.getPlaylistIndex());
                    play.innerHTML = "Pause";
                } else {
                    player.cuePlaylist(new_playlist);
                }
            } else {
                player.cuePlaylist(playlist);
            }
        });

        playAll.addEventListener("click", function(e) {
            e.preventDefault();
            player.loadPlaylist(playlist);
            play.innerHTML = "Pause";
        });
        play.addEventListener("click", function() {
            if (player.getPlayerState() == YT.PlayerState.PLAYING) {
                player.pauseVideo();
                play.innerHTML = "Play";
            } else {
                player.playVideo();
                play.innerHTML = "Pause";
            }
        });
        stop.addEventListener("click", function() {
            if (player.getPlayerState() == YT.PlayerState.PLAYING) {
                player.stopVideo();
                play.innerHTML = "Play";
            }
        });
        prev.addEventListener("click", function() {
            if (player.getPlayerState() == YT.PlayerState.PLAYING) {
                player.previousVideo();
            } else {
                player.previousVideo();
                player.pauseVideo();
            }
        });
        next.addEventListener("click", function() {
            if (player.getPlayerState() == YT.PlayerState.PLAYING) {
                player.nextVideo();
            } else {
                player.nextVideo();
                player.pauseVideo();
            }
        });
}

show.html.rb (file showing an individual playlist)

<section class="playlist">
  <div class="site-container">
    <% if @playlist.image.attached? %>
      <%= image_tag @playlist.image, size: "100x100", alt: "#{@playlist.title} image", class: "playlist-image"  %>
    <% end %>
    <div class="copy-area">
      <h1 class="playlist-title"><%= @playlist.title %></h1>
      <% if @is_user %>
        <p class="playlist_user">By you</p>
        <div class="playlist-actions">
            <%= link_to "Add editor", search_users_path %>
            <%= link_to "Edit", edit_playlist_path(@playlist) %>
            <%= button_to "Delete", @playlist, method: :delete %>
        </div>
      <% else %>
        <p class="playlist-user">By <%= @user.username ? @user.username : @user.email %></p>
      <% end %>
      # Editors
      <% if @playlist.editors.present? %>
        <div class="playlist-editors">
            <% @playlist.editors.each do |editor| %>
                <%= link_to editor.username, user_account_path(editor) %>
            <% end %>
        </div>
      <% end %>
      # Tags
      <% if @playlist.tags %>
        <div class="playlist-tags">
            <% @playlist.tags.each do |tag| %>
                <%= render "tags/tag", tag: tag, is_user: @is_user %>
            <% end %>
        </div>
      <% end %>
    </div>
    # Tracks
    <% if @tracks %>
        <% index = 0 %>
        <%= link_to "Play Playlist", '#', id: 'playPlaylist', data: {turbo_frame: 'mediaplayer'} %>
        <%= link_to "Add to queue", '#', id: 'cuePlaylist', data: {'playlist' => @track_ids.join(','), turbo_frame: 'mediaplayer'}  %>

        <div id="tracklist" class="playlist-tracks">
            <% for track in @tracks %>
                <%= render "tracks/track", track: track, index: index, user: @user %>
                <% index += 1 %>
            <% end %>
        </div>
    <% end %>
  </div>
</section>

This is a rails app, using plain javascript (and the youtube iframe api) to control the media player. Let me know if you have any thoughts. There are probably way more errors in the code, but I want to focus on the error in question stated above.

Thank you!

Upvotes: 0

Views: 43

Answers (1)

Jillian Hoenig
Jillian Hoenig

Reputation: 257

This seems pretty obvious in retrospect. The reason the playlist index was a random float after I added subsequent playlists to the queue, is that in youtubePlayer.js when I use loadPlaylist() function, I mixed up the parameters for index and start time - setting the new index to whatever the current time of the playing video is.

This:

player.loadPlaylist(new_playlist, player.getCurrentTime(), player.getPlaylistIndex());

Should be:

player.loadPlaylist(new_playlist, player.getPlaylistIndex(), player.getCurrentTime());

As shown in the Google youtube player API docs:

player.loadPlaylist(playlist:String|Array,
                    index:Number,
                    startSeconds:Number):Void

Upvotes: 0

Related Questions