Greasy Fork

Greasy Fork is available in English.

清水河畔音视频播放

通过 HTML5 多媒体功能播放帖子中上传的音视频附件。

目前为 2022-08-25 提交的版本,查看 最新版本

// ==UserScript==
// @name 清水河畔音视频播放
// @namespace bbs.uestc.edu.cn
// @license MIT
// @author ____
// @version 0.3.2
// @description 通过 HTML5 多媒体功能播放帖子中上传的音视频附件。
// @match *://bbs.uestc.edu.cn/forum.php*
// @connect b23.tv
// @connect  bilibili.com
// @grant GM_xmlhttpRequest
// @run-at document-end
// ==/UserScript==

function makeAv(container, a, kind) {
  let media = document.createElement(kind);
  media.controls = true;
  media.src = a.href;
  media.style.maxWidth = '100%';
  media.style.maxHeight = '80vh';
  media.style.display = 'block';
  media.style.margin = '0.5em auto';
  a.outerHTML = media.outerHTML;
  let outer = container.querySelector('dl.tattl');
  if (outer) {
    outer.style.width = 'auto';
    outer.style.height = 'auto';
  }
  let outer2 = container.querySelector('p.attnm');
  if (outer2) {
    outer2.style.height = 'auto';
  }
  let icon = container.querySelector('dl.tattl > dt');
  if (icon) {
    icon.style.display = 'none';
  }
}

[].forEach.call(document.querySelectorAll('#postlist ignore_js_op, .postlist .plc.cl .box.attach, .wp .vt .pbody .box.attach'), el => {
  let a = el.querySelector('a');
  if (a.href.match(/https?:\/\/.*?forum\.php\?mod=attachment&/)) {
    let fileName = a.textContent.trim();
    if (fileName.match(/\.(?:mp4|flv)/i)) {
      makeAv(el, a, 'video');
    } else if (fileName.match(/\.(?:mp3)/i)) {
      makeAv(el, a, 'audio');
    }
  }
});

function getRedirectUrl(url) {
  return new Promise(resolve => {
    if (window.GM_xmlhttpRequest) {
      GM_xmlhttpRequest({
        method: 'HEAD',
        url,
        onload: r => resolve(r.finalUrl),
      })
    } else {
      chrome.runtime.sendMessage({request: 'getRedirectUrl', url}).then(r => r && r.url && resolve(r.url));
    }
  });
}

function createIframe(src, extra) {
  let isPc = !!document.querySelector('#postlist');
  let el = document.createElement('iframe');
  el.style.display = 'block';
  el.style.width = isPc ? '80%' : '100%';
  el.style.aspectRatio = '16 / 9'
  el.style.margin = '0.5em auto';
  el.allowFullscreen = true;
  if (extra && extra.allow) {
    el.allow = extra.allow;
  }
  el.src = src;
  return el;
}

function makeBvPlayer(bv) {
  return createIframe(`https://player.bilibili.com/player.html?bvid=${encodeURIComponent(bv)}`);
}

function makeBilibiliLivePlayer(id) {
  return createIframe(`https://www.bilibili.com/blackboard/live/live-activity-player.html?cid=${id}&quality=0`, {
    allow: 'encrypted-media',
  });
}

const externalAvHandlers = [
  {
    regex: /https?:\/\/b23\.tv\/([^/?]+)/i,
    handler: url => getRedirectUrl(url).then(url => matchHandlers(url)),
  },
  {
    regex: /https?:\/\/(?:www|m)\.bilibili\.com\/video\/(BV[^/?]+)/i,
    handler: (url, match) => Promise.resolve(makeBvPlayer(match[1])),
  },
  {
    regex: /https?:\/\/live\.bilibili\.com\/([0-9]+)/i,
    handler: (_, match) => Promise.resolve(makeBilibiliLivePlayer(match[1])),
  },
];

function matchHandlers(url, extra) {
  for (let {regex, handler} of externalAvHandlers) {
    let match = url.match(regex);
    if (match) {
      return handler(url, match);
    }
  }
  return Promise.reject();
}

[].forEach.call(document.querySelectorAll('#postlist table.plhin .t_fsz table a, .postlist .plc.cl .message a, .wp .vt .bm .pbody .postmessage a'), a => {
  matchHandlers(a.href).then(el => {
    let e = a.insertAdjacentElement('afterend', document.createElement('br'));
    e = e.insertAdjacentElement('afterend', el);
    e = e.insertAdjacentElement('afterend', document.createElement('br'));
  });
});