From 416e9e7bac7003aece55fdc9d58bfce384ee9783 Mon Sep 17 00:00:00 2001 From: Anirudh Sevugan Date: Wed, 30 Jul 2025 19:14:47 -0500 Subject: [PATCH] Added new add-on system Addons can do anything, from changing the look and feel of the app, adding new features, and even add references to your favorite characters! --- simpliplay/main.js | 91 ++++++++++++++++++++++++++++++++++++++++- simpliplay/package.json | 2 +- simpliplay/preload.js | 4 +- simpliplay/renderer.js | 47 ++++++++++++++++++++- 4 files changed, 138 insertions(+), 6 deletions(-) diff --git a/simpliplay/main.js b/simpliplay/main.js index 11a921c..9cd6ce4 100644 --- a/simpliplay/main.js +++ b/simpliplay/main.js @@ -207,7 +207,94 @@ if (appMenu && !appMenu.submenu.items.some(item => item.label === 'Check for Upd } } - Menu.setApplicationMenu(menu); +const loadedAddons = new Map(); // key: addon filepath, value: MenuItem + +const newMenuItems = menu ? [...menu.items] : []; + +let addonsMenu; + +// Check if Add-ons menu already exists +const existingAddonsMenuItem = newMenuItems.find(item => item.label === 'Add-ons'); + +if (existingAddonsMenuItem) { + addonsMenu = existingAddonsMenuItem.submenu; +} else { + addonsMenu = new Menu(); + + // "Load Add-on" menu item + addonsMenu.append(new MenuItem({ + label: 'Load Add-on', + accelerator: 'CommandOrControl+Shift+A', + click: async () => { + const result = await dialog.showOpenDialog(mainWindow, { + title: 'Load Add-on', + filters: [{ name: 'JavaScript Files', extensions: ['simpliplay'] }], + properties: ['openFile'], + }); + + if (!result.canceled && result.filePaths.length > 0) { + const filePath = result.filePaths[0]; + const fileName = path.basename(filePath); + const fileURL = pathToFileURL(filePath).href; + + // Check if an addon with the same filename is already loaded + const alreadyLoaded = [...loadedAddons.keys()].some( + loadedPath => path.basename(loadedPath) === fileName + ); + + if (alreadyLoaded) { + await dialog.showMessageBox(mainWindow, { + type: 'error', + title: 'Add-on Load Error', + message: `An add-on named "${fileName}" is already loaded.`, + buttons: ['OK'] + }); + return; + } + + if (!loadedAddons.has(filePath)) { + mainWindow.webContents.send('load-addon', fileURL); + + const addonMenuItem = new MenuItem({ + label: fileName, + type: 'checkbox', + checked: true, + click: (menuItem) => { + if (menuItem.checked) { + mainWindow.webContents.send('load-addon', fileURL); + } else { + mainWindow.webContents.send('unload-addon', fileURL); + } + } + }); + + if (!addonsMenu.items.some(item => item.type === 'separator')) { + addonsMenu.append(new MenuItem({ type: 'separator' })); + } + + addonsMenu.append(addonMenuItem); + loadedAddons.set(filePath, addonMenuItem); + + // Rebuild the menu after adding the new addon item + Menu.setApplicationMenu(Menu.buildFromTemplate(newMenuItems)); + } + } + } + })); + + // Add the Add-ons menu only once here: + newMenuItems.push(new MenuItem({ label: 'Add-ons', submenu: addonsMenu })); + + // Set the application menu after adding Add-ons menu + Menu.setApplicationMenu(Menu.buildFromTemplate(newMenuItems)); +} + + +// Re-apply the full menu if you add newMenuItems outside of the if above +//Menu.setApplicationMenu(Menu.buildFromTemplate(newMenuItems)); + + + //Menu.setApplicationMenu(menu); }; const setupShortcuts = () => { @@ -334,4 +421,4 @@ app.on("window-all-closed", () => { app.on("will-quit", () => { globalShortcut.unregisterAll(); -}); +}); \ No newline at end of file diff --git a/simpliplay/package.json b/simpliplay/package.json index 0cee498..ec48dfa 100644 --- a/simpliplay/package.json +++ b/simpliplay/package.json @@ -1,6 +1,6 @@ { "name": "SimpliPlay", - "version": "2.0.3", + "version": "2.0.4", "description": "SimpliPlay - The mission to make media playback accessible on every device, anywhere, anytime.", "main": "./main.js", "scripts": { diff --git a/simpliplay/preload.js b/simpliplay/preload.js index 7ebdcbb..2825120 100644 --- a/simpliplay/preload.js +++ b/simpliplay/preload.js @@ -2,9 +2,9 @@ const { contextBridge, ipcRenderer } = require("electron"); contextBridge.exposeInMainWorld("electron", { receive: (channel, callback) => { - const validChannels = ["play-media"]; // ✅ Only allow specific, safe channels + const validChannels = ["play-media", "load-addon", "unload-addon"]; if (validChannels.includes(channel)) { - ipcRenderer.removeAllListeners(channel); // ✅ Prevent duplicate listeners + ipcRenderer.removeAllListeners(channel); // Prevent multiple callbacks ipcRenderer.on(channel, (_event, ...args) => callback(...args)); } }, diff --git a/simpliplay/renderer.js b/simpliplay/renderer.js index 0276c13..cc2494b 100644 --- a/simpliplay/renderer.js +++ b/simpliplay/renderer.js @@ -34,8 +34,37 @@ function isSafeURL(fileURL) { } } +// Load addon script dynamically +function loadAddon(fileURL) { + // Avoid duplicate scripts + if (document.querySelector(`script[data-addon="${fileURL}"]`)) return; -// ✅ Listen for "play-media" event from main process securely + const script = document.createElement('script'); + script.src = fileURL; + script.type = 'text/javascript'; + script.async = false; // optional, depends on your needs + script.setAttribute('data-addon', fileURL); + + document.head.appendChild(script); + + console.log(`addon loaded: ${fileURL}`) + alert("Addon loaded successfully"); +} + +// Unload addon script by removing the