Greasy Fork

yahvt

yet another html5 video tool

目前为 2017-01-30 提交的版本。查看 最新版本

// ==UserScript==
// @name        yahvt
// @description yet another html5 video tool
// @namespace   gnblizz
// @version     1.14
// @include     http://anilinkz.tv/*
// @include     http://www.animeboy.org/*
// @include     http://www.animeboy.tv/*
// @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://www.animesky.net/*
// @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://gooddrama.to/*
// @include     http://www.gooddrama.to/*
// @include     http://www.gooddrama.net/*
// @include     http://www.lovemyanime.net/*
// @include     http://www.theanime.tv/*
// @include     http://www.videozoo.me/*
// @include     about:blank?video=*
// @include     h*embed*
// @include     h*gogo/*
// @include     h*widget/*
// @match       http://*.mangaotaku.org/*
// @include     http://player.arkvid.tv/*
// @include     http://www.dramastream.org/*
// @exclude     https://openload.co/embed/*
// @grant       GM_xmlhttpRequest
// @icon        data:image/gif;base64,R0lGODlhMAAwAKECAAAAAICAgP///////yH5BAEKAAMALAAAAAAwADAAAALQnI+py+0Po5y02ouz3rz7D4biBJTmiabqyrbuC8fyHAf2jedpzuOvAAwKh6mhUfg7Hks3gHLpehptwIBTioxig0zrdStIgrslMFA8pCKp1oAZjXW6w/Mt/Nl2t8HeFl7o5QZgBagEYyawNxhUl7h4dlelFlZG+QVY6aglmIjjuKd50xla9RKI0mSCqaPJSMM0aEK4mhfbpSnTabM4WXrShtpHI6gqKvmKnCwns0tm2lOsLP3aUy08aK0zvc3d7b09Ei4+Tl5ufo6err7O3n5QAAA7
// @compatible  firefox
// @compatible  chrome
// ==/UserScript==
"use strict";
var doc=document, isTop=window.self==window.top, domain, isFF = /Firefox/i.test(navigator.userAgent);
try { domain = doc.domain.match(/^(?:www\.)?(.*)$/)[1]; } catch(e) { domain = 'unknown'; }
yahvt();

