Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing soundcloud's lib/audiomanager via on-page JS

I maintain a greasemonkey script that monitors the current track playing as well as the progress on Soundcloud. Previously, I could just do require("lib/audiomanager") to get access to an object that would allow me to view the state of the entire page such as playing track info.

The issue is, Soundcloud has moved to using webpack for their clientside Javascript. This stores all these classes as a specific number in a package, to my understanding. The number they are stored as appears to change every time the clientside JS is updated and recompiled.

The only way to access objects stored within webpack appears to be via the global webpackJsonp, like below. Number for the pack just needs to be unique.

webpackJsonp([6060], {
    0: function (e, t, n) {
        window.aman = n(726);
        e.exports = function (abc) {
            console.log("Exports called");
        };
    }
});

That code will execute and give me access to the object at that number in webpack. The object as defined in the clientside webpack'd JS is:

726: function (e, t, n) {
    (function (t) {
        function i(e) {
            var n = t(e.getContainerElement()),
                i = e.getState() === r.States.ERROR;
            n.toggleClass('blocked', i)
        }
        var r,
            s = n(53),
            o = n(14),
            a = 1000 / 60;
        e.exports = r = new s({
                flashAudioPath: n(2181),
                flashObjectID: 'flashAudioObject',
                updateInterval: a,
                debug: !1
            }),
            r.Errors = s.Errors,
            r.States = s.States,
            r.UPDATE_INTERVAL = a,
            o.once('audio:flash_block audio:flash_unblock', i)
    })
    .call(t, n(1))
},

So, the solutions I can think of:

  • Find an object whose webpack number does not change, that I can use to get a handle to this object
  • Iterate every webpack number and look for an object that has the same set of methods as this one.

The latter seems messy, and the first seems impossible. Any ideas?

Things I've tried:

  • Making a new n(53) like the desired object does as it seems to stay the same across updates. Gives me an audiomanager, but is definitely separate from the page's normal audiomanager, so I can't see what is playing.
like image 841
Ditmar Wendt Avatar asked Oct 26 '14 22:10

Ditmar Wendt


1 Answers

We, too, use SoundCloud API in our client-side scripts, so we ended up with a bit 'cleaner' code. Here is the main part of it (note that it doesn't contain try-catch blocks because all modules do exist):

var playManager, libAudio, eventBus;

webpackJsonp([], {0: function(a, b, require) 
{ 
    var modules = require.c;

    for (var moduleid in modules)
    {
        var el = require(moduleid);

        if (typeof el["playCurrent"] == "function")
        {
            playManager = el;
        }
        else if (typeof el["getSettings"] == "function")
        {
            libAudio = el;
        }
        else if (typeof el["trigger"] == "function" 
               && typeof el["bind"] == "function"
               && typeof el["listenToOnce"] == "function" &&
               typeof el["$"] != "function" &&
               typeof el["broadcast"] == "function")
        {
            eventBus = el;
        }
}     
like image 109
Daniel O'Hara Avatar answered Oct 20 '22 12:10

Daniel O'Hara