Microsoft Store Direct Download

Adds direct download links to Microsoft Store when browsing apps.

// ==UserScript==
// @name     Microsoft Store Direct Download
// @name:it     Download diretto dal Microsoft Store
// @namespace    StephenP
// @version  2.0.2.1
// @description  Adds direct download links to Microsoft Store when browsing apps.
// @description:it  Aggiunge i link per il download diretto dal Microsoft Store quando si naviga tra le applicazioni.
// @author       StephenP
// @grant    GM.xmlHttpRequest
// @connect	 rg-adguard.net
// @match    https://apps.microsoft.com/*
// @match    https://apps.microsoft.com/*
// @contributionURL https://buymeacoffee.com/stephenp_greasyfork
// ==/UserScript==
var dlBtn;
(function(){
  setInterval(checkReload, 1000);
})();
function checkReload(){
   let moreBtn=querySelectorAllShadows(".buy-box-container");
   if((moreBtn.length>0)&&(querySelectorAllShadows("#dlBtn").length==0)){
     /*const origDlBtn=querySelectorAllShadows("sl-button[href^=ms-windows-store]",moreBtn[0]);
     console.log(origDlBtn);*/
     dlBtn = document.createElement("DIV");
     dlBtn.id="dlBtn";
     dlBtn.setAttribute("aria-label","Download from AdGuard Store");
     dlBtn.style.background="#00a686";
     dlBtn.style.font="initial";
     dlBtn.style.textAlign="center";
     dlBtn.style.borderRadius="var(--sl-input-border-radius-large)";
     dlBtn.style.marginTop="0.5em";
     dlBtn.innerText="";
     dlBtn.appendChild(document.createElement("P"));
     dlBtn.firstChild.innerText="\u25bc";
     dlBtn.addEventListener("click",function(){openLink(document.location.href,"url")});
     moreBtn[0].appendChild(dlBtn);
  }
}
function openLink(id,type){
  try{
    dlBtn.firstChild.innerText="...";
    var link="type="+type+"&url="+id+"&ring=RP&lang=it-IT";
    GM.xmlHttpRequest({
      method: "POST",
      url: "https://store.rg-adguard.net/api/GetFiles",
      data: link,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      onload: function(response) {
        dlBtn.firstChild.innerText="\u25bc";
        try{
          var oldTable=querySelectorAllShadows("#linkTable");
          oldTable[0].parentNode.removeChild(oldTable[0]);
          var oldMsg=querySelectorAllShadows("#messageFromServer");
          oldMsg[0].parentNode.removeChild(oldMsg[0]);
        }
        catch(err){
          console.log(err);
        }
        try{
           output(response,type);
        }
        catch(err){
          console.log(err);
          if(type==="ProductId"){
            output(err,type);
          }
          else{
            let newId=querySelectorAllShadows("[product-id]")[0].getAttribute("product-id");
            openLink(newId,"ProductId");
          }
        }
      }
    });
  }
  catch(err){
    console.log(err);
    if(type==="ProductId"){
      output(err,type);
    }
    else{
      let newId=querySelectorAllShadows("[product-id]")[0].getAttribute("product-id");
      openLink(newId,"ProductId");
    }
  }
}
function output(response,type){
  var linkTable = document.createElement("div");
  linkTable.innerHTML=response.responseText;
  var justTable=linkTable.getElementsByTagName("TABLE")[0];
  var messageFromServer=linkTable.getElementsByTagName("P")[0];
  messageFromServer.id="messageFromServer";
  messageFromServer.style.fontWeight="bold";
  if(justTable!==undefined){
    justTable.id="linkTable";
    const rows=justTable.getElementsByTagName("TR");
    for(let row of rows){
      if(row.firstChild.firstChild){
        if(row.firstChild.firstChild.innerText.match(/\.appx$|\.appxbundle$|\.msix$|\.msixbundle$/)){
          row.style.fontWeight="bold";
        }
      }
    }
    let pNl=querySelectorAllShadows("sl-card");
    if(pNl.length>0){
      const pN=pNl[0].parentNode;
      pN.insertBefore(justTable, pN.querySelector("sl-card"));
      justTable.style.marginTop="2em";
      messageFromServer.style.color="green";
      pN.insertBefore(messageFromServer, pN.querySelector("sl-card"));
    }

  }
  else if((justTable===undefined)&&(type==="url")){
    let newId=querySelectorAllShadows("[product-id]")[0].getAttribute("product-id");
    openLink(newId,"ProductId");
  }
  else{
    messageFromServer.style.color="red";
    dlBtn.parentNode.parentNode.parentNode.appendChild(messageFromServer);
  }
}


//The following function has been taken from https://stackoverflow.com/questions/38701803/how-to-get-element-in-user-agent-shadow-root-with-javascript
/**
 * Finds all elements in the entire page matching `selector`, even if they are in shadowRoots.
 * Just like `querySelectorAll`, but automatically expand on all child `shadowRoot` elements.
 * @see https://stackoverflow.com/a/71692555/2228771
 */
function querySelectorAllShadows(selector, el = document.body) {
  // recurse on childShadows
  const childShadows = Array.from(el.querySelectorAll('*')).
    map(el => el.shadowRoot).filter(Boolean);

  // console.log('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`);

  const childResults = childShadows.map(child => querySelectorAllShadows(selector, child));

  // fuse all results into singular, flat array
  const result = Array.from(el.querySelectorAll(selector));
  return result.concat(childResults).flat();
}