yahvt

yet another html5 video tool

当前为 2016-01-18 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        yahvt
// @description yet another html5 video tool
// @namespace   gnblizz
// @include     http://anilinkz.tv/*
// @include     http://www.animeboy.org/*
// @include     http://www.animecenter.tv/*
// @include     http://www.animedreaming.tv/*
// @include     http://anime-exceed.com/*
// @include     http://www.animefreak.tv/*
// @include     http://www.animefushigi.co/*
// @include     http://www.animefushigi.com/*
// @include     http://www.animehere.com/*
// @include     http://www.animenova.org/*
// @include     http://www.animenova.tv/*
// @include     http://www.animeplus.tv/*
// @include     http://www.animeseason.com/*
// @include     http://ww1.animes-stream24.net/*
// @include     http://www.anime-sub.com/*
// @include     http://www.animetoon.eu/*
// @include     http://www.animetoon.org/*
// @include     http://www.animetoon.tv/*
// @include     http://www.animeultima.io/*
// @include     http://animewow.eu/*
// @include     http://www.animewow.eu/*
// @include     http://www.animewow.org/*
// @include     http://bestanimes.tv/*
// @include     http://www.chia-anime.tv/*
// @include     http://www.clipfish.de/*
// @include     http://dramago.com/*
// @include     http://www.dramago.com/*
// @include     http://www.dramagalaxy.eu/*
// @include     http://www.dramagalaxy.com/*
// @include     http://www.dramagalaxy.tv/*
// @include     http://dubbedanime.net/*
// @include     http://www.dubzonline.cm/*
// @include     http://www.dubzonline.com/*
// @include     http://freeanime.com/*
// @include     http://www.gogoanime.com/*
// @include     http://www.goodanime.co/*
// @include     http://www.goodanime.eu/*
// @include     http://www.goodanime.net/*
// @include     http://www.gooddrama.net/*
// @include     http://www.kumby.com/*
// @include     http://www.lovemyanime.net/*
// @include     http://www.otakucenter.com/*
// @include     http://www.theanime.tv/*
// @include     http://www.videozoo.me/*
// @include     http://www.waoanime.tv/*
// @include     *embed*
// @include     *gogo/*
// @include     *widget/*
// @include     http://player.arkvid.tv/*
// @version     1.06
// @grant       GM_xmlhttpRequest
// @icon        data:image/gif;base64,R0lGODlhMAAwAKECAAAAAICAgP///////yH5BAEKAAMALAAAAAAwADAAAALQnI+py+0Po5y02ouz3rz7D4biBJTmiabqyrbuC8fyHAf2jedpzuOvAAwKh6mhUfg7Hks3gHLpehptwIBTioxig0zrdStIgrslMFA8pCKp1oAZjXW6w/Mt/Nl2t8HeFl7o5QZgBagEYyawNxhUl7h4dlelFlZG+QVY6aglmIjjuKd50xla9RKI0mSCqaPJSMM0aEK4mhfbpSnTabM4WXrShtpHI6gqKvmKnCwns0tm2lOsLP3aUy08aK0zvc3d7b09Ei4+Tl5ufo6err7O3n5QAAA7
// @compatible  firefox
// ==/UserScript==
"use strict";
var domain; try { domain = document.domain.match(/^(?:www\.)?(.*)$/)[1]; } catch(e) { domain = 'unknown'; }

