Karaoke YouTube Video Search Timer Tutorial

Karaoke YouTube Video Search Timer Tutorial

Karaoke YouTube Video Search Timer Tutorial

On top of the recent Karaoke YouTube Video Search Loop Tutorial‘s work we take a curious turn. Back at Karaoke YouTube Video Search Event Timing Tutorial we had …

… worked, timing wise, via setTimeout timers, separated by the video duration (and a bit).

… leading us to a strategy to back this up with YouTube Embedded Iframe API event tracking. And today we complete the circle, backing up that YouTube Embedded Iframe API event with setTimeout checks and balances. This has us interested in calls of top.document (ie. grandparent) Javascript code from child code as per calls like …


function consolelog(inm) {
if (window.top) {
if (top.document.getElementById('postlist') && top.document.URL.indexOf('debug=') != -1) {
top.document.getElementById('postlist').style.display='block';
top.document.getElementById('postlist').innerHTML+='
' + inm;
} else if (('' + typeof window.top.consolelog) == 'function' && top.document.URL.indexOf('debug=') != -1) {
window.top.consolelog(inm);
} else {
console.log(inm);
}
} else {
console.log(inm);
}
}

Yes, we, along the way, start writing debug information to the screen if that top.document’s document.URL (ie. address bar URL) contains “debug=y”. But it’s not just debugging here. Consider …


if (top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0) { // another ahead playing
var bypass=false;
consolelog('one ahead playing');
if (('' + typeof window.top.getloopstatus) == 'function') {
if (window.top.getloopstatus() == true && window.top.getwasloopstatus() == true) {
if (('' + typeof window.top.particularrestart) == 'function') {
window.top.particularrestart(-1, vid.trim());
bypass=true;
}
}
}
if (!bypass) { setTimeout(cejy, 3000); } // not yet
return '';
}

… this snippet capturing a scenario …

  • we are looping …
  • we are in the child web application’s execution incarnation after the video flagged as “playing” (with that one space prefix) …
  • at the scenario where the user has never paused a video and we are past the time the video should have ended … and so …
  • perhaps an ENDED event was not triggered/detected … and so …
  • we refresh the relevant iframe’s “src” attribute (ie. its document.URL)

… as an example improving the looping reliability.

We improve on the changed helperer outerer stop_start_youtube.html for the changed karaoke_youtube_api.htm HTML and Javascript code’s live run link’s reliability with today’s hierarchical code calling and debugging using setTimeout timer concepts.


Previous relevant Karaoke YouTube Video Search Loop Tutorial is shown below.

Karaoke YouTube Video Search Loop Tutorial

Karaoke YouTube Video Search Loop Tutorial

On top of the progress of the recent Karaoke YouTube Video Search Event Timing Tutorial we wanted to offer a way, at least for non-mobile users, a “looping mechanism”.

We offer this functionality in two methodologies …

  • an automated programmatical approach using YouTube Embedded Iframe API event information
  • an emoji button 🔁 user button click approach

For non-mobile looping functionality we needed to improve on the changed helperer outerer stop_start_youtube.html for the changed karaoke_youtube_api.htm HTML and Javascript code’s live run link.


Previous relevant Karaoke YouTube Video Search Event Timing Tutorial is shown below.

Karaoke YouTube Video Search Event Timing Tutorial

Karaoke YouTube Video Search Event Timing Tutorial

Yesterday’s Karaoke YouTube Video Search Reveal Tutorial mentioned …

… worked, timing wise, via setTimeout timers, separated by the video duration (and a bit).

… and that strategy would be all fine and good for scenarios where your group of videos is played through with no delays and the autoplay for non-mobile platforms is all in working order, but as you might imagine, even for those non-mobile platforms, users are very likely to pause and resume viewing the videos, and we’d like to have a smarter approach.

