320/flac is bacc
This commit is contained in:
parent
29202f98a9
commit
3861935ddc
|
@ -1,6 +1,6 @@
|
||||||
# dzunlock
|
# dzunlock
|
||||||
|
|
||||||
enables deezer premium features lol
|
enables deezer hifi features lol
|
||||||
|
|
||||||
# how 2 install
|
# how 2 install
|
||||||
|
|
||||||
|
|
121
dzunlock.user.js
121
dzunlock.user.js
|
@ -1,9 +1,9 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name dzunlock
|
// @name dzunlock
|
||||||
// @namespace io.github.uhwot.dzunlock
|
// @namespace io.github.uhwot.dzunlock
|
||||||
// @description enables deezer premium features lol
|
// @description enables deezer hifi features lol
|
||||||
// @author uh wot
|
// @author uh wot
|
||||||
// @version 1.2.6
|
// @version 1.3
|
||||||
// @license GPL-3.0-only
|
// @license GPL-3.0-only
|
||||||
// @homepageURL https://git.freezer.life/uhwot/dzunlock
|
// @homepageURL https://git.freezer.life/uhwot/dzunlock
|
||||||
// @downloadURL https://git.freezer.life/uhwot/dzunlock/raw/branch/master/dzunlock.user.js
|
// @downloadURL https://git.freezer.life/uhwot/dzunlock/raw/branch/master/dzunlock.user.js
|
||||||
|
@ -14,7 +14,6 @@
|
||||||
// @match https://www.deezer.com/smarttracklist/*
|
// @match https://www.deezer.com/smarttracklist/*
|
||||||
// @require https://cdnjs.cloudflare.com/ajax/libs/aes-js/3.1.2/index.min.js
|
// @require https://cdnjs.cloudflare.com/ajax/libs/aes-js/3.1.2/index.min.js
|
||||||
// @grant GM_getValue
|
// @grant GM_getValue
|
||||||
// @grant GM_setValue
|
|
||||||
// @run-at document-start
|
// @run-at document-start
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
|
@ -85,11 +84,15 @@ fetchIntercept = {
|
||||||
|
|
||||||
// main code starts here
|
// main code starts here
|
||||||
|
|
||||||
const clientId = '119915'
|
|
||||||
const clientSecret = '2f5b4c9785ddc367975b83d90dc46f5c'
|
|
||||||
const playerTokenKey = [102, 228, 95, 242, 215, 50, 122, 26, 57, 216, 206, 38, 164, 237, 200, 85]
|
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)
|
const cipher = new aesjs.ModeOfOperation.ecb(playerTokenKey)
|
||||||
|
|
||||||
|
const quality_to_format = {
|
||||||
|
"standard": "MP3_128",
|
||||||
|
"high": "MP3_320",
|
||||||
|
"lossless": "FLAC"
|
||||||
|
}
|
||||||
|
|
||||||
function str2bin(str) {
|
function str2bin(str) {
|
||||||
return Array.from(str).map(function (item) {
|
return Array.from(str).map(function (item) {
|
||||||
return item.charCodeAt(0);
|
return item.charCodeAt(0);
|
||||||
|
@ -118,7 +121,7 @@ function playerTokenPatch(playerToken) {
|
||||||
playerToken = JSON.parse(decryptHex(playerToken))
|
playerToken = JSON.parse(decryptHex(playerToken))
|
||||||
|
|
||||||
// enables 320/flac quality selection
|
// enables 320/flac quality selection
|
||||||
playerToken.audio_qualities.wifi_streaming = ['low', 'standard', 'high']
|
playerToken.audio_qualities.wifi_streaming = ['low', 'standard', 'high', 'lossless']
|
||||||
// disables previews
|
// disables previews
|
||||||
playerToken.streaming = true
|
playerToken.streaming = true
|
||||||
playerToken.limited = false
|
playerToken.limited = false
|
||||||
|
@ -128,74 +131,19 @@ function playerTokenPatch(playerToken) {
|
||||||
return encryptHex(JSON.stringify(playerToken))
|
return encryptHex(JSON.stringify(playerToken))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renewAccessToken() {
|
|
||||||
let url = `https://connect.deezer.com/oauth/access_token.php?grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}&output=json`
|
|
||||||
let resp = await fetch(url)
|
|
||||||
let json = await resp.json()
|
|
||||||
access_token = json['access_token']
|
|
||||||
|
|
||||||
// cache access token
|
|
||||||
GM_setValue('access_token', access_token)
|
|
||||||
GM_setValue('access_token_expiry', Math.floor(Date.now() / 1000) + Number(json['expires']))
|
|
||||||
return access_token
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', (_) => {
|
window.addEventListener('DOMContentLoaded', (_) => {
|
||||||
unsafeWindow.dzPlayer.setTrackList = (function (old) {
|
unsafeWindow.dzPlayer.setTrackList = (function (old) {
|
||||||
return async function (data, ...args) {
|
return function (data, ...args) {
|
||||||
// don't get filesizes if account is hifi
|
// needed for deezer's player to accept 320/flac responses
|
||||||
if (unsafeWindow.dzPlayer.user_status.lossless) {
|
|
||||||
return old(data, ...args)
|
|
||||||
}
|
|
||||||
|
|
||||||
let batchList = []
|
|
||||||
|
|
||||||
for (let i = 0; i < data.data.length; i++) {
|
for (let i = 0; i < data.data.length; i++) {
|
||||||
const id = Number(data.data[i].SNG_ID)
|
const id = parseInt(data.data[i].SNG_ID)
|
||||||
if (id >= 0) { // we don't need filesizes for user-upped tracks
|
if (id >= 0) { // don't change filesizes on user-upped tracks
|
||||||
batchList.push({ 'relative_url': `/track/${id}` })
|
data.data[i].FILESIZE_MP3_320 = '1'
|
||||||
|
data.data[i].FILESIZE_FLAC = '1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return if all the tracks are user-upped
|
|
||||||
if (batchList.length === 0) {
|
|
||||||
return old(data, ...args)
|
|
||||||
}
|
|
||||||
|
|
||||||
batchList = JSON.stringify(batchList)
|
|
||||||
|
|
||||||
let access_token = GM_getValue('access_token', false)
|
|
||||||
const expiry = GM_getValue('access_token_expiry', 0)
|
|
||||||
if (!access_token || Math.floor(Date.now() / 1000) >= expiry) {
|
|
||||||
access_token = await renewAccessToken()
|
|
||||||
}
|
|
||||||
|
|
||||||
url = `https://api.deezer.com/batch?methods=${batchList}&access_token=${access_token}`
|
|
||||||
let resp = await fetch(url)
|
|
||||||
let json = await resp.json()
|
|
||||||
|
|
||||||
// renew access token if token is invalid
|
|
||||||
const error = json.batch_result[0].error
|
|
||||||
if (error && error.code === 300) {
|
|
||||||
access_token = await renewAccessToken()
|
|
||||||
url = `https://api.deezer.com/batch?methods=${batchList}&access_token=${access_token}`
|
|
||||||
resp = await fetch(url)
|
|
||||||
json = await resp.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
let userUppedSoFar = 0
|
|
||||||
|
|
||||||
for (let i = 0; i < data.data.length; i++) {
|
|
||||||
const id = Number(data.data[i].SNG_ID)
|
|
||||||
if (id < 0) { // user-uploaded track
|
|
||||||
userUppedSoFar++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
data.data[i].FILESIZE_MP3_320 = json.batch_result[i - userUppedSoFar].filesize_320
|
|
||||||
// for streaming while unlogged
|
|
||||||
data.data[i].MD5_ORIGIN = json.batch_result[i - userUppedSoFar].md5_origin
|
|
||||||
}
|
|
||||||
|
|
||||||
log(data)
|
log(data)
|
||||||
|
|
||||||
return old(data, ...args)
|
return old(data, ...args)
|
||||||
|
@ -206,6 +154,43 @@ window.addEventListener('DOMContentLoaded', (_) => {
|
||||||
fetchIntercept.register({
|
fetchIntercept.register({
|
||||||
request: function (url, config) {
|
request: function (url, config) {
|
||||||
// Modify the url or config here
|
// Modify the url or config here
|
||||||
|
if (url === 'https://media.deezer.com/v1/get_url') {
|
||||||
|
const quality = unsafeWindow.dzPlayer.control.getAudioQuality()
|
||||||
|
const track = unsafeWindow.dzPlayer.getCurrentSong()
|
||||||
|
const id = parseInt(track.SNG_ID)
|
||||||
|
|
||||||
|
let user_status_quality = quality
|
||||||
|
if (user_status_quality === 'high') {
|
||||||
|
user_status_quality = 'hq'
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_subbed = !unsafeWindow.dzPlayer.user_status.can_subscribe
|
||||||
|
let is_quality_available = unsafeWindow.dzPlayer.user_status[user_status_quality]
|
||||||
|
// STREAM_ADS_AVAILABLE is used to check if track is restricted to premium/hifi
|
||||||
|
if (quality === 'standard' && (track.RIGHTS.STREAM_ADS_AVAILABLE === true || is_subbed)) {
|
||||||
|
is_quality_available = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id >= 0 && !is_quality_available) {
|
||||||
|
const media_server = GM_getValue('media_server', 'https://dzmedia.herokuapp.com')
|
||||||
|
url = `${media_server}/get_url`
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
formats: ['FLAC', 'MP3_320', 'MP3_128', 'MP3_64', 'MP3_MISC'],
|
||||||
|
ids: [id]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < body.formats.length; i++) {
|
||||||
|
if (body.formats[0] !== quality_to_format[quality]) {
|
||||||
|
body.formats.shift()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.body = JSON.stringify(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [url, config];
|
return [url, config];
|
||||||
},
|
},
|
||||||
|
@ -229,8 +214,6 @@ fetchIntercept.register({
|
||||||
// disables ads
|
// disables ads
|
||||||
json.results.USER.OPTIONS.ads_display = false
|
json.results.USER.OPTIONS.ads_display = false
|
||||||
json.results.USER.OPTIONS.ads_audio = false
|
json.results.USER.OPTIONS.ads_audio = false
|
||||||
// disables call to get_url endpoint and enables track url gen
|
|
||||||
json.results.__DZR_GATEKEEPS__.use_media_service = false
|
|
||||||
|
|
||||||
json.results.PLAYER_TOKEN = playerTokenPatch(json.results.PLAYER_TOKEN)
|
json.results.PLAYER_TOKEN = playerTokenPatch(json.results.PLAYER_TOKEN)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue