// ==UserScript==
// @name Better Flow
// @description Makes editing the queue in flow possible.
// @author bertigert
// @version 1.0.2
// @icon https://www.google.com/s2/favicons?sz=64&domain=deezer.com
// @namespace Violentmonkey Scripts
// @match https://www.deezer.com/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
"use strict";
class Logger {
static PREFIX = "[Better Flow]";
constructor(debug=false) {
this.should_debug = debug;
}
debug(...args) {if (this.should_debug) console.debug(Logger.PREFIX, ...args);}
log(...args) {console.log(Logger.PREFIX, ...args);}
warn(...args) {console.warn(Logger.PREFIX, ...args);}
error(...args) {console.error(Logger.PREFIX, ...args);}
}
class DeezerPlayerHook {
static detect_and_hook_dzplayer(callback) {
const interval_id = setInterval(() => {
if (window.dzPlayer) {
clearInterval(interval_id);
callback(window.dzPlayer);
}
}, 10);
}
static hook_onLoadedTracks() {
logger.log("Hooking dzPlayer.onLoadedTracks");
const orig_onloadedtracks = dzPlayer.onLoadedTracks;
dzPlayer.onLoadedTracks = function (...args) {
try {
const data = args[1];
if ((data.addNext || data.addQueue) && dzPlayer.isRadio()) {
data.radio = true;
data.context.TYPE = dzPlayer.getContext()?.TYPE;
}
return orig_onloadedtracks.apply(this, args);
} catch (error) {
logger.error("Error in onLoadedTracks hook:", error);
}
};
}
}
const PATCHES = {
555: {
methods: [
{
identifiers: ["dispatchRemoveSong:e,"],
matches_and_replacements: [
{
match: /isPlayable\(\)\{const\{([^}]*)playerIsRadio:([a-z]+)(?:,)?/g,
replace: (_, $1, $2) => `isPlayable(){const ${$2}=false,{${$1}`,
}
]
},
{
identifiers: ["this.handleConfirm=this.handleConfirm.bind(this)"],
matches_and_replacements: [
{
match: /isPlayable\(\)\{const\{([^}]*)playerIsRadio:([a-z])(?:,)?/g,
replace: (_, $1, $2) => `isPlayable(){const ${$2}=false,{${$1}`,
}
]
}
]
},
2416: {
methods: [
{
identifiers: ["getStorageKey:e=>`ALERT_DISMISSED_${e}"],
matches_and_replacements: [
{
match: "e?t+1:",
replace: "",
},
{
match: "const{index:e,isRadio:t",
replace: "const t=false,{index:e",
},
]
}
]
},
9281: {
methods: [
{
identifiers: ["=1209600;"],
matches_and_replacements: [
{
match: /addNext:function(.*)if\([a-zA-Z]+\.isRadio\(\)\)return!1;/,
replace: (_, $1) => `addNext:function${$1}`,
}
]
},
]
},
9842: {
methods: [
{
identifiers: [`JSON.parse('{"default":`],
matches_and_replacements: [
{
match: /NB_SONG\|\|[a-zA-Z]+\.[a-zA-Z]+\.isRadio\(\)/,
replace: "NB_SONG",
}
]
}
]
}
}
const logger = new Logger(false);
(function wait_for_webpack_patcher(){
if (window.register_webpack_patches) {
logger.debug("Registering webpack patches");
window.register_webpack_patches(PATCHES);
DeezerPlayerHook.detect_and_hook_dzplayer((dzPlayer) => {
DeezerPlayerHook.hook_onLoadedTracks();
});
} else if (!window.webpackJsonpDeezer) {
setTimeout(wait_for_webpack_patcher, 0);
} else {
logger.warn("Webpack array found, but not patcher, stopping");
}
})();
})();