您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds buttons below video to play media in audio only mode. Works on mobile (m.youtube.com) and on desktop.
- // ==UserScript==
- // @name YouTube.com audio only mode buttons (Mobile / Desktop)
- // @namespace youtube-download-buttons-video-audio
- // @version 1.6
- // @description Adds buttons below video to play media in audio only mode. Works on mobile (m.youtube.com) and on desktop.
- // @author hlorand.hu
- // @match https://m.youtube.com/*
- // @match https://youtube.com/*
- // @match https://*.youtube.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
- // @grant none
- // @license https://creativecommons.org/licenses/by-nc-sa/4.0/
- // @run-at document-idle
- // ==/UserScript==
- // Screenshot: https://ibb.co/F7NJZHT
- (function() {
- //'use strict';
- // itag quality descriptors
- // https://gist.github.com/sidneys/7095afe4da4ae58694d128b1034e01e2
- function getQualityFromItag(itag) {
- const q = {
- '5':'FLV 240p',
- '6':'FLV 270p',
- '17':'3GP 144p',
- '18':'MP4 360p',
- '22':'MP4 720p',
- '34':'FLV 360p',
- '35':'FLV 480p',
- '36':'3GP 180p',
- '37':'MP4 1080p',
- '38':'MP4 3072p',
- '43':'WebM 360p',
- '44':'WebM 480p',
- '45':'WebM 720p',
- '46':'WebM 1080p',
- '82':'MP4 360p (3D)',
- '83':'MP4 480p (3D)',
- '84':'MP4 720p (3D)',
- '85':'MP4 1080p (3D)',
- '92':'HLS 240p (3D)',
- '93':'HLS 360p (3D)',
- '94':'HLS 480p (3D)',
- '95':'HLS 720p (3D)',
- '96':'HLS 1080p (3D)',
- '100':'WebM 360p (3D)',
- '101':'WebM 480p (3D)',
- '102':'WebM 720p (3D)',
- '132':'HLS 240p',
- '133':'MP4 240p Video Only',
- '134':'MP4 360p Video Only',
- '135':'MP4 480p Video Only',
- '136':'MP4 720p Video Only',
- '137':'MP4 1080p Video Only',
- '138':'MP4 2160p60 Video Only',
- '139':'M4A Audio Only 48k',
- '140':'M4A Audio Only 128k',
- '141':'M4A Audio Only 256k',
- '151':'HLS 72p',
- '160':'MP4 144p Video Only',
- '167':'WebM 360p Video Only',
- '168':'WebM 480p Video Only',
- '169':'WebM 1080p Video Only',
- '171':'WebM Audio Only 128k',
- '218':'WebM 480p Video Only',
- '218':'WebM 144p Video Only',
- '242':'WebM 240p Video Only',
- '243':'WebM 360p Video Only',
- '244':'WebM 480p Video Only',
- '245':'WebM 480p Video Only',
- '246':'WebM 480p Video Only',
- '247':'WebM 720p Video Only',
- '248':'WebM 1080p Video Only',
- '249':'WebM Audio Only 50k',
- '250':'WebM Audio Only 70k',
- '251':'WebM Audio Only 160k',
- '264':'MP4 1440p Video Only',
- '266':'MP4 2160p60 Video Only',
- '271':'WebM 1440p Video Only',
- '272':'WebM 4320p Video Only',
- '278':'WebM 144p Video Only',
- '298':'MP4 720p60 Video Only',
- '299':'MP4 1080p60 Video Only',
- '302':'WebM 720p60 Video Only ',
- '303':'WebM 1080p60 Video Only',
- '308':'WebM 1440p60 Video Only',
- '313':'WebM 2160p Video Only',
- '315':'WebM 2160p60 Video Only',
- '330':'WebM 144p60 Video Only (hdr)',
- '331':'WebM 240p60 Video Only (hdr)',
- '332':'WebM 360p60 Video Only (hdr)',
- '333':'WebM 480p60 Video Only (hdr)',
- '334':'WebM 720p60 Video Only (hdr)',
- '335':'WebM 1080p60 Video Only (hdr)',
- '336':'WebM 1440p60 Video Only (hdr)',
- '337':'WebM 2160p60 Video Only (hdr)'
- };
- return q[itag] || "Unknown";
- }
- function addbuttons(){
- document.getElementById("downloadbuttons").innerText = "";
- // do not add buttons on homepage
- if( !window.location.href.includes("watch") ) return;
- // if config not available, reload page
- if( window.location.href.includes("watch") && ( !ytplayer.config || !ytplayer.config.args ) ){
- window.location.reload();
- return;
- }
- // get video urls from youtube config
- let medias = ytplayer.config.args.raw_player_response.streamingData.adaptiveFormats;
- medias.push(...ytplayer.config.args.raw_player_response.streamingData.formats);
- let urls = [];
- for (let media of medias) {
- // calculate filesizes
- if( media.contentLength )
- // audio
- var _filesize = Math.round(media.contentLength / 1024 / 1024); // byte->MB
- else
- // video
- var _filesize = Math.round(media.approxDurationMs/1000 * media.bitrate/1024/1024/8) // bits/s->MB
- // collet the most important data to an object
- let data = {
- url : media.url.replace(/\\u0026/g, '&'),
- qualityDescription : getQualityFromItag(media.itag),
- qualityLabel : media.qualityLabel,
- filesize : _filesize
- };
- // filter videos that has audio+video stream both included or audio only
- if( data.qualityDescription.includes("Audio Only") || data.qualityDescription.includes("MP4") && !data.qualityDescription.includes("Only") )
- urls.push( data );
- }
- // filter out duplicates
- urls = Array.from(new Set(urls.map(a => a.url))).map(url => {
- return urls.find(a => a.url === url);
- });
- // create and add buttons
- urls.forEach((url)=>{
- let button = document.createElement('button');
- button.setAttribute("url", url.url);
- button.textContent = url.qualityDescription.replace(" Only","").replace("WebM","").replace("M4A","") + (isNaN(url.filesize) ? "" : " "+url.filesize+"M");
- button.className = "downloadbutton";
- button.style.margin = "4px";
- button.style.padding = "4px";
- button.style.position = "relative";
- button.style.backgroundColor = "chocolate";
- button.onclick = function() {
- document.write(`<html>
- <body>
- <video controls><source src=`+this.getAttribute("url")+`></video><br><br>
- <style>button{margin-bottom:5px;font-size:large;}video{width:100%;max-height:100vh;}</style>
- <button onclick="document.querySelector('video').playbackRate = 3">3</button><br>
- <button onclick="document.querySelector('video').playbackRate = 2.75">2.75</button><br>
- <button onclick="document.querySelector('video').playbackRate = 2.5">2.5</button><br>
- <button onclick="document.querySelector('video').playbackRate = 2.25">2.25</button><br>
- <button onclick="document.querySelector('video').playbackRate = 2">2</button><br>
- <button onclick="document.querySelector('video').playbackRate = 1.75">1.75</button><br>
- <button onclick="document.querySelector('video').playbackRate = 1.5">1.5</button><br>
- <button onclick="document.querySelector('video').playbackRate = 1">1</button><br>
- </body>
- </html>`);
- };
- let target = document.getElementById('downloadbuttons');
- target.insertBefore(button, target.firstChild);
- }); // end foreach
- } // end addbuttons
- // Periodically check if the buttons are visible (sometimes YouTube redraws its interface).
- setInterval(()=>{
- // Creating a div that will contain buttons.
- if( document.getElementById("downloadbuttons") == undefined ){
- // placement of buttons on desktop
- let parent = document.getElementById('above-the-fold');
- // placement of buttons on tablet
- if( !parent ){
- parent = document.querySelector('.watch-below-the-player');
- }
- // placement of buttons on mobile
- if( !parent ){
- parent = document.querySelector('.related-chips-slot-wrapper');
- }
- if( parent ){
- let wrapper = document.createElement('div');
- wrapper.setAttribute("id","downloadbuttons");
- parent.insertBefore(wrapper, parent.firstChild);
- addbuttons();
- }
- }
- // Sometimes the buttons are not added, so I check and add them if necessary.
- if( document.getElementById("downloadbuttons") && document.getElementById("downloadbuttons").textContent.trim() === '' ){
- addbuttons();
- }
- }, 1000);
- })();