That “smarter approach” we figure involves “drilling into” the YouTube Embedded Iframe API event workings and be interested in these events …

  • YT.PlayerState.PLAYING
    Parent caller of YouTube Embedded Iframe API event interfacer

    if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') < 11) {
    if (1 == 11) { // equivalent code below happens at stop_start_youtube.html
    if (top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp;' + vid + '##') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf(' ' + vid + '##') == 0) {
    top.document.getElementById('listeleven').innerHTML='&nbsp;' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
    }
    }
    } else {
    var thingos=top.document.getElementById('listeleven').innerHTML.split('^');
    if (top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp;') == 0) { // another ahead playing
    setTimeout(cejy, 3000); // not yet
    return '';
    }
    }
    Child YouTube Embedded Iframe API event interfacer

    if (event.data == YT.PlayerState.PLAYING) {
    top.document.getElementById('listeleven').innerHTML='&nbsp;' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
    }
  • YT.PlayerState.PAUSED
    Parent caller of YouTube Embedded Iframe API event interfacer

    if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') < 11) {
    if (1 == 11) { // equivalent code below happens at stop_start_youtube.html
    if (top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ' + vid + '##') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf(' ' + vid + '##') == 0) { // paused
    top.document.getElementById('listeleven').innerHTML='&nbsp; ' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
    }
    }
    } else {
    if ((top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ') == 0) && eval('' + thingos.length) == 2) { // another ahead paused
    if (eval(pausecount % 20) == 0) {
    pask=prompt('Previous video ' + top.document.getElementById('listeleven').innerHTML.split('##')[1].split('^')[0] + ' is paused. Do you want to leave it that way and proceed attempting to play ' + thingos[1].split('##')[1] + ' now?', 'yes');
    }
    pausecount++;
    if (pask == null) { pask=''; }
    if ((pask + ' ').substring(0,1).toLowerCase() != 'y') {
    setTimeout(cejy, 3000); // not yet
    return '';
    } else {
    top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
    pausecount=0;
    }
    } else if (top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ') == 0) { // another ahead paused
    if (thingos[1].indexOf(' ' + vid) == 0 || thingos[1].indexOf('&nbsp; ' + vid) == 0 || thingos[1].indexOf(vid) == 0) { // it is one ahead and here we are trying to autostart number 2 video
    if (eval(pausecount % 20) == 0) {
    pask=prompt('Previous video ' + top.document.getElementById('listeleven').innerHTML.split('##')[1].split('^')[0] + ' is on pause. Do you want to leave it that way and proceed attempting to play ' + thingos[1].split('##')[1] + ' now?', 'yes');
    }
    pausecount++;
    if (pask == null) { pask=''; }
    if ((pask + ' ').substring(0,1).toLowerCase() != 'y') {
    setTimeout(cejy, 3000); // not yet
    return '';
    } else {
    top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
    pausecount=0;
    }
    } else {
    setTimeout(cejy, 3000); // not yet
    return '';
    }
    }
    }
    Child YouTube Embedded Iframe API event interfacer

    if (event.data == YT.PlayerState.PAUSED) {
    top.document.getElementById('listeleven').innerHTML='&nbsp; ' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
    }
  • YT.PlayerState.ENDED
    Parent caller of YouTube Embedded Iframe API event interfacer

    if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') < 11) {
    if (1 == 11) { // equivalent code below happens at stop_start_youtube.html
    if (top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp;' + vid + '##') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf(' ' + vid + '##') == 0) {
    top.document.getElementById('listeleven').innerHTML='&nbsp;' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
    } else if (top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ' + vid + '##') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf(' ' + vid + '##') == 0) { // paused
    top.document.getElementById('listeleven').innerHTML='&nbsp; ' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
    } else if (1 == 11) { // if (event.data == YT.PlayerState.ENDED) {
    top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
    }

    }
    } else {
    var thingos=top.document.getElementById('listeleven').innerHTML.split('^');
    if ((top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ') == 0) && eval('' + thingos.length) == 2) { // another ahead paused
    if (eval(pausecount % 20) == 0) {
    pask=prompt('Previous video ' + top.document.getElementById('listeleven').innerHTML.split('##')[1].split('^')[0] + ' is paused. Do you want to leave it that way and proceed attempting to play ' + thingos[1].split('##')[1] + ' now?', 'yes');
    }
    pausecount++;
    if (pask == null) { pask=''; }
    if ((pask + ' ').substring(0,1).toLowerCase() != 'y') {
    setTimeout(cejy, 3000); // not yet
    return '';
    } else {
    top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
    pausecount=0;
    }
    } else if (top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ') == 0) { // another ahead paused
    if (thingos[1].indexOf(' ' + vid) == 0 || thingos[1].indexOf('&nbsp; ' + vid) == 0 || thingos[1].indexOf(vid) == 0) { // it is one ahead and here we are trying to autostart number 2 video
    if (eval(pausecount % 20) == 0) {
    pask=prompt('Previous video ' + top.document.getElementById('listeleven').innerHTML.split('##')[1].split('^')[0] + ' is on pause. Do you want to leave it that way and proceed attempting to play ' + thingos[1].split('##')[1] + ' now?', 'yes');
    }
    pausecount++;
    if (pask == null) { pask=''; }
    if ((pask + ' ').substring(0,1).toLowerCase() != 'y') {
    setTimeout(cejy, 3000); // not yet
    return '';
    } else {
    top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
    pausecount=0;
    }
    } else {
    setTimeout(cejy, 3000); // not yet
    return '';
    }
    } else if (top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp;') == 0) { // another ahead playing
    setTimeout(cejy, 3000); // not yet
    return '';
    } else {
    setTimeout(cejy, 3000); // not yet
    return '';
    }

    }
    Child YouTube Embedded Iframe API event interfacer

    if (event.data == YT.PlayerState.ENDED) {
    top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
    }

… with regard to …

Parent caller of YouTube Embedded Iframe API event interfacer

function cejy() {
var pask=null;
document.body.style.cursor='pointer';
if (ptddp != '') {

var vid='' + ourvid;
if (window.top) { // yeh but code
if (top.document.getElementById('listeleven') && eval('' + vid.trim().length) == 11) {
if (top.document.getElementById('listeleven').innerHTML != '') {
//alert(vid + ' *' + top.document.getElementById('listeleven').innerHTML + '*');
if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') != -1) {
if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') < 11) {
if (1 == 11) { // equivalent code below happens at stop_start_youtube.html
if (top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp;' + vid + '##') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf(' ' + vid + '##') == 0) {
//if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 0) { // playing
top.document.getElementById('listeleven').innerHTML='&nbsp;' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
//} else if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 2) {
// top.document.getElementById('listeleven').innerHTML='&nbsp;' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
//}
} else if (top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ' + vid + '##') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf(' ' + vid + '##') == 0) { // paused
//if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 0) {
top.document.getElementById('listeleven').innerHTML='&nbsp; ' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
//} else if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 1) {
// top.document.getElementById('listeleven').innerHTML='&nbsp; ' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim();
//}
} else if (1 == 11) { // if (event.data == YT.PlayerState.ENDED) {
top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
}
}
} else {
var thingos=top.document.getElementById('listeleven').innerHTML.split('^');
if ((top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ') == 0) && eval('' + thingos.length) == 2) { // another ahead paused
if (eval(pausecount % 20) == 0) {
pask=prompt('Previous video ' + top.document.getElementById('listeleven').innerHTML.split('##')[1].split('^')[0] + ' is paused. Do you want to leave it that way and proceed attempting to play ' + thingos[1].split('##')[1] + ' now?', 'yes');
}
pausecount++;
if (pask == null) { pask=''; }
if ((pask + ' ').substring(0,1).toLowerCase() != 'y') {
setTimeout(cejy, 3000); // not yet
return '';
} else {
top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
pausecount=0;
}
} else if (top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp; ') == 0) { // another ahead paused
if (thingos[1].indexOf(' ' + vid) == 0 || thingos[1].indexOf('&nbsp; ' + vid) == 0 || thingos[1].indexOf(vid) == 0) { // it is one ahead and here we are trying to autostart number 2 video
if (eval(pausecount % 20) == 0) {
pask=prompt('Previous video ' + top.document.getElementById('listeleven').innerHTML.split('##')[1].split('^')[0] + ' is on pause. Do you want to leave it that way and proceed attempting to play ' + thingos[1].split('##')[1] + ' now?', 'yes');
}
pausecount++;
if (pask == null) { pask=''; }
if ((pask + ' ').substring(0,1).toLowerCase() != 'y') {
setTimeout(cejy, 3000); // not yet
return '';
} else {
top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], '');
pausecount=0;
}
} else {
setTimeout(cejy, 3000); // not yet
return '';
}
} else if (top.document.getElementById('listeleven').innerHTML.indexOf(' ') == 0 || top.document.getElementById('listeleven').innerHTML.indexOf('&nbsp;') == 0) { // another ahead playing
setTimeout(cejy, 3000); // not yet
return '';
} else {
setTimeout(cejy, 3000); // not yet
return '';
}
}
}
}
}
}

