Greasy Fork is available in English.
Listen to only the audio on YouTube without loading the video.
当前为
// ==UserScript==
// @name Youtube Audio Mode
// @description Listen to only the audio on YouTube without loading the video.
// @version 0.2.4
// @author Burn
// @namespace https://openuserjs.org/users/burn
// @copyright 2022, burn (https://openuserjs.org/users/burn)
// @include https://www.youtube.com/*
// @match https://www.youtube.com/*
// @license MIT
// @run-at document-end
// @grant GM.setValue
// @grant GM.getValue
// @noframes
// ==/UserScript==
/*
PLEASE NOTE
I've found the original userscript on Github: https://github.com/teaqu/youtube-audio-mode
but it's not working anymore so I've opened an issue. After a month without receiving a reply
I've decided to update the script myself.
*/
(async function(open, originalFetch) {
const DBG = false;
let myLog = (msg) => {
DBG && console.log(GM_info.script.name + " | " + msg);
};
window.addEventListener("yt-navigate-finish", audioMode);
window.onYouTubeIframeAPIReady = await audioMode();
async function audioMode() {
if (location.pathname == "/watch") {
let video = document.getElementsByTagName("video")[0];
let audioMode = await GM.getValue("ytAudioMode");
await addToMenu(audioMode);
if (audioMode) {
setPoster(video, ["maxres", "hq", "sd"]);
watchFetchStream(video);
} else {myLog("audiomode disabled");}
}
}
function watchFetchStream(video) {
const constantMock = originalFetch;
unsafeWindow.fetch = function() {
return new Promise((resolve, reject) => {
constantMock.apply(this, arguments)
.then((response) => {
if(response.url.indexOf("mime=audio") > -1) { // && response.type != "cors"){
video.pause();
video.src = response.url.split("&range")[0];
video.play();
}
resolve(response);
})
.catch((error) => {
reject(response);
})
});
}
}
// Add audio mode to the settings menu
async function addToMenu(audioMode) {
let panel = document.getElementsByClassName("ytp-panel-menu")[0];
if (!panel.innerHTML.includes("Audio Mode")) {
panel.innerHTML += `
<div class="ytp-menuitem"
aria-checked="${audioMode}"
id="audio-mode">
<div class="ytp-menuitem-icon"></div>
<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);
location.reload();
}
}
}
// Set the video poster from thumbnails with the best avaliable format
// https://developers.google.com/youtube/v3/docs/thumbnails
async function setPoster(video, fmts) {
let img = new Image();
let videoId = location.search.match(/v=(.+?)(&|$)/)[1];
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 {
video.style.background = `url(${img.src}) no-repeat center`;
video.style.backgroundSize = "contain";
}
};
}
})(XMLHttpRequest.prototype.open, window.fetch || unsafeWindow.fetch);