Greasy Fork

Greasy Fork is available in English.

AbemaTV Shortcut Key Controller

AbemaTVでショートカットキーによる操作を可能にします。キーアサインはYouTube準拠。

当前为 2017-10-29 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        AbemaTV Shortcut Key Controller
// @namespace   knoa.jp
// @description AbemaTVでショートカットキーによる操作を可能にします。キーアサインはYouTube準拠。
// @include     https://abema.tv/*
// @version     2.0.4
// @grant       none
// ==/UserScript==
/*
共通:
[F]: フルスクリーン
[M]: ミュート
[マウスホイール]: 音量調整

リアルタイム放送:
[K], [Space], [Enter]: コメント入力欄フォーカス
[C]: コメント表示

タイムシフト放送:
[K], [Space], [Enter]: 再生・停止
[J], [←]: 10秒戻る
[L], [→]: 10秒進む
*/

// console.log('AbemaTV? => hireMe()');
(function(){
  const SCRIPTNAME = 'ShortcutKeyController';
  const DEBUG = false;/*
  [update]
  バグ修正
  */
  if(window === top) console.time(SCRIPTNAME);
  let site = {
    elements: {
      /* 共通 */
      fullscreenButton: function(){return $('use[*|href*="_screen.svg"]'/*タイムシフトのbuttonにaria-labelがないので*/).parentNode.parentNode},
      volumeSlider: function(){return $('button[aria-label="音声オンオフ切り替え"]').previousSibling.firstElementChild.firstElementChild},
      muteButton: function(){return $('button[aria-label="音声オンオフ切り替え"]')},
      /* リアルタイム */
      commentButton: function(){return $('use[*|href^="/images/icons/comment.svg"]').parentNode.parentNode},
      commentTextarea: function(){return $('textarea[placeholder="コメントを入力"]')},
      footer: function(){return $('button[aria-label^="フルスクリーン"]').parentNode.parentNode},
      closer: function(){return $('form:not([role="search"])').parentNode.parentNode.nextElementSibling;},
      /* タイムシフト */
      playButton: function(){return $((getComputedStyle($('use[*|href^="/images/icons/pause.svg"]')).cursor === 'pointer') ? 'use[*|href^="/images/icons/pause.svg"]' : 'use[*|href^="/images/icons/playback.svg"]').parentNode.parentNode},
      rewindButton: function(){return $('use[*|href^="/images/icons/rewind_10.svg"]').parentNode.parentNode},
      advancesButton: function(){return $('use[*|href^="/images/icons/advances_10.svg"]').parentNode.parentNode},
    },
    isCommentPaneHidden: function(){
      let form = $('form:not([role="search"])');
      return (form) ? (form.parentNode.parentNode.getAttribute('aria-hidden') === 'true') : false;
    },
    modifyVolume: function(e){
      let slider = site.elements.volumeSlider(), rect = slider.getBoundingClientRect();
      let volume = parseInt(slider.firstElementChild.style.height) / rect.height;
      switch(e.deltaMode){
        case(WheelEvent.DOM_DELTA_PIXEL):
          volume += -(e.deltaY/1000);
          break;
        case(WheelEvent.DOM_DELTA_LINE):
        default:
          volume += (0 < e.deltaY) ? -(1/10) : (1/10);
          break;
      }
      slider.dispatchEvent(new MouseEvent('mousedown', {
        clientX: rect.x + (rect.width/2),
        clientY: rect.y + (rect.height * (1 - volume)),
        bubbles: true,
      }));
    },
    assign: function(e){
      switch(true){
        case(location.href.startsWith('https://abema.tv/now-on-air/')):
          return core.realtime(e);
        case(location.href.startsWith('https://abema.tv/channels/')):
        case(location.href.startsWith('https://abema.tv/video/watch/')):
          return core.timeshift(e);
      }
    },
  };
  let core = {
    initialize: function(){
      window.addEventListener('wheel', site.assign, true);
      window.addEventListener('keydown', site.assign, true);
    },
    /* リアルタイム */
    realtime: function(e){
      switch(true){
        /* 音量 */
        case(e.type === 'wheel'):
          /* あらゆる場所でのイベントを拾ってwindow.addEventListenerで一括処理する代償をここで支払う */
          for(let target = e.target; target; target = target.parentNode){
            if([site.elements.closer(), site.elements.footer()].includes(target)){
              site.modifyVolume(e);
              return e.preventDefault();
            }
          }
        /* テキスト入力中は反応しない */
        case(['input', 'textarea', 'button'].includes(document.activeElement.localName)):
          break;
        /* Alt/Shift/Ctrl/Metaキーが押されていたら反応しない */
        case(e.altKey || e.shiftKey || e.ctrlKey || e.metaKey):
          break;
        /* コメント入力欄フォーカス */
        case(e.key == 'k'):
        case(e.key == ' '):
        case(e.key == 'Enter'):
          /* コメント欄が表示されていなければあらかじめ表示しておく */
          if(site.isCommentPaneHidden()) site.elements.commentButton().click();
          site.elements.commentTextarea().focus();
          return e.preventDefault();
        /* コメント */
        case(e.key == 'c'):
          if(site.isCommentPaneHidden()) site.elements.commentButton().click();
          else site.elements.closer().click();
          return e.preventDefault();
        /* フルスクリーン */
        case(e.key == 'f'):
          site.elements.fullscreenButton().click();
          return e.preventDefault();
        /* ミュート */
        case(e.key == 'm'):
          site.elements.muteButton().click();
          return e.preventDefault();
      }
    },
    /* タイムシフト */
    timeshift: function(e){
      switch(true){
        /* 音量 */
        case(e.type === 'wheel'):
          site.modifyVolume(e);
          return e.preventDefault();
        /* テキスト入力中は反応しない */
        case(['input', 'textarea', 'button'].includes(document.activeElement.localName)):
          break;
        /* Alt/Shift/Ctrl/Metaキーが押されていたら反応しない */
        case(e.altKey || e.shiftKey || e.ctrlKey || e.metaKey):
          break;
        /* 再生・停止トグル */
        case(e.key == 'k'):
        case(e.key == ' '):
        case(e.key == 'Enter'):
          site.elements.playButton().click();
          return e.preventDefault();
        /* 10秒戻る */
        case(e.key == 'j'):
        case(e.key == 'ArrowLeft'):
          site.elements.rewindButton().click();
          return e.preventDefault();
        /* 10秒進む */
        case(e.key == 'l'):
        case(e.key == 'ArrowRight'):
          site.elements.advancesButton().click();
          return e.preventDefault();
        /* フルスクリーン */
        case(e.key == 'f'):
          site.elements.fullscreenButton().click();
          return e.preventDefault();
        /* ミュート */
        case(e.key == 'm'):
          site.elements.muteButton().click();
          return e.preventDefault();
      }
    },
  };
  let $ = function(s){return document.querySelector(s)};
  let log = (DEBUG) ? console.log.bind(null, SCRIPTNAME + ':') : function(){};
  core.initialize();
  if(window === top) console.timeEnd(SCRIPTNAME);
})();