yahvt

yet another html5 video tool

  1. // ==UserScript==
  2. // @name yahvt
  3. // @description yet another html5 video tool
  4. // @namespace gnblizz
  5. // @homepageURL https://greasyfork.org/en/scripts/14476-yahvt
  6. // @version 1.17
  7. // @include http://anilinkz.io/*
  8. // @include http://www.animecenter.tv/*
  9. // @include http://www.animedreaming.tv/*
  10. // @include http://anime-exceed.com/*
  11. // @include http://www.animefreak.tv/*
  12. // @include http://www.animenova.org/*
  13. // @include http://play.animenova.org/*
  14. // @include http://www.animeplus.tv/*
  15. // @include http://www.animeseason.com/*
  16. // @include http://as.animes-stream24.tv/*
  17. // @include http://www.anime-sub.co/*
  18. // @include http://www.animetoon.org/*
  19. // @include http://www.animeultima.io/*
  20. // @include http://www.animewow.org/*
  21. // @include http://bestanimes.tv/*
  22. // @include http://www.chia-anime.tv/*
  23. // @include http://www.clipfish.de/*
  24. // @include http://dramago.com/*
  25. // @include http://www.drama.net/*
  26. // @include http://www.dramago.com/*
  27. // @include http://www.dramagalaxy.tv/*
  28. // @include http://dubbedanime.net/*
  29. // @include http://www.dubzonline.ca/*
  30. // @include http://freeanime.com/*
  31. // @include http://www.gogoanime.to/*
  32. // @include http://www.goodanime.co/*
  33. // @include http://www.gooddrama.to/*
  34. // @include http://www.lovemyanime.net/*
  35. // @include http://playbb.me/*
  36. // @include http://video66.org/new/*
  37. // @include http://videozoo.me/*
  38. // @include http://www.videozoo.me/*
  39. // @include about:blank?video=*
  40. // @include h*embed*
  41. // @include h*gogo/*
  42. // @include h*widget/*
  43. // @exclude https://apis.google.com/*
  44. // @exclude https://archive.org/embed/*
  45. // @exclude https://openload.co/embed/*
  46. // @run-at document-start
  47. // @grant GM_xmlhttpRequest
  48. // @icon data:image/gif;base64,R0lGODlhMAAwAKECAAAAAICAgP///////yH5BAEKAAMALAAAAAAwADAAAALQnI+py+0Po5y02ouz3rz7D4biBJTmiabqyrbuC8fyHAf2jedpzuOvAAwKh6mhUfg7Hks3gHLpehptwIBTioxig0zrdStIgrslMFA8pCKp1oAZjXW6w/Mt/Nl2t8HeFl7o5QZgBagEYyawNxhUl7h4dlelFlZG+QVY6aglmIjjuKd50xla9RKI0mSCqaPJSMM0aEK4mhfbpSnTabM4WXrShtpHI6gqKvmKnCwns0tm2lOsLP3aUy08aK0zvc3d7b09Ei4+Tl5ufo6err7O3n5QAAA7
  49. // @compatible firefox
  50. // @compatible chrome
  51. // ==/UserScript==
  52. "use strict";
  53. var doc=document, isTop=window.self==window.top, domain = (doc.domain||'unknown.').split('.').reverse(), insertionPoint, isFF = /Firefox/i.test(navigator.userAgent), maxmsg=99;
  54.  
  55. doc.addEventListener('DOMContentLoaded', yahvt);
  56.  
  57. !function earlyHacks(){
  58. switch(domain[1]) {
  59. case 'clipfish'://.de
  60. if(isFF) nn('SCRIPT', { TEXT: 'checkMobile=function(){isMobile=true;}' }, doc.body);
  61. else Object.defineProperty(navigator, "userAgent", {value: 'fake Android'});
  62. break;
  63. }
  64. }();
  65.  
  66. function sites(){
  67. var a,i,o,e,b;
  68. //console.log('yahvt: domain =', domain);
  69. switch(domain[1]) {
  70. case 'anilinkz'://.tv => io
  71. SetStyle('ID=yahvt_noad', '#waifu,body>div:empty[style*="z-index: 2147483647;"]{display:none;}');
  72. allowFullscreen('#player');
  73. /*setTimeout(function () {
  74. var i = setInterval(function () {}, 999);
  75. do { clearInterval(i); } while(--i);
  76. i = setTimeout(function () {}, 999);
  77. do { clearTimeout(i); } while(--i);
  78. }, 45000);//*/
  79. break;
  80. case 'animecenter'://.tv
  81. allowFullscreen('#video');
  82. break;
  83. case 'animedreaming'://.tv
  84. allowFullscreen('.videoholder');
  85. break;
  86. case 'anime-exceed'://.com
  87. allowFullscreen('#player', (/^\/cool\//.test(location.pathname)?'':'body'),0,999);
  88. break;
  89. case 'animefreak'://.tv
  90. a=na('.multi'); for(o of a) {
  91. e = o.getAttribute('onclick');
  92. if(e && /loadParts\('http/.test(e))
  93. o.onclick = function(event) {
  94. var vid_file = decodeURIComponent(this.getAttribute('onclick').match(/loadParts\('([^']+)'/)[1]);
  95. doc.getElementById("player").innerHTML = '<video controls width="100%" height="412" src="' + vid_file + '" allowfullscreen="true" autoplay></video>';
  96. };
  97. }
  98. break;
  99. case 'animenova'://.tv => org
  100. case 'animeplus'://.tv
  101. case 'animetoon'://.tv => org
  102. case 'animewow'://.eu => org
  103. case 'dramagalaxy'://.eu,com => tv
  104. case 'dramago'://.com
  105. case 'gooddrama'://.net => to
  106. allowFullscreen('#streams');
  107. return 1;
  108. case 'animeseason'://.com
  109. if(fn('#series_info'))
  110. SetStyle('table a:visited{color:gray;}table a:hover{color:#FC0;}');
  111. allowFullscreen('#video_source', 0, '#player_list A');
  112. break;
  113. case 'drama'://.net
  114. SetStyle('#Movie>div:first-child{height:411px}#Movie.max>div:first-child{height:585px}#Movie>div>iframe{width:100%;height:100%;}div.header{z-index:99;}div.container{z-index:unset;}');
  115. allowFullscreen('#Movie');
  116. break;
  117. case 'anime-sub'://.com => co
  118. allowFullscreen('#movie-content');
  119. break;
  120. case 'animeultima'://.tv => io // error
  121. allowFullscreen('#pembed');
  122. break;
  123. case 'bestanimes'://.tv
  124. allowFullscreen('.post');
  125. break;
  126. case 'freeanime'://.com
  127. nn('SCRIPT', { HTML: '$(window).unbind();\n$("#header").css("background-attachment","scroll")'}, doc.body);
  128. allowFullscreen('.z-video', 0, 'ul.z-tabs-nav LI', 999);
  129. break;
  130. case 'goodanime'://.net => co
  131. allowFullscreen('#content');
  132. case 'dubzonline'://.com => ca
  133. return(location.pathname == '/embed.php');
  134. case 'lovemyanime'://.net
  135. //allowFullscreen('.player-area');
  136. break;
  137. case 'animes-stream24'://.net => .tv
  138. allowFullscreen('#main');
  139. break;
  140. case 'gogoanime'://.com => .to
  141. return location.pathname=='/flowplayer/' || allowFullscreen('#content');
  142. case 'video66'://.org
  143. case 'playbb'://.me
  144. case 'videozoo'://.me
  145. return 1;// return(location.pathname == '/dr_video_player.php');
  146. case 'unknown'://about:blank?video="..."
  147. if(/^about:blank\?video=/.test(location.href))
  148. return nn('SCRIPT', { TEXT: '("'+location.href.slice(18)+'")' }, doc.body);
  149. break;
  150. default:
  151. return(/(embed\b|\/gogo\/|\/widget\/)/.test(doc.URL));
  152. }
  153.  
  154. function allowFullscreen(selTop, selFrame, mirrors, delay) {
  155. if(delay)
  156. window.setTimeout( function() { allowFullscreen(selTop, selFrame, mirrors); }, delay);
  157. else {
  158. var a,i;
  159. if(isTop) {
  160. if(mirrors) {
  161. a = doc.querySelectorAll(mirrors);
  162. for(i of a) {
  163. i.addEventListener('click', function() {
  164. window.setTimeout( function() { doc.querySelector(selTop+' IFRAME').setAttribute('allowfullscreen', 'true'); }, 99);
  165. });
  166. }
  167. }
  168. a = doc.querySelectorAll(selTop+' IFRAME');
  169. if(!a.length) console.log('yahvt: couldn\'t apply fullscreen attribute because '+selTop+' IFRAME not found in '+doc.URL);
  170. for(i of a) { i.setAttribute('allowfullscreen', 'true'); }
  171. } else if(selFrame) {
  172. a = doc.querySelectorAll(selFrame+' IFRAME');
  173. for(i of a) { i.setAttribute('allowfullscreen', 'true'); }
  174. }
  175. }
  176. }}
  177.  
  178. // FULL SCREEN API
  179.  
  180. //requires about:config full-screen-api.allow-trusted-requests-only=false
  181. function SetFullScreenMode(v) {
  182. (v.requestFullscreen||v.mozRequestFullScreen||v.webkitRequestFullscreen||v.webkitEnterFullscreen).call(v);
  183. //console.info('To allow full screen mode, you may want to set full-screen-api.allow-trusted-requests-only to false in about:config.');
  184. }
  185.  
  186. function FullScreenElement() {
  187. if(doc.exitFullscreen) return doc.fullscreenElement;
  188. if(doc.mozCancelFullScreen) return doc.mozFullScreenElement;
  189. if(doc.webkitExitFullscreen) return doc.webkitFullscreenElement;
  190. }
  191.  
  192. function EndFullScreenMode() {
  193. if(!FullScreenElement()) return false;
  194. (doc.exitFullscreen||doc.mozCancelFullScreen||doc.webkitExitFullscreen).call(doc);
  195. return true;
  196. }
  197.  
  198. function OnFullScreenChange(fn) {
  199. if(doc.exitFullscreen) doc.addEventListener("fullscreenchange", fn);
  200. if(doc.mozCancelFullScreen) doc.addEventListener("mozfullscreenchange", fn);
  201. if(doc.webkitExitFullscreen) doc.addEventListener("webkitfullscreenchange", fn);
  202. }
  203.  
  204. function SetFocus(v) {
  205. if(!v) v = fn('VIDEO');
  206. setTimeout(function(){ v.focus(); }, 0);
  207. }
  208.  
  209. // new node
  210. function nn(name, attributes, insertion) {
  211. var a = name.split('.'), i = a.shift().split('#'), node = doc.createElement(i.shift());
  212. if(i[0]) node.id = i[0];
  213. if(a[0]) node.className = a.join(' ');
  214. if(attributes) {
  215. var names = Object.keys(attributes);
  216. for(name of names) {
  217. var value = attributes[name];
  218. switch(name) {
  219. case 'TEXT':
  220. node.textContent = value;
  221. break;
  222. case 'HTML':
  223. node.innerHTML = value;
  224. break;
  225. case 'style':
  226. if(typeof value == 'object')
  227. value = ConvertCSS(value);
  228. default:
  229. node.setAttribute(name, value);
  230. }
  231. }
  232. }
  233. if(insertion) {
  234. if(insertion.appendChild)
  235. insertion.appendChild(node);
  236. else {
  237. i = Object.keys(insertion)[0];
  238. if(i) {
  239. a = insertion[i];
  240. switch(i) {
  241. case 'append': a.appendChild(node); break;
  242. case 'insert': a.insertBefore(node, a.firstChild); break;
  243. case 'before': a.parentNode.insertBefore(node, a); break;
  244. case 'after': a.parentNode.insertBefore(node, a.nextSibling); break;
  245. }
  246. }}}
  247. return node;
  248. }
  249.  
  250. // find node
  251. function fn(name, parent) {
  252. if(!parent) parent = doc;
  253. switch(name.charAt(0)) {
  254. case '#': return parent.getElementById(name.slice(1));
  255. case '.': return parent.getElementsByClassName(name.slice(1))[0];
  256. case '?': return parent.querySelector(name.slice(1));
  257. }
  258. return parent.getElementsByTagName(name)[0];
  259. }
  260.  
  261. // find nodes array
  262. function na(name, parent) {
  263. if(!parent) parent = doc;
  264. return (name.charAt(0)=='.') ? parent.getElementsByClassName(name.slice(1)) : parent.getElementsByTagName(name);
  265. }
  266.  
  267. // remove node
  268. function rn(node) {
  269. if(typeof(node)=='string') node = fn(node);
  270. if(node) return node.parentNode.removeChild(node);
  271. }
  272.  
  273. function domainName(href) {
  274. if(!href) href = location.href;
  275. var m = href.match(/\:\/\/(?:www\.|embed\.)?([^\/]+)/);
  276. if(m) return m[1];
  277. return 'unknown';
  278. }
  279.  
  280. function Remember(name, value) {
  281. try {
  282. if(sessionStorage) switch(value) {
  283. case '':
  284. sessionStorage.removeItem(name);
  285. break;
  286. case undefined:
  287. value = 'yes';
  288. default:
  289. sessionStorage.setItem(name, value);
  290. }
  291. }catch(e){}
  292. }
  293.  
  294. function remembered(name, forget) {
  295. try {
  296. var x = sessionStorage.getItem(name);
  297. if(forget) sessionStorage.removeItem(name);
  298. return x;
  299. } catch(e) {
  300. if(name=='autoplay' && (domain[1]=='unknown' || /\bnoflash\b/.test(location.search) || /(part|clip|chunk)_?0?[2-9]/.test(location.pathname))) return 'yes';
  301. }
  302. }
  303.  
  304. // style
  305. function SetStyle() {
  306. var i = 0, style = '', t, name = 'STYLE';
  307. if(arguments[0].startsWith('ID='))
  308. name += '#' + arguments[i++].slice(3);
  309. do {
  310. style += arguments[i++];
  311. t = arguments[i++];
  312. switch(typeof t) {
  313. case 'object':
  314. t = ConvertCSS(t);
  315. case 'string':
  316. style += '{' + t + '}\n';
  317. }
  318. } while(i < arguments.length);
  319. return nn(name, { TEXT: style }, doc.head);
  320. }
  321.  
  322. function ConvertCSS(def) {
  323. var names = Object.keys(def), style = '', name, value;
  324. for(name of names) {
  325. value = def[name];
  326. if(typeof value == 'number' && ['zIndex','opacity'].indexOf(name) < 0) value += 'px';
  327. style += name.replace(/([A-Z])/g, '-$1').toLowerCase().concat(': ', value, '; ');
  328. }
  329. return style.trimRight();
  330. }
  331.  
  332. ///////////////////////////////////////////////////////////
  333.  
  334. function findVideoFiles() {
  335. function getScript(o) {
  336. s = o.innerHTML;
  337. if(s.length) {
  338. var m = s.match(/^eval(\(function\(p(?:,[a-ek]){5}\).+\bsplit\b.+)$/m), timer;
  339. if(m) {
  340. try { s += eval(m[1]); console.log('yahvt: Packed script detected.'); } catch(e) { console.log('yahvt: Packed script parse error.'); }
  341. }
  342. s = unescape(s.replace(/\s\/\/.*$/gm,'').replace(/\s+/gm,' ').replace(/\/\*.*\*\//g,'').replace(/'/g,'"'));
  343. /*if(domain[1]=='dailymotion')*/ s = s.replace(/\\\//g, '/');
  344. return s;
  345. }
  346. }
  347. function add(m) { if(m && v.indexOf(m)<0) v.push(m); }
  348. function addm1(m) { if(m && v.indexOf(m[1])<0) v.push(m[1]); }
  349. function find(pattern) {
  350. var g = /g/.test(pattern.flags);
  351. do {
  352. var m = pattern.exec(s);
  353. if(!m) break;
  354. try {
  355. add(decodeURIComponent(unescape(m[1])));
  356. } catch(e) {
  357. add(m[1]);
  358. }
  359. } while(g);
  360. }
  361. //findVideoFiles() {
  362. var v = [], s, m, a, i, p;
  363. a = fn('VIDEO', doc.body);
  364. if(a) {//usually doesn't exist yet
  365. add(a.getAttribute('src'));
  366. a = na('SOURCE', a);
  367. for(i of a) {
  368. add(i.getAttribute('src'));
  369. }
  370. }
  371. a = na('SCRIPT', (domain[1]=='videozoo' ? doc.documentElement : doc.body));
  372. //console.log(a.length, 'scripts at', domain[1]);
  373. for(i of a) {
  374. if(getScript(i)) {
  375. //console.log(s);
  376. find(/"(https?:\/\/[^"]+\.(?:mp4|flv)\b.*?)"/gi); //find(/"(https?:\/\/[^"]+\.(?:mp4|flv)\b[^"]*)"/gi);
  377. find(/"(.+\.php\b.+\.(?:mp4|flv))"/gi);
  378. find(/"([^"]+\bpicasa\.php\b[^"]+)"/gi);
  379. find(/"(https\:\/\/[^"]*\.google(?:video\.com\/videoplayback|usercontent.com\/)[^"]+)"/gi);
  380. }
  381. }
  382. switch(domain[1]) {
  383. case 'trollvid'://.net// Is this of any use today? TODO obsolete?
  384. for(i of a) {
  385. s = i.innerHTML; m = s.match(/['"](http.+?data.*?file.*?)['"]/i); addm1(m);
  386. }
  387. a = na('SCRIPT', doc.head); for(i of a) {
  388. m = i.innerHTML.match(/unescape\(atob\('(.+?)'/);
  389. if(m) { m = unescape(atob(m[1])); if(/\.(mp4|flv)/i.test(m)) add(m); }
  390. }
  391. break;
  392. case 'videobam'://.com// Is this of any use today?
  393. for(i of a) {
  394. s = i.innerHTML; m = s.match(/['"](http:\\\/\\\/[^'"]+\.(?:mp4|flv)\b[^'"]*)['"]/i); if(m) add(m[1].replace(/\\\//g,'/'));
  395. }
  396. case 'yourupload'://.com
  397. try {
  398. s = fn('#player').nextElementSibling.textContent;
  399. m = s.match(/'(\/play\/\d+\.flv\?.+?)'/);if(m) add(m[1]);
  400. }catch(e){ console.log(e); }
  401. }
  402. try {// even if it looks wierd...
  403. m = fn('?#flowplayer+script').innerHTML.replace(/\s+/g, ' ').match(/\/\* playlist\: \[ \{ url\: '(.*)'/)[1];
  404. if(!/\<|\>/.test(m)) {
  405. console.log('yahvt: html5_path in comment found.');
  406. add(m);
  407. }
  408. } catch(e){}
  409. a = na('PARAM'); for(i of a) { p = i.getAttribute('value'); m = p.match(/video=(https?:\/\/[^'"]+\.mp4[^'"&]*)/i); addm1(m); }
  410. a = na('EMBED'); for(i of a) { p = i.getAttribute('src'); m = p.match(/video=(https?:\/\/[^'"]+\.mp4[^'"&]*)/i); addm1(m); }
  411. switch(domain[1]) {
  412. case 'dailymotion':
  413. case 'vidstreaming':
  414. return v.reverse();
  415. case 'mp4upload':
  416. i = v.length;
  417. if(i) do {
  418. a = v[--i];
  419. if(a.match(/\.com\/\w+(?:\.mp4)?$/)) {
  420. console.log('yahvt:', a, 'ignored.');
  421. delete v[i];
  422. }
  423. } while(i);
  424. }
  425. return v;
  426. }
  427.  
  428. function yahvt(loadevent) {
  429. function insertVideo() {
  430. function ShowSomeInfo(meta) {
  431. var style = '', txt = domainName() + (nvp ? (' video part '+nvp.now) : ' video'), src = v.currentSrc, m, adr = ['mailto:gnblizz'];
  432. if(meta) {
  433. var t = v.duration + .5;
  434. txt += '<br>pixel format: ' + v.videoWidth + 'x' + v.videoHeight
  435. + '<br>duration: ' + Math.floor(t/60) + ':' + ('0' + Math.floor(t%60)).slice(-2);
  436. } else style = { color: '#666' };
  437. m = src.match(/https?:\/\/([^:?/]+)/);
  438. if(m) txt += '<br>video host name: ' + m[1];
  439. m = src.match(/.*\/([^?/]*)/);
  440. if(m) txt += '<br>video file name: ' + m[1];
  441. 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 - zoom';
  442. if(meta) {
  443. adr.push('@web.de?subject=yahvt%20at%20', doc.domain);
  444. 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('')
  445. + '" title="email the author directly">gnblizz</a>.</small>';
  446. }
  447. nn('DIV.info', { HTML: txt, style: style }, v.parentNode);
  448. window.setTimeout(StopInfo, 15000);
  449. }
  450. function StopInfo() {
  451. if(!v.paused || v.currentTime < 5) return rn(fn('?div.info', p));
  452. var div = fn('.info', p);
  453. if(div) nn('SMALL', { HTML: '<br><br>If there are issues regarding yahvt, someone has to complain.<br>Therefore, the two links above.' }, div);
  454. }
  455. function NextPart(name) {
  456. var m = name.match(/^(.*(?:part|clip|chunk)_?0?)(\d+)(.*)$/), i;
  457. if(m)
  458. return {now: i = parseInt(m[2]), next: ++i, URL: m[1]+i+m.pop()};
  459. }
  460. function StartStop() {
  461. if(v.paused) v.play();
  462. else v.pause();
  463. }
  464. //insertVideo() {
  465. var nvp = NextPart(doc.URL), txt = '<video controls ' + (autoplay ? 'autoplay ' : '') +
  466. 'width="100%" height="100%" tabindex="0', altClick, hTimer2, autoHide, smw, delay = 2;
  467. av.push(av[0]+'&noflash');
  468. av.push(av[0]+'&html5=true');
  469. av.forEach(function(x){ txt += '"><source src="' + x.replace(/\?/g,'&').replace('&','?'); });
  470. txt += '"></video>';
  471. if(fn('#flowplayer')) txt += '<div id="flowplayer"></div>';
  472. else if(fn('#player')) txt += '<div id="player"></div>';
  473. if(insertionPoint);//TODO
  474. else doc.body.innerHTML = txt;
  475. console.log('yahvt: starting ' + domainName() + (nvp ? (' video part '+nvp.now) : ' video'));
  476. var v = fn('VIDEO'), p = v.parentNode;
  477. v.onloadedmetadata = function(event) {
  478. if(!isFF && !isTop) {
  479. window.addEventListener('message', function(event) {
  480. console.log('event.data = ', event.data);
  481. if(event.data == 'canhandlezoom')
  482. document.defaultView.name = 'yahvtframe';
  483. }, false);
  484. }
  485. //console.log('yahvt: now playing: '+v.currentSrc);
  486. StopInfo();
  487. var format = [v.videoWidth, v.videoHeight].join('x'), info2 = nn('DIV.info2', {TEXT: format}, v.parentNode);
  488. window.setTimeout(function() {
  489. rn(info2);
  490. if(doc.defaultView.name == 'yahvtframe' && v.clientWidth == v.videoWidth) {
  491. info2 = nn('DIV.info2', { TEXT: 'press "Z" to zoom to window size', style: 'color: mediumseagreen;' }, v.parentNode);
  492. window.setTimeout(function() { rn(info2); }, 3000);
  493. }
  494. }, 5000);
  495. if(!isTop)
  496. window.top.postMessage('videoformat'+ format, '*');
  497. if(remembered('fullscreen', true)=='yes')
  498. SetFullScreenMode(v.parentNode);
  499. SetFocus(v);
  500. };
  501. p.onmousemove = function(event) {
  502. if(hTimer2) clearTimeout(hTimer2);
  503. else p.style.cursor = '';
  504. if(autoHide) {
  505. hTimer2 = setTimeout(function() {
  506. hTimer2 = 0;
  507. p.style.cursor = 'none';
  508. }, 3456);
  509. } else hTimer2 = 0;
  510. delay = 1;
  511. };
  512. v.onplaying = function(event) {
  513. autoHide = 1;
  514. StopInfo();
  515. hTimer2 = setTimeout(function() {
  516. hTimer2 = 0;
  517. p.style.cursor = 'none';
  518. }, delay * 3456);
  519. };
  520. v.onpause = function(event) {
  521. if(hTimer2) clearTimeout(hTimer2);
  522. else p.style.cursor = '';
  523. autoHide = 0;
  524. hTimer2 = 0;
  525. delay = 0;
  526. };
  527. v.onkeypress = function(event) {
  528. if(event.altKey || event.metaKey || event.ctrlKey) return;
  529. var info2;
  530. switch(event.key.toUpperCase()) {
  531. case ' ':
  532. if(isFF) return;
  533. case 'P':
  534. StartStop();
  535. break;
  536. case 'A':// toggle stretch mode
  537. if(v.style.objectFit) {
  538. v.style.objectFit = '';
  539. p.style.height = '';
  540. v.style.objectPosition = v.style.objectPosition ? '' : 'center top';
  541. } else {
  542. v.style.objectFit = 'fill';
  543. p.style.height = '100%';
  544. }
  545. break;
  546. case 'F':// toggle full screen
  547. if(!EndFullScreenMode())
  548. SetFullScreenMode(v.parentNode);
  549. break;
  550. case 'H':// toggle LMB behavior
  551. ((altClick = !altClick) ? v.addEventListener : v.removeEventListener).call(v, 'click', StartStop, false);
  552. break;
  553. case 'I':// show some info
  554. if(!rn(fn('?div.info', p)))
  555. ShowSomeInfo(true);
  556. break;
  557. case 'Q':// quick view
  558. if(!smw) {
  559. info2 = nn('DIV.info2', { TEXT: 'press "Q" to end quick view mode' }, v.parentNode);
  560. smw = window.setTimeout(function() { rn(info2); }, 3000);
  561. }
  562. v.playbackRate = v.playbackRate != 1 ? 1 : 2;
  563. break;
  564. case 'S':// slow motion
  565. if(!smw) {
  566. info2 = nn('DIV.info2', { TEXT: 'press "S" to end slow motion mode' }, v.parentNode);
  567. smw = window.setTimeout(function() { rn(info2); }, 3000);
  568. }
  569. v.playbackRate = v.playbackRate != 1 ? 1 : .05;
  570. break;
  571. case 'Y': case 'Z':// toggle zoom mode
  572. if(doc.defaultView.name == 'yahvtframe') {
  573. window.top.postMessage('keystrokeZ', '*');
  574. break;
  575. }
  576. if(p.style.width) {
  577. p.style.width = '';
  578. p.style.minHeight = p.parentNode.clientHeight+'px';
  579. p.style.margin = '';
  580. } else if(v.videoWidth) {
  581. p.style.width = v.videoWidth+'px';
  582. p.style.minHeight = v.videoHeight+'px';
  583. p.style.margin = '0px auto';
  584. }
  585. break;
  586. default:
  587. return;
  588. }
  589. event.preventDefault();
  590. event.stopPropagation();
  591. };
  592. v.onkeydown = function(event) {
  593. if(event.altKey || event.metaKey || event.ctrlKey || event.shiftKey) return;
  594. switch(event.key) {
  595. case 'ArrowRight':
  596. v.currentTime += v.paused ? .5 : 5;
  597. break;
  598. case 'ArrowLeft':
  599. v.currentTime -= v.paused ? .5 : 5;
  600. break;
  601. case 'Escape':
  602. v.playbackRate = 1;
  603. default:
  604. return;
  605. }
  606. event.preventDefault();
  607. event.stopImmediatePropagation();
  608. };
  609. if(!isFF) {
  610. v.onclick = function(event) {
  611. if(doc.hasFocus()) StartStop();
  612. SetFocus(v);
  613. //onmousedown event.preventDefault();?
  614. };
  615. }
  616. v.lastChild.onerror = function(event) {
  617. StopInfo();
  618. if(!/\bnoflash\b/.test(location.search)) {
  619. Remember('autoplay');
  620. location.search = location.search ? location.search+'&noflash' : '?noflash';
  621. throw 'redirecting to location + noflash';
  622. }
  623. console.log('yahvt: video load error');
  624. if(nvp && nvp.now>1)
  625. if(!isTop) window.top.postMessage('videoended', '*');
  626. 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>';
  627. remembered('fullscreen', true);// discard value
  628. };
  629. v.onended = function(event) {
  630. var wasFullScreen = EndFullScreenMode();
  631. autoHide = 0;
  632. p.style.cursor = '';
  633. if(!isTop && !fn('#VideoCloseButton')) {
  634. if(!nvp) window.top.postMessage('videoended', '*');
  635. nn('BUTTON#VideoCloseButton', { type: 'button', TEXT: 'x', title: 'close' }, p).onclick = function(event){
  636. if(nvp) window.top.postMessage('videoended', '*');
  637. location.replace('about:blank');
  638. return false;
  639. };
  640. }
  641. if(nvp) {
  642. var btnNext = nn('BUTTON#NextPartButton', { type: 'button', TEXT: nvp.next, title: 'on to part '+nvp.next }, p), req = new XMLHttpRequest();
  643. btnNext.onclick = function(event) {
  644. console.log('yahvt: redirecting to part '+nvp.next);
  645. Remember('autoplay');
  646. Remember('fullscreen', (wasFullScreen ? 'yes' : ''));
  647. location.replace(nvp.URL);
  648. return false;
  649. };
  650. btnNext.focus();
  651. if(req) {
  652. req.open('HEAD', nvp.URL, true);
  653. req.onloadend = function() {
  654. switch(req.status) {
  655. case 200:
  656. if(req.statusText != 'Not Found')
  657. btnNext.click();
  658. case 404:
  659. rn(btnNext);
  660. }
  661. };
  662. req.send();
  663. }
  664. }//nfv
  665. };//v.onended
  666. ShowSomeInfo(false);
  667. OnFullScreenChange(function(event) { fn('VIDEO').focus(); });
  668. }
  669. function Block(event) {
  670. event.preventDefault();
  671. if(maxmsg>=0) {
  672. console.warn("yahvt: blocking script element:", event.target.src, event.defaultPrevented);
  673. if(!(--maxmsg)) {
  674. //console.log('yahvt:', event);
  675. throw('to many alien script requests.');
  676. } //trollvid tries again and again, causing heavy CPU load, so we give up
  677. }else doc.defaultView.removeEventListener('beforescriptexecute', Block);
  678. }
  679. //yahvt() {
  680. try {
  681. if(!isTop && !doc.styleSheets.length && !doc.body.childElementCount)
  682. SetStyle('ID=yahvt_contrast', 'body{background-color: black; color: white;}');
  683. if(sites()) {
  684. var av = findVideoFiles();
  685. if(av && av.length) {
  686. // we block things only after we are sure they aren't needed
  687. if(!insertionPoint) {
  688. doc.defaultView.addEventListener('beforescriptexecute', Block);
  689. var n = setTimeout(function(){},0); while(--n){clearTimeout(n);};
  690. n = setInterval(function(){},999); while(n){clearInterval(n--);};
  691. }
  692. console.log('yahvt: Found '+av.length+' video source'+(av.length==1 ? '' : 's')+' at '+domainName()+'.');
  693. console.log('yahvt:', av);
  694. if(/\/blank.mp4$/.test(av[0])) av.push(av.shift());
  695. var v = fn('VIDEO');
  696. if(v) { v.pause(); v.removeAttribute('src'); }
  697. SetStyle(
  698. 'body,html', {padding:0, margin:0, height:'100%', overflow:'hidden', background:'#000', color:'#fff', fontSize:14},
  699. 'video', {outline:0},
  700. '#player,#flowplayer', {display:'none'},
  701. 'button#VideoCloseButton', {position: 'absolute', top:0, right:0, height:25, minWidth:25},
  702. 'button#NextPartButton', {position: 'absolute', top:0, right:30, height:25, minWidth:25},
  703. '.info a', {color:'unset'},
  704. '.info', {position: 'absolute', top:50, left:50, textShadow:'1px 1px black'},
  705. '.info2', {position: 'absolute', top:1, left:2, textShadow:'1px 1px black', fontSize:'large'}
  706. );
  707. var autoplay = remembered('autoplay', true) == 'yes';
  708. if(!isTop && !autoplay) {
  709. doc.body.innerHTML = '<center><p>Video '+((/(part|clip|chunk)_?\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>';
  710. fn('BUTTON').onclick = function() { autoplay = true; insertVideo(); };
  711. fn('BUTTON').focus();
  712. } else {
  713. insertVideo();
  714. }
  715. } else {
  716. if(/^video(wing|zoo)$/.test(domain[1]) && !/\bnoflash\b/i.test(location.search)) {
  717. console.log('yahvt: redirecting to location + noflash');
  718. location.search = location.search ? location.search+'&noflash' : '?noflash';
  719. }
  720. var as = na('SCRIPT'), i;
  721. for(i of as) {
  722. if(/_url\s*=\s*\"video not found\"/i.test(i.innerHTML)) { doc.body.innerHTML = '<p>Video not found.</p>'; break; }
  723. }
  724. }
  725. }
  726. } catch(e) { console.log('yahvt:', e); }
  727. }
  728.  
  729. function receiveMessage(event) {
  730. function RestoreFormat() {
  731. var view = fn('#yahvt_currentview');
  732. if(view) view.removeAttribute('id');
  733. rn('#yahvt_fmtbtn');
  734. rn('#yahvt_dimmer');
  735. }
  736. function InsertButton() {
  737. rn('#yahvt_fmtbtn');
  738. var spn, btn;
  739. try {
  740. spn = fn('?#player_tabs>li[title="about videotabs"]~li:last-child');
  741. if(spn)
  742. return nn('LI#yahvt_fmtbtn', {title: 'video width', style: 'float:right;padding:5px;', TEXT: x},{before: spn});
  743. switch(domain[1]) {
  744. case 'animecenter':
  745. case 'freeanime':
  746. return nn('BUTTON#yahvt_fmtbtn', {title: 'video width', type: 'button', style: 'float:left;', TEXT: x } , fn('.rating_div'));
  747. case 'anilinkz':
  748. return nn('BUTTON#yahvt_fmtbtn', {title: 'video width', type: 'button', style: 'float:right;margin:12px 12px 0px 0px;', TEXT: x}, {before: fn('#watchmode').parentNode});
  749. case 'animeseason':
  750. return nn('DIV#yahvt_fmtbtn', { title: 'video width', style: 'background:url(/images/video_icons.png) -171px 0 no-repeat;width:57px;height:55px;margin-right:55px;line-height:55px;cursor:pointer;', HTML: '<style>#yahvt_fmtbtn + div{display:none;}</style>'+x}, { before: fn('#video_views')});
  751. case 'drama':
  752. return nn('DIV#yahvt_fmtbtn', { title: 'video width', style: {textAlign: 'center'}, TEXT: x}, { insert: fn('.p-right-buttons')});
  753. }
  754. } catch(e) {
  755. console.log(e);
  756. }
  757. return nn('BUTTON#yahvt_fmtbtn', {title: 'video width', type: 'button', style: 'position:absolute;top:-21px;left:1px;', TEXT: x}, nn('SPAN',{style:'position:relative;'},{after: frame}));
  758. }
  759. function FindFrame(event) {
  760. var frames = na('IFRAME'), i;
  761. for(i of frames) {
  762. if(i.contentWindow === event.source) return i;
  763. }
  764. }
  765. //receiveMessage
  766. try {
  767. //console.log('yahvt: received message', event);
  768. if(typeof event.data != 'string') return;
  769. var frame = FindFrame(event), style, fullwinstyle, dim;
  770. if(!frame) return;
  771. switch(event.data.slice(0,11)) {
  772. case 'videoformat':
  773. frame.name = 'yahvtframe';
  774. if(!isFF) frame.contentWindow.postMessage('canhandlezoom', '*');
  775. var m = event.data.match(/(\d+)x(\d+)$/), x = parseInt(m[1]), y = parseInt(m[2])+(isFF ? 56 : 64), id, zi=100000, disable = false;
  776. //RestoreFormat();
  777. m = frame.parentNode;
  778. if(!m.id) m.id = 'yahvt_currentview';
  779. id = '#' + m.id;
  780. style = fn('#yahvt_top_style');
  781. if(style) {
  782. disable = style.disabled;
  783. rn(style);
  784. }
  785. style = SetStyle('ID=yahvt_top_style',
  786. 'html,body', { width: '100%', height: '100%', overflow: 'hidden'},
  787. id, { width: frame.clientWidth, height: frame.clientHeight, minHeight: frame.clientHeight},
  788. id+(isFF ? '>iframe' : '>iframe:not(:-webkit-full-screen)'), { border: '0px !important', position: 'fixed', width: x+'px!important', height: y+'px!important', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', margin: '0 auto', maxWidth: '100%', maxHeight: '100%', zIndex: zi},
  789. '#yahvt_fmtbtn', {display: 'none' },
  790. 'div#parent-container', {opacity: 1}, // animeultima
  791. '#yahvt_dimmer>div', { backgroundColor: 'black', opacity: '.85'},
  792. '#yahvt_dimmer>.topshade', { position: 'fixed', width: '100%', height: 'calc(50% - '+y/2+'px)', top: 0, left: 0, zIndex: zi},
  793. '#yahvt_dimmer>.bottomshade', { position: 'fixed', width: '100%', height: 'calc(50% - '+y/2+'px)', bottom: 0, left: 0, zIndex: zi},
  794. '#yahvt_dimmer>.leftshade', { position: 'fixed', width: 'calc(50% - '+x/2+'px)', height: y, top: 'calc(50% - '+y/2+'px)', left: 0, zIndex: zi},
  795. '#yahvt_dimmer>.rightshade', { position: 'fixed', width: 'calc(50% - '+x/2+'px)', height: y, top: 'calc(50% - '+y/2+'px)', right: 0, zIndex: zi}
  796. );
  797. style.disabled = disable;
  798. InsertButton().onclick = function() { style.disabled = false; };
  799.  
  800. if(!fn('#yahvt_fullWin_style')) SetStyle('ID=yahvt_fullWin_style',
  801. 'body '+id+'>iframe', { position: 'fixed!important', width:'100%!important', height: '100%!important', top: 0, left: 0, transform: 'unset!important', zIndex: zi},
  802. '#yahvt_dimmer', { display: 'none'}
  803. ).disabled = true;
  804.  
  805. rn('#yahvt_dimmer');
  806. dim = nn('DIV#yahvt_dimmer', 0, m);
  807. nn('div.topshade', 0, dim);
  808. nn('div.bottomshade', 0, dim);
  809. nn('div.leftshade', 0, dim);
  810. nn('div.rightshade', 0, dim);
  811. dim.onclick = function() { style.disabled = true; };
  812. break;
  813. case 'videoended':
  814. //var view = fn('#yahvt_currentview'); if(view) view.removeAttribute('id');
  815. rn('#yahvt_fmtbtn');
  816. rn('#yahvt_dimmer');
  817. rn('#yahvt_top_style');
  818. rn('#yahvt_fullWin_style');
  819. break;
  820. case 'keystrokeZ':
  821. fullwinstyle = fn('#yahvt_fullWin_style');
  822. fullwinstyle.disabled = !fullwinstyle.disabled;
  823. if(!isFF && !fullwinstyle.disabled) fn('#yahvt_top_style').disabled = true;//chrome fix
  824. break;
  825. }
  826. } catch(e){ console.log(e); }
  827. }
  828. if(isTop && !/^(anime-exceed|animefreak|anime-sub|bestanimes|clipfish)$/.test(domain[1]))
  829. window.addEventListener('message', receiveMessage, false);
  830.  
  831. // public domain by gnblizz
  832. // contact me with my username + '@web.de'