// More conventional workflow code follows ... until the action pair of codelines to try to play the video

if (document.getElementById('c0')) { document.getElementById('c0').checked=true; }
if (document.getElementById('ejkaraoke')) { document.getElementById('ejkaraoke').click(); }
}
Child YouTube Embedded Iframe API event interfacer

function onPlayerStateChange(event) {
one=0;
onepause=0;
if (window.top) {
if (top.document.getElementById('listeleven') && eval('' + vid.trim().length) == 11) {
if (top.document.getElementById('listeleven').innerHTML != '') {
if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') != -1) {
if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') < 11) { if (event.data == YT.PlayerState.PLAYING) { //alert('playing event.data=' + event.data); //if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 0) { top.document.getElementById('listeleven').innerHTML='&nbsp;' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim(); //} else if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 2) { // top.document.getElementById('listeleven').innerHTML=' ' + top.document.getElementById('listeleven').innerHTML.trim(); //} } else if (event.data == YT.PlayerState.PAUSED) { //alert('paused event.data=' + event.data); //if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 0) { top.document.getElementById('listeleven').innerHTML='&nbsp; ' + top.document.getElementById('listeleven').innerHTML.replace('&nbsp;',' ').trim(); //} else if (top.document.getElementById('listeleven').innerHTML.indexOf(vid + '##') == 1) { // top.document.getElementById('listeleven').innerHTML=' ' + top.document.getElementById('listeleven').innerHTML.trim(); //} } else if (event.data == YT.PlayerState.ENDED) { //alert('ended event.data=' + event.data); top.document.getElementById('listeleven').innerHTML = top.document.getElementById('listeleven').innerHTML.replace( top.document.getElementById('listeleven').innerHTML.split('^')[0] + '^', '').replace( top.document.getElementById('listeleven').innerHTML.split('^')[0], ''); //} else { //alert('event.data=' + event.data); } } } } } } // More conventional workflow code follows }

And so, again, we improve on the changed helperer outerer stop_start_youtube.html for the changed karaoke_youtube_api.htm HTML and Javascript code's live run link.


Previous relevant Karaoke YouTube Video Search Reveal Tutorial is shown below.

Karaoke YouTube Video Search Reveal Tutorial

Karaoke YouTube Video Search Reveal Tutorial

Around here, in our mind at least, we try to simplify many webpage design "look" issues into one of ...

  • overlay ... or ...
  • reveal

... issue categories. It doesn't fit all situations, but it seems to fit a lot. Today we have a "reveal" themed improvement, and ever since the introduction of "the dynamic duo of reveal" details/summary HTML element combination (alas not to all web browser brands, but most) we've had less head scratching to do regarding decision making in this neck of the woods.

Some of our new "Reveal" button functionality fits into the amended set of display modes like ...

  • Ready ... each fills a window and might autoplay synchronously
  • Grid ... each sits within a 3x3 grid table and does not attempt autoplay
  • Reveal ... each sits in a details/summary nested by a table cell of a window and might autoplay synchronously
  • Synchronize ... each sits in a table cell of a window and might autoplay synchronously
  • Superimpose ... each sits on top of the last table cell in a window and might autoplay synchronously

... adding that "verticality" (as distinct from the "Synchronize" horizontality) and action happening "above the fold" within eyesight feeling (as "Ready" and "Superimpose" do) with the advantage over "Ready" of showing you a bigger picture.

Programmatically you can control the opening and closing of the details elements, if you like ...


var readie=false;
var dets=top.document.getElementsByTagName('details');
//alert('' + dets.length);
for (var idets=0; idets<dets.length; idets++) {
//alert(('' + dets[idets].getAttribute('open')));
if (('' + dets[idets].getAttribute('open')).replace('undefined','n').replace('null','n') != 'n') {
try {
dets[idets].open=false; //removeAttribute('open');
} catch(cgf) { }
//alert('close ' + idets);
readie=true;
} else if (readie) {
readie=false;
try {
dets[idets].open=true; //setAttribute('open', true);
} catch(cgf) { }
//alert('open ' + idets);
//lastdet=('' + dets[idets].id);
}
if (readie && 1 == 2) {
//lastdet='dt1';
try {
dets[0].open=true; //top.document.getElementById('dt1').open=true; //setAttribute('open', true);
} catch(cgf) { }
//alert('Open 0');
}
}

... worked, timing wise, via setTimeout timers, separated by the video duration (and a bit).

And so, onto yesterday's Karaoke YouTube Video Search Order Tutorial you might consider the changed karaoke_youtube_api.htm HTML and Javascript code's live run link could be worth your perusal.


Previous relevant Karaoke YouTube Video Search Order Tutorial is shown below.

Karaoke YouTube Video Search Order Tutorial

Karaoke YouTube Video Search Order Tutorial

Perhaps you were around when we recently presented the One or Several Did You Know Quiz Mobile Cursor CSS Tutorial where we created ...

  • some non-mobile platform logic to allow for a select (ie. dropdown) element with multiple selection honour the order in which a user enters single click selections ... and today we do this in the project of yesterday's Karaoke YouTube Video Search Improvement Tutorial ... as well as ...
  • some mobile platform logic to allow for a select (ie. dropdown) element with multiple selection honour the order in which a user enters single click selections, focussing on select element "onchange" event logic as per ...

    var lastajaxs='';
    // Within select event "onchange logic we have calling Javascript code ...
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && lastajaxs != '') {
    preajaxswatch(); //setTimeout(preajaxswatch,100);
    } else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    preajaxswatch();
    }
    // ... calling the called function ...
    function preajaxswatch() {
    var tickis=' ' + String.fromCodePoint(10004);
    var appis='';
    var tcnt=1;
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    rep+=' --- ';
    if (document.getElementById('ajaxs') && ourmto) {
    rep+=' .-. ';
    var sin=document.getElementById('ajaxs');
    var lajaxs='', lajaxsd='';
    for (var ii=0; ii<sin.options.length; ii++) {
    if (sin.options[ii].selected) {
    if (sin.options[ii].value != '' && (',' + lastajaxs + ',').indexOf(',' + sin.options[ii].value + ',') != -1) {
    lajaxs+=lajaxsd + sin.options[ii].value; lajaxsd=','; tcnt++;
    if (sin.options[ii].innerText.indexOf(tickis) == -1) {
    sin.options[ii].innerText+=tickis + ' ' + eval(1 + eval('' + (',' + lastajaxs).split(',' + sin.options[ii].value)[0].substring(1).split(',').length));
    }
    }
    }
    }
    for (var iii=0; iii<sin.options.length; iii++) {
    if (sin.options[iii].selected) {
    if (sin.options[iii].value != '' && (',' + lastajaxs + ',').indexOf(',' + sin.options[iii].value + ',') == -1) {
    appis+=lajaxsd + sin.options[iii].value;
    lajaxs+=lajaxsd + sin.options[iii].value;
    lajaxsd=',';
    if (sin.options[iii].innerText.indexOf(tickis) == -1) {
    sin.options[iii].innerText+=tickis + ' ' + tcnt;
    }
    tcnt++;
    }
    }
    }
    if (lajaxs != '' && lajaxs != lastajaxs && (eval('' + lajaxs.split(',').length) != eval('' + lastajaxs.split(',').length) || eval('' + lajaxs.length) != eval('' + lastajaxs.length))) {
    //if (lajaxs.indexOf(',') != -1) { document.getElementById('myh1').innerHTML+=(rep + ' 2:' + lajaxs); }
    if (appis != '') {
    lastajaxs+=appis;
    } else {
    lastajaxs=lajaxs;
    }
    rep+=(' 2:' + lastajaxs);
    ajaxclist=lastajaxs;
    ajaxoncnt=eval('' + ajaxclist.split(',').length);
    ajaxf='';
    }
    }
    }
    }

Again the changed karaoke_youtube_api.htm HTML and Javascript code's live run link might be worth your perusal.


Previous relevant Karaoke YouTube Video Search Improvement Tutorial is shown below.

Karaoke YouTube Video Search Improvement Tutorial

Karaoke YouTube Video Search Improvement Tutorial

We need to thank last Friday's ABC The Drum episode's last story about the wonderful Hummingsong Community Choir, in turn leading me to this Australia's Got Talent YouTube video ...

... and onto some research into Keane (the band who wrote that "Somewhere Only We Know" song that had stayed in my mind, quietly, for a very long time) and others like Lily Allen who have covered it.

Software came into it with me wanting to sequence some video versions of that song, and some unexpected surprises when submitting our inhouse Karaoke YouTube API for Iframe interfacer to the task where we found ...

  • issues when ( and ) appear in a YouTube video title ... and ...
  • issues with video duration calculations with the more recent minutes and seconds format we use when ...
  • setting the ">1" checkbox after a YouTube video search dropdown and selecting several videos and then choosing out of ...
    1. Ready ... each fills a window and might autoplay synchronously
    2. Grid ... each sits within a 3x3 grid table and does not attempt autoplay
    3. Synchronize ... each sits in a table cell of a window and might autoplay synchronously
    4. Superimpose ... each sits on top of the last table cell in a window and might autoplay synchronously

    ... modes of play, where "Ready" and "Synchronize" needed further tweaking

And so, we improve on the recent Karaoke YouTube Video Search Update Tutorial, where helping out is a changed stop_start_youtube.html for the changed karaoke_youtube_api.htm HTML and Javascript code's live run link.

Would you like to overdose on "Somewhere Only We Know"? Try selecting your own from this link.


Previous relevant Karaoke YouTube Video Search Update Tutorial is shown below.

Karaoke YouTube Video Search Update Tutorial

Karaoke YouTube Video Search Update Tutorial

Way back at the time of writing Karaoke YouTube Video Search Error 503 Tutorial we were first allowing for ...

... the latter "original intention" functionality only kicking in once a YouTube video of interest is found. In other words, finding what you want is beyond the scope of the API here, unless you (the user) settle for a channel or user or playlist of interest.

We discovered this YouTube website search functionality integration failing the other day with our YouTube API integrated inhouse web application (via Karaoke thoughts), and discovered that the jQuery Ajax return data had changed.

Because it is jQuery Ajax debugging is best done using "console.log" we've had our arm twisted a lot lately, admitting (ie. we're very fond of alert() Javascript windows around here, but alert() popup windows have that disadvantage of affecting window focus, and this can muck up what you are looking at, a bit like if we look at photons we interfere).

