// ==UserScript==
// @name Enhance twitch
// @namespace http://tampermonkey.net/
// @version 1.8
// @description Show images/video in chat,Auto click claim bonus,Better dark mode, Always Set Source Quality
// @author Bum
// @require http://code.jquery.com/jquery-3.4.1.min.js
// @match https://www.twitch.tv/*
// @match https://clips.twitch.tv/*
// @grant none
// ==/UserScript==
var alwaysSourceQuality = "true";
var displayImages = "true";
var displayVideos = "true";
var autoPlayClips = "false";
if (localStorage.getItem("displayImages") != null) {
displayImages = localStorage.getItem("displayImages");
}
if (localStorage.getItem("displayVideos") != null) {
displayVideos = localStorage.getItem("displayVideos");
}
if (localStorage.getItem("alwaysSourceQuality") != null) {
alwaysSourceQuality = localStorage.getItem("alwaysSourceQuality");
}
if (localStorage.getItem("autoPlayClips") != null) {
autoPlayClips = localStorage.getItem("autoPlayClips");
}
function GM_addStyle(css) {
const style = document.getElementById("GM_addStyle") || (function() {
const style = document.createElement('style');
style.type = 'text/css';
style.id = "GM_addStyle";
document.head.appendChild(style);
return style;
})();
const sheet = style.sheet;
sheet.insertRule(css, (sheet.rules || sheet.cssRules || []).length);
}
(function() {
'use strict';
var config = { attributes: false, childList: true, subtree: true };
function getMenuItem(id, display, checked){
if (checked == "true"){
var res = '<div class="tw-pd-05"><div data-a-target="high-contrast-color-checkbox" class="tw-align-items-center tw-flex"><label class="tw-drop-down-menu-input-item__label tw-flex-grow-1 tw-mg-r-2" for="'+id+'">'+display+'</label><div class="tw-toggle" data-a-target="high-contrast-color-checkbox"><input type="checkbox" id="'+id+'" label="Readable Colors" class="tw-toggle__input" data-a-target="tw-toggle" checked=""><label for="'+id+'" class="tw-toggle__button"><p class="tw-hide-accessible">'+display+'</p></label></div></div></div>';
return res;
}
else{
var res2 = ' <div class="tw-pd-05"><div class="tw-align-items-center tw-flex"><label class="tw-drop-down-menu-input-item__label tw-flex-grow-1 tw-mg-r-2" for="'+id+'">'+display+'</label><div class="tw-toggle"><input type="checkbox" label="Subscribers-Only Chat" id="'+id+'" class="tw-toggle__input" data-a-target="tw-toggle"><label for="'+id+'" class="tw-toggle__button"><p class="tw-hide-accessible">'+display+'</p></label></div></div></div>';
return res2;
}
}
function addMenu(){
var menu = $(".chat-settings__content");
var isReady = menu.length > 0;
if (!isReady) {
setTimeout(addMenu, 50);
return;
}
if ($(".customEnhanceMenu").length > 0 )
return;
menu.append('<div class="tw-border-t tw-mg-t-1 tw-mg-x-05 tw-pd-b-1 customEnhanceMenu"></div><div class="tw-mg-y-05 tw-pd-x-05"><p class="tw-c-text-alt-2 tw-font-size-6 tw-strong tw-upcase">Enhance Twitch</p></div>');
menu.append(getMenuItem('displayImages','Display Images', displayImages));
$("#displayImages").change(function() {
localStorage.setItem("displayImages", this.checked);
displayImages = localStorage.getItem("displayImages");
});
menu.append(getMenuItem('displayVideos','Display Videos',displayVideos));
$("#displayVideos").change(function() {
localStorage.setItem("displayVideos", this.checked);
displayVideos = localStorage.getItem("displayVideos");
});
menu.append(getMenuItem('alwaysSourceQuality','Always Source Quality',alwaysSourceQuality));
$("#alwaysSourceQuality").change(function() {
localStorage.setItem("alwaysSourceQuality", this.checked);
alwaysSourceQuality = localStorage.getItem("alwaysSourceQuality");
if (alwaysSourceQuality == "true")
localStorage.setItem('video-quality', '{"default":"chunked"}');
});
menu.append(getMenuItem('autoPlayClips','Auto play clips',autoPlayClips));
$("#autoPlayClips").change(function() {
localStorage.setItem("autoPlayClips", this.checked);
autoPlayClips = localStorage.getItem("autoPlayClips");
});
}
var SupportedImageFormats = [".jpg", ".jpeg", ".png", ".webp", ".gif"];
var SupportedVideoFormats = [".mp4",".webm"];
var maxHeight = "240";
var maxWidth = "300";
GM_addStyle("iframe[class^='imgur-embed']{max-width: "+maxWidth+"px !important;}");
GM_addStyle("svg[class*='logotwitchwordmark']{display: none !important;}");
function isSupportedImage(url) {
var length = SupportedImageFormats.length;
while(length--) {
if (url.indexOf(SupportedImageFormats[length])!=-1) {
return true;
}
}
return false;
}
function isSupportedVideo(url) {
var length = SupportedVideoFormats.length;
while(length--) {
if (url.indexOf(SupportedVideoFormats[length])!=-1) {
return true;
}
}
return false;
}
function alterNode(node) {
var thisUrl = $(node).text();
var parentToScroll = $(node).parent().parent().parent().parent();
if (displayImages == "true" && isSupportedImage(thisUrl)){
$(node).html("<br><img src='" + thisUrl + "' width='" + maxWidth +"px'/>");
parentToScroll.animate({scrollTop:parentToScroll.scrollTop() + 500}, 'slow');
}
else if (displayVideos == "true" && thisUrl.indexOf("www.youtube") > 0 ){
if (thisUrl.indexOf("watch") > 0){
var videoId = thisUrl.match('v=([^&]*)')[1];
$(node).html('<br><iframe width="'+ maxWidth +'" height="'+ maxHeight +'" src="https://www.youtube.com/embed/' + videoId+'"></iframe>');
parentToScroll.animate({scrollTop:parentToScroll.scrollTop() + 500}, 'slow');
}
}
else if (displayVideos == "true" && isSupportedVideo(thisUrl)){
$(node).html('<br><video width="'+ maxWidth +'" height="'+ maxHeight +'" controls autoplay muted><source src="'+thisUrl +'" type="video/mp4"></video>');
parentToScroll.animate({scrollTop:parentToScroll.scrollTop() + 500}, 'slow');
}
else if (displayImages == "true" && thisUrl.indexOf("https://gyazo.com") > -1 ){
$(node).html("<br><img src='" + thisUrl.replace("https://gyazo.com", "https://i.gyazo.com") +".png' width='" + maxWidth +"px'/>");
parentToScroll.animate({scrollTop:parentToScroll.scrollTop() + 500}, 'slow');
}
else if (displayImages == "true" && thisUrl.indexOf("imgur") > -1){
var imgurId = "";
if (thisUrl.indexOf("gallery") > -1){
imgurId = thisUrl.match('gallery\/([^#]*)')[1];
try{
$(node).html('<div style="width:200"><blockquote class="imgur-embed-pub" lang="en" data-id="a/'+ imgurId +'"><a href="//imgur.com/'+ imgurId +'" ></a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script></div>');
}
catch(err){
}
}
else{
imgurId = thisUrl.match('a\/([^#]*)')[1];
try{
$(node).html('<div style="width:200"><blockquote class="imgur-embed-pub" lang="en" data-id="a/'+ imgurId +'"><a href="//imgur.com/'+ imgurId +'" ></a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script></div>');
}
catch(err){
}
}
parentToScroll.animate({scrollTop:parentToScroll.scrollTop() + 500}, 'slow');
}
else if (displayVideos == "true" && thisUrl.indexOf("clips.twitch.tv") > -1){
var clipId = thisUrl.match('.tv\/(.*)')[1];
$(node).html('<iframe src="https://clips.twitch.tv/embed?clip='+clipId+'&autoplay='+autoPlayClips+'&muted=true" frameborder="0" allowfullscreen="true" height="'+maxHeight+'" width="'+maxWidth+'"></iframe>');
parentToScroll.animate({scrollTop:parentToScroll.scrollTop() + 500}, 'slow');
}
else if (displayVideos == "true" && thisUrl.indexOf("twitch") > -1 && thisUrl.indexOf("clip") > -1){
var clipId1 = thisUrl.match('clip\/([^?]*)')[1];
$(node).html('<iframe src="https://clips.twitch.tv/embed?clip='+clipId1+'&autoplay='+autoPlayClips+'&muted=true" frameborder="0" allowfullscreen="true" height="'+maxHeight+'" width="'+maxWidth+'"></iframe>');
parentToScroll.animate({scrollTop:parentToScroll.scrollTop() + 500}, 'slow');
}
}
// Callback function to execute when mutations are observed
var callback = function(mutationsList, observer) {
for(var mutation of mutationsList) {
mutation.addedNodes.forEach(function(node) {
if (node.classList != undefined && node.classList.contains('link-fragment')) {
alterNode(node);
}
if (node.querySelectorAll){
node.querySelectorAll('.link-fragment').forEach(function(node) {
alterNode(node);
})
node.querySelectorAll('.text-fragment').forEach(function(node) {
alterNode(node);
})
}
});
}
};
var callbackAddMenu = function(mutationsList, observer) {
$('button[data-a-target="chat-settings"]').click(function(){
addMenu();
});
};
var callbackClaim = function(mutationsList, observer) {
for(var mutation of mutationsList) {
$(".claimable-bonus__icon").click();
}
};
var observerMenu = new MutationObserver(callbackAddMenu);
// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);
function _appendObserver() {
var isReady = $("div.chat-list").length > 0;
if (!isReady) {
setTimeout(_appendObserver, 500);
return;
}
if (!$("div.chat-list").hasClass("enhanceAppended")){
$("div.chat-list").addClass("enhanceAppended");
var targetNode = $("div.chat-list").get(0);
var targetNode2 = $(".right-column").get(0);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
observerMenu.observe(targetNode2, config);
}
}
_appendObserver();
function watchInSquad(){
$('button[data-a-player-state="playing"]').click();
$("main").children().each(function(){
$(this).attr("style","display:none !important;");
});
$(".right-column").parent().attr("style","display:none !important;");
var btnWatchInSquad = $("<button class = 'tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-bottom-right-radius-medium tw-border-top-left-radius-medium tw-border-top-right-radius-medium tw-core-button tw-core-button--secondary tw-full-width tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative'> Exit Squad Mode </button>");
btnWatchInSquad.addClass("enhanceTwitchAttached");
btnWatchInSquad.addClass("enhanceTwitchButtonSquadMode");
btnWatchInSquad.css("padding","10px");
$("main").append(btnWatchInSquad);
btnWatchInSquad.click(function(event){
$("#enhanceSquadModeIframe").remove();
$("main").children().each(function(){
$(this).attr("style","");
});
$(".right-column").parent().attr("style","");
$(this).remove();
$('button[data-a-player-state="paused"]').click();
});
$('<iframe src="'+window.location.href + '/squad" frameborder="0" scrolling="no" id="enhanceSquadModeIframe" style="height:100%"></iframe>').appendTo('main');
}
function exitSquadMode(){
if ( $("#enhanceSquadModeIframe").length > 0 && $("#enhanceSquadModeIframe").attr("src").indexOf(window.location.href) == -1){
$("#enhanceSquadModeIframe").remove();
$("main").children().each(function(){
$(this).attr("style","");
});
$(".right-column").parent().attr("style","");
$(".enhanceTwitchButtonSquadMode").remove();
$('button[data-a-player-state="paused"]').click();
};
};
function _addWatchInSquad(){
var elWatchInSquad = $('button[data-a-target="squad-stream-banner-button"]:not(.enhanceTwitchAttached)');
if (elWatchInSquad.length > 0){
var elSquad = elWatchInSquad.parent().parent();
elWatchInSquad.detach();
var streamingWith = elSquad.find(".tw-ellipsis").text();
var btnWatchInSquad = $("<button class = 'tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-bottom-right-radius-medium tw-border-top-left-radius-medium tw-border-top-right-radius-medium tw-core-button tw-core-button--secondary tw-full-width tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative'> Watch In Squad Mode </button>");
btnWatchInSquad.attr("data-toggle","tooltip");
btnWatchInSquad.attr("title",streamingWith);
btnWatchInSquad.addClass("enhanceTwitchAttached");
btnWatchInSquad.css("margin-left","10px");
btnWatchInSquad.css("padding","10px");
$(".channel-header__right").append(btnWatchInSquad);
elSquad.parent().css("display","none");
$(".persistent-player").css("top","0");
btnWatchInSquad.click(function(event){
watchInSquad();
});
return;
}else{
var elPrevious = $('.enhanceTwitchAttached');
if (elPrevious.length > 0){
var streamerStr = $(".channel-header__avatar-dropdown").find("figure").attr("aria-label");
if (elPrevious.attr("title").indexOf(streamerStr) == -1)
elPrevious.remove();
}
}
}
var targetNodeRoot = document.getElementById('root');
var configRoot = { attributes: false, childList: true, subtree: true };
var callbackRoot = function(mutationsList, observer) {
$(".claimable-bonus__icon").click();
_appendObserver();
var exitButton = $ ('button[data-a-target="squad-stream-exit-button"]:not(.enhanceTwitchAttached)');
if (exitButton.length> 0){
exitButton.attr("style","display: none !important");
exitButton.addClass("enhanceTwitchAttached");
}
exitSquadMode();
};
var callbackPlayer = function(mutationList,observer){
_addWatchInSquad();
}
function appendPlayerObserver(){
var targetNodePlayer = $('.persistent-player');
var isReady = targetNodePlayer.length > 0;
if (!isReady) {
setTimeout(appendPlayerObserver, 500);
return;
}
var observerPlayer = new MutationObserver(callbackPlayer);
observerPlayer.observe(targetNodePlayer.get(0), config);
}
appendPlayerObserver();
// Create an observer instance linked to the callback function
var observerroot = new MutationObserver(callbackRoot);
// Start observing the target node for configured mutations
observerroot.observe(targetNodeRoot, config);
var callbackQuality = function(mutationsList, observer) {
localStorage.setItem('video-quality', '{"default":"chunked"}');
};
function _appendQualityObserver() {
var isReady = $('div[data-a-target="player-controls"]').length > 0;
if (!isReady) {
setTimeout(_appendQualityObserver, 500);
return;
}
var targetNodeQuality = $('div[data-a-target="player-controls"]').get(0);
var observerQuality = new MutationObserver(callbackQuality);
observerQuality.observe(targetNodeQuality, config);
}
if (alwaysSourceQuality == "true"){
_appendQualityObserver();
}
})();