Multiple instances of Deezer Webapp

The music streaming service Deezer doesn’t allow you to crossfade tracks.. quite frustrating. While attempting to use their API to work out how I could script a crossfade (not possible) I went down the rabbit hole of wondering if I could have two separate “instances” of Deezer open and just trigger one to play as the other one gets towards the end.

Sadly when you do this the other browser or browser session detects usage on another device and stops playing.

deezer for developers account is currently being used on another device

My main interest now is how quickly it manages to stop the other device/tab/app/browser, even across different internet connections and computers.

Digging further into it – websockets and the Jabber protocol are used to relay messages between the players and Deezer.

deezer websockets

ok, cool method to communicate, very efficient and allows for easy two way communication across their ecosystem. However… very easy to manipulate and log.

Here is a web player playing a song and then (last frame) being told to stop the song because someone else is logged in and playing a song…

<iq from='REDACTED@messaging.deezer.com' type='set' xmlns='jabber:client' id='REDACTED-REDACTED-REDACTED-REDACTED-REDACTED:sendIQ'>
    <pubsub xmlns='http://jabber.org/protocol/pubsub'>
        <publish node='SingleInstancePlayback'>
            <item>
                <![CDATA[{"APP":"LIMITATION","ACTION":"PLAY","VALUE":{"USER_ID":REDACTED,"UNIQID":"REDACTED-REDACTED-REDACTED-REDACTED-REDACTED","SNG_ID":"3119769"}}]]>
            </item>
        </publish>
    </pubsub>
</iq>
 
<iq xmlns='jabber:client' from='REDACTED@messaging.deezer.com' to='REDACTED@messaging.deezer.com/REDACTED' id='REDACTED-REDACTED-REDACTED-REDACTED-REDACTED:sendIQ' type='result'>
    <pubsub xmlns='http://jabber.org/protocol/pubsub'>
        <publish node='SingleInstancePlayback'>
            <item id='60BFE3330D06' />
        </publish>
    </pubsub>
</iq>
 
<message xmlns='jabber:client' from='REDACTED@messaging.deezer.com' to='REDACTED@messaging.deezer.com/REDACTED' type='headline'>
    <event xmlns='http://jabber.org/protocol/pubsub#event'>
        <items node='SingleInstancePlayback'>
            <item id='60BFB363348D'>{"APP":"LIMITATION","ACTION":"PLAY","VALUE":{"USER_ID":REDACTED,"UNIQID":"REDACTED-REDACTED-REDACTED-REDACTED-REDACTED","SNG_ID":"371133191"}}</item>
        </items>
    </event>
    <addresses xmlns='http://jabber.org/protocol/address'>
<address type='replyto' jid='REDACTED@messaging.deezer.com/REDACTED' /></addresses>
</message>

Easy.. mangle that last message.. didn’t know which bit was important but it seems simply replacing “<items” with “<lolitems” works!

So for those that want multiple concurrent playbacks on Deezer via the web app (not sure if it works on the thick client install on Windows) the following Fiddler4 custom rules script works in the “class Handlers” section:

    static function OnWebSocketMessage(oMsg: WebSocketMessage) {
        FiddlerApplication.Log.LogString("EDITED WEBSOCKETS");
        var sPayload = oMsg.PayloadAsString();
        var changedPayload = sPayload.Replace('<items node=\'SingleInstancePlayback\'>', '<lolitems node=\'SingleInstancePlayback\'>');
        changedPayload = changedPayload.Replace('</items>', '</lolitems>');
        oMsg.SetPayload(changedPayload);
    }  

HTTPS Interception needs to be enabled!

Enjoy :) Not sure how long it will last, probably trivial for them to secure.

I’ve also found a trivial way to get past the restrictions on skipping in playlists, seeking in songs and getting the higher quality audio!

Add this into the “OnBeforeResponse” section:

		if (oSession.HostnameIs("www.deezer.com") && oSession.oResponse.headers.ExistsAndContains("Content-Type","application/json")){
			oSession.utilDecodeResponse();
			oSession.utilReplaceInResponse('\"standard\:true,','\"standard\":false,');
			oSession.utilReplaceInResponse('\"high\":false,','\"high\":true,');
			oSession.utilReplaceInResponse('\"lossless\":false','\"lossless\":true');
			oSession.utilReplaceInResponse('\"mobile_hq\":false,','\"mobile_hq\":true,');
			oSession.utilReplaceInResponse('\"mobile_lossless\":false,','\"mobile_lossless\":true,');
			oSession.utilReplaceInResponse('\"web_hq\":false,','\"web_hq\":true,');
			oSession.utilReplaceInResponse('\"web_lossless\":false,','\"web_lossless\":true,');
			oSession.utilReplaceInResponse('\"ads_display\":true,','\"ads_display\":false,');
			oSession.utilReplaceInResponse('\"ads_audio\":true,','\"ads_audio\":false,');
			oSession.utilReplaceInResponse('\"multi_account\":false,','\"multi_account\":true,');
			oSession.utilReplaceInResponse('\"multi_account_max_allowed\":1,','\"multi_account_max_allowed\":3,');
		}
This entry was posted in Uncategorized. Bookmark the permalink.

Comment on this topic

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s