BeatStars Downloader

Used for automatically downloading BeatStars content

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

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

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        BeatStars Downloader
// @namespace   BeatStarsDL
// @match       *://www.beatstars.com/*/tracks
// @match       *://beatstars.com/*/tracks
// @grant       none
// @version     1.0
// @author      OliverP
// @description Used for automatically downloading BeatStars content
// @inject-into auto
// ==/UserScript==

/*
-----------------------How to use-----------------------
1. Go into the tracks page of the user you want to download the tracks from
2. Click on "Load tracks" to load all available tracks of the user (the script is scrolling down automatically to do that)
3. Click on Download and wait until it completes
4. A modal will pop-up and allow you to copy the track names and the URLs (in a 2 line per track txt format)
5, Copy it into your downloader of choice or into the provided Python script
--------------------------------------------------------
*/

var my_css = '.modal{display:none;position:fixed;z-index:100000;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,0.4)}.modal-content{position:fixed;bottom:0;background-color:#fefefe;width:100%;-webkit-animation-name:slideIn;-webkit-animation-duration:.4s;animation-name:slideIn;animation-duration:.4s}.close{color:#fff;float:right;font-size:28px;font-weight:700}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer}.modal-header{padding:2px 16px;background-color:#5cb85c;color:#fff}.modal-body{padding:2px 16px}';
var new_sty = document.createElement("style");
new_sty.setAttribute("type", "text/css");
new_sty.appendChild(document.createTextNode(my_css));
document.body.appendChild(new_sty);
document.body.innerHTML += '<div id="myModal" class="modal"><div class="modal-content"><div class="modal-header"><span class="close">&times;</span><h2>Download complete</h2></div><div class="modal-body"><p>Links:</p><textarea id="urllinks_dl" style="font-size: 9px;"></textarea><button id="copydl">Copy</button><span id="copyreport" style="color: green;"></span></div></div></div>';

const checkElement = async selector => {
  while ( document.querySelector(selector) === null) {
    await new Promise( resolve =>  requestAnimationFrame(resolve) )
  }
  return document.querySelector(selector); 
};

function sleepFor(sleepDuration){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* Do nothing */ }
}

function copyText(){ //For the URL copying
  var copyText = document.getElementById("urllinks_dl");
  var copyReport = document.getElementById("copyreport");

  copyText.select();
  copyText.setSelectionRange(0, 99999);

  navigator.clipboard.writeText(copyText.value);

  copyReport.innerHTML = "Successfully copied";
}

function download(fileName, fileType, text) {
  var blob = new Blob([text], { type: fileType });

  var a = document.createElement('a');
  a.download = fileName;
  a.href = URL.createObjectURL(blob);
  a.dataset.downloadurl = [fileType, a.download, a.href].join(':');
  a.style.display = "none";
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(function() { URL.revokeObjectURL(a.href); }, 1500);
}

function preload(){ //Preloads tracks by scrolling until no more load
    (function scroll() {
      if(window.scrollY != window.scrollMaxY){
        window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
        setTimeout(scroll, 1000);
      }else{
        document.body.scrollTop = document.documentElement.scrollTop = 0;
      }
    })();
}

function dlCheck(){ //Starts download
    checkElement('.btn-download').then((selector) => {
      var dlbtn_el = document.getElementsByClassName('btn-download');
      timer = 0;
      (function next() {
        if(dlbtn_el.length-1>timer) { //Until there are downloadable tracks
            console.log((timer+1)+"/"+(dlbtn_el.length-1))
            var musiccnt = document.getElementsByClassName("number ng-star-inserted"); var count = musiccnt.length; for(var i = 0; i < count; i++){ if(musiccnt[i].innerHTML.includes(timer)){ music = musiccnt[i]; } }
            list += "\n"+music.parentNode.parentNode.childNodes[2].children[0].children[0].innerHTML;
            do_download(dlbtn_el[timer], (timer+1), (dlbtn_el.length-1));
            list += "\n";
            timer += 1;
            setTimeout(next, 1000);
        }else{
          if(dlbtn_el.length-1 == timer){ //When the download is finished
            console.log(list);
            document.getElementById("urllinks_dl").innerHTML = list.trim();
            var modal = document.getElementById("myModal");
            modal.style.display = "block";
          }
        }
      })();
  });
}

async function do_download(item, timer, full_length){
    return new Promise((resolve,reject)=>{
      item.click();
      download(timer, full_length)
      resolve();
    });

}

list="" //This list will contain the download links
async function download(timer, full_length){
    window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
    await new Promise(r => setTimeout(r, 1000));
    var downloadbtn = document.getElementsByClassName("mat-button-wrapper"); var count = downloadbtn.length; for(var i = 0; i < count; i++){ if(downloadbtn[i].innerHTML.includes("Download")){ btn = downloadbtn[i]; } }
    list+=btn.closest('a').href; //Add download link to the list
    var closebtn = document.getElementsByClassName("mat-dialog-title"); var count = closebtn.length; for(var i = 0; i < count; i++){ if(closebtn[i].innerHTML.includes("Free Download")){ closebtn[i].innerHTML += " "+timer+"/"+full_length; btn1 = closebtn[i]; } }
    btn1.parentNode.childNodes[1].click();
    await new Promise(r => setTimeout(r, 3000));

}

window.addEventListener("DOMContentLoaded", function(event) { //Adds the buttons to the site
  checkElement('.title').then((selector) => {
    selector.innerHTML += "<button id='prlbtn'>Load tracks</button><button id='dlbtn'>Download</button>";
    var dlbtn = document.getElementById("dlbtn");
    dlbtn.onclick = function() {
      dlCheck();
    }
    var prlbtn = document.getElementById("prlbtn");
    prlbtn.onclick = function() {
      preload();
    }
    var copydl = document.getElementById("copydl");
    copydl.onclick = function() {
      copyText();
    }
  });
});

var modal = document.getElementById("myModal");
var span = document.getElementsByClassName("close")[0];

// When the user clicks on the close button, close the modal
span.onclick = function() {
  modal.style.display = "none";
}

// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
  if (event.target == modal) {
    modal.style.display = "none";
  }
}