Enhance twitch

Show images/video in chat,Auto click claim bonus, hide offline channels, always source quality and more

目前为 2020-07-23 提交的版本。查看 最新版本

// ==UserScript==
// @name         Enhance twitch
// @namespace    http://tampermonkey.net/
// @version      1.9.0
// @description  Show images/video in chat,Auto click claim bonus, hide offline channels, always source quality and more
// @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";
var hideHypeTrain = "false";
var hideBitGiftLeaderBoard = "false";
var hideUnfollowButton = "false";
var ultraWide = "true";
var hideOfflineChannels = "true";

if (localStorage.getItem("displayImages") != null) {
    displayImages = localStorage.getItem("displayImages");
}
if (localStorage.getItem("hideOfflineChannels") != null) {
    hideOfflineChannels = localStorage.getItem("hideOfflineChannels");
}
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");
}
if (localStorage.getItem("hideHypeTrain") != null) {
    hideHypeTrain = localStorage.getItem("hideHypeTrain");
}
if (localStorage.getItem("hideBitGiftLeaderBoard") != null) {
    hideBitGiftLeaderBoard = localStorage.getItem("hideBitGiftLeaderBoard");
}
if (localStorage.getItem("hideUnfollowButton") != null) {
    hideUnfollowButton = localStorage.getItem("hideUnfollowButton");
}

if (localStorage.getItem("ultraWide") != null) {
    ultraWide = localStorage.getItem("ultraWide");
}

if (ultraWide == "true"){

    GM_addStyle(".browse-root-page__wrapper{    left: 0;    position: relative;    width: 100%; max-width: 10000px;}");
}


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);
}

$( window ).on( "load", function() {
    if (hideUnfollowButton == "true")
        GM_addStyle('button[data-a-target="unfollow-button"]{display: none !important;}');
});

function RemoveCssRule(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;
    for (var i=0; i<sheet.cssRules.length; i++) {
        if (sheet.cssRules[i].selectorText == css) {
            sheet.deleteRule (i);
        }
    }
}

function LoadTwitchEnhance(){
    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");
        });
        //hideOfflineChannels

        menu.append(getMenuItem('fixhideOfflineChannels','Hide offline channels',hideOfflineChannels));
        $("#fixhideOfflineChannels").change(function() {
            localStorage.setItem("hideOfflineChannels", this.checked);
            hideOfflineChannels = localStorage.getItem("hideOfflineChannels");
        });

        menu.append(getMenuItem('hideHypeTrain','Hide hype train',hideHypeTrain));
        $("#hideHypeTrain").change(function() {
            localStorage.setItem("hideHypeTrain", this.checked);
            hideHypeTrain = localStorage.getItem("hideHypeTrain");
            if (hideHypeTrain == "false")
                RemoveCssRule(".community-highlight-stack__scroll-area--disable");
            else
                GM_addStyle(".community-highlight-stack__scroll-area--disable{display: none !important;}");
        });

        menu.append(getMenuItem('hideBitGiftLeaderBoard','Hide gift/bit leaderboard',hideBitGiftLeaderBoard));
        $("#hideBitGiftLeaderBoard").change(function() {
            localStorage.setItem("hideBitGiftLeaderBoard", this.checked);
            hideBitGiftLeaderBoard = localStorage.getItem("hideBitGiftLeaderBoard");
            if (hideBitGiftLeaderBoard == "false")
                RemoveCssRule(".channel-leaderboard");
            else
                GM_addStyle(".channel-leaderboard{display: none !important;}");
        });

        menu.append(getMenuItem('hideUnfollowButton','Hide unfollow button',hideUnfollowButton));
        $("#hideUnfollowButton").change(function() {
            localStorage.setItem("hideUnfollowButton", this.checked);
            hideUnfollowButton = localStorage.getItem("hideUnfollowButton");
            if (hideUnfollowButton == "false")
                RemoveCssRule('button[data-a-target="unfollow-button"]');
            else
                GM_addStyle('button[data-a-target="unfollow-button"]{display: none !important;}');
        });
    }

    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;}");
    if (hideHypeTrain == "true")
        GM_addStyle(".community-highlight-stack__scroll-area--disable{display: none !important;}");
    if (hideBitGiftLeaderBoard == "true")
        GM_addStyle(".channel-leaderboard{display: none !important;}");
    GM_addStyle(".btnRefreshEnhance button{height: 15px; width: 100%}");
    GM_addStyle(".chat-settings{    max-height: 500px !important;    overflow: hidden !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&parent=twitch.tv" 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&parent=twitch.tv" 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"]:not(.fixMenuAppended)').click(function(){
            $('button[data-a-target="chat-settings"]').addClass("fixMenuAppended");
            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();

        if (hideOfflineChannels == "true"){
            for(var mutation of mutationsList){
                mutation.addedNodes.forEach(function(node) {
                    //side-nav-card__avatar
                    var channelStatus = $(node).find(".side-nav-card__avatar");
                    var offlineChannels = $(node).find(".side-nav-card__avatar--offline");
                    if (offlineChannels.length > 0){
                        var parentStatus = offlineChannels.parent().parent().parent().parent();
                        if (!parentStatus[0].hasAttribute('aria-label')){
                            parentStatus.css("display","none");
                        }
                    }
                    if (channelStatus.length > 0){
                        var elemToObserve = channelStatus.get(0);
                        var observer = new MutationObserver(function(mutations) {
                            mutations.forEach(function(mutation) {
                                var channelIsOffline = mutation.target.classList.contains('side-nav-card__avatar--offline');
                                var parentStatus = $($(mutation)[0].target).parent().parent().parent().parent();
                                if(channelIsOffline){
                                    if (!parentStatus[0].hasAttribute('aria-label')){
                                        parentStatus.css("display","none");
                                    }
                                }
                                else{
                                    parentStatus.css("display","block");
                                }
                            });
                        });
                        observer.observe(elemToObserve, {attributes: true});
                    }
                });
            }
        }

        if (window.location.href == "https://www.twitch.tv/"){
            var videoMainPage = $(".featured-content-carousel:not(.fixVideoPausedOnce)").find("video");
            if (videoMainPage.length > 0){
                videoMainPage.get(0).pause();
                videoMainPage.parent().click(function(){
                    $(".featured-content-carousel").addClass('fixVideoPausedOnce');
                });
            }
        }

        var linkArg = $(".social-media-space--content").find(".tw-avatar").attr("aria-label");
        if ($(".social-media-space--content:not(.fixLinksAppended)").length > 0 || $(".social-media-space--content").attr("id") != "fix" + linkArg){
            var appendable = $(".social-media-space--content").find('.tw-title').parent();
            if (appendable.length>0) {
                $("#fixVideosLinks").remove();
                $("#fixClipsLinks").remove();
                $("#fixSpanLinks").remove();
                appendable.append('<a target="_blank" id ="fixVideosLinks" href="/'+linkArg+'/videos"><span>Videos</span></a><span id = "fixSpanLinks"> / </span>');
                appendable.append('<a target="_blank" id ="fixClipsLinks" href="/'+linkArg+'/clips?filter=clips&range=7d"><span>Clips</span></a>');
                $(".social-media-space--content").addClass("fixLinksAppended");
                $(".social-media-space--content").attr("id","fix"+linkArg);
            }
        }
    };
    var callbackPlayer = function(mutationList,observer){
       // disabled for now _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();
        Object.defineProperty(document, 'hidden', {value: false});
        Object.defineProperty(document, 'visibilityState', {value: 'visible'});
    }

}

(function() {
    'use strict';
    LoadTwitchEnhance();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址