NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Twitch-Preview
// @namespace http://johnbjorge.com
// @version 1.0
// @author John Bjorge
// @description Replaces twitch channel thumbnail image with live stream on mouse over.
// @supportURL https://github.com/JohnBjorge/Twitch-Preview
// @include http://www.twitch.tv/directory/game/*
// @include https://www.twitch.tv/directory/game/*
// @grant GM_addStyle
// @run-at document-start
// @require https://code.jquery.com/jquery-1.11.2.min.js
// @require https://gist.githubusercontent.com/BrockA/2625891/raw/9c97aa67ff9c5d56be34a55ad6c18a314e5eb548/waitForKeyElements.js
// ==/UserScript==
$(function() {
if(window.top !== window.self) {
return;
}
var timeout = null; //timer for hovering over channel
var browser = browserInfo().browser.toUpperCase(); //current browser (chrome or firefox)
// Waits for channel elements to load, once loaded calls main.
// False means continues to check for new elements (infinite scroll)
waitForKeyElements(".streams .stream .content .thumb, .videos .video .content .thumb .cap", main, false);
// Once channel elements have loaded the function main detects mouse enter and mouse leave events
// on the given channelNode. If mouse hovers over element for 1 second stream preview is generated.
function main(channelNode) {
channelNode.mouseenter(function() {
var node = $(this).find("a.cap");
timeout = setTimeout(function() {
showPreview(node, false);
}, 1000);
});
channelNode.mouseleave(function() {
removePreview();
clearTimeout(timeout);
});
}
// Generates a preview of stream on channel thumbnail. Takes an element the channel thumbnail
// and the channel name, and a boolean for testing with a dummy frame.
function showPreview(element, dummyFrame = false) {
var channel = $(element).attr("href");
channel = channel.replace(/\//g, "");
var previewElement = getPreviewElement(element.width(), element.height(), channel, dummyFrame);
previewElement.prependTo(element);
cleanPreviewElement();
}
// Returns a preview element with embedded video. Embeds flash if chrome, embeds html5 if firefox.
// Preview element is of size height and width of the given channel. Dummy frame is used for
// testing purposes and is an empty div with red border and black fill.
function getPreviewElement(width, height, channel, dummyFrame) {
var previewElement = "";
if (dummyFrame === true) {
previewElement = $("<div id='streamPreview'></div>");
previewElement.css("height", height);
previewElement.css("width", width);
previewElement.css("border", "5px solid red");
previewElement.css("background-color", "black");
} else {
if (browser === 'CHROME') {
//crappy work around using flash
previewElement = $("<div id='streamPreview'><iframe src='https://www-cdn.jtvnw.net/swflibs/TwitchPlayer.swf?channel=" + channel + "' height=" + height + " width=" + width + " frameborder='0' scrolling='no'></iframe></div>");
} else if (browser === 'FIREFOX') {
//must click lock in browser to left of url and disable protection for twitch site
previewElement = $("<div id='streamPreview'><iframe src='https://player.twitch.tv/?channel=" + channel + "' height=" + height + " width=" + width + " frameborder='0' scrolling='no'></iframe></div>");
} else {
//if it's unrecognized browser I'm gonna go with flash working but doubtful it would work
previewElement = $("<div id='streamPreview'><iframe src='https://www-cdn.jtvnw.net/swflibs/TwitchPlayer.swf?channel=" + channel + "' height=" + height + " width=" + width + " frameborder='0' scrolling='no'></iframe></div>");
}
}
return previewElement;
}
// Removes uneeded stream elements such as volume, pause button, etc
function cleanPreviewElement() {
if (browser === 'FIREFOX') {
var iframe = $("#streamPreview iframe");
$("#streamPreview iframe").on('load', function() {
$("div.player-hover:nth-child(15)", iframe.contents()).remove();
$("div.player-hover:nth-child(19)", iframe.contents()).remove();
$("button.player-button:nth-child(19)", iframe.contents()).remove();
});
}
}
// Removes the current stream preview element
function removePreview() {
$("#streamPreview").remove();
}
// Returns the name of browser and the version
function browserInfo() {
browserInfo = (function(){
var ua= navigator.userAgent, tem,
M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem= /\brv[ :]+(\d+)/g.exec(ua) || [];
return 'IE '+(tem[1] || '');
}
if(M[1]=== 'Chrome'){
tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem!= null) return tem.slice(1).join(' ').replace('OPR', 'Opera');
}
M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
return { 'browser': M[0], 'version': M[1] };
})();
return browserInfo;
}
});