You'll know you're "getting into it" if your console.log statements get longer ... as you can see a bit of below ...


$.ajax({ url: dp + "legend_via_map.php",
data: {"url":dprefix + qsel},
type: 'get',
success: function(output) {
//document.title+=' success ' + output.indexOf('-describedby=') + ' ' + output.indexOf('described') + ' ';
//alert(output);
var teq=' title="';
var teqtwo='';
console.log('Success:');
var selc='', fosecs=0.0, afosecs=[], ifo=0, fofactor=1.0;
console.log('1');
var qqbits=output.split('v=');
console.log('2');
var qqtbits=output.split('-describedby='); //'/watch?'); // '"commandMetadata":{"webCommandMetadata":{"url":"/watch'); // '-describedby=');
if (qqbits.length > 1 && qqtbits.length == 1) {
qqtbits=output.split('watchEndpoint');
teq='"title":{';
teqtwo='"text":"';
}
console.log('3 ' + teq);
if (qqtbits.length == 1 && output.indexOf('503 ') != -1) { document.title+=' ... please try again later.'; }
console.log('4');
var qdelim=' ', tqbits, ttqqbits='', attqqbits=[], durbits='', adurbits;
console.log('5');
var q11=11;
var teqx='';
console.log('6');
var fgs='findings are ', sze='', is_okay=true, jis_okay=0;
console.log('7 ' + qqbits.length + ' ' + qqtbits.length);
if (qqbits.length > 1 && qqtbits.length == 1) {
console.log('error: ' + dprefix + qsel); window.open(dprefix + qsel, '_blank'); //, 'top=30,left=30,width=900,height=900');
}
for (var ifgs=1; ifgs<qqtbits.length; ifgs++) {
fosecs=0.0;
fofactor=1.0;
tqbits=qqtbits[eval(-1 + ifgs)].split(teq); //' title="');
ttqqbits=qqtbits[eval(-1 + ifgs)].split('v=')[eval(-1 + qqtbits[eval(-1 + ifgs)].split('v=').length)].substring(0,q11);


if (selc == '') { // && document.getElementById('ajax').innerHTML == '') {
// document.title+=' 1 ';
if (zeroplay == 0) {
// document.title+=' 2 ';
document.getElementById("myh1").innerHTML=document.getElementById("myh1").innerHTML.replace('Karaoke via ',ourvid + ' Video Lookup via ');
if (ttqqbits.indexOf('<') != -1) {
sze=" size=" + eval(-1 + qqtbits.length) + " ";
} else {
sze=" size=" + qqtbits.length + " ";
}
document.getElementById("myform").innerHTML+="<input type=hidden name=justplay id=justplay value=y></input>";
}
if (ttqqbits.indexOf('<') == -1) {
if (document.URL.indexOf('minimize=') != -1) { domin=true; }
selc=preselc + "<select" + sze + " title='YouTube videos' id=ajaxs ondblclick=dputy(this); onchange=puty(this);><option id=ominpossible value=>Optionally choose YouTube title below ...</option></select> <div id=placeforvideo></div>";
}
}
// more code follows ... until ...
}
if (is_okay) { document.getElementById('ajax').innerHTML=selc; if (document.URL.indexOf('pvostid=') !== -1) { if (parent.document.getElementById('ajaxs')) { parent.document.getElementById('ajaxs').innerHTML+='<option value=" ... and then ...">... and then ...</option>' + selc.split('</select>')[0].split('Optionally choose YouTube title below ...</option>')[1]; parent.ajaxsih=parent.document.getElementById('ajaxs').innerHTML; parent.document.getElementById('ajaxs').size='' + eval(26 + parent.document.getElementById('ajaxs').size); } } if (domin) { mintoajax(); } }
}
});

