ZenzaWatch 上級者用設定

ZenzaWatchの上級者向け設定。変更する時だけ有効にすればOK

目前为 2017-11-16 提交的版本。查看 最新版本

// ==UserScript==
// @name        ZenzaWatch 上級者用設定
// @namespace   https://github.com/segabito/
// @description ZenzaWatchの上級者向け設定。変更する時だけ有効にすればOK
// @include     http://www.nicovideo.jp/my/*
// @version     0.2.8
// @author      segabito macmoto
// @license     public domain
// @grant       none
// @noframes
// ==/UserScript==


(function() {

  var monkey = function(ZenzaWatch) {

    var _ = ZenzaWatch.lib._;
    var $ = ZenzaWatch.lib.$;

    var console;
    var debugMode = !true;
    var panel;

    var dummyConsole = {
      log: _.noop, error: _.noop, time: _.noop, timeEnd: _.noop, trace: _.noop
    };
    console = debugMode ? window.console : dummyConsole;
    var __tpl__ = (`
      <span class="openZenzaAdvancedSettingPanel"><span></span>ZenzaWatch上級者設定</span>
    `).trim();

    var __css__ = (`
      .userDetail .openZenzaAdvancedSettingPanel {
        display: inline-block;
        position: absolute;
        top: 40px;
        right: 8px;
        padding: 2px 8px;
        text-align: center;
        background: #fff;
        border: #ccc solid 1px;
        color: #0033cc;
        cursor: pointer;
      }

      .userDetail .openZenzaAdvancedSettingPanel:active {
        background: #ccc;
      }

      .openZenzaAdvancedSettingPanel span {
        display: inline-block;
        width: 10px;
        height: 8px;
        background: url(http://uni.res.nimg.jp/img/zero_my/icons.png) no-repeat;
        background-position: -8px -141px;
      }


      .summer2017Area {
        display: none !important;
      }
    `).trim();



    var SettingPanel = function() { this.initialize.apply(this, arguments); };
    SettingPanel.__css__ = (`
      .zenzaAdvancedSettingPanel {
        position: fixed;
        left: 50%;
        top: -100vh;
        pointer-events: none;
        transform: translate(-50%, -50%);
        z-index: 200000;
        width: 90vw;
        height: 90vh;
        color: #000;
        background: rgba(192, 192, 192, 0.95);
        transition: top 0.4s ease;
        user-select: none;
        -webkit-user-select: none;
        -moz-user-select: none;
        overflow-y: hidden;
      }
      .zenzaAdvancedSettingPanel.show {
        opacity: 1;
        top: 50%;
        overflow-y: scroll;
        overflow-x: hidden;
      }

      .zenzaAdvancedSettingPanel.show {
        border: 2px outset #fff;
        box-shadow: 6px 6px 6px rgba(0, 0, 0, 0.5);
        pointer-events: auto;
      }

      .zenzaAdvancedSettingPanel .settingPanelInner {
        box-sizing: border-box;
        margin: 16px;
        overflow: visible;
      }
      .zenzaAdvancedSettingPanel .caption {
        background: #333;
        font-size: 20px;
        padding: 4px 8px;
        color: #fff;
      }

      .zenzaAdvancedSettingPanel .caption.sub {
        margin: 8px;
        font-size: 16px;
      }

      .zenzaAdvancedSettingPanel .example {
        display: inline-block;
        margin: 0 16px;
        font-family: sans-serif;
      }

      .zenzaAdvancedSettingPanel label {
        display: inline-block;
        box-sizing: border-box;
        width: 100%;
        padding: 4px 8px;
        cursor: pointer;
      }

      .zenzaAdvancedSettingPanel .control {
        border-radius: 4px;
        background: rgba(88, 88, 88, 0.3);
        padding: 8px;
        margin: 16px 4px;
      }

      .zenzaAdvancedSettingPanel .control:hover {
        border-color: #ff9;
      }

      .zenzaAdvancedSettingPanel button {
        font-size: 10pt;
        padding: 4px 8px;
        background: #888;
        border-radius: 4px;
        border: solid 1px;
        cursor: pointer;
      }

      .zenzaAdvancedSettingPanel input[type=checkbox] {
        transform: scale(2);
        margin-left: 8px;
        margin-right: 16px;
      }

      .zenzaAdvancedSettingPanel .control.checked {
      }

      .zenzaAdvancedSettingPanel input[type=text] {
        font-size: 24px;
        background: #ccc;
        color: #000;
        width: 90%;
        margin: 0 5%;
        padding: 8px;
        border-radius: 8px;
      }
      .zenzaAdvancedSettingPanel input[type=text].update {
        color: #003;
        background: #fff;
        box-shadow: 0 0 8px #ff9;
      }
      .zenzaAdvancedSettingPanel input[type=text].update:before {
        content: 'ok';
        position: absolute;
        left: 0;
        z-index: 100;
        color: blue;
      }

      .zenzaAdvancedSettingPanel input[type=text].error {
        color: #300;
        background: #f00;
      }

      .zenzaAdvancedSettingPanel select {
        font-size:24px;
        margin: 0 5%;
        border-radius: 8px;
       }

      .zenzaAdvancedSetting-close {
        width: 50%;
        z-index: 160000;
        margin: 16px auto;
        padding: 8px 16px;
        cursor: pointer;
        box-sizing: border-box;
        text-align: center;
        line-height: 30px;
        font-size: 24px;
        border: outset 2px;
        box-shadow: 0 0 4px #000;
        transition:
          opacity 0.4s ease,
          transform 0.2s ease,
          background 0.2s ease,
          box-shadow 0.2s ease
            ;
        pointer-events: auto;
        transform-origin: center center;
      }

      .textAreaInput {
        width: 90%;
        height: 200px;
        margin: 0 5%;
        word-break: break-all;
        overflow: scroll;
      }

      .zenzaAdvancedSetting-rawData,
      .zenzaAdvancedSetting-playlistData {
        width: 90%;
        height: 300px;
        margin: 0 5%;
        word-break: break-all;
        overflow: scroll;
      }

      .zenzaAdvancedSetting-close:active {
        box-shadow: none;
        border: inset 2px;
        transform: scale(0.8);
      }

      .zenzaAdvancedSettingPanel:not(.debug) .debugOnly {
        display: none !important;
      }


      .example code {
        font-family: monospace;
        display: inline-block;
        margin: 4px;
        padding: 4px 8px;
        background: #333;
        color: #fe8;
        border-radius: 4px;
      }

    `).trim();

    const commands = (`
      <option value="">なし</option>
      <option value="togglePlay">再生/停止</option>
      <option value="fullScreen">フルスクリーン ON/OFF</option>
      <option value="toggle-mute">ミュート ON/OFF</option>
      <option value="toggle-showComment">コメント表示 ON/OFF</option>
      <option value="toggle-backComment">コメントの背面表示 ON/OFF</option>
      <option value="toggle-loop">ループ ON/OFF</option>
      <option value="toggle-enableFilter">NG設定 ON/OFF</option>
      <option value="screenShot">スクリーンショット</option>
      <option value="deflistAdd">とりあえずマイリスト</option>
    `).trim();

    SettingPanel.__tpl__ = (`
      <div class="zenzaAdvancedSettingPanel">
        <div class="settingPanelInner">
          <div class="enableFullScreenOnDoubleClickControl control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="enableFullScreenOnDoubleClick">
              画面ダブルクリックでフルスクリーン切り換え
            </label>
          </div>

          <div class="autoCloseFullScreenControl control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="autoCloseFullScreen">
              再生終了時に自動でフルスクリーン解除

            </label>
          </div>

          <div class="continueNextPageControl control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="continueNextPage">
              再生中にページを切り換えても続きから再開する
            </label>
          </div>

          <div class="enableDblclickClose control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="enableDblclickClose">
              背景のダブルクリックでプレイヤーを閉じる
            </label>
          </div>

          <div class="autoDisableDmc control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="autoDisableDmc">
              旧システムのほうが画質が良さそうな時は旧システムにする。(旧システム側が1280x720を超える時)
            </label>
          </div>

          <div class="autoZenTube control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="autoZenTube">
              自動ZenTube (ZenTubeから戻す時は動画を右クリックからリロード)
            </label>
          </div>


          <div class="enableSlotLayoutEmulation control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="commentLayer.enableSlotLayoutEmulation">
              Flash版のコメントスロット処理をエミュレーションする
            </label>
          </div>

          <div class="touch-tap2command control toggle">
            <label>
              2本指タッチ
              <select data-setting-name="touch.tap2command">
                ${commands}
              </select>
            </label>
          </div>

          <div class="touch-tap3command control toggle">
            <label>
              3本指タッチ
              <select data-setting-name="touch.tap3command">
                ${commands}
              </select>
            </label>
          </div>

          <div class="touch-tap3command control toggle">
            <label>
              4本指タッチ
              <select data-setting-name="touch.tap4command">
                ${commands}
              </select>
            </label>
          </div>

          <div class="touch-tap5command control toggle">
            <label>
              5本指タッチ
              <select data-setting-name="touch.tap5command">
                ${commands}
              </select>
            </label>
          </div>


          <p class="caption sub">NGワード正規表現</p>
          <span class="example">入力例: <code>([wWwW]+$|^ん[?\?]$|洗った?$)</code> 文法エラーがある時は更新されません</span>
          <input type="text" class="textInput wordRegFilterInput"
            data-setting-name="wordRegFilter">

          <p class="caption sub">NGワード正規表現フラグ</p>
          <span class="example">入力例: <code>i</code></span>
          <input type="text" class="textInput wordRegFilterFlagsInput"
            data-setting-name="wordRegFilterFlags">

          <p class="caption sub">NG tag</p>
          <span class="example">連続再生中にこのタグのある動画があったらスキップ</span>
          <textarea class="videoTagFilter textAreaInput"
            data-setting-name="videoTagFilter"></textarea>

          <p class="caption sub">NG owner</p>
          <span class="example">連続再生中にこの投稿者IDがあったらスキップ。 チャンネルの場合はchをつける 数字の後に 入力例<code>2525 #コメント</code></span>
          <textarea class="videoOwnerFilter textAreaInput"
            data-setting-name="videoOwnerFilter"></textarea>

          <div class="debugControl control toggle">
            <label>
              <input type="checkbox" class="checkbox" data-setting-name="debug">
              デバッグモード
            </label>
          </div>

          <div class="debugOnly">
            <p class="caption sub">生データ(ZenzaWatch設定)</p>
            <span class="example">丸ごとコピペで保存/復元可能。 ここを消すと設定がリセットされます。</span>
            <textarea class="zenzaAdvancedSetting-rawData"></textarea>

            <p class="caption sub">生データ(プレイリスト)</p>
            <span class="example">丸ごとコピペで保存/復元可能。 編集は自己責任で</span>
            <textarea class="zenzaAdvancedSetting-playlistData"></textarea>

          </div>

          <div class="zenzaAdvancedSetting-close">閉じる</div>

        </div>
      </div>
    `).trim();

    _.assign(SettingPanel.prototype, {
      initialize: function(params) {
        this._playerConfig     = params.playerConfig;
        this._$container       = params.$container;

        this._update$rawData = _.debounce(this._update$rawData.bind(this), 500);
        this._playerConfig.on('update', this._onPlayerConfigUpdate.bind(this));
        this._initializeDom();
      },
      _initializeDom: function() {
        var $container = this._$container;
        var config = this._playerConfig;

        ZenzaWatch.util.addStyle(SettingPanel.__css__);
        $container.append(SettingPanel.__tpl__);

        var $panel = this._$panel = $container.find('.zenzaAdvancedSettingPanel');
        this._$view =
          $container.find('.zenzaAdvancedSettingPanel');
        this._$view.on('click', function(e) {
          e.stopPropagation();
        });
        this._$view.on('wheel', function(e) {
          e.stopPropagation();
        });

        this._$rawData = $panel.find('.zenzaAdvancedSetting-rawData');
        this._$rawData.val(JSON.stringify(config.exportConfig()));
        this._$rawData.on('change', function() {
          var val = this._$rawData.val();
          var data;
          if (val === '') { val = '{}'; }

          try {
            data = JSON.parse(val);
          } catch (e) {
            alert(e);
            return;
          }

          if (confirm('設定データを直接書き換えしますか?')) {
            config.clearConfig();
            config.importConfig(data);
            location.reload();
          }

        }.bind(this));

        this._$playlistData = $panel.find('.zenzaAdvancedSetting-playlistData');
        this._$playlistData.val(JSON.stringify(ZenzaWatch.external.playlist.export()));
        this._$playlistData.on('change', function() {
          var val = this._$playlistData.val();
          var data;
          if (val === '') { val = '{}'; }

          try {
            data = JSON.parse(val);
          } catch (e) {
            alert(e);
            return;
          }

          if (confirm('プレイリストデータを直接書き換えしますか?')) {
            ZenzaWatch.external.playlist.import(data);
            location.reload();
          }

        }.bind(this));

        var onInputItemChange = this._onInputItemChange.bind(this);
        var $check = $panel.find('input[type=checkbox]');
        $check.each(function(i, check) {
          var $c = $(check);
          var settingName = $c.attr('data-setting-name');
          var val = config.getValue(settingName);
          $c.prop('checked', val);
          $c.closest('.control').toggleClass('checked', val);
        });
        $check.on('change', this._onToggleItemChange.bind(this));

        var $text = $panel.find('input[type=text]');
        $text.each(function(i, text) {
          var $t = $(text);
          var settingName = $t.attr('data-setting-name');
          var val = config.getValue(settingName);
          $t.val(val);
        });
        $text.on('change', onInputItemChange);

        var $select = $panel.find('select');
        $select.each(function(i, select) {
          var $s = $(select);
          var settingName = $s.attr('data-setting-name');
          var val = config.getValue(settingName);
          $s.val(val);
        });
        $select.on('change', onInputItemChange);

        var $textarea = $panel.find('.textAreaInput');
        $textarea.each(function(i, textarea) {
          var $t = $(textarea);
          var settingName = $t.attr('data-setting-name');
          var val = config.getValue(settingName);
          $t.val(val);
        });
        $textarea.on('change', onInputItemChange);


        $panel.find('.zenzaAdvancedSetting-close').on('mousedown', function(e) {
          e.stopPropagation();
          this.hide();
        }.bind(this));

        $panel.toggleClass('debug', config.getValue('debug'));

        //ZenzaWatch.emitter.on('hideHover', _.bind(function() {
        //  this.hide();
        //}, this));

      },
      _onPlayerConfigUpdate: function(key, value) {
        switch (key) {
          case 'debug':
            this._$panel.toggleClass('debug', value);
            break;
          case 'wordRegFilter':
          case 'wordRegFilterFlags':
            this._$panel.find('.' + key + 'Input').val(value);
            break;
          case 'enableFullScreenOnDoubleClick':
          case 'autoCloseFullScreen':
          case 'continueNextPage':
            this._$panel
              .find('.' + key + 'Control').toggleClass('checked', value)
              .find('input[type=checkbox]').prop('checked', value);
            break;
        }
        this._update$rawData();
      },
      _update$rawData: function() {
        this._$rawData.val(JSON.stringify(this._playerConfig.exportConfig()));
      },
      _onToggleItemChange: function(e) {
        var $target = $(e.target);
        var settingName = $target.attr('data-setting-name');
        var val = !!$target.prop('checked');

        this._playerConfig.setValue(settingName, val);
        $target.closest('.control').toggleClass('checked', val);
      },
      _onInputItemChange: function(e) {
        var $target = $(e.target);
        var settingName = $target.attr('data-setting-name');
        var val = $target.val();

        window.setTimeout(function() {
          $target.removeClass('update error');
        }, 300);

        window.console.log('onInputItemChange', settingName, val);
        var reg;
        switch (settingName) {
          case 'wordRegFilter':
            try {
              reg = new RegExp(val);
              $target.addClass('update');
            } catch(err) {
              $target.addClass('error');
              //alert('正規表現にエラーがあります');
              return;
            }
            break;
          case 'wordRegFilterFlags':
            try {
              reg = new RegExp('', val);
              $target.addClass('update');
            } catch(err) {
              $target.addClass('error');
              //alert('正規表現にエラーがあります');
              return;
            }
            break;
          default:
            $target.addClass('update');
            break;
        }

        this._playerConfig.setValue(settingName, val);
      },
      _beforeShow: function() {
        if (this._$playlistData) {
          this._$playlistData.val(
            JSON.stringify(ZenzaWatch.external.playlist.export())
          );
        }
      },
      toggle: function(v) {
        ZenzaWatch.external.execCommand('close');
        this._$view.toggleClass('show', v);
        if (this._$view.hasClass('show')) { this._beforeShow(); }
      },
      show: function() {
        this.toggle(true);
      },
      hide: function() {
        this.toggle(false);
      }
    });


    var initializePanel = function() {
      initializePanel = _.noop;
      panel = new SettingPanel({
        playerConfig: ZenzaWatch.config,
        $container: $('body')
      });
    };

    var initialize = function() {
      var $button = $(__tpl__);
      ZenzaWatch.util.addStyle(__css__);

      $('.accountEdit').after($button);
      $button.on('click', function() {
        initializePanel();
        panel.toggle();
      });

    };

    initialize();
  };

  var loadMonkey = function() {
    var script = document.createElement('script');
    script.id = 'ZenzaWatchAdvancedSettingsLoader';
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('charset', 'UTF-8');
    script.appendChild(document.createTextNode('(' + monkey + ')(window.ZenzaWatch);'));
    document.body.appendChild(script);
  };

  var waitForZenzaWatch = function() {
    if (window.ZenzaWatch && window.ZenzaWatch.ready) {
      window.console.log('ZenzaWatch is Ready');
      loadMonkey();
    } else {
      document.body.addEventListener('ZenzaWatchInitialize', function() {
        window.console.log('onZenzaWatchReady');
        loadMonkey();
      });
    }
  };
  waitForZenzaWatch();

})();