V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yamedie
V2EX  ›  Podcast

篡改猴脚本:给 web 版小宇宙 FM 增加播放速率选项

  •  
  •   yamedie · 2023-12-20 21:16:14 +08:00 · 1354 次点击
    这是一个创建于 367 天前的主题,其中的信息可能已经有所发展或是发生改变。

    通过TamperMonkey 扩展写脚本,给小宇宙播放页面增加了倍速选项,方便在电脑上收听。

    搭配枫言枫语的这个播客榜单上班摸鱼 探索自己感兴趣的播客节目,真不错!

    后续如果有新功能迭代,最新代码会在 博客 上进行更新。

    xyzfm.png

    // ==UserScript==
    // @name         小宇宙 FM-增加倍速选项
    // @namespace    http://tampermonkey.net/
    // @version      0.6
    // @description  try to take over the world!
    // @author       icheer
    // @match        https://www.xiaoyuzhoufm.com/episode/*
    // @match        https://www.xiaoyuzhoufm.com/podcast/*
    // @icon         https://www.google.com/s2/favicons?sz=64&domain=xiaoyuzhoufm.com
    // @grant        none
    // ==/UserScript==
    
    (async function init (delay = 0) {
      const sleep = time => new Promise(resolve => setTimeout(resolve, time));
      const $ = sel => document.querySelector(sel);
      const CE = tag => document.createElement(tag);
      await sleep(delay);
      const panel = $('.controls');
      if (!panel) return console.error('panel not found');
      const audio = $('audio');
      if (!audio) return console.error('audio not found');
      // v0.1 倍速选项
      // 倍速下拉框
      const select = CE('select');
      // 0.5 倍速听谈话类节目太魔性了,是一个无用的选项,需要的话可以自己在下方添加<option value="0.5x">0.5x</option>
      select.innerHTML = `
        <option value="1x">1x</option>
        <option value="1.25x">1.25x</option>
        <option value="1.5x">1.5x</option>
        <option value="1.75x">1.75x</option>
        <option value="2x">2x</option>
        <option value="3x">3x</option>
      `;
      select.style = 'width: 72px; height: 28px; margin: 0 10px; padding: 0 4px; border-radius: 4px; border: 1px solid #ccc; font-size: 14px; color: #333; outline: none';
      panel.insertBefore(select, panel.children[0]);
      // 最后一次选择的倍速偏好,自动带入
      if (localStorage.getItem('xyzRate')) {
        const rate = parseFloat(localStorage.getItem('xyzRate')) || 1;
        audio.playbackRate = rate;
        select.value = rate + 'x';
      }
      // 选择倍速时,让倍速生效,并在 localStorage 中记录偏好,以便下次自动生效
      select.addEventListener('change', e => {
        const rate = parseFloat(e.target.value) || 1;
        audio.playbackRate = rate;
        localStorage.setItem('xyzRate', rate);
      });
      // v0.2 下载按钮
      // 下载按钮
      const download = CE('a');
      download.innerText = '下载音频';
      download.style = 'display: inline-block; width: 72px; margin: 0 75px 0 10px; text-align: left; color: var(--theme-color); font-size: 14px; text-decoration: none';
      download.href = audio.src;
      download.target = '_blank';
      const title = $('h1') && $('h1').innerText.trim();
      const fileName = audio.src.split('/').pop();
      const extName = fileName.split('.').pop();
      download.download = title ? `${title}.${extName}` : fileName;;
      panel.appendChild(download);
      // v0.3 循环播放
      // 循环播放复选框
      const loopLabel = CE('label');
      const loopBox = CE('input');
      const loopSpan = CE('span');
      loopLabel.style = 'margin: 0 10px; color: var(--theme-color); font-size: 14px';
      loopBox.type = 'checkbox';
      loopBox.style = 'display: inline-block; vertical-align: middle; margin-right: 4px; background: #fff; opacity: 0.15';
      loopSpan.style = 'display: inline-block; vertical-align: middle'
      loopSpan.innerText = '循环';
      loopLabel.appendChild(loopBox);
      loopLabel.appendChild(loopSpan);
      panel.insertBefore(loopLabel, panel.children[0]);
      // 切换循环播放时,使 audio.loop 生效
      loopBox.addEventListener('change', e => {
        audio.loop = e.target.checked;
        loopBox.style.opacity = e.target.checked ? 1 : 0.15;
      });
      // v0.4 二维码淡化
      const qrcode = $('main aside');
      if (qrcode) {
        qrcode.style.opacity = 0.08;
        qrcode.addEventListener('mouseenter', e => {
          e.target.style.opacity = 1;
        });
        qrcode.addEventListener('mouseleave', e => {
          e.target.style.opacity = 0.08;
        });
      }
      // v0.5 左右按键控制播放进度
      // 左右按键控制播放进度
      const btnLeft = $('.controls button[aria-label^="后退"]');
      const btnRight = $('.controls button[aria-label^="前进"]');
      document.addEventListener('keyup', e => {
        if (e.key === 'ArrowLeft') {
          btnLeft && btnLeft.click();
        } else if (e.key === 'ArrowRight') {
          btnRight && btnRight.click();
        }
      });
      // v0.6 调出单集列表页面隐藏着的播放面板
      if (/^\/podcast\//.test(location.pathname)) {
        $('section.wrap').style.transform = 'none';
        audio.onplay = () => {
          const rate = parseFloat(localStorage.getItem('xyzRate')) || 1;
          if (audio.playbackRate !== rate) audio.playbackRate = rate;
        };
      }
      // 解决在单集和列表之间切换时,功能失效的问题
      if (delay === 500) {
        history.pushState = () => init(150);
      }
      if ($('.podcast-title')) {
        $('.podcast-title').onclick = () => init(150);
      }
    })(500);
    
    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2764 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 14:23 · PVG 22:23 · LAX 06:23 · JFK 09:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.