tim1986 / Panning Audio Slider

// ==UserScript==
// @name         Panning Audio Slider
// @namespace    https://openuserjs.org/users/tim1986
// @version      0.1
// @description  Panning audio slider for Twitch and Youtube, ads might interfere.
// @author       @tim1986
// @match        http://*.twitch.tv/*
// @match        https://*.twitch.tv/*
// @match        http://*.youtube.com/*
// @match        https://*.youtube.com/*
// @exclude      http://*.twitch.tv/videos/*
// @exclude      https://*.twitch.tv/videos/*
// @exclude      http://player.twitch.tv/*video=*
// @exclude      https://player.twitch.tv/*video=*
// @exclude      http://clips.twitch.tv/*
// @exclude      https://clips.twitch.tv/*
// @grant        none
// @noframes
// @run-at document-end
// @license MIT
// ==/UserScript==

// ==OpenUserJS==
// @author tim1986
// ==/OpenUserJS==

// Animation keyframes generated by Animista http://animista.net
/* ----------------------------------------------
 * Generated by Animista on 2018-1-11 3:27:2
 * w: http://animista.net, t: @cssanimista
 * ---------------------------------------------- */

/**
 * ----------------------------------------
 * animation fade-in
 * ----------------------------------------
 */
// Slider CSS originally from https://www.w3schools.com/howto/howto_js_rangeslider.asp with necessary changes

(function() {
    'use strict';
    const regex = /(?!\/videos\/.*)/g;
    setInterval(function(){
        if (document.querySelectorAll('#PanValueDisplay').length < 1){
            if (document.querySelector('.ytp-live-badge[disabled="true"]') === null || (document.location.host == 'www.twitch.tv' && regex.exec(document.location.pathname))) {
                var container = document.querySelector('.player, #movie_player.html5-video-player, .html5-video-player');
                if (container != null){
                    console.log('[Panning Audio Slider] This is a live stream. Adding panning audio slider.');
                    var cssnode = document.createElement('style');
                    cssnode.innerHTML = '@-webkit-keyframes fade-in{0%{opacity:0;}100%{opacity:1;}}@keyframes fade-in{0%{opacity:0;}100%{opacity:1;}}.slidecontainer{width:40%;position:absolute;top:96%;left:30%;z-index:9999;opacity:0.01;-webkit-animation:fade-in 2s reverse;animation:fade-in 2s reverse;transition:opacity.2s;-webkit-transition:.2s;}.slider{-webkit-appearance:none;width:100%;height:25px;background:#d3d3d3;outline:none;}.slidecontainer:hover{opacity:1;}.slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:25px;height:25px;background:#4CAF50;cursor:pointer;}.slider::-moz-range-thumb{width:25px;height:25px;background:#4CAF50;cursor:pointer;}#PanValueDisplay{position:absolute;top:-58%;left:49%;color:#71c174;z-index:9999;}';
                    container.appendChild(cssnode);
                    var divnode = document.createElement('div');
                    divnode.className = 'slidecontainer';
                    divnode.innerHTML = '<input type="range" min="-100" max="100" value="0" class="slider" id="PanSlider"><p id="PanValueDisplay">0.0</p>';
                    container.appendChild(divnode);
                    var scriptnode = document.createElement('script');
                    scriptnode.innerHTML = 'var slider=document.getElementById("PanSlider");var output=document.getElementById("PanValueDisplay");var audioCtx=new(window.AudioContext||window.webkitAudioContext)();var myAudio=document.querySelector("video");var source=audioCtx.createMediaElementSource(myAudio);var panNode=audioCtx.createStereoPanner({pan: 0});slider.oninput=function(){output.innerHTML=this.value/100;panNode.pan.value=this.value/100;};source.connect(panNode);panNode.connect(audioCtx.destination);';
                    document.body.appendChild(scriptnode);
                } else {
                    console.log('[Panning Audio Slider] Not a live stream.');
                }
            } else {
                console.log('[Panning Audio Slider] Not a live stream.');
            }
        }
    }, 3000);
})();