Youtube Audio Mode

Listen to only the audio on YouTube without loading the video.

目前為 2018-09-09 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Youtube Audio Mode
// @description Listen to only the audio on YouTube without loading the video.
// @version     1.1
// @include     https://www.youtube.com/*
// @license     GPL-3.0+; http://www.gnu.org/licenses/gpl-3.0.txt
// @run-at      document-start
// @grant       GM_xmlhttpRequest
// @grant       GM.setValue
// @grant       GM.getValue
// @noframes
// @namespace https://greasyfork.org/users/195276
// ==/UserScript==


(function(send) {

    // Keep track of the current video
    let videoId;

    XMLHttpRequest.prototype.send = function() {

        // Listen for audio requests
        this.addEventListener("readystatechange", async function() {

            // Add audio mode to the player's to menu
            if (videoId != ytcsi.gt().info.docid) {
                videoId = ytcsi.gt().info.docid;
                addAudoModeToMenu();
            }

            let video = document.getElementsByTagName("video")[0];

            // Set audio
            if (await GM.getValue("ytAudioMode", true)
                && ! this.responseURL.includes("live=1")
                && this.responseURL.includes("audio")
                && ! video.src.includes('audio')
                && videoId
            ) {
                video.pause();
                video.src = this.responseURL.split("&range")[0];
                video.play();

                // Set poster image
                setPoster(video, ["maxres", "sd", "hq"]);
            }
        }, false);
        send.apply(this, arguments);
    };

    // Add audio mode to the settings menu
    async function addAudoModeToMenu() {
        let audioMode = await GM.getValue("ytAudioMode", true);
        let panel = document.getElementsByClassName("ytp-panel-menu")[0];
        panel.innerHTML += `
            <div class="ytp-menuitem"
                aria-checked="${audioMode}"
                id="audio-mode">
                <div class="ytp-menuitem-label">Audio Mode</div>
                <div class="ytp-menuitem-content">
                    <div class="ytp-menuitem-toggle-checkbox">
                </div>
            </div>`;

        // Toggle audio mode on or off
        let audioToggle = document.getElementById("audio-mode");
        audioToggle.onclick = async function() {
            let audioMode = ! await GM.getValue("ytAudioMode");
            this.setAttribute("aria-checked", audioMode);
            GM.setValue("ytAudioMode", audioMode);
            let video = document.getElementsByTagName("video")[0];

            // Reload page to go back to video
            if ( ! audioMode) {
              location.reload();
            }
        }
    }

    // Set the video poster from thumbnails with the best avaliable format
    // https://developers.google.com/youtube/v3/docs/thumbnails
    function setPoster(video, fmts) {
        let img = new Image();
        img.src = `//i.ytimg.com/vi/${videoId}/${fmts.shift()}default.jpg`
        img.onload = function() {
            // A height 90 is YouTube"s not found image.
            if (img.height <= 90) {
                setPoster(video, fmts);
            } else {
                // Background image used as poster does not work on edge with
                // preload.
                video.style.background = `url(${img.src}) no-repeat center`;
                video.style.backgroundSize = "contain";
            }
        };
    }
})(XMLHttpRequest.prototype.send);