function sites(){
  var a,i,o,e,b;
  //console.log('domain='+domain);
  switch(location.hostname.match(/([^.]+)\.\w+$/)[1]) {
  case 'anilinkz'://.tv
    allowFullscreen('#player');
    break;
  case 'animecenter'://.tv
    allowFullscreen('#video');
    break;
  case 'animedreaming'://.tv
    allowFullscreen('.videoholder');
    break;
  case 'anime-exceed'://.com
    allowFullscreen('#player', (/^\/cool\//.test(location.pathname)?'':'body'),0,999);
    break;
  case 'animefreak'://.tv
    a=objs('.multi'); for(o of a) {
      e = o.getAttribute('onclick');
      if(e && /loadParts\('http/.test(e))
	o.onclick = function(event) {
	  var vid_file = decodeURIComponent(this.getAttribute('onclick').match(/loadParts\('([^']+)'/)[1]);
	  document.getElementById("player").innerHTML = '<video controls width="100%" height="412" src="' + vid_file + '" allowfullscreen="true" autoplay></video>';
	};
    }
    break;
  case 'animefushigi'://.co,com
    allowFullscreen('#vidboxx', '.videoloadbg');
    break;
  case 'animehere'://.com
    allowFullscreen('#playbox');
    break;
  case 'animenova'://.org,tv
  case 'animeplus'://.tv
  case 'animetoon'://.eu,org,tv
  case 'animewow'://.eu,org
  case 'dramagalaxy'://.com,eu,tv
  case 'dramago'://.com
  case 'gooddrama'://.net
    allowFullscreen('#streams');
    break;
  case 'animeseason'://.com
    if(obj('#series_info'))
      SetStyle('table a:visited{color:gray;}table a:hover{color:#FC0;}');
    allowFullscreen('#video_source', 0, '#player_list A');
    break;
  case 'anime-sub'://.com
    allowFullscreen('#movie-content');
    break;
  case 'animeultima'://.io
    allowFullscreen('#pembed');
    break;
  case 'bestanimes'://.tv
    allowFullscreen('.post');
    break;
  case 'clipfish'://.de
    obj('+SCRIPT', document.body).innerHTML = 'checkMobile=function(){isMobile=true;}';
    break;
  case 'freeanime'://.com
    obj('+SCRIPT', document.body).innerHTML = '$(window).unbind();\n$("#header").css("background-attachment","scroll")';
    allowFullscreen('.z-video', 0, 'ul.z-tabs-nav LI', 999);
    break;
  case 'dubzonline'://.cm,com
  case 'theanime'://.tv
  case 'goodanime'://.co,eu,net
  case 'videozoo'://.me
    allowFullscreen('#content');
    break;
  case 'lovemyanime'://.net
    allowFullscreen('.player-area');
    break;
  case 'animes-stream24'://.net
    allowFullscreen('#main');
    break;
  case 'gogoanime'://.com
    return location.pathname=='/flowplayer/' || allowFullscreen('#content');
  //case 'chia-anime':return !top; // ok
  //case 'dubbedanime':break;      // ok
  //case 'waoanime':break;   // how did that get in here?
  //case 'animeboy':break;   // broken, flash only
  //case 'kumby':break;      // server down
  //case 'otakucenter':break;// server down
  case 'arkvid':
    return domain=='player.arkvid.tv';
  //case 'yucache'://.net
  //case 'yourupload'://.com
  //  if(document.URL.match(/[?&]/) == '&') // bad URL?
  //     document.location.replace(document.URL.replace('&', '?'));
  default:
    return(/(embed\b|\/gogo\/|\/widget\/)/.test(document.URL));
  }

function allowFullscreen(selTop, selFrame, mirrors, delay) {
  if(delay)
    window.setTimeout( function() { allowFullscreen(selTop, selFrame, mirrors); }, delay);
  else {
    var a,i;
    if(window.self==window.top) {
      if(mirrors) {
	a = document.querySelectorAll(mirrors);
	for(i of a) {
	  i.addEventListener('click', function() {
	    window.setTimeout( function() { document.querySelector(selTop+' IFRAME').setAttribute('allowfullscreen', 'true'); }, 99);
	  });
	}
      }
      a = document.querySelectorAll(selTop+' IFRAME');
      if(!a.length)console.log('couldn\'t applay fullscreen attribute because '+selTop+' IFRAME not found in '+document.URL);
      for(i of a) { i.setAttribute('allowfullscreen', 'true'); }
    } else if(selFrame) {
      a = document.querySelectorAll(selFrame+' IFRAME');
      for(i of a) { i.setAttribute('allowfullscreen', 'true'); }
    }
  }
}}

function findVideoFiles() {
  var v = [], s, m, a, i, p;
  a = obj('VIDEO', document.body); if(a) {//usually doesn't exist yet
    if(m = a.getAttribute('src')) v.push(m);
    a = objs('SOURCE', a);
    for(i of a) {
      if(m = i.getAttribute('src')) v.push(m);
    }
  }
  a = objs('SCRIPT', document.body); for(i of a) { 
    if(s=getScript(i)) {
      find(/"(http:\/\/[^"]+\.(?:mp4|flv)\b[^"]*)"/gi);
      find(/"(.+\.php\b.+\.(?:mp4|flv))"/gi);
      find(/"([^"]+\bpicasa\.php\b[^"]+)"/gi);
      find(/"(https\:\/\/[^"]*\.google(?:video\.com\/videoplayback|usercontent.com\/)[^"]+)"/gi);
    }
  }
  if(/trollvid\.net$/i.test(domain)) {//Is this of any use today?
    for(i of a) {
      s = i.innerHTML; m = s.match(/['"](http.+?data.*?file.*?)['"]/i); if(m) v.push(m[1]);
    }
    a = objs('SCRIPT', document.head); for(i of a) {
      m = i.innerHTML.match(/unescape\(atob\('(.+?)'/);
      if(m) { m = unescape(atob(m[1])); if(/\.(mp4|flv)/i.test(m)) v.push(m); }
    }
  } else if('videobam.com' == domain) {//Is this of any use today?
    for(i of a) {
      s = i.innerHTML; m = s.match(/['"](http:\\\/\\\/[^'"]+\.(?:mp4|flv)\b[^'"]*)['"]/i); if(m) v.push(m[1].replace(/\\\//g,'/'));
    }
  }
  try {//even if it looks wierd...
    m = document.querySelector('#flowplayer+script').innerHTML.replace(/\s+/g, ' ').match(/\/\* playlist\: \[ \{ url\: '(.*)'/)[1];
    v.push(m);
  } catch(e){}
  a = objs('PARAM'); for(i of a) { p = i.getAttribute('value'); m = p.match(/video=(http:\/\/[^'"]+\.mp4[^'"&]*)/i); if(m) v.push(m[1]); }
  a = objs('EMBED'); for(i of a) { p = i.getAttribute('src'); m = p.match(/video=(http:\/\/[^'"]+\.mp4[^'"&]*)/i); if(m) v.push(m[1]); }
  return v;
function find(pattern /*,v */) {
  var g = /g[imy]*$/.test(pattern.toSource());
  do {
    var m = pattern.exec(s);
    if(!m) break;
    m = decodeURIComponent(unescape(m[1]));
    if(v.indexOf(m)<0) v.push(m);
  } while(g);
}
function getScript(s) {
  if(!(s=s.innerHTML).length) return s;
  var m = s.match(/^eval(\(function\(p(?:,[a-ek]){5}\).+\bsplit\b.+)$/m), timer;
  if(m) { try { s += eval(m[1]); } catch(e) { console.log('Packed script parse error.'); } }
  return unescape(s.replace(/\s\/\/.*$/gm,'').replace(/\s+/gm,' ').replace(/\/\*.*\*\//g,'').replace(/'/g,'"'));
}}

(function yahvt() {
  try {
  if(sites()) {
    var av = findVideoFiles();
    if(av && av.length) {
      console.log('found '+av.length+' video source'+(av.length==1 ? '' : 's')+' at '+domain+'.');
      var autoplay = remembered('autoplay', true) == 'yes';
      if(window.self != window.top && !autoplay) {
	document.body.innerHTML = '<center><p>Video '+((/(part|clip)_?\d/.test(av[0]+document.URL)) ? 'part ' : '')+'found at ' + domainName(document.URL) + '.</p><button type="button" style="padding:10px;width:98%">play</button></center><div id="flowplayer" style="display:none"></div>';
	obj('BUTTON').onclick = function() { autoplay = true; insertVideo(); }
      } else {
	insertVideo();
      }
    } else {
      if(/^video(?:wing|zoo).me$/.test(domain) && !/\bnoflash\b/i.test(location.search))
	location.search = location.search ? (location.search+'&noflash') : '?noflash';
      var as = objs('SCRIPT'), i;
      for(i of as) {
	if(/_url\s*=\s*\"video not found\"/i.test(i.innerHTML)) { document.body.innerHTML = '<p>Video not found.</p>'; break; }
      }
    }
  }
  } catch(e) { console.log('yahvt: ' + e); }

function insertVideo() {
  av.push(av[0]+'&noflash'); av.push(av[0]+'&html5=true');
  var nvf = NextPart(document.URL), txt = '<video controls ' + (autoplay ? 'autoplay ' : '') + 'width="100%" height="100%" tabindex="0';
  av.forEach(function(x){ txt += '"><source src="' + x.replace(/\?/g,'&').replace('&','?'); });
  txt += '"></video>';
  if(obj('#flowplayer')) txt += '<div id="flowplayer" style="display:none"></div>';
  else if(obj('#player')) txt += '<div id="player" style="display:none"></div>';
  document.body.innerHTML = txt;
  console.log('starting ' + domain + (nvf ? (' video part '+nvf[2]) : ' video'));
  var v = obj('VIDEO');
  v.oncanplay = function(e) {//note: multiple calls
    //console.log('now playing: '+v.currentSrc);
    if(remembered('fullscreen', true)=='yes')
      SetFullScreenMode();
    v.oncanplay = '';
  };
  v.lastChild.onerror = function(e) {
    console.log('video load error');
    if(!/\bnoflash\b/.test(location.search)) {
      Remember('autoplay');
      console.log('redirecting to location + noflash');
      location.search = location.search ? location.search + '&noflash' : '?noflash';
    }
    if(nvf && nvf[2]>1)
      document.body.innerHTML = '<center><br>No Part '+nvf[2]+' could be found, so this must be...<br><br><big><b>The End</b></big><br></center>';
    remembered('fullscreen', true);// discard value
  };
  v.onended = function(e) {
    //console.log('video.onended()');
    var wasFullScreen = EndFullScreenMode();
    if(window.self != window.top && !obj('#VideoCloseButton')) {
      var btnClose = MakeAButton('x', 'close', 0);
      btnClose.id = 'VideoCloseButton';
      btnClose.onclick = function(e){ location.replace('about:blank'); };
    }
    if(nvf) {
      var btnNext = MakeAButton(nvf[0], 'on to part '+nvf[0], 1);
      btnNext.onclick = function(e) {
        console.log('redirecting to part '+nvf[0]);
	Remember('autoplay');
	Remember('fullscreen', (wasFullScreen ? 'yes' : ''));
	location.replace(nvf[1]);
      };
      switch(resourceExists(nvf[1])) { // can't tell if it's valid, though
      case true: btnNext.click();
      case false: RemoveElement(btnNext);
      }
    } else {//nfv
      var vf = v.currentSrc, m = vf.match(/^(.*(?:part|clip)_?0?)(\d+)(.*)$/);
      if(m) {
	var inp = parseInt(m[2])+1;
	vf = m[1] + inp + m[3];
	var btnNext2 = MakeAButton(inp, 'on to part '+inp, 1);
	btnNext2.onclick = function(e) {
	  Remember('fullscreen', (wasFullScreen ? 'yes' : ''));
	  av = [vf];
	  insertVideo();
	};
	console.log('about to insert video part '+inp);
	try {
	  var rv = GM_xmlhttpRequest({
	    url: vf,
	    method: "HEAD",
	    onload: function(response) {
	      if(/^Content-Type:\s*video\b/m.test(response.responseHeaders)) {
		console.log('video resource found');
		btnNext2.click();
	      } else {
		console.log('invalid video resource');
	      }
	      RemoveElement(btnNext2);
	    },
	    onerror: function(response) {
	      console.log('--onerror-response:\n'+response.responseHeaders);
	      RemoveElement(btnNext2);
	    }
	  });
	} catch(e) {
	  switch(resourceExists(vf)) { // CORS blocked most likely
	  case true: btnNext2.click();
	  case false: RemoveElement(btnNext2);
	  }
	}
      }//m
    }//!nfv
  };//v.onended

function NextPart(name) {
  var m = name.match(/^(.*(?:part|clip)_?0?)(\d+)(.*)$/);
  if(m) {
    m[2] = parseInt(m[2]);
    m[1] = m[1]+(m[2]+1)+m.pop();
    m[0] = m[2]+1;
    }
  return m;
}}}());

function resourceExists(url){
  try {
    var http = new XMLHttpRequest();
    http.open('HEAD', url, false);
    http.send();
    return http.status != 404;
  } catch(e){}
}

//requires about:config full-screen-api.allow-trusted-requests-only=false
function SetFullScreenMode() {
  var v = obj('VIDEO'); // full-screen-api.allow-trusted-requests-only;false (about:config)
  try{
    v.mozRequestFullScreen();
  }catch(e){}
}

function EndFullScreenMode() {
  try {
    if(document.mozFullScreenElement) {
      document.mozCancelFullScreen();
      return true;
    }
  }catch(e){}
  return false;
}

function obj(name, parent) {
  if(!parent) parent = document;
  var node = null;
  switch (name.charAt(0)) {
  case '#': node = parent.getElementById(name.slice(1)); break;
  case '.': node = parent.getElementsByClassName(name.slice(1))[0]; break;
  case '+': node = document.createElement(name.slice(1).toUpperCase()); if(parent != document) parent.appendChild(node); break;
  default:  node = parent.getElementsByTagName(name)[0]; break;
  }
  return node;
}

function objs(name, parent) {
  if(!parent) parent = document;
  return (name.charAt(0)=='.') ? parent.getElementsByClassName(name.slice(1)) : parent.getElementsByTagName(name);
}

function SetStyle(style) {
  obj('+STYLE', obj('HEAD')).innerHTML = style;
}

function RemoveElement(node) { 
  if(typeof(node)=='string') node = obj(node);
  if(node) return node.parentNode.removeChild(node);
}

function domainName(href) {
  if(!href) href = location.href;
  var m = href.match(/\:\/\/(?:www\.|embed\.)?([^\/]+)/);
  if(m) return m[1];
  return 'unknown';
}

function Remember(name, value) {
  switch(value) {
  case '':
    sessionStorage.removeItem(name);
    break;
  case undefined:
    value = 'yes';
  default:
    sessionStorage.setItem(name, value);
  }
}

function remembered(name, forget) {
  var x = sessionStorage.getItem(name);
  if(forget) sessionStorage.removeItem(name);
  return x;
}

function MakeAButton(caption, help, style, parent) {
  var b = obj('+BUTTON');
  b.setAttribute('type', 'button');
  b.innerHTML = caption;
  if(help) b.setAttribute('title', help);
  if(typeof(style)=='number') style = 'top:0px;right:'+(30*style)+'px;height:25px;min-width:25px;';
  b.setAttribute('style', style);
  if(!b.style.position) b.style.position = 'absolute';
  if(!parent) parent = document.body;
  parent.appendChild(b);
  return b;
}

// public domain by gnblizz
// contact me with my username + '@web.de'