From 8be1999a6baa7ee4ba2bd9fdae2dcebae1d11f66 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Sun, 26 Apr 2026 09:50:59 -0700 Subject: [PATCH] Rewrite tray: simple menu, no server-URL config --- desktop-client/tray.js | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 desktop-client/tray.js diff --git a/desktop-client/tray.js b/desktop-client/tray.js new file mode 100644 index 0000000..59ba8cd --- /dev/null +++ b/desktop-client/tray.js @@ -0,0 +1,73 @@ +const { Tray, Menu, nativeImage, shell, clipboard } = require('electron'); + +// Minimal green-circle tray icon, kept from the previous version for visual continuity. +const TRAY_ICON_BASE64 = + 'data:image/png;base64,' + + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAa' + + 'RJREFUWEftlj1OxDAQhe0TcARuABUNDQUF4gRIFJyAG9BQcQJOwA1oKGgoOAI3wP' + + 'vkWRnZjr1xsgVilCiy4/n85s14nMGO/wY79v/dAfwH4T8IpUNoSj9FxAPiS+IHRO' + + 'nzEscvUz4gnkV8JF5C7BNfEe8j6pznxFvEp8RviM8RfyXOlxPVd0j5QAgOBaET5E' + + 'xgXxBPIS5GzlMEMxIJ3kLwPPFT4gPEudC+ILYimlkuJKovoeSBaEuCg8CTiHPC0r' + + 'sQnETM7Q7HqRdS70ygIHYb4p/Ee4hziT0cDx23BaGMwA3EF4nXEi8iz6fOF4Tae+' + + 'LniOuJsxN5PxZ+JgTfIL5K7E4cJIiScr5LjA7lPmvuP0/ETvAEvQn4Tqy+HNNyTk' + + 'fiWeT/0niDe4kqEkX5e5bOGwmhOsRsN2UEQ/qvY/ISxOuIq4k7tI2EcJ38NcT3iX' + + 'PB7S4/EuoISgYrLKD1dOhOPFP6+4R7ieoQPNv9/ULZ+zfis+0Y1e+F7oF3H5F+Xt' + + 'T5p0AqBYeEeEF8k/gtcS56z6f/E5UOLHL8A8a4yC0IHbH4AAAAASUVORK5CYII='; + +let trayInstance = null; +let opts = null; +let currentTitle = null; +let currentArtist = null; + +function buildMenu() { + const url = `http://localhost:${opts.port}/`; + const nowPlaying = + currentTitle && currentArtist + ? `${currentTitle} — ${currentArtist}` + : currentTitle || 'Nothing playing'; + + return Menu.buildFromTemplate([ + { label: "What's That Music", enabled: false }, + { label: `Now Playing: ${nowPlaying}`, enabled: false }, + { type: 'separator' }, + { label: 'Show Player', click: () => opts.onShow && opts.onShow() }, + { label: 'Open Overlay in Browser', click: () => shell.openExternal(url) }, + { label: 'Copy OBS URL', click: () => clipboard.writeText(url) }, + { type: 'separator' }, + { label: 'Quit', click: () => opts.onQuit && opts.onQuit() }, + ]); +} + +/** + * @param {Object} options + * @param {number} options.port + * @param {() => void} options.onShow + * @param {() => void} options.onQuit + * @returns {{ update: (info: { title: string|null, artist: string|null }) => void, destroy: () => void }} + */ +function createTray(options) { + opts = options; + + const icon = nativeImage.createFromDataURL(TRAY_ICON_BASE64); + icon.setTemplateImage(true); + + trayInstance = new Tray(icon); + trayInstance.setToolTip("What's That Music"); + trayInstance.setContextMenu(buildMenu()); + + return { + update({ title, artist }) { + currentTitle = title || null; + currentArtist = artist || null; + if (trayInstance) trayInstance.setContextMenu(buildMenu()); + }, + destroy() { + if (trayInstance) { + trayInstance.destroy(); + trayInstance = null; + } + }, + }; +} + +module.exports = { createTray };