Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Event Listener quits (?) from listening... Youtube API - No console error

EDIT - 2016-06-25
(I removed my june 16th update, since not relevant anymore.
   I left my OP below...)



I've spent another 4 hours on this today.
Here is the situation now:

My function WORKS for two links.
The video params are defined in an array.
The two other links aren't working.

I get a Uncaught TypeError: thisPlayer.loadVideoById is not a function for links #3 and #4.
BUT THE SAME function works good for links #1 and #2.

Seems like the youtube objects are defined only for the two firsts.
WHY?

Please, have a close look to the console on this live link:
https://www.bessetteweb.com/?p=youtube-video-test
I inserted A LOT of console.log messagess to make it clear.

Here is my actual code:

// Global variable for the player
var player = [];
var statePlaying=false;

playerArr = [{
            linkID:"link0",
            divID:"player1",
            ytID:"5V_wKuw2mvI", // Heavy metal playlist
            start:20,
            end:30
            },
            {
            linkID:"link1",
            divID:"player2",
            ytID:"u9Dg-g7t2l4", // Disturbed
            start:10,
            end:20
            },
            {
            linkID:"link2",
            divID:"player3",
            ytID:"39b5v3-d6ZA", // Maiden
            start:30,
            end:40
            },
            {
            linkID:"link3",
            divID:"player4",
            ytID:"z8ZqFlw6hYg", // Slayer
            start:120,
            end:136
            }];

// This function gets called when API is ready to use
function onYouTubePlayerAPIReady() {

    // Binding events loop
    console.log("playerArr.length: "+playerArr.length);
    for(i=0;i<playerArr.length;i++){
        console.log("");
        console.log("onPlayerReady for loop ->i: "+i);

        var playButton = document.getElementById(playerArr[i].linkID);
        console.log("playButton.id: "+playButton.id);

        var thisArr = playerArr[i];
        console.log("playerArr[i] object (below): ");
        console.log(thisArr);

        playButton.addEventListener("click", function() {
            thisLinkID = $(this).attr("id").replace("link","");

            console.log("");
            console.log("------------------");
            console.log("Link #"+(parseInt(thisLinkID)+1)+" clicked.");
            console.log("------------------");

            var ytID = playerArr[thisLinkID].ytID;
            var start = playerArr[thisLinkID].start;
            var end = playerArr[thisLinkID].end;

            var thisPlayer = new YT.Player(playerArr[thisLinkID].divID);

            console.log("ytID: "+ytID);
            console.log("start: "+start);
            console.log("end: "+end);
            console.log("");

            console.log("Below are the google ads, blocked by AdBlocker.");

            $("#ytplayerModal").css({"display":"block"});
            $("#ytplayerModal").animate({"opacity":"0.7"},1000,function(){

                console.log("");
                console.log("player show()");
                $(".ytplayer").show();

                console.log("Youtube player object:");
                console.log(thisPlayer);
                console.log("");
                console.log('loadVideoById() parameters --\> videoId:'+ytID+', startSeconds:'+start+', endSeconds:'+end);

                thisPlayer.loadVideoById({'videoId':ytID, 'startSeconds':start, 'endSeconds':end});
                console.log("");
            });

            // Bugfix - Set Interval instead of listener
            setTimeout(function(){
                var IntervalCounter=0;
                listenerInterval = setInterval( function() {

                    var state = thisPlayer.getPlayerState();    //player[thisLinkID].getPlayerState();
                    var stateMsg;

                    switch (state){
                        case -1: stateMsg="unstarted"; thisPlayer.playVideo(); console.log("player["+thisLinkID+"]"); break;
                        case  0: stateMsg="ended"; break;
                        case  1: stateMsg="playing"; break;
                        case  2: stateMsg="paused"; break;
                        case  3: stateMsg="buffering"; break;
                        case  5: stateMsg="video cued"; break;
                        default: stateMsg="Undefined player state...";
                    }
                    console.log(state+" : "+stateMsg);

                    if(state==1){
                        statePlaying=true;
                    }

                    // Closes the modal
                    if((statePlaying) && (state==0)){
                    //if((statePlaying) && (stateObj.data==0)){
                        setTimeout(function(){
                            console.log("Closing Modal");
                            $(".ytplayer").css({"display":"none"});
                            $("#ytplayerModal").animate({"opacity":"0"},1000,function(){
                                $("#ytplayerModal").css({"display":"none"});
                            });
                            statePlaying=false;
                        },500);
                        clearInterval(listenerInterval);
                        console.log("Interval loop stopped on video end.")
                    }

                    // Stop the interval at 1000... Endless instead!
                    IntervalCounter++;
                    if((IntervalCounter>999)&&(state!=1)&&(state!=2)&&(state!=0)){
                        clearInterval(listenerInterval);
                        console.log("Interval loop willingly stopped. Endless otherwise.")
                    }
                }, 10);
            },1100);    // Interval setTimeout
        });
    }
}

// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);



Here is a snapshot of my console log: Console-log



-----------------
Here is my original post - june 14th :

I spent 6 hours on this already.
(plus 1 editing this question!)

I'm kind of debugging the last 4 lines of it.

Problem is that I get NO console error as a hint.



Concept:
I want to link numerous Youtube videos to text links.
The wanted effect for the user is to be able to click on a citation link while reading a text... In order to be able to confirm the citation.
The video has NOT to play entirely.

The video shall start at a specific timecode AND end at a specific timecode.
Bonus complexity: All this is wanted to be shown in a modal view style.

My code WORKED quite fast for ONE video. See here.

I based my code on this tutorial and succedded real fast.

Then, having this working...
I had the need to build arrays to handle multiple videos.
For links ids, players ids, timecodes for start/end... AND LISTENERS!
Fun begins!

Like said, I spent most of my day on this. I always encountered bugs WITH console errors as clear (LOLLL) guides.

I am satisfied of my work... This is going in the right direction I think.
This is almost working...


But this time, no errors! See here. (check the console!)

WHATT!!! NO ERROR?!?
My arms are hacked off now.
In fact, the 1st shows but video doesn't start... And the second looks to be completely lost in the haze.

In console log messages, I see the 1st occurance of the onStateChange listener, wich is -1 (Unstarted). But then ??? It dies!
Arrgg!

I have to overstep my pride... And bring it as a question on StackOveflow.
;)



My full code (for multiple links):
This is a page called via ajax... So all external ressources like jQuery are already loaded.

<style>
.ytplayer{
    position:fixed;
    z-index:2;
    width:60%;
    height:40%;
    top:30%;
    left:20%;
    display:none;
}
#ytplayerModal{
    display:none;
    background-color:#000;
    opacity:0;
    position:fixed;
    z-index:1;
    top:0;
    left:0;
    width:100%;
    height:100%;
}
.ytTriggerPlay{
    text-decoration:underline;
    color:dodgerblue;
    cursor:pointer;
}
</style>



<h1>Youtube modal trigger link test</h1>
<br>
<br>
<div id="text">
    Lorem ipsum dolor sit amet, consectetur <a id="0" class="ytTriggerPlay">adipiscing elit</a>. Quisque feugiat lectus ut est vestibulum ornare. Vivamus felis nulla, facilisis id cursus non, pharetra non diam. Sed pellentesque turpis vel sem tincidunt consectetur. Aenean ut lorem erat. Donec ut tellus sed leo ultrices cursus. <a id="1" class="ytTriggerPlay">Cras varius libero</a> ut purus suscipit ultrices. Vivamus eget efficitur turpis. Aenean suscipit, dui nec luctus fringilla, neque tellus fringilla risus, et porta enim justo et turpis. Sed risus orci, vehicula sed eleifend eget, tincidunt ut turpis. Vestibulum in sapien non lacus tristique mattis id eget tortor.<br>
    <br>
    Proin est purus, maximus id nunc vel, consectetur tristique urna. Mauris cursus ipsum a varius luctus. Nunc interdum condimentum massa vitae rutrum. Morbi volutpat nec lorem eleifend malesuada. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis fringilla metus vel nunc elementum efficitur. Duis sed dolor diam. In eu ultrices libero, eget lobortis mi. Sed pretium orci non augue vehicula, eget placerat leo lacinia. Sed sed gravida dui. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In bibendum, erat eget venenatis elementum, nulla enim posuere lacus, quis efficitur dolor ex quis ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Phasellus volutpat finibus odio id venenatis. Fusce at leo libero. Cras eget velit sed justo egestas vehicula efficitur sit amet ex.<br>
</div>

<!--iframe id="ytplayer" type="text/html" width="720" height="405" src="https://www.youtube.com/embed/5V_wKuw2mvI?end=60&start=20" frameborder="0" allowfullscreen-->

