Key media control for niconico

ニコニコ動画本体側でいろいろ便利になった結果、今は音量を表示するだけの機能のみ

当前为 2024-08-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Key media control for niconico
  3. // @namespace https://htsign.hateblo.jp
  4. // @version 0.9.5
  5. // @description ニコニコ動画本体側でいろいろ便利になった結果、今は音量を表示するだけの機能のみ
  6. // @author htsign
  7. // @match https://www.nicovideo.jp/watch/*
  8. // @match https://live.nicovideo.jp/watch/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (() => {
  13. 'use strict';
  14.  
  15. /** @type {function(string): HTMLElement | null} */
  16. const $ = Document.prototype.querySelector.bind(document);
  17.  
  18. const getVolumeBar = () => $('[aria-label="volume"]');
  19.  
  20. {
  21. const TEXT_CLASS = 'volumeText';
  22.  
  23. /**
  24. * @param {HTMLElement} volumeBar
  25. * @returns {void}
  26. */
  27. const showVolume = volumeBar => {
  28. /** @type {[, string | number | undefined]} */
  29. let [, volume] = volumeBar.style.transform.match(/scaleX\(([^\)]+?)\)/) ?? [];
  30.  
  31. let volumeElement = $(`.${TEXT_CLASS}`);
  32. if (volumeElement == null) {
  33. const attributes = {
  34. className: TEXT_CLASS,
  35. style: `
  36. position: absolute;
  37. left: calc(var(--sizes-x10) + 10px);
  38. transform: translateY(-.5rem);
  39. width: max-content;
  40. `,
  41. };
  42. volumeElement = Object.assign(document.createElement('output'), attributes);
  43. }
  44.  
  45. const container = volumeBar.parentElement;
  46. if (volume != null) {
  47. container.append(Object.assign(volumeElement, { textContent: `${(volume * 100).toFixed()} %` }));
  48. }
  49. else if (!Number.isNaN(volume = parseInt(volumeBar.style.marginLeft))) {
  50. volumeElement.style.lineHeight = 2.5;
  51. container.append(Object.assign(volumeElement, { textContent: `${volume.toFixed()} %` }));
  52. }
  53. };
  54.  
  55. const main = () => {
  56. const volumeBar = getVolumeBar();
  57. if (volumeBar == null) return requestAnimationFrame(main);
  58.  
  59. const observer = new MutationObserver(records => {
  60. records
  61. .map(record => record.target)
  62. .forEach(showVolume);
  63. });
  64. observer.observe(volumeBar, { attributeFilter: ['style'] });
  65.  
  66. showVolume(volumeBar);
  67. };
  68. main();
  69. }
  70. })();