... used both in the "where in the code do we get to" sense and a "variable watch debugging" sense ... and with the changed karaoke_youtube_api.htm HTML and Javascript code.


Previous relevant Karaoke YouTube Video Search Error 503 Tutorial is shown below.

Karaoke YouTube Video Search Error 503 Tutorial

Karaoke YouTube Video Search Error 503 Tutorial

Working on the code changes of yesterday's Karaoke YouTube Video Search Refinement Tutorial's inhouse HTML code, serving as our portal into use of the wonderful API for Iframe embedded videos, we learnt more about the HTTP status/error code 503 ...


503 Service Unavailable
The server cannot handle the request (because it is overloaded or down for maintenance). Generally, this is a temporary state.

... in that our penchant for "hotkey" like ...


<input title="Can use , or && for 'and' and || for 'or' search logics. Prefix && enforces in title search." onblur="findduration(this,'');" name='youtubeid' id='youtubeid' placeholder="Can use , or && for 'and' and || for 'or' search logics. Prefix && enforces in title search." type='text' value='' onkeyup='ycval(event);' oninput=yprecval(this); onclick='yofc(this);'></input>

... event sensitivity, as powerful as "hotkey" (textbox) looking might be, but can also "run off the rails" with too much activity if combined with jQuery Ajax methodologies and can, as of yesterday (not today, but please read on), be a burden to the destination of the Ajax requests, that being in our case the YouTube website's search functionality (via ?search_query= arguments).

