Greasy Fork is available in English.

Bandcamp Volume Bar

Adds a volume bar to Bandcamp

  1. // ==UserScript==
  2. // @name Bandcamp Volume Bar
  3. // @version 1.1.8
  4. // @author Redcrafter
  5. // @description Adds a volume bar to Bandcamp
  6. // @license Apache-2.0; http://www.apache.org/licenses/LICENSE-2.0.txt
  7. // @match *://*.bandcamp.com/*
  8. // @namespace https://github.com/Redcrafter
  9. // ==/UserScript==
  10.  
  11. var gen = document.querySelector("meta[name=generator]");
  12. if(!gen || gen.content != "Bandcamp") {
  13. return;
  14. }
  15.  
  16. var style = document.createElement("style");
  17. style.textContent = ".volumeControl{align-items:center;display:flex;height:52px;margin-top:1em}.volumeControl .thumb{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.volumeControl>.speaker{background:#fff;border:1px solid #d9d9d9;border-radius:2px;color:#000;cursor:pointer;font-size:32px;height:54px;line-height:54px;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:54px}.volumeControl>.speaker>svg{margin:11px}";
  18. document.head.appendChild(style);
  19.  
  20. var dragWidth = 226;
  21. var dragging = false;
  22. var dragPos = 0;
  23. var percentage = parseFloat(localStorage.getItem("volume")) || 0.5;
  24. var speaker, volumeInner, audio, volume;
  25.  
  26. function onLoad() {
  27. audio = document.getElementsByTagName("audio")[0];
  28. updateVolume();
  29.  
  30. var container = document.createElement("div");
  31. container.classList.add("volumeControl");
  32.  
  33. speaker = document.createElement("i");
  34. speaker.classList.add("speaker");
  35. speaker.addEventListener("click", function () {
  36. audio.muted = !audio.muted;
  37. updateHtml();
  38. });
  39. container.appendChild(speaker);
  40.  
  41. var volume = document.createElement("div");
  42. volume.classList.add("progbar");
  43. container.appendChild(volume);
  44.  
  45. var fill = document.createElement("div");
  46. fill.classList.add("progbar_empty");
  47. fill.style.width = "248px";
  48. volume.appendChild(fill);
  49.  
  50. volumeInner = document.createElement("div");
  51. volumeInner.classList.add("thumb");
  52. volumeInner.addEventListener("mousedown", function (e) {
  53. dragging = true;
  54. dragPos = e.offsetX;
  55. });
  56. fill.appendChild(volumeInner);
  57. document.querySelector(".inline_player").appendChild(container);
  58.  
  59. updateHtml();
  60.  
  61. document.addEventListener("mouseup", function () {
  62. if (dragging) {
  63. localStorage.setItem("volume", percentage);
  64. dragging = false;
  65. }
  66. });
  67. document.addEventListener("mousemove", function (e) {
  68. if (dragging) {
  69. var pos = volume.getBoundingClientRect();
  70.  
  71. audio.muted = false;
  72. percentage = clamp(((e.pageX - pos.left) - dragPos) / dragWidth, 0, 1);
  73. updateVolume();
  74. updateHtml();
  75. }
  76. });
  77. }
  78.  
  79. if (document.readyState == 'complete') {
  80. onLoad();
  81. } else {
  82. window.addEventListener("load", onLoad);
  83. }
  84.  
  85. function updateVolume() {
  86. audio.volume = (Math.exp(percentage) - 1) / (Math.E - 1);
  87. }
  88.  
  89. function updateHtml() {
  90. // svgs from https://www.material.io/resources/icons
  91. if (audio.muted) {
  92. speaker.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
  93. volumeInner.style.left = "0%";
  94. } else {
  95. if (percentage <= 0) {
  96. speaker.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32"><path d="M7 9v6h4l5 5V4l-5 5H7z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
  97. } else if (percentage < 0.5) {
  98. speaker.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32"><path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
  99. } else {
  100. speaker.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
  101. }
  102. volumeInner.style.left = dragWidth * percentage + 'px';
  103. }
  104. }
  105.  
  106. function clamp(num, min, max) {
  107. return num <= min ? min : num >= max ? max : num;
  108. }