Songsterr Plus Patcher

Trick Songsterr to unlock plus features.

// ==UserScript==
// @name Songsterr Plus Patcher
// @namespace https://github.com/Strikeless
// @version 1.1.1
// @description Trick Songsterr to unlock plus features.
// @license The Unlicense
// @supportURL https://github.com/Strikeless/SongsterrPlusPatcher
// @match http*://*.songsterr.com/*
// @run-at document-start
// @grant unsafeWindow
// ==/UserScript==

(function () {
    function notifyError(err) {
        alert(
            "Songsterr Plus Patcher encountered an error."
            + "\nfeel free to report this issue at https://github.com/Strikeless/SongsterrPlusPatcher ."
            + "\nIf the issue persists, you can disable the userscript and try some of the other userscripts for Songsterr on Greasyfork."
            + "\n    (alternatively, consider subscribing Songsterr plus, if you have the money to throw and you enjoy their service.)"
            + "\n\n" + err
        );
    }

    try {
        const fetchParent = unsafeWindow || window; // unsafeWindow required to wrap the fetch function in the same context that the actual site uses.
        const innerFetch = fetchParent.fetch;

        function mockProfile(profile) {
            if (profile.plan == "plus") {
                console.log("Songsterr Plus Patcher: You already have Songsterr plus!");
                return profile;
            }

            profile.plan = "plus";
            profile.subscription = {
                plan: {
                    id: "plus"
                }
            };

            return profile;
        }

        /*
         * Wrap the fetch function in our own version that intercepts requests to the profile detail endpoint, mocking plus status.
         */
        function interceptingFetch(resource, options) {
            var resource_url = JSON.stringify(resource); // Not really sure if JSON.stringify is the right tool for the job, but it works. (unlike toString)

            if (resource_url.includes("/auth/profile")) {
                console.log("Songsterr Plus Patcher: Intercepting /auth/profile request to " + resource_url + ".");

                return innerFetch(resource, options)
                    .then(response => response.json())
                    .then(responseProfile => mockProfile(responseProfile))
                    .then(mockedProfile => new Response(JSON.stringify(mockedProfile)))
                    .catch(err => notifyError(err));
            } else {
                return innerFetch(resource, options);
            }
        }

        Object.defineProperty(fetchParent, "fetch", {
            value: function () {
                return interceptingFetch(...arguments);
            },
            configurable: true,
            enumerable: false,
            writable: true,
        });

        document.addEventListener("DOMContentLoaded", () => {
            try {
                /*
                 * Additionally change use.hasPlus to true in the state JSON. This is the old way things were done, and
                 * no longer seems to be necessary with mocked profile responses, but probably wont do any harm either.
                 */
                const stateElement = document.getElementById("state");
                const stateJson = JSON.parse(stateElement.innerHTML);

                stateJson.user.hasPlus = true;
                stateElement.innerHTML = JSON.stringify(stateJson);

                /*
                 * For some reason when reloading or opening a tab directly via URL, the tab viewer doesn't load the actual tablature.
                 * This attempts to fix the issue by removing the parent apptab element, hopefully resulting in the site recreating it with the tablature.
                 */
                if (document.getElementById("tablature") == null) {
                    console.log("Songsterr Plus Patcher: tablature element doesn't exist, attempting to fix by removing entire apptab element and letting site recreate it.");
                    document.getElementById("apptab").remove();
                }
            } catch (err) {
                notifyError(err);
            }
        });
    } catch (err) {
        notifyError(err);
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址