Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
JamExchange Room @so Live Radio like Player with "User Requests" (YouTube only, UserScript)
// ==UserScript==
// @name JamExchange Player
// @namespace jamexchange
// @description JamExchange Room @SO Live Radio like Player with "User Requests" (YoutTube only)
// @include http://chat.stackoverflow.com/rooms/39426/*
// @version 1.1.0
// @grant none
// ==/UserScript==
/*
## Change Log:
1.1.0
==
[+feat]dynamic player dimensions
[bugfix?]hopefully "next" button is visible now
[feat]modify youtube onebox css, make room for buttons?
1
==
.published
using formulae: init->get_all_vids,POP->play; onAddedVid->PUSH; onVidEnd/onVidErr->POP->play
### TODO:
- run from console, import by script, minimize, bookmarklet
- click on youtube onebox, play instantly
- change vid list from arry to obj(+name, etc)
- more play ctrls ?
- pause vid on very brief window activation/deactivation (when not current tab/active window for at lepast 15s)
- better/efficient vid extraction (REGEX FTW++)
*/
window.vids = [];
var vidId = '';
window.vidPlayer = ''; //because to be available from console
var initState = 0;
var roomTitle = document.getElementById('roomname').textContent;
var targetMutate = document.querySelector('#chat');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
[].forEach.call(mutation.addedNodes, function(node) {
if (node.getElementsByTagName('a').length < 1) return;
[].forEach.call(node.getElementsByTagName('a'), function(onebox) {
if (!/https?:\/\/(www\.)?youtu(be.com\/|\.be\/)/.test(onebox.href)) return; //meh
vids.push(onebox.href);
if (initState === 2) { //player is initialized
if (vids.length === 1) playNext(); //if ever will be empty
}
});
});
if (initState === 1) initPlayer();
});
});
observer.observe(targetMutate, {childList: true});
$( document ).ready(function(){
//fake up player
document.getElementById('roomdesc').innerHTML = '';
document.getElementById('roomdesc').setAttribute('id', 'player');
//setup youtube api script
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
//morph CSS (code c from SO, long live SO helping to write for SO on SO)
var css = '',
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
style.type = 'text/css';
css += '.ob-youtube { height: 116px; line-height: 116px; } ';
css += '.ob-youtube-title { left: 250px; transition: none !important; } ';
css += '.ob-youtube-preview { position:relative; top: -32px; } ';
css += '.ob-youtube-overlay { height: 116px !important; line-height: 116px !important; } ';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
document.getElementById("room-tags").remove(); //make some more room
});
window.onYouTubeIframeAPIReady = function() { //needs global
console.log('YouTube player API ready.');
initState = 1;
}
function onPlayerReady(event) {
//event.target.setVolume(100);
event.target.playVideo();
console.log('YT player ready.');
}
function onPlayerError(event) {
console.log('YT player error ' + event.data + ' occured. Consult API docs: https://developers.google.com/youtube/iframe_api_reference');
playNext();
}
function onPlayerStateChange(event) {
var states = ['ended', 'playing', 'paused', 'buffering', 'video cued'];
var state = states[event.data] || 'unstarted';
console.log('YT player state changed to: ' + state);
if (event.data === 1) {
document.title = '▶';
document.title += ' ' + vidPlayer.getVideoData().title + ' (by: ' + vidPlayer.getVideoData().author + ') @JamExchange 39.426FM';
} else {
document.title = roomTitle;
}
if (event.data === 0) { //video ENDED video
playNext();
}
}
window.playNext = function () { //simple button access
vidPlayer.loadVideoById(extractId(vids.pop()), 0, "medium"); //play next video
}
function extractId(url){
return url.replace(/^.*?v=|^.*?tu.be\//, ''); //needs more testing... maybe playlist crash??
}
function initPlayer(vidId) {
initState = 2;
vidId = extractId(vids.pop());// || 'kkGeOWYOFoA'; //default (Numbers By Nature) <- does not compute
console.log('JamExchange player initializing...');
var w = document.getElementById('roomtitle').clientWidth;
w < 200 && (w = 200);
var h = w < 356 ? 200 : (w/16*9)|0;
console.log(w,h);
window.vidPlayer = new YT.Player('player', {
width: w,
height: h,
videoId: vidId,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
,'onError': onPlayerError
}
});
document.getElementById('toggle-favorite').outerHTML += '<input type="button" value="&#9658;&#9658;" '
+ 'onclick="playNext()" style="padding:1px 3px 3px 5px;position:relative;top:-3px" title="Next">';
}
@rlemon

This comment has been minimized.

Copy link

@rlemon rlemon commented Apr 8, 2015

niiiice

@Unihedro

This comment has been minimized.

Copy link

@Unihedro Unihedro commented Apr 29, 2015

ugh you misspelled "YouTube" in the userscript description as "YoutTube". plz fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment