const { notificationImage, icons, save_temp_icons, secondsToMinutes, ToastStyles } = require("./utils"); const getSongControls = require('../../providers/song-controls'); const registerCallback = require("../../providers/song-info"); const { changeProtocolHandler } = require("../../providers/protocol-handler"); const { setTrayOnClick, setTrayOnDoubleClick } = require("../../tray"); const { Notification, app, ipcMain } = require("electron"); const path = require('path'); const config = require("./config"); let songControls; let savedNotification; /** @param {Electron.BrowserWindow} win */ module.exports = (win) => { songControls = getSongControls(win); let currentSeconds = 0; ipcMain.on('apiLoaded', () => win.webContents.send('setupTimeChangedListener')); ipcMain.on('timeChanged', (_, t) => currentSeconds = t); if (app.isPackaged) save_temp_icons(); let savedSongInfo; let lastUrl; // Register songInfoCallback registerCallback(songInfo => { savedSongInfo = { ...songInfo }; if (!songInfo.isPaused && (songInfo.url !== lastUrl || config.get("unpauseNotification")) ) { lastUrl = songInfo.url sendNotification(songInfo); } }); if (config.get("trayControls")) { setTrayOnClick(() => { if (savedNotification) { savedNotification.close(); savedNotification = undefined; } else if (savedSongInfo) { sendNotification({ ...savedSongInfo, elapsedSeconds: currentSeconds }) } }); setTrayOnDoubleClick(() => { if (win.isVisible()) { win.hide(); } else win.show(); }) } app.once("before-quit", () => { savedNotification?.close(); }); changeProtocolHandler( (cmd) => { if (Object.keys(songControls).includes(cmd)) { songControls[cmd](); if (config.get("refreshOnPlayPause") && ( cmd === 'pause' || (cmd === 'play' && !config.get("unpauseNotification")) ) ) { setImmediate(() => sendNotification({ ...savedSongInfo, isPaused: cmd === 'pause', elapsedSeconds: currentSeconds }) ); } } } ) } function sendNotification(songInfo) { const iconSrc = notificationImage(songInfo); savedNotification?.close(); savedNotification = new Notification({ title: songInfo.title || "Playing", body: songInfo.artist, icon: iconSrc, silent: true, // https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/schema-root // https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-schema // https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/adaptive-interactive-toasts?tabs=xml // https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype toastXml: get_xml(songInfo, iconSrc), }); savedNotification.on("close", (_) => { savedNotification = undefined; }); savedNotification.show(); } const get_xml = (songInfo, iconSrc) => { switch (config.get("toastStyle")) { default: case ToastStyles.logo: case ToastStyles.legacy: return xml_logo(songInfo, iconSrc); case ToastStyles.banner_top_custom: return xml_banner_top_custom(songInfo, iconSrc); case ToastStyles.hero: return xml_hero(songInfo, iconSrc); case ToastStyles.banner_bottom: return xml_banner_bottom(songInfo, iconSrc); case ToastStyles.banner_centered_bottom: return xml_banner_centered_bottom(songInfo, iconSrc); case ToastStyles.banner_centered_top: return xml_banner_centered_top(songInfo, iconSrc); }; } const iconLocation = app.isPackaged ? path.resolve(app.getPath("userData"), 'icons') : path.resolve(__dirname, '..', '..', 'assets/media-icons-black'); const display = (kind) => { if (config.get("toastStyle") === ToastStyles.legacy ) { return `content="${icons[kind]}"`; } else { return `\ content="${config.get("hideButtonText") ? "" : kind.charAt(0).toUpperCase() + kind.slice(1)}"\ imageUri="file:///${path.resolve(__dirname, iconLocation, `${kind}.png`)}" `; } } const getButton = (kind) => ``; const getButtons = (isPaused) => `\ ${getButton('previous')} ${isPaused ? getButton('play') : getButton('pause')} ${getButton('next')} \ `; const toast = (content, isPaused) => `\ `; const xml_logo = ({title, artist, isPaused}, imgSrc) => toast(`\ ${title} ${artist}\ `, isPaused); const xml_hero = ({title, artist, isPaused}, imgSrc) => toast(`\ ${title} ${artist}\ `, isPaused); const xml_banner_bottom = ({title, artist, isPaused}, imgSrc) => toast(`\ ${title} ${artist}\ `, isPaused); const xml_banner_top_custom = (songInfo, imgSrc) => toast(`\ ${songInfo.title} ${songInfo.artist} ${xml_more_data(songInfo)} \ `, songInfo.isPaused); const xml_more_data = ({ album, elapsedSeconds, songDuration })=> `\ ${album ? `${album}` : ''} ${secondsToMinutes(elapsedSeconds)} / ${secondsToMinutes(songDuration)} \ `; const xml_banner_centered_bottom = ({title, artist, isPaused}, imgSrc) => toast(`\ ${title} ${artist} \ `, isPaused); const xml_banner_centered_top = ({title, artist, isPaused}, imgSrc) => toast(`\ ${title} ${artist} \ `, isPaused); const titleFontPicker = (title) => { if (title.length <= 13) { return 'Header'; } else if (title.length <= 22) { return 'Subheader'; } else if (title.length <= 26) { return 'Title'; } else { return 'Subtitle'; } }