Greasy Fork

Greasy Fork is available in English.

AbemaTV Auto Reload

AbemaTV(HTML5版)を閲覧中に動画が止まったとき、チャンネルを切り替えて動画を再読み込みします。

目前为 2016-12-11 提交的版本,查看 最新版本

// ==UserScript==
// @name         AbemaTV Auto Reload
// @namespace    http://greasyfork.icu/ja/scripts/25598
// @version      2
// @description  AbemaTV(HTML5版)を閲覧中に動画が止まったとき、チャンネルを切り替えて動画を再読み込みします。
// @include      https://abema.tv/now-on-air/*
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  function log(s, t) {
    if (ls.debug) {
      if (t) console[t]('AutoReload', s);
      else console.log('AutoReload', s);
    }
  }

  function logV(s, t) {
    if (ls.debug) {
      try {
        var v = returnVideo('logV');
        if (v) {
          var a = [v.readyState, v.networkState, v.played.length, v.currentTime, v.id.slice(v.id.indexOf('-') + 1), { 'duration': v.duration, 'seeking': v.seeking, 'preload': v.preload, 'ended': v.ended, 'srcLength': v.src.length }, Object.assign({}, flag)];
          if (Array.isArray(s)) {
            for (var i = 0, j = s.length; i < j; i++) {
              a.unshift(s[i]);
            }
          } else a.unshift(s);
          if (v.paused) a.push('paused');
          if (v.error) a.push('error', v.error.code);
          log(a, t);
        } else log(['logV not found Video', s], 'warn');
      } catch (error) { log(['logV error', s, error], 'error'); }
    }
  }

  //デスクトップ通知
  function notify(a, t, s) {
    var title = 'AbemaTV Auto Reload',
      message = a,
      notifi;
    log(['notify', a], t);
    if ('Notification' in window) {
      if (Notification.permission === 'granted') {
        notifi = new Notification(title, { body: message });
      } else if (Notification.permission !== 'denied') {
        Notification.requestPermission(function(permission) {
          if (permission === 'granted') {
            notifi = new Notification(title, { body: message });
          }
        });
      }
      if (notifi) setTimeout(notifi.close.bind(notifi), s ? s : 3000);
    } else alert(title + '\n\n' + message);
  }

  //HTML5動画の要素を返す
  function returnVideo(s) {
    var e = document.getElementsByTagName('video') || null,
      v;
    if (!e) log(['returnVideo error', s], 'debug');
    else {
      var len = e.length;
      v = e[0];
      if (len > 1) {
        for (var i = 0; i < len; i++) {
          if (e[i].id && /^videoplayer/.test(e[i].id)) {
            v = e[i];
            break;
          }
        }
      }
    }
    return v;
  }

  //左下のチャンネルロゴ画像の要素を返す
  function returnChLogo(s) {
    var e = document.querySelector('div[class*="styles__channel-logo"] > img');
    if (s) {
      if (e) {
        chId = e.getAttribute('alt');
        log(['chId', chId]);
      } else log('returnChLogo error', 'error');
    }
    return e;
  }

  //動画のチャンネルを切り替えて読み直す
  function reloadVideo(s) {
    logV(['reloadVideo', s], 'warn');
    if (!flag.reload && !document.hidden) {
      flag.reload = true;
      flag.loadstart = false;
      if (flag.countReload > 3) {
        flag.countReload = 0;
        reloadPage();
      } else {
        flag.countReload++;
        eNext.click();
      }
    }
  }

  //ページを再読み込みする
  function reloadPage() {
    notify('ページを再読み込みします!');
    if (flag.reload) {
      setTimeout(function() {
        location.reload();
      }, 500);
    } else location.reload();
  }

  //動画が切り替わったかを調べる
  function checkChangeV(a) {
    logV('checkChangeV');
    var e = returnVideo('checkChangeV');
    if (!flag.change1 && !e) {
      log(['checkChangeV1', a]);
      flag.change1 = true;
      setTimeout(function() {
        flag.change1 = false;
        checkChangeV('checkChangeV');
      }, 550);
    } else if (!flag.change2 && e && (!eV || e.id !== eV.id)) {
      log(['checkChangeV2', a]);
      flag.change2 = true;
      setTimeout(function() {
        addEventVideo('checkChangeV');
        flag.change2 = false;
      }, 1000);
    } else {
      log(['checkChangeV3', a]);
      checkPlayingVideo(e.currentTime, 'checkChangeV3');
    }
  }

  //動画の停止&エラープロパティがtrueになっているかを調べる
  function checkPausedErrorVideo(s) {
    if (!flag.checkPausedErrorVideo) logV(['checkPausedErrorVideo', s]);
    if (!flag.reload && eV.paused && eV.error) reloadVideo('checkPausedErrorVideo');
    else if (!flag.checkPausedErrorVideo) {
      flag.checkPausedErrorVideo = true;
      checkChangeV('checkPausedErrorVideo');
      setTimeout(function() {
        flag.checkPausedErrorVideo = false;
      }, 1500);
    }
  }

  //動画が実際に再生中なのかを調べる
  function checkPlayingVideo(o, s) {
    setTimeout(function() {
      var now = eV.currentTime;
      log([s, 'time', o, now]);
      if (!now || now === o) reloadVideo(s);
    }, 500);
  }

  //動画の取得中にエラーが発生したとき
  function videoError() {
    logV('videoError');
    if (flag.reload !== undefined && flag.reload === false && eV.error) {
      var old = eV.currentTime;
      if (!old) reloadVideo('videoError');
      else checkPlayingVideo(old, 'videoError');
    } else checkPausedErrorVideo('videoError');
  }

  //動画をこれから読み込むとき
  function videoLoadstart() {
    logV('videoLoadstart');
    if (!flag.loadstart && eV.readyState < 3 || eV.networkState !== 2) {
      flag.loadstart = true;
      checkPausedErrorVideo('videoLoadstart');
      setTimeout(function() {
        try {
          if (!eV) checkChangeV('videoLoadstart');
          else if (!eV.paused && !eV.played.length) reloadVideo('videoLoadstart');
          else if (flag.loadstart && eV.readyState === 2 && eV.networkState === 2) reloadVideo('videoLoadstart');
          else checkPausedErrorVideo('videoLoadstart');
        } catch (error) { logV(['videoLoadstart error', error, eV], 'error'); }
        flag.loadstart = false;
      }, 10000);
    }
  }

  //動画を一時停止したとき
  function videoPause() { checkPausedErrorVideo('videoPause'); }

  //動画を再生し始めたときや再生中にソースが切り替わったとき
  function videoPlaying() {
    logV('videoPlaying');
    if (flag.countReload) flag.countReload = 0;
  }

  //動画を取得できなかったときや取得し終えたとき
  function videoStalled() {
    logV('videoStalled');
    if (eV && (eV.readyState < 3 || eV.networkState !== 2)) {
      logV('videoStalled');
      if (eV.readyState <= 1) {
        if (!eV || !eV.hasOwnProperty('readyState') || !eV.hasOwnProperty('networkState')) {
          reloadVideo('videoStalled');
          return;
        }
        var old = eV.currentTime;
        if (!old) reloadVideo('videoStalled');
        else checkPlayingVideo(old, 'videoStalled');
      } else checkPausedErrorVideo('videoStalled');
    }
  }

  //動画の読み込みを待っているとき
  function videoWaiting() {
    logV('videoWaiting');
    var old = eV.currentTime;
    if (!old) reloadVideo('videoWaiting');
    else checkPlayingVideo(old, 'videoWaiting');
  }

  //動画を再生できるがキャッシュが足りないとき
  function videoCanplay() { logV('videoCanplay'); }
  //動画を再生できてキャッシュも足りるとき
  function videoCanplaythrough() { logV('videoCanplaythrough'); }
  //動画の長さが変更されたとき
  function videoDurationchange() {
    if (eV.readyState < 3 || eV.networkState !== 2) logV('videoDurationchange');
  }
  //動画が空になったとき
  function videoEmpied() { logV('videoEmpied'); }
  //動画を最後まで再生したとき
  function videoEnded() { logV('videoEnded'); }
  //動画のメタ情報を読み込んだとき
  function videoLoadedmetadata() { logV('videoLoadedmetadata'); }
  //動画を再生できる状態になったとき
  function videoLoadeddata() { logV('videoLoadeddata'); }
  //動画を(手動操作で)再生し始めたとき
  function videoPlay() { logV('videoPlay'); }
  //動画を取得しているとき
  function videoProgress() { logV('videoProgress'); }
  //動画をシークし終えたとき
  function videoSeeked() { logV('videoSeeked'); }
  //動画をシークし始めたとき
  function videoSeeking() { logV('videoSeeking'); }
  //動画の取得を取りやめたとき
  function videoSuspend() { logV('videoSuspend'); }
  //動画の再生位置が更新されたとき
  function videoTimeupdate() {
    if (eV.readyState < 3 || eV.networkState !== 2) logV('videoTimeupdate');
  }

  //ページが見えている状態かを調べる
  function checkPageVisibility() {
    var h = document.hidden;
    log(['checkPageVisibility', h]);
    if (flag.hidden && !h) checkPlayingVideo(eV.currentTime, 'checkPageVisibility');
    flag.hidden = h;
  }

  //ページにイベントリスナーを追加
  function addEventPage() {
    log('addEventPage');
    document.addEventListener('visibilitychange', checkPageVisibility, false);
  }

  //動画にイベントリスナーを追加
  function addEventVideo(s) {
    logV(['addEventVideo', s]);
    if (!flag.reload) {
      var e = returnVideo('addEventVideo1');
      if (!e) {
        checkChangeV('addEventVideo1');
        return;
      }
      setTimeout(function() {
        eV = returnVideo('addEventVideo2');
        if (!eV) {
          checkChangeV('addEventVideo2');
          return;
        }
        eV.addEventListener('error', videoError, false);
        eV.addEventListener('loadstart', videoLoadstart, false);
        eV.addEventListener('pause', videoPause, false);
        eV.addEventListener('playing', videoPlaying, false);
        eV.addEventListener('stalled', videoStalled, false);
        eV.addEventListener('waiting', videoWaiting, false);
        if (ls.debug) {
          eV.addEventListener('canplay', videoCanplay, false);
          eV.addEventListener('canplaythrough', videoCanplaythrough, false);
          eV.addEventListener('durationchange', videoDurationchange, false);
          eV.addEventListener('emptied', videoEmpied, false);
          eV.addEventListener('ended', videoEnded, false);
          eV.addEventListener('loadeddata', videoLoadeddata, false);
          eV.addEventListener('loadedmetadata', videoLoadedmetadata, false);
          eV.addEventListener('play', videoPlay, false);
          eV.addEventListener('progress', videoProgress, false);
          eV.addEventListener('seeked', videoSeeked, false);
          eV.addEventListener('seeking', videoSeeking, false);
          eV.addEventListener('suspend', videoSuspend, false);
          eV.addEventListener('timeupdate', videoTimeupdate, false);
        }
      }, 100);
    }
  }

  //動画が表示されるのを待つ
  function waitShowVideo(s) {
    log(['waitShowVideo', s, flag.show]);
    if (!flag.show) {
      flag.show = true;
      clearInterval(interval);
      setTimeout(function() {
        eV = returnVideo('waitShowVideo');
        if (eV) {
          if (s === 'init') startObserve();
          else addEventVideo('waitShowVideo1');
          flag.show = false;
        } else {
          clearInterval(interval);
          interval = setInterval(function() {
            eV = returnVideo('waitShowVideo');
            if (eV) {
              clearInterval(interval);
              if (s === 'init') startObserve();
              else addEventVideo('waitShowVideo2');
              flag.show = false;
            } else if (flag.countWaitShowVideo > 100) clearInterval(interval);
            flag.countWaitShowVideo++;
          }, 100);
        }
      }, 400);
    }
    if (s === 'observerC') {
      if (flag.reload) {
        flag.reload = false;
        ePrev.click();
      }
      returnChLogo('waitShowVideo-observerC');
    }
  }

  function waitShowVideoC() { waitShowVideo('observerC'); }

  function waitShowVideoV() { waitShowVideo('observerV'); }

  //ページを開いて動画が表示されたら1度だけ実行
  function startObserve() {
    log('startObserve');
    ePrev = document.querySelector('div[class^="style__box"] > button:first-child');
    eNext = document.querySelector('div[class^="style__box"] > button:last-child');
    observerC.observe(returnChLogo(), moConfig);
    observerV.observe(eV.parentNode, moConfig2);
    addEventPage();
    addEventVideo('startObserve');
  }

  //ページを開いたときに1度だけ実行
  function init() {
    log('init');
    waitShowVideo('init');
  }

  var ls = JSON.parse(localStorage.getItem('AutoReload')) || {},
    observerC = new MutationObserver(waitShowVideoC),
    observerV = new MutationObserver(waitShowVideoV),
    moConfig = { attributes: true, characterData: true },
    moConfig2 = { childList: true },
    flag = {
      change1: false,
      change2: false,
      checkPausedErrorVideo: false,
      countReload: 0,
      countWaitShowVideo: 0,
      hidden: false,
      loadstart: false,
      reload: false,
      show: false
    },
    eV, ePrev, eNext, chId, interval;
  init();

})();