Comment Render Smoother

公式HTML5プレイヤーのコメントの動きをなめらかにする(主にFirefox)

目前为 2019-02-03 提交的版本,查看 最新版本

// ==UserScript==
// @name           Comment Render Smoother
// @description    公式HTML5プレイヤーのコメントの動きをなめらかにする(主にFirefox)
// @match          *://www.nicovideo.jp/watch/*
// @grant          none
// @author         anonymous 
// @license        public domain
// @version        0.0.1
// @noframes
// @namespace https://greasyfork.org/users/218
// ==/UserScript==

const monkey = (() => {

  const SEC_PER_FRAME_MS = 1000 / 60;

  const toFrameTime = (time) => { //return time; // こっちは体感しづらいかも
    const timeMs = time * 1000;
    const currentFrame = Math.ceil(timeMs / SEC_PER_FRAME_MS);
    return currentFrame * SEC_PER_FRAME_MS / 1000;
  };

  const init = () => {
    if (!window.__videoplayer) { return; }
    console.log('%cinitialize Comment Render Smoother', 'background: cyan;');
    const player = window.__videoplayer;
    const _currentTime = player.currentTime.bind(player);
    let worldTime = performance.now();
    let lastVideoTime = _currentTime();
    let stallCount = 0;

    player.currentTime = (time) => {
      const now = performance.now();
      if (typeof time === 'number') {
        lastVideoTime = time;
        worldTime = now;
        return _currentTime(time);
      }


      const isPlaying = !player.paused();
      const videoTime = _currentTime();
      const playbackRate = 1.0; // 簡略化のために 1.0 固定

      if (isPlaying && lastVideoTime === videoTime) {
        stallCount ++;
      } else {
        stallCount = 0;
      }

      stallCount = 0;
      if (
        !isPlaying ||                     // 再生してない or
        lastVideoTime > videoTime ||      // 時間が戻った ≒ シークした or
        videoTime - lastVideoTime > 1 ||  // いきなり1秒以上も進んだ ≒ シークした or
        stallCount > 5                    // 詰まってんじゃねーの?  の時
      ) {
        lastVideoTime = videoTime;
        worldTime = now;

        return videoTime;
      } else {
        const timeDiff = (now - worldTime) * playbackRate / 1000;
        return toFrameTime(lastVideoTime + timeDiff);
      }
    };
    player.play();
  };

  // TODO: なんかプレイヤー初期化のタイミングでやる
  setTimeout(init, 5000);

});

if (document.querySelector('#js-app')) {
  const script = document.createElement('script');
  script.setAttribute('type', 'text/javascript');
  script.setAttribute('charset', 'UTF-8');
  script.appendChild(document.createTextNode(`(${monkey})();`));
  document.body.appendChild(script);
}