yahvt

yet another html5 video tool

目前為 2016-07-30 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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.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://www.gooddrama.net/*
// @include     http://www.lovemyanime.net/*
// @include     http://www.theanime.tv/*
// @include     http://www.videozoo.me/*
// @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/*
// @version     1.11
// @grant       GM_xmlhttpRequest
// @icon        data:image/gif;base64,R0lGODlhMAAwAKECAAAAAICAgP///////yH5BAEKAAMALAAAAAAwADAAAALQnI+py+0Po5y02ouz3rz7D4biBJTmiabqyrbuC8fyHAf2jedpzuOvAAwKh6mhUfg7Hks3gHLpehptwIBTioxig0zrdStIgrslMFA8pCKp1oAZjXW6w/Mt/Nl2t8HeFl7o5QZgBagEYyawNxhUl7h4dlelFlZG+QVY6aglmIjjuKd50xla9RKI0mSCqaPJSMM0aEK4mhfbpSnTabM4WXrShtpHI6gqKvmKnCwns0tm2lOsLP3aUy08aK0zvc3d7b09Ei4+Tl5ufo6err7O3n5QAAA7
// @compatible  firefox
// ==/UserScript==
"use strict";
var doc=document, isTop=window.self==window.top, domain;
try { domain = doc.domain.match(/^(?:www\.)?(.*)$/)[1]; } catch(e) { domain = 'unknown'; alert('document.domain'); }
yahvt();

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]);
          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
    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 '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
    obj('+SCRIPT', doc.body).innerHTML = 'checkMobile=function(){isMobile=true;}';
    break;
  case 'freeanime'://.com
    obj('+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':
    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('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) {
  //if(!v) v = obj('VIDEO');
  (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);
}

//

function NoScriptClickBugHandler(event) {
  var v = event.currentTarget;
  if(v.paused) v.play();
  else v.pause();
}

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('Packed script detected.'); } catch(e) { console.log('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[imy]*$/.test(pattern.toSource());
    do {
      var m = pattern.exec(s);
      if(!m) break;
      add(decodeURIComponent(unescape(m[1])));
    } while(g);
  }
  var v = [], s, m, a, i, p;
  a = obj('VIDEO', doc.body); if(a) {//usually doesn't exist yet
    add(a.getAttribute('src'));
    a = objs('SOURCE', a);
    for(i of a) {
      add(i.getAttribute('src'));
    }
  }
  a = objs('SCRIPT', (domain=='videozoo.me' ? doc.documentElement : doc.body)); for(i of a) { 
    if(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); addm1(m);
    }
    a = objs('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('html5_path in comment found.');
      add(m);
    }
  } catch(e){}
  try {// animeboy
    add(unescape(obj('NOSCRIPT').innerHTML.match(/<param\sname="movie"\svalue="\S+&fpath=([^&]+)&/i)[1]).replace(/\+/g,'%20'));
    console.log('movie param in noscript found.');
  } catch(e){}
  a = objs('PARAM'); for(i of a) { p = i.getAttribute('value'); m = p.match(/video=(http:\/\/[^'"]+\.mp4[^'"&]*)/i); addm1(m); }
  a = objs('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(a, 'ignored.')
        delete v[i];
      }
    } while(i);
  }
  return v;
}

//(
function yahvt() {
function insertVideo() {
function ShowSomeInfo(meta) {
  var div = obj('+DIV.info'), txt = domain + (nvf ? (' video part '+nvf[2]) : ' video'), src = v.currentSrc, m, adr = ['mailto:gnblizz'];
  if(meta) {
    var t = v.duration + .5;
    txt += '<br>original size: ' + 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' : '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;
  v.parentNode.appendChild(div);
  window.setTimeout(StopInfo, 15000);
}
function StopInfo() {
  var o = v.parentNode.querySelector('div.info');
  if(o) RemoveElement(o);
}
function NextPart(name) {
  var m = name.match(/^(.*(?:part|clip)_?0?)(\d+)(.*)$/);
  if(m) {
    m[2] = parseInt(m[2]);// current part number
    m[1] = m[1]+(m[0]=m[2]+1)+m.pop();// next part URL
  }
  return m;
}
  var nvf = NextPart(doc.URL), txt = '<video controls ' + (autoplay ? 'autoplay ' : '') + 'width="100%" height="100%" tabindex="1', altClick;
  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(obj('#flowplayer')) txt += '<div id="flowplayer"></div>';
  else if(obj('#player')) txt += '<div id="player"></div>';
  doc.body.innerHTML = txt;
  console.log('starting ' + domain + (nvf ? (' video part '+nvf[2]) : ' video'));
  var v = obj('VIDEO');
  v.onloadedmetadata = function(event) {
    StopInfo();
    //console.log('now playing: '+v.currentSrc);
    if(remembered('fullscreen', true)=='yes')
      SetFullScreenMode(v);
    v.focus();
  };
  v.onkeypress = function(event) {
    if(event.altKey || event.metaKey || event.ctrlKey) return;
    var key = event.key;
    if(key.length == 1) {
      switch(key.toUpperCase()) {
      case 'A':// toggle stretch mode
        v.style.objectFit = v.style.objectFit ? '' : 'fill';
        v.parentNode.style.height = '100%';
        break;
      case 'H':// toggle LMB behavior
        ((altClick = !altClick) ? v.addEventListener : v.removeEventListener).call(v, 'click', NoScriptClickBugHandler, false);
        break;
      case 'I':// show some info
        ShowSomeInfo(true);
        break;
      case 'F':// toggle full screen
        if(!EndFullScreenMode())
          SetFullScreenMode(v);
        break;
      case 'Y':
      case 'Z':// toggle zoom mode
        if(v.parentNode.style.width) {
          v.parentNode.style.width = '';
          v.parentNode.style.margin = '';
        } else if(v.videoWidth) {
          v.parentNode.style.width = v.videoWidth+'px';
          v.parentNode.style.minHeight = v.videoHeight+'px';
          v.parentNode.style.margin = '0px auto';
        }
        break;
      default:
        return;
      }
    } else if(!event.shiftKey) {
      switch(key) {
      case 'ArrowRight':
        v.currentTime += v.paused ? .5 : 5;
        break;
      case 'ArrowLeft':
        v.currentTime -= v.paused ? .5 : 5;
        break;
      default:
        return;
      }
    } else return;
    event.preventDefault();
    event.stopImmediatePropagation();
  };
  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('video load error');
    if(nvf && nvf[2]>1)
      doc.body.innerHTML = '<center style="color:orange;"><br><br>No part '+nvf[2]+' 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 && !obj('#VideoCloseButton')) {
      var btnClose = MakeAButton('x', 'close', 0);
      btnClose.id = 'VideoCloseButton';
      btnClose.onclick = function(event){ location.replace('about:blank'); };
    }
    if(nvf) {
      var btnNext = MakeAButton(nvf[0], 'on to part '+nvf[0], 1);
      btnNext.onclick = function(event) {
        console.log('redirecting to part '+nvf[0]);
        Remember('autoplay');
        Remember('fullscreen', (wasFullScreen ? 'yes' : ''));
        location.replace(nvf[1]);
      };
      TestResource(nvf[1], btnNext);
    } else {//nfv
      var vf = v.currentSrc, m = vf.match(/^(.*(?:part|clip)_?0?)(\d+)(.*)$/);
      if(m) {
        console.log('using alternate next part algorithm (experimental)');
        var inp = parseInt(m[2])+1;
        vf = m[1] + inp + m[3];
        var btnNext2 = MakeAButton(inp, 'on to part '+inp, 1);
        btnNext2.onclick = function(event) {
          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) {
          TestResource(vf, btnNext2);
        }
      }//m
    }//!nfv 
  };//v.onended
  ShowSomeInfo(false);
  OnFullScreenChange(function(event) { obj('VIDEO').focus(); });
}
  try {
    if(sites()) {
      var av = findVideoFiles();
      if(av && av.length) {
        if(av[0].match(/\/blank.mp4$/)) av.push(av.shift());
        var v = obj('VIDEO'); if(v) { v.pause(); v.src = ''; }
        //SetStyle('body,html{padding:0px;margin:0px;height:100%;overflow:hidden;background:#000;color:#fff;font-size:14px;}\nvideo{outline:0;}\n#player,#flowplayer{display:none}\n.info{position:absolute;top:50px;left:50px;text-shadow:1px 1px black;}');
        SetStyle(
          MakeCSSStringX('body,html',{padding:0, margin:0, height:'100%', overflow:'hidden', background:'#000', color:'#fff', font_size:14}) + 
          MakeCSSStringX('video', {outline:0}) +
          MakeCSSStringX('#player,#flowplayer', {display:'none'}) +
          MakeCSSStringX('.info', {position:'absolute', top:50, left:50, text_shadow:'1px 1px black'}) +
          MakeCSSStringX('.info a', {color:'unset'})
        );
        console.log('Found '+av.length+' video source'+(av.length==1 ? '' : 's')+' at '+domain+'.');
        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>';
          autoplay = true;
          obj('BUTTON').onclick = function() { insertVideo(); }
        } else {
          insertVideo();
        }
      } else {
        if(/^video(?:wing|zoo).me$/.test(domain) && !/\bnoflash\b/i.test(location.search)) {
          console.log('redirecting to location + noflash');
          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)) { doc.body.innerHTML = '<p>Video not found.</p>'; break; }
        }
      }
    }
  } catch(e) { console.log('yahvt: ' + e); }
}
//());

