Greasy Fork is available in English.

Script di aiuto per ArenaVision

Uno script che rende la navigazione su Arenavision facile con i touchscreen e sui browser con adblock abilitato. È un grado di ottenere i link diretti AceStream per i browser che non supportano il lettore video integrato nella pagina.

// ==UserScript==
// @name     ArenaVision Helper
// @name:it  Script di aiuto per ArenaVision
// @namespace    StephenP
// @version      1.9.2
// @description  A script that makes browsing ArenaVision website easier on touchscreens and on browsers with adblock enabled. It can retrieve direct AceStream links for browsers that don't support the player embedded in the page.
// @description:it  Uno script che rende la navigazione su Arenavision facile con i touchscreen e sui browser con adblock abilitato. È un grado di ottenere i link diretti AceStream per i browser che non supportano il lettore video integrato nella pagina.
// @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://arenavision.site/*
// @include https://www.arenavision.site/*
// @include https://linkotes.com/*
// @include https://linkotes.com
// @connect *
// ==/UserScript==
//NOTE: I would like to avoid using 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();
var chLinks=listLinks();
var channel=0;
const altListName="OG";           //set the name for the alternate list of channel: "OG" was for Olympic Games
const altListLinkTag="olympic";		//set a text that is included in the links of the alternate list of channels, but not in the standard ArenaVision list. Olympic Channels used to include "olympic" in the href.
const isAlternateAvailable=false;	//set to true if an alternate list is available at the moment: could be the next Olympic Games, the World Soccer Championship or anything else.
(function(){
  let iframes=document.getElementsByTagName("IFRAME");
  while(iframes.length>0){//removes iframes, none of them is necessary as they are only used for ads both on arenavision and linkotes
    iframes[0].remove();
  }
  console.log(document.location);
  var newHTML='<div id="selector" style="z-index: 3; font-size: 1em; 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><label id="alternateLabel" for="alternate" style="display: none; margin-left: 5px;">'+altListName+'</label><input style="font-size: 1em; display: none" type="checkbox" id="alternate"></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.getElementsByClassName("title").length>0){
    if(document.getElementsByClassName("title")[0].innerHTML.toLowerCase().includes("events")){
      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;
            if(isAlternateAvailable){
              document.getElementById("alternate").style.display="inline";
              document.getElementById("alternateLabel").style.display="inline";
            }
            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);
        }
      }
      document.body.innerHTML+=newHTMLFooter;
    }
    else{
       document.body.innerHTML+=newHTMLFooter;
    }
  }
  else{
     document.body.innerHTML+=newHTMLFooter;
  }
})();
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(){
  channel=document.getElementById("ch").value.toString();
  let channelName=channel;
  if(document.getElementById("alternate").checked===true){
    channelName=altListName+channel;
  }
  infobox.innerHTML="Loading channel "+channelName+"...";
  infobox.style.display="block";
  //Old method, left for reference
  /*var globalURL=location.href.substring(0,location.href.lastIndexOf("/")+1)+"arenavision-";
  var channelURL;
  channelURL=globalURL+channel;*/
  //New method
  var offset=0;
  if(document.getElementById("alternate").checked===true){
		for(let chLink of chLinks){
      offset++;
      if(chLink.includes(altListLinkTag)){
        offset--;
        break;
      }
    }
  }
  var channelURL=chLinks[offset+parseInt(channel)-1];
  console.log(channelURL);
  try {  
    var request = new XMLHttpRequest();  
    request.onreadystatechange = function() {
      
      if (request.readyState == 4) {  
        if(request.status==404){
          infobox.innerHTML="Channel "+channelName+" 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 "+channelName+" 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 "+channelName+" 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){
  if(prevUrl.indexOf("?url=")>-1){
    prevUrl=prevUrl.substring(prevUrl.indexOf("?url=")+5);
  }
  console.log("Executing recursive resolver on "+prevUrl);
  GM.xmlHttpRequest({
    method: "GET",
    headers: {
      "User-Agent": "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4371.0 Safari/537.36 AceStream /3.1.8.0",
      "Referer": chLinks[channel-1]
    },
    url: prevUrl,
    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.includes("127.0.0.1")){
          aceResolver(response.finalUrl);
        }
        else{
          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 listLinks(){
  let t=document.getElementsByClassName("leaf");
  var m=[];
  for (let x of t){
    let l=x.getElementsByTagName("A");
    if((l.length==1)&&(x.parentNode.parentNode.className.includes("expanded"))){
    	m.push(l[0].href);
    }
  }
  console.log("LINKS:");
  console.log(m);
  return m;
}
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");
    }
  }
}