NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name VK Media Api Support // @description Adds support for browser's media api in VK // @version 1.0.0 // @author Syleront // @match *://*.vk.com/* // @run-at document-idle // @license MIT // @copyright 2020, Syleront // ==/UserScript== (() => { const { navigator } = unsafeWindow; if ("mediaSession" in navigator) { const { getAudioPlayer, MediaMetadata } = unsafeWindow; const ap = getAudioPlayer(); ap.on(null, "start", (audioData) => { const title = XmlDecode(audioData[3]); const artist = XmlDecode(audioData[4]); const artworks = audioData[14] || null; let artwork; if (artworks !== null) { let list = artworks.split(","); artwork = [{ src: list[list.length - 1], sizes: "80x80", type: "image/jpeg" }]; } navigator.mediaSession.metadata = new MediaMetadata({ title, artist, artwork }); }); navigator.mediaSession.setActionHandler("play", () => { ap.play(); }); navigator.mediaSession.setActionHandler("pause", () => { ap.pause(); }); navigator.mediaSession.setActionHandler("nexttrack", () => { ap.playNext(); }); navigator.mediaSession.setActionHandler("previoustrack", () => { ap.playPrev(); }); } else { console.log("Media api is not supported in this browser"); } function XmlDecode(str) { // source: https://github.com/mdevils/node-html-entities/blob/master/lib/xml-entities.js const ALPHA_INDEX = { "<": "<", ">": ">", """: "\"", "&apos": "\"", "&": "&", "<": "<", ">": ">", """: "\"", "'": "\"", "&": "&" }; if (!str || !str.length) { return ""; } return str.replace(/&#?[0-9a-zA-Z]+;?/g, (s) => { if (s.charAt(1) === "#") { let code = s.charAt(2).toLowerCase() === "x" ? parseInt(s.substr(3), 16) : parseInt(s.substr(2)); if (isNaN(code) || code < -32768 || code > 65535) { return ""; } return String.fromCharCode(code); } return ALPHA_INDEX[s] || s; }); } })();