ScoreSaber Downloader

Adds a download button to Score Saber song pages

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         ScoreSaber Downloader
// @version      1.3.2
// @description  Adds a download button to Score Saber song pages
// @author       bhackel
// @match        https://scoresaber.com/leaderboard/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @connect      beatsaver.com
// @namespace https://greasyfork.org/en/users/324178-bhackel
// ==/UserScript==

(function() {
    'use strict';

    // Obtain the song hash from the page
    var rightBoxDiv = document.getElementsByClassName("box has-shadow")[0]
    var id = rightBoxDiv.children[4].innerText
    var url = "https://beatsaver.com/api/maps/by-hash/" + id;
    var response;

    // Create buttons with text, function, and classes
    var oneclickButton = document.createElement('Button');
    oneclickButton.className = "bhackel-button button is-dark has-background-grey-dark";
    oneclickButton.innerHTML = "OneClick";
    oneclickButton.addEventListener("click", oneclick);

    var zipButton = document.createElement('Button');
    zipButton.className = "bhackel-button button is-dark has-background-grey-dark";
    zipButton.innerHTML = "Zip";
    zipButton.addEventListener("click", zip);

    var previewButton = document.createElement('Button');
    previewButton.className = "bhackel-button button is-dark has-background-grey-dark";
    previewButton.innerHTML = "View Map";
    previewButton.addEventListener("click", preview);

    // Add the buttons to the page
    rightBoxDiv.append(oneclickButton, zipButton, previewButton);

    // Setup for Beat Saver API call - error handling
    function error(rspObj) {
        console.error("There was an error downloading the song: " + rspObj.status + " " + rspObj.statusText);
    }

    // Setup for Beat Saver API call - requesting data
    function request(url) {
        GM_xmlhttpRequest ({
            method:         "GET",
            url:            url,
            responseType:   "json",
            onload:         process_response,
            onabort:        error,
            onerror:        error,
            ontimeout:      error
        });
    }

    // Setup for Beat Saver API call - response from the API
    function process_response(rspObj) {
        // Check for invalid responses
        if (rspObj.status != 200 && rspObj.status != 304) {
            error(rspObj);
            return;
        }

        response = rspObj.response;
    }

    // Get the response from Beat Saver
    request(url);

    function oneclick() {
        // Create a OneClick URL from the API response
        var oneclick_url = 'beatsaver://' + response.key
        // Open the URL
        window.location.href = oneclick_url;
    }

    function zip() {
        // Create a zip download URL from the API response
        var zip_url = 'https://beatsaver.com' + response.directDownload;
        // Open the URL
        window.location.href = zip_url;
    }

    function preview() {
        // Create a map preview URL from the API response
        var preview_url = 'https://skystudioapps.com/bs-viewer/?id=' + response.key;

        var difficulties = [];
        var difficulty = 0;

        // Get all difficulties for the song
        var difficulties_dict = response.metadata.characteristics[0].difficulties;
        if (difficulties_dict.easy) { difficulties.push('Easy'); }
        if (difficulties_dict.normal) { difficulties.push('Normal'); }
        if (difficulties_dict.hard) { difficulties.push('Hard'); }
        if (difficulties_dict.expert) { difficulties.push('Expert'); }
        if (difficulties_dict.expertPlus) { difficulties.push('Expert+'); }

        // Find the index of the selected difficulty
        var difficulty_str = document.getElementsByClassName("is-active")[0];
        // For other modes, the page doesn't show a selected difficulty
        if (difficulty_str) {
            difficulty = difficulties.indexOf(difficulty_str.textContent);
        }

        // Add difficulty index to the URL, and open it
        preview_url += '&difficulty=' + difficulty;
        window.open(preview_url,'_blank');
    }

})();