YT Media Controls+

New volume bar for enchanced precision and higher range + fix for media keys on YouTube

2023-12-17 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

// ==UserScript==
// @name         YT Media Controls+
// @namespace    by Zimeh
// @version      2
// @description  New volume bar for enchanced precision and higher range + fix for media keys on YouTube
// @author       Zimeh
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// @license      MIT
// ==/UserScript==

typeof update !== 'undefined' && clearInterval(update)
if(!localStorage.customVolume || localStorage.customVolume > 100 || localStorage.customVolume < 0) localStorage.customVolume = '25'
let isContainerInserted = false
let hasIcon = false
const container = document.createElement("div");
container.id = 'volumep_container'
container.innerHTML = `
<style>
    #volumep_container{
        padding-bottom:10px;
        padding-top:10px;
        user-select:none;
    }

    #volumep_meter_icon{
        display:flex;
        justify-content:center;
        align-items:center;
    }
    
    #volumep_meter_val{
        width:80px;
        display:flex;
        justify-content:center;
        align-items:center;
    }

    #volumep_meter{
        font-size:22px;
        width:130px;
        border-radius:5px 0px 0px 5px;
        background-color:#2b2b2b;
        height:30px;
        user-select:none;
        color:#ddd;
        font-weight:bold;
        display:flex;
        justify-content:center;
        align-items:center
    }

    #volumep_slider { 
        -webkit-appearance: none;
        position: relative;
        margin:0px;
        overflow: hidden;
        outline:none;
        height: 30px;
        width: 700px;
        border-radius:0px 5px 5px 0px;
        cursor: pointer;
    }
    
    ::-webkit-slider-runnable-track {
        background: #ddd;
        border-radius:0px 5px 5px 0px;
    }
    
    ::-webkit-slider-thumb {
        -webkit-appearance: none;
        width: 0px; /* 1 */
        height: 40px;
        background: #fff;
        box-shadow: -700px 0 0 700px dodgerblue; /* 2 */
    }
    
    ::-moz-range-track {
        height: 40px;
        background: #ddd;
        border-radius:0px 5px 5px 0px;
    }
    
    ::-moz-range-thumb {
        background: #fff;
        height: 0px;
        width: 0px; /* 1 */
        border: 3px solid #999; /* 1 */
        border-radius: 0 !important;
        box-shadow: -700px 0 0 700px dodgerblue;
        box-sizing: border-box;
    }
    
    ::-ms-fill-lower { 
        background: dodgerblue;
    }
    
    ::-ms-thumb { 
        background: #fff;
        border: 2px solid #999; /* 1 */
        height: 0px;
        width: 0px; /* 1 */
        box-sizing: border-box;
    }
    
    ::-ms-ticks-after { 
        display: none; 
    }
    
    ::-ms-ticks-before { 
        display: none; 
    }
    
    ::-ms-track { 
        background: #ddd;
        border-radius:0px 5px 5px 0px;
        color: transparent;
        height: 0px;
        border: none;
    }
    
    ::-ms-tooltip { 
        display: none;
    }

    #volumep_controls > svg:hover{
        cursor:pointer;
        fill:#cccccc;
        color:#cccccc
    }
</style>
<div style="display:flex">
    <div id="volumep_meter">
        <div id="volumep_meter_icon"></div>
        <div id="volumep_meter_val">${localStorage.customVolume}%</div>
    </div>   
    <input id="volumep_slider" max="100" step="0.1" value="${localStorage.customVolume}" type="range" />
    <div id="volumep_controls">
        <svg width="30" id="volumep_deduct" height="30" viewBox="0 0 24 24"><path fill="#9e9e9e" d="M19 12.998H5v-2h14z"/></svg>
        <svg width="30" id="volumep_add" height="30" viewBox="0 0 24 24"><path fill="#9e9e9e" d="M19 12.998h-6v6h-2v-6H5v-2h6v-6h2v6h6z"/></svg>
    </div>
</div>
`

function setCustomVol(v) {
    localStorage.customVolume = v
    document.querySelector('video').volume = v / 100
    document.getElementById('volumep_meter_val').innerText = v + '%'
    document.getElementById('volumep_slider').value = v
}

var update = setInterval(()=>{
    const vid = document.querySelector('video')

    if(!isContainerInserted){
        document.getElementById('above-the-fold').prepend(container)
        document.getElementById('volumep_slider').addEventListener('input', v => {  if(v.target.value == '4e-17') return setCustomVol(0); v.target.value = parseFloat(v.target.value); setCustomVol(v.target.value)  })
        document.getElementById('volumep_add').addEventListener('mousedown', v => { if(parseFloat(localStorage.customVolume)+0.1 <= 100) setCustomVol((parseFloat(localStorage.customVolume)+0.1).toFixed(1)) })
        document.getElementById('volumep_deduct').addEventListener('mousedown', v => { if(parseFloat(localStorage.customVolume)-0.1 >= 0) setCustomVol((parseFloat(localStorage.customVolume)-0.1).toFixed(1)) })
        isContainerInserted = true
    }

    if(localStorage.customVolume && localStorage.customVolume !== vid.volume*100){
        vid.volume = localStorage.customVolume / 100
        var icon = '<svg width="25" height="25" viewBox="0 0 24 24"><path fill="none" stroke="#ddd" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5L6 9H2v6h4l5 4zm11 4l-6 6m0-6l6 6"/></svg>'

        if(localStorage.customVolume > 0) icon = '<svg width="25" height="25" viewBox="0 0 24 24"><path fill="none" stroke="#ddd" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5L6 9H2v6h4l5 4zm4.54 3.46a5 5 0 0 1 0 7.07"/></svg>'
        if(localStorage.customVolume > 20) icon = '<svg width="25" height="25" viewBox="0 0 24 24"><path fill="none" stroke="#ddd" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5L6 9H2v6h4l5 4zm4.54 3.46a5 5 0 0 1 0 7.07m3.53-10.6a10 10 0 0 1 0 14.14"/></svg>'
        if(localStorage.customVolume > 75) icon = '<svg width="30" height="30" viewBox="0 0 24 24"><path fill="#ddd" d="M3 10v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71V6.41c0-.89-1.08-1.34-1.71-.71L7 9H4c-.55 0-1 .45-1 1m13.5 2A4.5 4.5 0 0 0 14 7.97v8.05c1.48-.73 2.5-2.25 2.5-4.02M14 4.45v.2c0 .38.25.71.6.85C17.18 6.53 19 9.06 19 12s-1.82 5.47-4.4 6.5c-.36.14-.6.47-.6.85v.2c0 .63.63 1.07 1.21.85C18.6 19.11 21 15.84 21 12s-2.4-7.11-5.79-8.4c-.58-.23-1.21.22-1.21.85"/></svg></svg>'

        if(icon !== sessionStorage.currentIcon || !hasIcon) {
            document.getElementById('volumep_meter_icon').innerHTML = icon
            sessionStorage.currentIcon = icon
            hasIcon = true
        }
    }

    if (!window.navigator.mediaSession.metadata.canSkip) {

        window.navigator.mediaSession.metadata.canSkip = true
 
        window.navigator.mediaSession.setActionHandler('previoustrack', function() {
            if (document.getElementsByClassName('ytp-prev-button')[0] && document.getElementsByClassName('ytp-prev-button')[0].style.display !== 'none') document.getElementsByClassName('ytp-prev-button')[0].click();
            else history.back()
        });
 
        window.navigator.mediaSession.setActionHandler('nexttrack', function() {
            document.getElementsByClassName('ytp-next-button')[0].click()
        });
    }
}, 250)