// ==UserScript== // @name deezrpc // @namespace http://tampermonkey.net/ // @version 1.0 // @description 🎼 | Discord RPC for Deezer // @author qilinmoe // @match *://www.deezer.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=deezer.com // @grant GM_xmlhttpRequest // @updateURL https://raw.githubusercontent.com/qilinmoe/deezrpc/refs/heads/master/assets/deezrpc.user.js // @downloadURL https://raw.githubusercontent.com/qilinmoe/deezrpc/refs/heads/master/assets/deezrpc.user.js // ==/UserScript== (function() { 'use strict'; const BASE_URL = "http://127.0.0.1:5000"; let lastState = ""; let lastTrackJson = ""; let serverSessionId = null; let cachedTrackData = null; function sendToEndpoint(endpoint, payload) { GM_xmlhttpRequest({ method: "POST", url: BASE_URL + endpoint, headers: { "Content-Type": "application/json" }, data: JSON.stringify(payload), onerror: (err) => {} }); } const originalMetadataDescriptor = Object.getOwnPropertyDescriptor(MediaSession.prototype, 'metadata'); // eslint-disable-line no-undef if (originalMetadataDescriptor) { Object.defineProperty(navigator.mediaSession, 'metadata', { set: function(value) { if (value) { let coverUrl = ""; if (value.artwork && value.artwork.length > 0) { coverUrl = value.artwork[value.artwork.length - 1].src; } const trackData = { title: value.title || "Unknown Title", artist: value.artist || "Unknown Artist", album: value.album || "Unknown Album", coverUrl: coverUrl }; cachedTrackData = trackData; const currentJson = JSON.stringify(trackData); if (currentJson !== lastTrackJson) { lastTrackJson = currentJson; console.log("( deezrpc ) • Track:", trackData); sendToEndpoint("/track_info", trackData); } } originalMetadataDescriptor.set.call(this, value); }, get: function() { return originalMetadataDescriptor.get.call(this); } }); } function checkState() { let newState = "paused"; const pauseButton = document.querySelector('button[data-testid="play_button_pause"]'); const playButton = document.querySelector('button[data-testid="play_button_play"]'); if (pauseButton) { newState = "playing"; } else if (playButton) { newState = "paused"; } if (newState !== lastState) { console.log(`( deezrpc ) • New state detected: ${newState}`); sendToEndpoint("/player_info", { state: newState }); lastState = newState; } } setInterval(checkState, 1000); const workerCode = ` self.onmessage = function() { setInterval(() => { self.postMessage('tick'); }, 5000); }; `; const blob = new Blob([workerCode], { type: "text/javascript" }); const workerUrl = URL.createObjectURL(blob); const heartBeatWorker = new Worker(workerUrl); heartBeatWorker.postMessage('start'); heartBeatWorker.onmessage = function() { GM_xmlhttpRequest({ method: "POST", url: BASE_URL + "/keepalive", onload: function(response) { try { const json = JSON.parse(response.responseText); if (serverSessionId === null) { serverSessionId = json.session_id; } else if (json.session_id !== serverSessionId) { console.log("( deezrpc ) • Server restart detected! Resyncing..."); serverSessionId = json.session_id; if (cachedTrackData) { sendToEndpoint("/track_info", cachedTrackData); } lastState = ""; } } catch(e) {} }, onerror: (err) => {} }); }; console.log("( deezrpc ) • Hook attached."); })();