Greasy Fork is available in English.
[DEPRECATED] Please use https://github.com/odensc/ttv-ublock instead
And don't forget to keep that in the code (for optimizations purposes)
//Opti (we don't care of the numbers updating)
if(mutations.length === 1 && mutations[0].target.classList.contains("tw-animated-number--monospaced"))
return;
Here is an update enhancind some things @rend if you can put it into master
It adds double click for fullscreen, optimize some things and take the good translation for the Theater button (and add the good placeholder when hovering it), hide the white flash when loading a stream and show stream informations on fullscreen mode
I did put //# after every changed line (you can also use a text diff checker)
(function() {
if (window.location.origin == "https://cdn.embedly.com") {
document.getElementsByTagName("html")[0].style = "overflow: hidden";
window.addEventListener("message", (event) => {
window.parent.postMessage(event.data, "*");
});
}
else if (window.location.origin == "https://player.twitch.tv") {
//More optimized
let interval = setInterval(()=> {//#
var logo = document.querySelector('[data-a-target="player-twitch-logo-button"]');
var card = document.getElementsByClassName("tw-card")[0];
var panel = document.getElementsByClassName("stream-info-social-panel")[0];
var fullscreenButton = document.querySelector('[data-a-target="player-fullscreen-button"]');
//We copy the button from the real interface (so we have the title in the good language)
let realTheaterButton = window.parent.document.querySelector('[data-a-target="player-theatre-mode-button"]');//#
var theaterButton = realTheaterButton.parentElement.cloneNode(true).getElementsByTagName("button")[0];
if (!logo || !card || !panel || !fullscreenButton)
return;
clearInterval(interval);//#
logo.remove();
card.style.display = "none";//#
window.parent.addEventListener("fullscreenchange", _ => card.style.display = window.parent.document.fullscreenElement ? "" : "none");//#
panel.remove();
fullscreenButton.parentElement.parentElement.insertBefore(theaterButton.parentElement, fullscreenButton.parentElement);//#
//#removed lines here
theaterButton.removeAttribute('disabled');
fullscreenButton.removeAttribute('disabled');
theaterButton.className = theaterButton.className.split("--disabled").join("");
fullscreenButton.className = fullscreenButton.className.split("--disabled").join("");
fullscreenButton.onclick = function () {
window.parent.postMessage("fullscreen", "*");
}
theaterButton.onclick = function () {
window.parent.postMessage("theater", "*");
}
//Show the iframe once it is loaded
window.parent.document.getElementById("embed-adblock").style.visibility = "";//#
//Double click
let treshold = 400;//#
let lastClick = -1;//#
document.querySelector(".click-handler").addEventListener("click", () => {//#
let now = Date.now();//#
//If the user took less than 400ms to double click
if(now < lastClick+treshold){//#
fullscreenButton.click();//Go fullscreen//#
//So that if the user triple click, it will not go full screen and then roll back
lastClick = -1;//#
}else//#
lastClick = now;//#
});//#
}, 50);//#
} else {
var lastStreamer, oldHtml;
window.addEventListener("message", (event) => {
if (event.data.eventName == 'UPDATE_STATE' && event.data.params.quality) {//#
if (/^((?:160|360|480|720|1080)p(?:30|60)|chunked)$/.test(event.data.params.quality))//#
localStorage.setItem('embAdbQuality', event.data.params.quality);//#
}else if (event.data == "fullscreen")//#
document.querySelector(`[data-a-target="player-fullscreen-button"]`).click();
else if (event.data == "theater")
document.querySelector(`[data-a-target="player-theatre-mode-button"]`).click();
});
var observer = new MutationObserver(function (mutations, observer) {
var container = document.querySelector(".video-player .tw-absolute");
if (!container)
return;
if (window.location.pathname.indexOf("/directory") == 0)
return;
if(mutations.length === 1 && mutations[0].target.classList.contains("tw-animated-number--monospaced"))
return;
var streamerName = window.location.pathname.replace("/", "");
//var twitchUrl = `https://player.twitch.tv/?channel=${streamerName}&muted=false&parent=cdn.embedly.com&quality=chunked`
//var iframeUrl = `https://cdn.embedly.com/widgets/media.html?src=${encodeURIComponent(twitchUrl)}&type=text%2Fhtml&card=1&schema=twitch`;
var quality = localStorage["embAdbQuality"] || "chunked";//#
var iframeUrl = `https://player.twitch.tv/?channel=${streamerName}&muted=false&parent=twitch.tv&quality=${quality}`; //#
var existingIframe = document.getElementById("embed-adblock");
if ((!streamerName && !lastStreamer) || streamerName.indexOf("videos/") == 0) {
lastStreamer = null;
for (let el of container.children)
el.hidden = false;
if (existingIframe) {
existingIframe.src = "";
existingIframe.style.visibility = "hidden";//#
existingIframe.hidden = true;
}
return;
}
else if (!streamerName)
return;
for (let el of container.children) {
if (el.tagName != "IFRAME")
el.hidden = true;
if (el.tagName == "VIDEO")
el.src = "";
}
if (!existingIframe) {
existingIframe = document.createElement("iframe");
existingIframe.id = "embed-adblock";
existingIframe.style = "width: 100%; height: 100%";
existingIframe.src = iframeUrl;
//hide iframe when loading (to avoid white screen)
existingIframe.style.visibility = "hidden";//#
container.appendChild(existingIframe);
}
else if (streamerName != lastStreamer) {
//hide iframe when loading (to avoid white screen)
existingIframe.style.visibility = "hidden";//#
existingIframe.src = iframeUrl;
existingIframe.hidden = false;
}
lastStreamer = streamerName
});
var observeInterval = setInterval(() => {
var observee = document.getElementsByClassName("root-scrollable__wrapper tw-full-width tw-relative")[0];
if (!observee)
return;
observer.observe(observee, { attributes: false, childList: true, subtree: true });
clearInterval(observeInterval);
}, 100);
}
})();
window.addEventListener("message", (event) => {
if (event.data.eventName == 'UPDATE_STATE' && event.data.params.quality) {
if (/^((?:160|360|480|720|1080)p(?:30|60)|chunked)$/.test(event.data.params.quality))
localStorage.setItem('embAdbQuality', event.data.params.quality);
}
if (event.data == "fullscreen")
document.querySelector(`[data-a-target="player-fullscreen-button"]`).click();
else if (event.data == "theater")
document.querySelector(`[data-a-target="player-theatre-mode-button"]`).click();
});
...
var quality = localStorage["embAdbQuality"] || "chunked";
var iframeUrl = `https://player.twitch.tv/?channel=${streamerName}&muted=false&parent=twitch.tv&quality=${quality}`; // Not using an intermediate stream for now since it's faster
else if (event.data.eventName == 'UPDATE_STATE' && event.data.params.quality && !document.hidden) {
if (/^((?:160|360|480|720|1080)p(?:30|60)|chunked)$/.test(event.data.params.quality))
window.localStorage.setItem("embedQuality", event.data.params.quality);
}
Twitch lower the quality when a tab loses focus, need the !document.hidden to stop saving the quality during that time.
This post is about community helping with updates
Hey, I just updated your script for adding buttons and making them work (fullscreen & studio mode) and remove logo ! I also optimized a little thing in the code that matters in the observer
It also remove the top title of the embeded stream (when we hover if with the mouse) which is not on the normal twitch player.
Here is the code: