ArenaVision Helper

A script that makes browsing ArenaVision website easier on touchscreens and on browsers with adblock enabled

As of 2021-02-22. See the latest version.

// ==UserScript==
// @name     ArenaVision Helper
// @namespace    StephenP
// @version      1.8.6
// @description  A script that makes browsing ArenaVision website easier on touchscreens and on browsers with adblock enabled
// @author       StephenP
// @grant        GM.xmlHttpRequest
// @grant        GM.openInTab
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEVldC3+AwD/dW//rKr///+uAvmgAAAAAXRSTlMAQObYZgAAAFdJREFUCNdFjtERgCAMQ8MGRliADUS7ACX7zyQCan7yLtdLCiCQGzB8EodW8ERBzpM8YFIRU4NyqlasQoyeXBywq3Uo0anKfnw5UyaC5Tp73sJv4h9db9zQhg1MUu12QwAAAABJRU5ErkJggg==
// @include https://arenavision.cc/*
// @include https://www.arenavision.cc/*
// @include https://arenavision.in/*
// @include https://www.arenavision.in/*
// @include https://arenavision.biz/*
// @include https://www.arenavision.biz/*
// @include https://arenavision.us/*
// @include https://www.arenavision.us/*
// @include https://arenavision.link/*
// @include https://www.arenavision.link/*
// @include https://arenavision.live/*
// @include https://www.arenavision.live/*
// @include https://arenavision.club/*
// @include https://www.arenavision.club/*
// @include https://linkotes.com/*
// @include https://linkotes.com
// @connect *
// ==/UserScript==
//NOTE: I would likely avoid to use the "@connect *" property, but the process of retrieving the acestream link is very complex and it will probably be changed day by day as the Arenavision's webmaster tries to prevent my script from working. As Tampermonkey validates every URL a XmlHttpRequest is going through, I need to be sure that any possible domain is allowed to successfully complete the request.
var infobox=setupInfobox();
(function(){
  let iframes=document.getElementsByTagName("IFRAME");
  for (iframe of iframes){//removes iframes, none of them is necessary as they are only used for ads both on arenavision and linkotes
    iframe.remove();
  }
  console.log(document.location);
  var newHTML='<div id="selector" style="z-index: 3; font-size: 2em; position: fixed; text-align: center; color: white; padding: 0.5em; background-color: #303030; top: 0; left: 0; height: 1.5em; width: 100%;"><div style="margin: auto"><label for="ch">Channel: </label><input style="font-size: 1em; width: 30%;" id="ch" name="Channel" type="number" max="99" min="1" value="1"><button style="font-size: 1em" id="go">GO!</button></div></div>';
  var newHTMLFooter='<div style="padding: 1em; width: 100%; position: fixed; bottom: 0; left: 0; color: white; background-color: #303030;">If ArenaVision is actively blocking this script you can use <a style="color: orange;" href="https://linkotes.com/arenavision/">linkotes.com</a> instead: it provides the direct Acestream IDs/AceLive files for the same ArenaVision channels.</div>';
  var menus=document.getElementsByClassName("expanded");
  for(var m=0;m<menus.length;m++){
    menus[m].children[0].removeAttribute("href");
  }
  if(document.location.href.includes("guide")){
    var tableList=document.getElementsByTagName("TABLE");
    var table;
    var h=0;
    for(;h<tableList.length;h++){
      try{
        if(tableList[h].children[0].children[0].children.length==6){
          table=tableList[h].cloneNode(true);
          table.style.paddingTop="5em";
          table.style.paddingBottom="5em";
          document.body.innerHTML="";
          document.head.innerHTML="";
          document.body.style="margin: 0;";
          var lines=table.getElementsByTagName("TR");
          var totalLines=lines.length-2;
          lines[0].style.fontWeight="bold";
          for(var i=1;i<totalLines;i++){
            try{
              //channels=lines[i].children[5].innerHTML.match(/\d+/g).map(Number);
              lines[i].style.border="1px solid black";
              if(i%2==0){
                lines[i].style.backgroundColor="#f2f2f2";
              }
              else{
                lines[i].style.backgroundColor="#e0e0e0";
              }
            }
            catch(err){
              lines[i].parentNode.removeChild(lines[i]);
              i--;
              totalLines--;
            }
          }
          document.body.innerHTML=newHTML;
          document.body.style.fontFamily="Arial";
          document.body.appendChild(table);
          document.body.innerHTML+=newHTMLFooter;
          document.body.appendChild(infobox);
          document.getElementById("go").addEventListener("click", function(){goToChannel()});
          document.getElementById("ch").addEventListener("keypress", function(e){if(e.key=='Enter'){goToChannel()}});
          h=-1;
          break;
        }
      }
      catch(err){
        console.log(err);
      }
    }
    if(h==tableList.length){
      ignoreTableReconstruction(newHTML,newHTMLFooter);
    }
  }
  else if((document.location.href.includes("/stream/live/arenavision-"))&&(!document.location.href.includes("#exception"))){
    var links=document.getElementsByTagName("SCRIPT");
    for(var j=0;j<links.length;j++){
      if(links[j].innerHTML.includes('window.atob("')){
        extractLink(links[j].innerHTML);
      }
    }
  }
})();
function ignoreTableReconstruction(newHTML,newHTMLFooter){
  document.body.innerHTML=newHTML+document.body.innerHTML+newHTMLFooter;
  document.body.appendChild(infobox);
  infobox.innerHTML="Can't decode events table. I'll just add the channel selector.";
  infobox.style.display="block";
  setTimeout(function(){infobox.style.display="none";},5000);
  document.getElementById("go").addEventListener("click", function(){goToChannel()});
  document.getElementById("ch").addEventListener("keypress", function(e){if(e.key=='Enter'){goToChannel()}});
}
function goToChannel(){
  var channel=document.getElementById("ch").value.toString();
  infobox.innerHTML="Loading channel "+channel+"...";
  infobox.style.display="block";
  var globalURL=location.href.substring(0,location.href.lastIndexOf("/")+1)+"arenavision-";
  var channelURL;
  channelURL=globalURL+channel;
  try {  
    var request = new XMLHttpRequest();  
    request.onreadystatechange = function() {
      
      if (request.readyState == 4) {  
        if(request.status==404){
          infobox.innerHTML="Channel "+channel+" is not available.";
          setTimeout(function(){infobox.style.display="none";},5000);
        }
        else if(request.status==403){
          infobox.innerHTML="Error 403: the access to the page requested is forbidden.";
          setTimeout(function(){infobox.style.display="none";},5000);
        }
        else if(request.status==1006){
          infobox.innerHTML="Your IP address has been banned from ArenaVision server. Reinitiate your connection to get a new IP.";
          setTimeout(function(){infobox.style.display="none";},10000);
        }
        else{
          var channelPageHTML = request.responseText;
          if(channelPageHTML.includes('window.atob("')){
            extractLink(channelPageHTML);
          }
          else{
            if(channelPageHTML.includes('class="ray_id"')){//if server needs to do a check for DDos protection, tries to load the channel page in an IFrame
              useIframe(channelURL);
              infobox.innerHTML="Trying to load channel "+channel+" with another method...";
            }
            else{                                           //otherwise, if it was just impossible to retrieve the link, the script opens the original page in a new tab 
              openTab(channelURL+"#exception",false);   //and avoids the execution of the script, so you can try to watch the stream on the page.
              infobox.style.display="none";
            }
          }
        }
      }  
    };
    request.open('GET', channelURL); 
    request.send();
  }
  catch (err) { 
    useIframe(channelURL);
    infobox.innerHTML="Trying to load channel "+channel+" with another method...";
    console.log(err);
  }
}
function useIframe(channelURL){//loads the channel page in an IFrame, required if XHR returns a DDos protection page.
  var chpage=document.createElement("IFRAME");
  chpage.src=channelURL+"#exception";
  chpage.style.width="0";
  chpage.style.height="0";
  chpage.style.border="none";
  chpage.style.position="fixed";
  document.body.appendChild(chpage);
  chpage.onload = function() {
    extractLink(chpage.contentDocument.documentElement.innerHTML);
  }
}
function extractLink(page){//This function should support both AceStreams and HTTP streams.
  try{
    var linkStart=page.indexOf('window.atob("')+13;
    var linkEnd=page.indexOf('"',linkStart);
    var acestream=window.atob(page.substring(linkStart,linkEnd));
    console.log("Decoded link: "+acestream);
    linkStart=acestream.indexOf("?id=")+4;
    if(linkStart==3){//indexOf("?id=")==0 
      linkStart=acestream.indexOf("?url=")+5;
      if(linkStart==4){//indexOf("?id=")==0 
        linkStart=acestream.indexOf("http");
      }
    }
    linkEnd=acestream.indexOf("&");
    if(linkEnd==-1){
      acestream=acestream.substring(linkStart);
    }
    else{
      acestream=acestream.substring(linkStart,linkEnd);
    }
    if(acestream.includes("pb.m3u8")){
      GM.xmlHttpRequest({
        method: "GET",
        url: "https://"+window.location.hostname+acestream,
        onload: function(response) {
          aceResolver(response.finalUrl);
        },
        onerror: function(response) {//shall be the same as onload
          aceResolver(response.finalUrl);    
        }
      });  
    }
    else{
      openLink(acestream);
    }
  }
  catch(err){
    infobox.innerHTML="Failed to load the link.";
    setTimeout(function(){infobox.style.display="none";},5000);
  }
}
function aceResolver(prevUrl){
  console.log("Executing recursive resolver on "+prevUrl.substring(prevUrl.indexOf("?url=")+5));
  GM.xmlHttpRequest({
    method: "GET",
    headers: {
      "User-Agent": "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.50 Safari/537.36 AceStream /3.1.32"
    },
    url: prevUrl.substring(prevUrl.indexOf("?url=")+5),
    onload: function(response) {
      console.log(response.finalUrl);
      //infobox.innerHTML="Downloading the link...";
      infobox.innerHTML="Opening the link...";
      setTimeout(function(){infobox.style.display="none";},5000);
      if(response.finalUrl.match(/[0-9a-fA-F]{40}/g)!==null){
        openLink(response.finalUrl.match(/[0-9a-fA-F]{40}/g));
      }
      else{
        openTab(response.finalUrl,true);
      }
      //openTab(response.finalUrl,true);
    },
    onerror: function(response) {
      console.log(response);
      if((response.finalUrl!==null)&&(response.finalUrl!==undefined)){
        if(response.finalUrl.match(/[0-9a-fA-F]{40}/g)!==null){
          openLink(response.finalUrl.match(/[0-9a-fA-F]{40}/g));
        }
        else{
          openTab(response.finalUrl,true);
        }
      }
      else{
        infobox.innerHTML="Failed to load the link.";
        setTimeout(function(){infobox.style.display="none";},5000);
      }
    }
  });    
}
function openLink(acestream){
  console.log('AceStream ID or HTTP(S) URL: '+acestream);
  if(acestream!==null){
    infobox.innerHTML="Opening the link...";
    setTimeout(function(){infobox.style.display="none";},5000);
    if(!acestream.includes("://")){
      openTab('acestream://'+acestream,true);
    }
    else{
      openTab(acestream,true);
    }
  }
  else{
    infobox.innerHTML="I can't open the link. Open Ace Player manually and then try again.";
    setTimeout(function(){infobox.style.display="none";},5000);
  }
}
function setupInfobox(){
  var infobox=document.createElement("DIV");
  infobox.style.position="fixed";
  infobox.style.bottom="2em";
  infobox.style.right="2em";
  infobox.style.zIndex="9999";
  infobox.style.backgroundColor="#303030";
  infobox.style.borderRadius="5px";
  infobox.style.padding="1em";
  infobox.style.color="white";
  infobox.style.boxShadow="5px 5px 5px rgba(0,0,0,0.5)";
  infobox.style.textAlign="left";
  infobox.innerHTML="[empty]";
  infobox.style.display="none";
  return infobox;
}
function openTab(url,method){//this function roughly provides compatibility for different userscript managers.
  if(method===true){
    window.location.href=url;
  }
  else{
    try{
      GM.openInTab(url,method);
      window.open(url,"_new");
    }
    catch(err){
      window.open(url,"_new");
    }
  }
}