function TestResource(url, btn) {
  var req = new XMLHttpRequest();
  if(req) {
    req.open('HEAD', url, true);
    req.onloadend = function () {
      switch(req.status) {
      case 200:
        if(req.statusText != 'Not Found')
          btn.click();
      case 404:
        RemoveElement(btn);
      }
    };
    req.send();
  }
}

function obj(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];
  case '+':
    var a = name.split(','); name = a.shift();
    var m = name.match(/^\+([A-Za-z]+)\b/), node = doc.createElement(m[1]);
    m = name.match(/\.\w+/); if(m) node.className = m[0].slice(1);
    m = name.match(/#\w+/); if(m) node.id = 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);
      node.setAttribute(l[0], l[1]);
    };
    if(parent != doc) parent.appendChild(node);
    return node;
  }
  return parent.getElementsByTagName(name)[0];
}

function objs(name, parent) {
  if(!parent) parent = doc;
  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,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 = doc.body;
  parent.appendChild(b);
  return b;
}

function MakeCSSString(d) {
  var names = Object.getOwnPropertyNames(d), style = '', x, v;
  for(x of names) {
    v = d[x];
    if(typeof(v) == 'number') v += 'px';
    style += x.replace(/_/g,'-') + ':' + v + '; '
  }
  return style;
}

function MakeCSSStringX(name, d) {
  return name + '{' + MakeCSSString(d) + '}\n';
}

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