We were (yesterday) sometimes bombarding YouTube with too many requests in a short period of time, hence the HTTP status/error code 503 we now inform the user of in a changed webpage title (though now we hope you do not get this error anymore).

How do we go about getting the web application to curb its enthusiasm regarding asking YouTube for a search functionality response? You may have noticed in the HTML above for the textbox another event, the incredibly useful ...

... called as a user completes their textbox entry (on non-mobile platforms, they tab out of the textbox). Intervention at this event gives us the opportunity to call a halt to a more carefully timed (2 second) amount of "hotkey" based YouTube search functionality requesting, a vast improvement on the potentiality for several requests a second without this dampening down of activity (and sometimes getting into 503 unpopularity with YouTube, we're guessing).

The following new Javascript global variables ...


var lastgetytlist=''; // store and compare against the last YouTube (perhaps search functionality) query (if the same, do not repeat)
var amwaiting=null; // variable for a setInterval call dampening down the YouTube request rate ... via the control of ...
var allowable=true; // if true, you are clear to request from YouTube, else false

... should be of interest as you examine the HTML improved functionality (for karaoke_youtube_api.htm) which you can try for yourself at this live run link.


Previous relevant Karaoke YouTube Video Search Refinement Tutorial is shown below.

Karaoke YouTube Video Search Refinement Tutorial

Karaoke YouTube Video Search Refinement Tutorial

The last time we changed our YouTube video lookup interfacer, that used a Karaoke idea for its first incarnation, hence the name "karaoke_youtube_api.htm" as you can read about at Other Side of the World Iframe Tutorial, it was an integration job. Today we work at the other end of the equation, if you like, channelling YouTube search functionality "under the hood" (and we thank this great link for the heads up here) ...

  • Boolean Operators
  • Google Search Operator ... Force your search terms in the name of the video

... but being tickled pink with PHP and Javascript we allowed for user usage, now, as per ...


Can use , or && for 'and' and || for 'or' search logics. Prefix && enforces in title search.

The example below making use of this new functionality (for karaoke_youtube_api.htm) you can see in action below shows an initial YouTube search of "South America" be refined to "South America && Sao Paulo" to include a drilling down into videos about Brazil's most populous city...


Previous relevant Other Side of the World Iframe Tutorial is shown below.

Other Side of the World Iframe Tutorial

Other Side of the World Iframe Tutorial

Our "Other Side of the World" web application we've been developing lately has made extensive use of the HTML iframe element, mainly as a "reader" of data in that Client Pre-emptive Iframe technique way. But the HTML iframe element is probably better known for its data integration and display talents, and it is these that we call upon today, to (software) integrate two other existing sources of data so that, display-wise we have four table (td) cells in play now those being the original ...

We now think the use of all this can have you hopping around the world discovering lots of geographical based, video based and timezone based information about lots of places around the world, lots of which you may never have known much about.

We've software integrated today, as well as integrated "where" web application thoughts with "when" web application thoughts.

Another feature of today's changes involves the geolocation features of the Javascript ...


navigator.geolocation.getCurrentPosition(success[, error[, options]])

... syntax method of allowing Location Services, if allowed by the user, return a latitude and longitude position of the user themselves, information used at the instigation of the web application, and which we also used with HTML/Javascript Where Does It Get Me To Primer Tutorial and Google Chart Map Chart Select Event Primer Tutorial in the past.

The code for this remains as just HTML (apart from the supervised PHP for the Google Chart interface) that you could call other_side_of_the_world.htm (changed in this way for our HTML iframe (software) integration purposes today) if you like, or want to try out (or try out for a specific (argument) location, such as Alice Springs try out), again. It also required small changes to ...

We hope you try it out and discover some new things!


Previous relevant Other Side of the World Onblur Tutorial is shown below.

Other Side of the World Onblur Tutorial

Other Side of the World Onblur Tutorial

The onblur event in web programming is a very important event regarding interactive keyboard entries made by the user. We base new functionality, today, with our "Other Side of the World" web application, by allowing a user who enters in their own "place" information, can have that information filtered through the same "autocomplete" database provided by the wonderful Weather Underground and its great API service.

When we presented the last Weather Underground related blog posting we even used this functionality also interfacing to the onkeyup keyboard event, making it look up the database after just a few characters typed into the associated HTML input type=text text box, but today we lessen the interaction, presuming the user knows a location of interest and will only want information after tabbing out of this text box ... hence the onblur event, only, logic interface to new functionality that creates an additional HTML select (dropdown) element of use to populate those same ...

  • placename
  • country ... linked to ...
  • latitude
  • longitude

... fields as talked about yesterday when we presented Other Side of the World Places Tutorial as shown below.

So that's the idea, but making it happen involved some tweaking of the parts to the Weather Underground blog posting Weather API via Iframe jQuery Ajax AutoComplete Tutorial from some time back, the changes for which we'll explain later.

Again we call on Client Pre-emptive Iframe techniques for this, telling us that you can just keep on adding HTML iframe elements to make this technique happen for several different sources of information, as necessary.

The code for this is just HTML (apart from the supervised PHP for the Google Chart interface) that you could call other_side_of_the_world.htm (changed in this way for our onblur event purposes today) if you like, or want to try out (or try out for a specific (argument) location, such as Darwin try out), again. It also required small changes to ...


Previous relevant Other Side of the World Places Tutorial is shown below.

Other Side of the World Places Tutorial

Other Side of the World Places Tutorial

A fair while ago now we were in the midst of writing a Geographicals Suite of web applications that, given Latitude and Longitude pairs you could calculate things like ...

  1. Sun Angle at noon
  2. Moon Angle at noon
  3. Coriolis Effect
  4. Distance between Geographical Locations
  5. Weather at Geographical Location

... and that we eventually added some "placename" capabilities to all this, introduced with PHP/Javascript/HTML Sun Angle Tutorial, which harnessed all this useful goodwill of this useful webpage (thanks) publishing some placename geographicals data.

  • placename
  • country ... linked to ...
  • latitude
  • longitude

... and that we "channel" today, via our beloved Client Pre-emptive Iframe techniques, so that we reuse PHP, rather than having to create new PHP, as an aid to the modularization for added "placename" functionality to our "Other Side of the World" web application we started presenting yesterday with Other Side of the World Primer Tutorial as shown below.

Another thing we are trialling today is a concept (that admittedly seems to need more work in Firefox) of an HTML select (dropdown) element having an onclick event (after an onchange event that changes that select element value to a non-nothing value) having a logic whereby that select element value is used to repopulate the ...

  • placename (, country) (Great Circle Distance in km away)
  • latitude
  • longitude

... HTML input type=text and type=number fields automatically. In the normal case of events in non-Firefox web browsers an onchange event change of value to a non-nothing value just causes that select element value to be one of the places shown on the Google Charts Map Chart that we display.

The default is to show five of the nearest placenames in the derived list, but a "+" button can increase that number of "nearest"s as required.

The code for this is just HTML (apart from the supervised PHP for the Google Chart interface) that you could call other_side_of_the_world.htm (changed in this way for our purposes today) if you like, or want to try out, again perhaps?


Previous relevant Other Side of the World Primer Tutorial is shown below.

Other Side of the World Primer Tutorial

Other Side of the World Primer Tutorial

Today we've written a first draft of an "Other Side of the World" web application using a Google Chart Map Chart embedded into an HTML iframe element to show the user ...

  • the position of the place that they enter in for their latitude and longitude ... as well as ...
  • "the other side of the world" to the position of the place that they enter in for their latitude and longitude, calculated by imagining you take a trip from your original location through the middle of the Earth and straight through onto the other location

Is this our "sister" location? Am not sure. But somebody was telling "Porkies" to me as a child where we were told "China" as being on the other side.

The code for this is just HTML (apart from the supervised PHP for the Google Chart interface) that you could call other_side_of_the_world.html if you like, or want to try out.

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

This entry was posted in eLearning, Event-Driven Programming, Tutorials and tagged , , , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *