diff --git a/README.md b/README.md index 10efd7c..c33f10c 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,4 @@ enables deezer hifi features lol - install [violentmonke](https://violentmonkey.github.io/) (other userscript extensions may work, but are not supported) -- click [this link](https://git.freezer.life/uhwot/dzunlock/raw/branch/master/dzunlock.user.js) \ No newline at end of file +- click [this link](https://uhwotgit.fly.dev/uhwot/dzunlock/raw/branch/master/dzunlock.user.js) diff --git a/dzunlock.user.js b/dzunlock.user.js index 6a69b1e..0f45cfe 100644 --- a/dzunlock.user.js +++ b/dzunlock.user.js @@ -3,10 +3,10 @@ // @namespace io.github.uhwot.dzunlock // @description enables deezer hifi features lol // @author uh wot -// @version 1.3.3 +// @version 1.4.3 // @license GPL-3.0-only -// @homepageURL https://git.freezer.life/uhwot/dzunlock -// @downloadURL https://git.freezer.life/uhwot/dzunlock/raw/branch/master/dzunlock.user.js +// @homepageURL https://git.uhwot.cf/uhwot/dzunlock +// @downloadURL https://uhwotgit.fly.dev/uhwot/dzunlock/raw/branch/master/dzunlock.user.js // @icon https://cdns-files.dzcdn.net/cache/images/common/favicon/favicon-96x96.852baf648e79894b668670e115e4a375.png // @include /^https:\/\/www\.deezer\.com\/[a-z]{2}\/($|track|album|artist|playlist|episode|show|profile|channels|podcasts|radio|\?|#)/ // @match https://www.deezer.com/search/* @@ -26,65 +26,6 @@ function log(...args) { } } -// https://github.com/werk85/fetch-intercept/blob/develop/src/attach.js modified for browser support -let interceptors = []; - -function interceptor(fetch, ...args) { - const reversedInterceptors = interceptors.reduce((array, interceptor) => [interceptor].concat(array), []); - let promise = Promise.resolve(args); - - // Register request interceptors - reversedInterceptors.forEach(({ request, requestError }) => { - if (request || requestError) { - promise = promise.then(args => request(...args), requestError); - } - }); - - // Register fetch call - promise = promise.then(args => { - const request = new Request(...args); - return fetch(request).then(response => { - response.request = request; - return response; - }).catch(error => { - error.request = request; - return Promise.reject(error); - }); - }); - - // Register response interceptors - reversedInterceptors.forEach(({ response, responseError }) => { - if (response || responseError) { - promise = promise.then(response, responseError); - } - }); - - return promise; -} - -unsafeWindow.fetch = (function (fetch) { - return function (...args) { - return interceptor(fetch, ...args); - }; -})(unsafeWindow.fetch); - -fetchIntercept = { - register: function (interceptor) { - interceptors.push(interceptor); - return () => { - const index = interceptors.indexOf(interceptor); - if (index >= 0) { - interceptors.splice(index, 1); - } - }; - }, - clear: function () { - interceptors = []; - } -}; - -// main code starts here - const playerTokenKey = [102, 228, 95, 242, 215, 50, 122, 26, 57, 216, 206, 38, 164, 237, 200, 85] const cipher = new aesjs.ModeOfOperation.ecb(playerTokenKey) @@ -126,6 +67,8 @@ function playerTokenPatch(playerToken) { // disables previews playerToken.streaming = true playerToken.limited = false + // disables skip limit on mixes + playerToken.radio_skips = 0 log(playerToken) @@ -152,12 +95,59 @@ window.addEventListener('DOMContentLoaded', (_) => { })(unsafeWindow.dzPlayer.setTrackList); }); -fetchIntercept.register({ - request: function (url, config) { - // Modify the url or config here +// https://greasyfork.org/en/scripts/38248-websocket-logger/code +unsafeWindow.WebSocket = new Proxy(unsafeWindow.WebSocket, { + construct: function (target, args, _) { + const url = args[0] + const ws = new target(url) + + if (url !== 'wss://messaging.deezer.com/websocket') { + return ws + } else { + log('hooking websocket') + + return new Proxy(ws, { + set: function (target, prop, val) { + if (prop == 'onmessage') { + var onmsg = val; + val = function (e) { + if (e.data.includes('SingleInstancePlayback')) { + log('preventing SingleInstancePlayback pubsub receive') + return + } + onmsg(e) + }; + } + return target[prop] = val + }, + get: function (target, prop) { + var val = target[prop]; + if (prop == 'send') val = function (data) { + if (data.includes('SingleInstancePlayback')) { + log('preventing SingleInstancePlayback pubsub send') + return + } + target.send(data) + }; + else if (typeof val == 'function') val = val.bind(target) + return val + } + }) + } + } +}) + +unsafeWindow.fetch = (function (fetch) { + return async function (url, init) { if (url === 'https://media.deezer.com/v1/get_url') { + let track + if (unsafeWindow.dzPlayer.getPosition() === 0) { + track = unsafeWindow.dzPlayer.getCurrentSong() + } else { + track = unsafeWindow.dzPlayer.getNextSong() // gapless playback + } + const quality = unsafeWindow.dzPlayer.control.getAudioQuality() - const track = unsafeWindow.dzPlayer.getCurrentSong() const id = parseInt(track.SNG_ID) let is_subbed = !unsafeWindow.dzPlayer.user_status.can_subscribe @@ -168,7 +158,7 @@ fetchIntercept.register({ } if (id >= 0 && !is_quality_available) { - const media_server = GM_getValue('media_server', 'https://dzmedia.herokuapp.com') + const media_server = GM_getValue('media_server', 'https://dzmedia.fly.dev') url = `${media_server}/get_url` const body = { @@ -184,24 +174,14 @@ fetchIntercept.register({ } } - config.body = JSON.stringify(body) + init.body = JSON.stringify(body) } } - return [url, config]; - }, + let resp = await fetch(url, init) - requestError: function (error) { - // Called when an error occured during another 'request' interceptor call - - return Promise.reject(error); - }, - - response: async function (response) { - // Modify the response object - - if (response.url.startsWith('https://www.deezer.com/ajax/gw-light.php?method=deezer.getUserData')) { - let json = await response.json() + if (url.startsWith('https://www.deezer.com/ajax/gw-light.php?method=deezer.getUserData')) { + let json = await resp.json() // removes upgrade popup stuff json.results.USER.ENTRYPOINTS = {} @@ -215,25 +195,24 @@ fetchIntercept.register({ log(json) - return new Response(JSON.stringify(json)) - } + resp = new Response(JSON.stringify(json), resp) + } else if (url.startsWith('https://www.deezer.com/ajax/gw-light.php?method=deezer.userMenu')) { + let json = await resp.json() - if (response.url.startsWith('https://www.deezer.com/ajax/gw-light.php?method=log.listen')) { - const json = await response.json() + delete json.results.MARKETING_PUSH + delete json.results.MARKETING_PUSH_DATA + + resp = new Response(JSON.stringify(json), resp) + } else if (url.startsWith('https://www.deezer.com/ajax/gw-light.php?method=log.listen')) { + const json = await resp.json() if (typeof json.results === 'string') { json.results = playerTokenPatch(json.results) } - return new Response(JSON.stringify(json)) + resp = new Response(JSON.stringify(json), resp) } - return response; - }, - - responseError: function (error) { - // Handle an fetch error - - return Promise.reject(error); - } -}); \ No newline at end of file + return resp + }; +})(unsafeWindow.fetch);