<div id="ytplayerModal"></div>
<div id="player1" class="ytplayer"></div>
<div id="player2" class="ytplayer"></div>

<script>
// https://developers.google.com/youtube/iframe_api_reference
// https://css-tricks.com/play-button-youtube-and-vimeo-api/

// Global variable for the player
var player = [];
var statePlaying=false;

playerArr = [{
            linkID:"0",
            divID:"player1",
            ytID:"5V_wKuw2mvI", // Heavy metal playlist
            start:20,
            end:40,
            },
            {
            linkID:"1",
            divID:"player2",
            ytID:"39b5v3-d6ZA", // Maiden
            start:30,
            end:60,
            }];

// This function gets called when API is ready to use

function onYouTubePlayerAPIReady() {
    for(i=0;i<playerArr.length;i++){
        // Create the global player from the specific iframe (#video)
        thisPlayer = new YT.Player(playerArr[i].divID, {
            height: '352',
            width: '640',
            videoId: '5V_wKuw2mvI',
            startSeconds:20,
            endSeconds:40,
            events: {
                // Call this function when player is ready to use
                // 'onReady': onPlayerReady         // Commented out willingly.
            }
        });
        player[i] = thisPlayer;

    }
    onPlayerReady();
}

function onPlayerReady(event) {

    // Binding events loop
    console.log("playerArr.length: "+playerArr.length);
    for(i=0;i<playerArr.length;i++){
        console.log("");
        console.log("onPlayerReady for loop ->i: "+i);

        var playButton = document.getElementById(playerArr[i].linkID);
        console.log("playButton.id: "+playButton.id);

        var thisArr = playerArr[i];
        console.log("playerArr[i] object (below): ");
        console.log(thisArr);

        var thissPlayer = player[i];

        playButton.addEventListener("click", function() {
            thisLinkID = parseInt($(this).attr("id"));
            console.log("thisLinkID: "+thisLinkID);

            var ytID = playerArr[thisLinkID].ytID;
            var start = playerArr[thisLinkID].start;
            var end = playerArr[thisLinkID].end;

            console.log("ytID: "+ytID);
            console.log("start: "+start);
            console.log("end: "+end);
            console.log("thissPlayer object (below): ");
            console.log(thissPlayer);

            $("#ytplayerModal").css({"display":"block"});
            $("#ytplayerModal").animate({"opacity":"0.7"},1000,function(thissPlayer,ytID,start,end){
                $(".ytplayer").show();

                player[thisLinkID].loadVideoById({videoId:ytID, startSeconds:start, endSeconds:end});
                setTimeout(function(){
                    player[thisLinkID].playVideo();
                },500);
            });
        });



        thissPlayer.addEventListener("onStateChange", function(stateObj){
            console.log("Player State: "+stateObj.data);
            console.log("Again, thissPlayer object in the onStateChange listener (below).");
            console.log(thissPlayer);
            // State sequence : -1, 3, 1, 2, 0, which is: Unstarted, Buffering, Playing, Paused, Ended.

            if(stateObj.data==1){
                statePlaying=true;
            }
            console.log("Player State bolean memory: "+statePlaying);

            // Closes the modal
            if((statePlaying) && (stateObj.data==0)){
                setTimeout(function(){
                    console.log("Closing Modal");
                    $(".ytplayer").css({"display":"none"});
                    $("#ytplayerModal").animate({"opacity":"0"},1000,function(){
                        $("#ytplayerModal").css({"display":"none"});
                    });
                    statePlaying=false;
                },500);
            }
        });
    }
}

// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
</script>
like image 508
Louys Patrice Bessette Avatar asked Jun 14 '16 23:06

Louys Patrice Bessette


1 Answers

There was a temporary issue with the iFrame Player API that you can read about here: https://code.google.com/p/gdata-issues/issues/detail?id=4706

As a temporary fix, you just need to add the event listener within the onReady event:

function onReady() {
player.addEventListener('onStateChange', function(e) {
console.log('State is:', e.data);
});
}

Also, as someone mentioned on the Google Code Issue Thread, you set an interval and poll the player for its current state instead of listening for the onStateChange event. Here is an example code snippet for doing that:

setInterval( function() {
var state = player.getPlayerState();
if ( playerState !== state ) {
onPlayerStateChange( {
data: state
});
}
}, 10);
like image 179
Android Enthusiast Avatar answered Oct 12 '22 06:10

Android Enthusiast