Youtube Audio Mode

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

  1. // ==UserScript==
  2. // @name Youtube Audio Mode
  3. // @description Listen to only the audio on YouTube without loading the video.
  4. // @version 1.2.2
  5. // @include https://www.youtube.com/*
  6. // @license GPL-3.0+; http://www.gnu.org/licenses/gpl-3.0.txt
  7. // @run-at document-end
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM.setValue
  10. // @grant GM.getValue
  11. // @noframes
  12. // @namespace https://greasyfork.org/users/195276
  13. // ==/UserScript==
  14.  
  15. (function(open) {
  16. window.addEventListener("yt-navigate-finish", audioMode);
  17. window.onYouTubeIframeAPIReady = audioMode();
  18.  
  19. async function audioMode() {
  20. if (location.pathname == "/watch") {
  21. let video = document.getElementsByTagName("video")[0];
  22. let audioMode = await GM.getValue("ytAudioMode");
  23. addToMenu(audioMode);
  24. if (audioMode) {
  25. setPoster(video, ["maxres", "hq", "sd"]);
  26. watchStream(video);
  27. }
  28. }
  29. }
  30.  
  31. // Watch the media streams so we can select the audio
  32. function watchStream(video) {
  33. XMLHttpRequest.prototype.open = function(method, url) {
  34. let validStream = /^(?!.*live=1).+audio.+$/;
  35. if (validStream.test(url) && ! video.src.includes("audio")) {
  36. video.pause();
  37. video.src = url.split("&range")[0];
  38. video.play();
  39. }
  40. open.apply(this, arguments);
  41. }
  42. }
  43.  
  44. // Add audio mode to the settings menu
  45. async function addToMenu(audioMode) {
  46. let panel = document.getElementsByClassName("ytp-panel-menu")[0];
  47. if (!panel.innerHTML.includes("Audio Mode")) {
  48. panel.innerHTML += `
  49. <div class="ytp-menuitem"
  50. aria-checked="${audioMode}"
  51. id="audio-mode">
  52. <div class="ytp-menuitem-icon"></div>
  53. <div class="ytp-menuitem-label">Audio Mode</div>
  54. <div class="ytp-menuitem-content">
  55. <div class="ytp-menuitem-toggle-checkbox">
  56. </div>
  57. </div>`;
  58.  
  59. // Toggle audio mode on or off
  60. let audioToggle = document.getElementById("audio-mode");
  61. audioToggle.onclick = async function() {
  62. let audioMode = ! await GM.getValue("ytAudioMode");
  63. this.setAttribute("aria-checked", audioMode);
  64. GM.setValue("ytAudioMode", audioMode);
  65. location.reload();
  66. }
  67. }
  68. }
  69.  
  70. // Set the video poster from thumbnails with the best avaliable format
  71. // https://developers.google.com/youtube/v3/docs/thumbnails
  72. async function setPoster(video, fmts) {
  73. let img = new Image();
  74. let videoId = location.search.match(/v=(.+?)(&|$)/)[1];
  75. img.src = `//i.ytimg.com/vi/${videoId}/${fmts.shift()}default.jpg`
  76. img.onload = function() {
  77. // A height 90 is YouTube"s not found image.
  78. if (img.height <= 90) {
  79. setPoster(video, fmts);
  80. } else {
  81. video.style.background = `url(${img.src}) no-repeat center`;
  82. video.style.backgroundSize = "contain";
  83. }
  84. };
  85. }
  86. })(XMLHttpRequest.prototype.open);