function sites(){
  var a,i,o,e,b;
  //console.log('yahvt: domain =', domain);
  if(!location.hostname) {//about:blank?video=
    a = location.href.match(/^about:blank\?(video=".*")/);
    if(a)
      nn('SCRIPT', doc.body).textContent = 'var '+a[1];
    return a != null;
  }
  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=na('.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]);
          doc.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 'animesky'://.net
  case 'animetoon'://.eu,org,tv
  case 'animewow'://.eu,org
  case 'dramagalaxy'://.com,eu,tv
  case 'dramago'://.com
  case 'gooddrama'://.net,to
    allowFullscreen('#streams');
    break;
  case 'animeseason'://.com
    if(fn('#series_info'))
      SetStyle('table a:visited{color:gray;}table a:hover{color:#FC0;}');
    allowFullscreen('#video_source', 0, '#player_list A');
    break;
  case 'animeboy'://.org,tv
  case 'dramastream'://.org
    allowFullscreen('div[align]', 'center');
    break;
  case 'anime-sub'://.com
    allowFullscreen('#movie-content');
    break;
  case 'animeultima'://.io
    allowFullscreen('#pembed');
    break;
  case 'bestanimes'://.tv
    allowFullscreen('.post');
    break;
  case 'clipfish'://.de
    if(isFF) nn('SCRIPT', doc.body).innerHTML = 'checkMobile=function(){isMobile=true;}';
    else Object.defineProperty(navigator, "userAgent", {value: 'fake Android'});// too late! TODO: @run-at document-start
    break;
  case 'freeanime'://.com
    nn('SCRIPT', doc.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');
    return(location.pathname == '/embed.php');
  case 'lovemyanime'://.net
    allowFullscreen('.player-area');
    break;
  case 'animes-stream24'://.net
    allowFullscreen('#main');
    break;
  case 'gogoanime'://.com
    return location.pathname=='/flowplayer/' || allowFullscreen('#content');
  case 'arkvid'://.tv
    return domain=='player.arkvid.tv';
  case 'mangaotaku': // animeboy,dramastream
    return 1;//  return(location.pathname == '/dr_video_player.php');
  default:
    return(/(embed\b|\/gogo\/|\/widget\/)/.test(doc.URL));
  }

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

// FULL SCREEN API

//requires about:config full-screen-api.allow-trusted-requests-only=false
function SetFullScreenMode(v) {
  (v.requestFullscreen||v.mozRequestFullScreen||v.webkitRequestFullscreen||v.webkitEnterFullscreen).call(v);
  //console.info('To allow full screen mode, you may want to set full-screen-api.allow-trusted-requests-only to false in about:config.');
}

function FullScreenElement() {
  if(doc.exitFullscreen) return doc.fullscreenElement;
  if(doc.mozCancelFullScreen) return doc.mozFullScreenElement;
  if(doc.webkitExitFullscreen) return doc.webkitFullscreenElement;
}

function EndFullScreenMode() {
  if(!FullScreenElement()) return false;
  (doc.exitFullscreen||doc.mozCancelFullScreen||doc.webkitExitFullscreen).call(doc);
  return true;
}

function OnFullScreenChange(fn) {
  if(doc.exitFullscreen) doc.addEventListener("fullscreenchange", fn);
  if(doc.mozCancelFullScreen) doc.addEventListener("mozfullscreenchange", fn);
  if(doc.webkitExitFullscreen) doc.addEventListener("webkitfullscreenchange", fn);
}

// new node
function nn(name, parent) {
  var a = name.split(/,(?! )/); name = a.shift();
  var node = doc.createElement(name.match(/^\w+/)[0]),
  m = name.match(/#\w+/); if(m) node.id = m[0].slice(1);
  m = name.match(/\.\w+/); if(m) node.className = m[0].slice(1);
  while(a.length) {
    var l = a.shift().split('=');
    if(!l[1]) l.push(l[0]);
    else if(/^".*"$/.test(l[1])) l[1] = l[1].slice(1,-1);
    switch(l[0]){
    case '': node.textContent = l[1]; break;
    case 'HTML': node.innerHTML = l[1]; break;
    default: node.setAttribute(l[0], l[1]);
    }
  };
  if(parent) parent.appendChild(node);
  return node;
}

// find node
function fn(name, parent) {
  if(!parent) parent = doc;
  switch(name.charAt(0)) {
  case '#':
    return parent.getElementById(name.slice(1));
  case '.':
    return parent.getElementsByClassName(name.slice(1))[0];
  }
  return parent.getElementsByTagName(name)[0];
}

// find nodes array
function na(name, parent) {
  if(!parent) parent = doc;
  return (name.charAt(0)=='.') ? parent.getElementsByClassName(name.slice(1)) : parent.getElementsByTagName(name);
}

// remove node
function rn(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) {
 try {
  if(sessionStorage) switch(value) {
  case '':
    sessionStorage.removeItem(name);
    break;
  case undefined:
    value = 'yes';
  default:
    sessionStorage.setItem(name, value);
  }
 }catch(e){}
}

function remembered(name, forget) {
  try {
    var x = sessionStorage.getItem(name);
    if(forget) sessionStorage.removeItem(name);
    return x;
  } catch(e) {
    if(name=='autoplay' && (domain=='unknown' || /\bnoflash\b/.test(location.search) || /(part|clip)_?0?[2-9]/.test(location.pathname))) return 'yes';
  }
}

// style
function SetStyle(style) {
  nn('STYLE', fn('HEAD')).innerHTML = style;
}

function MakeCSSString(name, def) {
  var names = Object.getOwnPropertyNames(def), style = (names.indexOf('top') < 0 ? '' : 'position:absolute;' ), x, value;
  for(x of names) {
    value = def[x];
    if(typeof(value) == 'number') value += 'px';
    style += x.replace(/_/g,'-') + ': ' + value + '; ';
  }
  return name + '{' + style + '}\n';
}

function findVideoFiles() {
function getScript(o) {
  s = o.innerHTML;
  if(s.length) {
    var m = s.match(/^eval(\(function\(p(?:,[a-ek]){5}\).+\bsplit\b.+)$/m), timer;
    if(m) {
      try { s += eval(m[1]); console.log('yahvt: Packed script detected.'); } catch(e) { console.log('yahvt: Packed script parse error.'); }
    }
    return s = unescape(s.replace(/\s\/\/.*$/gm,'').replace(/\s+/gm,' ').replace(/\/\*.*\*\//g,'').replace(/'/g,'"'));
  }
}
function add(m) { if(m && v.indexOf(m)<0) v.push(m); }
function addm1(m) { if(m && v.indexOf(m[1])<0) v.push(m[1]); }
function find(pattern) {
  var g = /g/.test(pattern.flags);
  do {
    var m = pattern.exec(s);
    if(!m) break;
    add(decodeURIComponent(unescape(m[1])));
  } while(g);
}
//findVideoFiles() {
  var v = [], s, m, a, i, p;
  a = fn('VIDEO', doc.body);
  if(a) {//usually doesn't exist yet
    add(a.getAttribute('src'));
    a = na('SOURCE', a);
    for(i of a) {
      add(i.getAttribute('src'));
    }
  }
  a = na('SCRIPT', (domain=='videozoo.me' ? doc.documentElement : doc.body)); for(i of a) {
    if(getScript(i)) {
      //console.log('yahvt:' ,s);
      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? TODO obsolete?
    for(i of a) {
      s = i.innerHTML; m = s.match(/['"](http.+?data.*?file.*?)['"]/i); addm1(m);
    }
    a = na('SCRIPT', doc.head); for(i of a) {
      m = i.innerHTML.match(/unescape\(atob\('(.+?)'/);
      if(m) { m = unescape(atob(m[1])); if(/\.(mp4|flv)/i.test(m)) add(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) add(m[1].replace(/\\\//g,'/'));
    }
  }
  try {// even if it looks wierd...
    m = doc.querySelector('#flowplayer+script').innerHTML.replace(/\s+/g, ' ').match(/\/\* playlist\: \[ \{ url\: '(.*)'/)[1];
    if(!/\<|\>/.test(m)) {
      console.log('yahvt: html5_path in comment found.');
      add(m);
    }
  } catch(e){}
  try {// animeboy
    add(unescape(fn('NOSCRIPT').innerHTML.match(/<param\sname="movie"\svalue="\S+&fpath=([^&]+)&/i)[1]).replace(/\+/g,'%20'));
    console.log('yahvt: movie param in noscript found.');
  } catch(e){}
  a = na('PARAM'); for(i of a) { p = i.getAttribute('value'); m = p.match(/video=(http:\/\/[^'"]+\.mp4[^'"&]*)/i); addm1(m); }
  a = na('EMBED'); for(i of a) { p = i.getAttribute('src'); m = p.match(/video=(http:\/\/[^'"]+\.mp4[^'"&]*)/i); addm1(m); }
  if(domain=='mp4upload.com') {
    i = v.length;
    if(i) do {
      a = v[--i];
      if(a.match(/\.com\/[a-z]+\.mp4$/)) {
        console.log('yahvt:', a, 'ignored.');
        delete v[i];
      }
    } while(i);
  }
  return v;
}

//(
function yahvt() {
function insertVideo() {
function ShowSomeInfo(meta) {
  var div = nn('DIV.info'), txt = domain + (nvp ? (' video part '+nvp.now) : ' video'), src = v.currentSrc, m, adr = ['mailto:gnblizz'];
  if(meta) {
    var t = v.duration + .5;
    txt += '<br>pixel format: ' + v.videoWidth + 'x' + v.videoHeight
    + '<br>duration: ' + Math.floor(t/60) + ':' + ('0' + Math.floor(t%60)).slice(-2);
  } else div.style.color = '#666';
  m = src.match(/https?:\/\/([^:?/]+)/);
  if(m) txt += '<br>video host name: ' + m[1];
  m = src.match(/.*\/([^?/]*)/);
  if(m) txt += '<br>video file name: ' + m[1];
  txt += '<br><br>A - toggle stretch mode<br>F - toggle full screen mode<br>I - '+(meta ? 'this info<br>Q - quick viewing<br>S - slow motion' : 'some info')+'<br>Z - toggle zoom to 100%';
  if(meta) {
    adr.push('@web.de?subject=yahvt%20at%20', document.domain);
    txt += '<br><br><small><a target="_newtab" href="https://greasyfork.org/en/scripts/14476-yahvt" title="info, code, feedback and stats of yahvt">yahvt</a> is public domain by <a href="' + adr.join('')
        + '" title="email the author directly">gnblizz</a>.</small>';
  }
  div.innerHTML = txt;
  p.appendChild(div);
  window.setTimeout(StopInfo, 15000);
}
function StopInfo() {
  return rn(p.querySelector('div.info,div.info2'));
}
function NextPart(name) {
  var m = name.match(/^(.*(?:part|clip)_?0?)(\d+)(.*)$/), i;
  if(m)
    return {now: i = parseInt(m[2]), next: ++i, URL: m[1]+i+m.pop()};
  else {
    m = name.match(/^(.*%26sp%3D)a(%26episode%3D\d+)A(%26.*)$/);//animeboy,mangaotaku
    if(m)
      return {now: 'A', next: 'B', URL: m[1]+'b'+m[2]+'B'+m.pop()};
  }
}
function StartStop() {
  if(v.paused) v.play();
  else v.pause();
}
function TestResource(url, btn) {
  var req = new XMLHttpRequest();
  try {
  if(req) {
    req.open('HEAD', url, true);
    req.onloadend = function () {
      switch(req.status) {
      case 200:
        if(req.statusText != 'Not Found')
          btn.click();
      case 404:
        rn(btn);
      }
    };
    req.send();
  }
  }catch(e){console.log('yahvt:', e, url, req);}
}
//insertVideo() {
  var nvp = NextPart(doc.URL), txt = '<video controls ' + (autoplay ? 'autoplay ' : '') +
    'width="100%" height="100%" tabindex="1', altClick, smw;
  av.push(av[0]+'&noflash');
  av.push(av[0]+'&html5=true');
  av.forEach(function(x){ txt += '"><source src="' + x.replace(/\?/g,'&').replace('&','?'); });
  txt += '"></video>';
  if(fn('#flowplayer')) txt += '<div id="flowplayer"></div>';
  else if(fn('#player')) txt += '<div id="player"></div>';
  doc.body.innerHTML = txt;
  console.log('yahvt: starting ' + domain + (nvp ? (' video part '+nvp.now) : ' video'));
  var v = fn('VIDEO'), p = v.parentNode;
  v.onloadedmetadata = function(event) {
    //console.log('yahvt: now playing: '+v.currentSrc);
    StopInfo();
    nn('DIV.info2,='+ v.videoWidth + 'x' + v.videoHeight, p);
    window.setTimeout(StopInfo, 3000);
    if(remembered('fullscreen', true)=='yes')
      SetFullScreenMode(v);
    v.focus();
  };
  v.onkeypress = function(event) {
    if(event.altKey || event.metaKey || event.ctrlKey) return;
    switch(event.key.toUpperCase()) {
    case ' ':
      if(isFF) return;
    case 'P':
      StartStop();
      break;
    case 'A':// toggle stretch mode
      v.style.objectFit = v.style.objectFit ? '' : 'fill';
      p.style.height = '100%';
      break;
    case 'F':// toggle full screen
      if(!EndFullScreenMode())
        SetFullScreenMode(v);
      break;
    case 'H':// toggle LMB behavior
      ((altClick = !altClick) ? v.addEventListener : v.removeEventListener).call(v, 'click', StartStop, false);
      break;
    case 'I':// show some info
      if(!rn(p.querySelector('div.info')))
        ShowSomeInfo(true);
      break;
    case 'Q':// quick view
      if(!smw) {
        nn('DIV.info2,=press "Q" to end quick view mode', p);
        smw = window.setTimeout(StopInfo, 3000);
      }
      v.playbackRate = v.playbackRate != 1 ? 1 : 2;
      break;
    case 'S':// slow motion
      if(!smw) {
        nn('DIV.info2,=press "S" to end slow motion mode', p);
        smw = window.setTimeout(StopInfo, 3000);
      }
      v.playbackRate = v.playbackRate != 1 ? 1 : .05;
      break;
    case 'Y': case 'Z':// toggle zoom mode
      if(p.style.width) {
        p.style.width = '';
        p.style.margin = '';
      } else if(v.videoWidth) {
        p.style.width = v.videoWidth+'px';
        p.style.minHeight = v.videoHeight+'px';
        p.style.margin = '0px auto';
      }
      break;
    default:
      return;
    }
    event.preventDefault();
    event.stopPropagation();
  };
  v.onkeydown = function(event) {
    if(event.altKey || event.metaKey || event.ctrlKey || event.shiftKey) return;
    switch(event.key) {
    case 'ArrowRight':
      v.currentTime += v.paused ? .5 : 5;
      break;
    case 'ArrowLeft':
      v.currentTime -= v.paused ? .5 : 5;
      break;
    case 'Escape':
      v.playbackRate = 1;
    default:
      return;
    }
    event.preventDefault();
    event.stopImmediatePropagation();
  };
  if(!isFF) {
    v.onclick = function(event) {
      if(!document.hasFocus()) v.focus();
      else StartStop();
    }
  }
  v.lastChild.onerror = function(event) {
    StopInfo();
    if(!/\bnoflash\b/.test(location.search)) {
      Remember('autoplay');
      location.search = location.search ? location.search+'&noflash' : '?noflash';
      throw 'redirecting to location + noflash';
    }
    console.log('yahvt: video load error');
    if(nvp && nvp.now>1)
      doc.body.innerHTML = '<center style="color:orange;"><br><br>No part '+nvp.now+' could be found, so this must be...<br><b style="font-size:333%;"><br>The End</b></center>';
    remembered('fullscreen', true);// discard value
  };
  v.onended = function(event) {
    var wasFullScreen = EndFullScreenMode();
    if(!isTop && !fn('#VideoCloseButton')) {
      nn('BUTTON#VideoCloseButton,type=button,=x,title=close', p).onclick = function(event){
        location.replace('about:blank');
        return false;
      };
    }
    if(nvp) {
      var btnNext = nn('BUTTON#NextPartButton,type=button,='+nvp.next+',title=on to part '+nvp.next, p);
      btnNext.onclick = function(event) {
        console.log('yahvt: redirecting to part '+nvp.next);
        Remember('autoplay');
        Remember('fullscreen', (wasFullScreen ? 'yes' : ''));
        location.replace(nvp.URL);
        return false;
      };
      btnNext.focus();
      TestResource(nvp.URL, btnNext);
    } else {//nfv
      var vf = v.currentSrc, m = vf.match(/^(.*(?:part|clip)_?0?)(\d+)(.*)$/);
      if(m) {
        console.log('yahvt: using alternate next part algorithm (experimental)');
        // This is when no part information was found in the page location, but in the video file name instead.
        // I forgot long time ago where I saw such scenario and don't know how to test it anymore. TODO
        var inp = parseInt(m[2])+1;
        vf = m[1] + inp + m[3];
        var btnNext2 = nn('BUTTON#NextPartButton,type=button,='+inp+',title=on to part '+inp, p);
        btnNext2.onclick = function(event) {
          Remember('fullscreen', (wasFullScreen ? 'yes' : ''));
          av = [vf];
          insertVideo();
        };
        console.log('yahvt: 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('yahvt: video resource found');
                btnNext2.click();
              } else {
                console.log('yahvt: invalid video resource');
              }
              rn(btnNext2);
            },
            onerror: function(response) {
              console.log('yahvt: --onerror-response:\n'+response.responseHeaders);
              rn(btnNext2);
            }
          });
        } catch(e) {
          TestResource(vf, btnNext2);
        }
      }//m
    }//!nfv
  };//v.onended
  ShowSomeInfo(false);
  OnFullScreenChange(function(event) { fn('VIDEO').focus(); });
}
//yahvt() {
  try {
    if(sites()) {
      var av = findVideoFiles();
      if(av && av.length) {
        console.log('yahvt: Found '+av.length+' video source'+(av.length==1 ? '' : 's')+' at '+domain+'.');
        if(/\/blank.mp4$/.test(av[0])) av.push(av.shift());
        var v = fn('VIDEO');
        if(v) { v.pause(); v.removeAttribute('src'); }
        SetStyle(
          MakeCSSString('body,html',{padding:0, margin:0, height:'100%', overflow:'hidden', background:'#000', color:'#fff', font_size:14}) + 
          MakeCSSString('video', {outline:0}) +
          MakeCSSString('#player,#flowplayer', {display:'none'}) +
          MakeCSSString('button#VideoCloseButton', {top:0, right:0, height:25, min_width:25}) +
          MakeCSSString('button#NextPartButton', {top:0, right:30, height:25, min_width:25}) +
          MakeCSSString('.info a', {color:'unset'}) +
          MakeCSSString('.info', {top:50, left:50, text_shadow:'1px 1px black'}) +
          MakeCSSString('.info2', {top:1, left:2, text_shadow:'1px 1px black', font_size:'large'})
        );
        var autoplay = remembered('autoplay', true) == 'yes';
        if(!isTop && !autoplay) {
          doc.body.innerHTML = '<center><p>Video '+((/(part|clip)_?\d/.test(av[0]+doc.URL)) ? 'part ' : '')+'found at ' + domainName(doc.URL) + '.</p><button type="button" style="padding:10px;width:98%">play</button></center><div id="flowplayer" style="display:none"></div>';
          fn('BUTTON').onclick = function() { autoplay = true; insertVideo(); }
          fn('BUTTON').focus();
        } else {
          insertVideo();
        }
      } else {
        if(/^video(?:wing|zoo).me$/.test(domain) && !/\bnoflash\b/i.test(location.search)) {
          console.log('yahvt: redirecting to location + noflash');
          location.search = location.search ? location.search+'&noflash' : '?noflash';
        }
        var as = na('SCRIPT'), i;
        for(i of as) {
          if(/_url\s*=\s*\"video not found\"/i.test(i.innerHTML)) { doc.body.innerHTML = '<p>Video not found.</p>'; break; }
        }
      }
    }
  } catch(e) { console.log('yahvt:', e); }
}
//());

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