From 952da07230ab474346a0f9ac4eb43c78f49cee9b Mon Sep 17 00:00:00 2001 From: Julien Maille Date: Thu, 12 Feb 2026 16:00:19 +0100 Subject: [PATCH] IMP: cleanup and add npm run dev:desktop to test neutralino app locally --- js/desktop/discord-rpc.js | 18 ---------- neutralino.config.dev.json | 48 +++++++++++++++++++++++++ package.json | 3 +- public/neutralino_loader.html | 37 ++++++++++++-------- scripts/dev-runner.js | 66 +++++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 35 deletions(-) create mode 100644 neutralino.config.dev.json create mode 100644 scripts/dev-runner.js diff --git a/js/desktop/discord-rpc.js b/js/desktop/discord-rpc.js index 61c3be1..40c8d3f 100644 --- a/js/desktop/discord-rpc.js +++ b/js/desktop/discord-rpc.js @@ -38,24 +38,6 @@ export function initializeDiscordRPC(player) { .catch((e) => console.error('Dispatch failed', e)); } - // Heartbeat & Debug Ping - setInterval(() => { - if (player.currentTrack) { - sendUpdate(player.currentTrack, player.audio.paused); - } else { - const idlingData = { - details: 'Idling', - state: 'Monochrome', - largeImageKey: 'monochrome', - largeImageText: 'Monochrome', - smallImageKey: 'pause', - smallImageText: 'Paused', - }; - Neutralino.events.broadcast('discord:update', idlingData).catch(() => {}); - Neutralino.extensions.dispatch(EXTENSION_ID, 'discord:update', idlingData).catch(() => {}); - } - }, 5000); - player.audio.addEventListener('play', () => { sendUpdate(player.currentTrack); }); diff --git a/neutralino.config.dev.json b/neutralino.config.dev.json new file mode 100644 index 0000000..a06782d --- /dev/null +++ b/neutralino.config.dev.json @@ -0,0 +1,48 @@ +{ + "applicationId": "com.monochrome.app", + "applicationName": "Monochrome", + "applicationIcon": "public/assets/appicon.png", + "author": "Monochrome", + "description": "Monochrome - Lossless music streaming", + "version": "1.0.0", + "defaultMode": "window", + "documentRoot": "/", + "url": "/public/neutralino_loader.html", + "enableServer": true, + "enableNativeAPI": true, + "enableExtensions": true, + "tokenSecurity": "none", + "modes": { + "window": { + "title": "Monochrome (DEV)", + "icon": "public/assets/appicon.png", + "width": 1280, + "height": 800, + "minWidth": 800, + "minHeight": 600, + "center": true, + "resizable": true, + "hidden": false, + "borderless": false, + "enableInspector": true, + "openInspectorOnStartup": true, + "exitProcessOnClose": true + } + }, + "port": 5050, + "cli": { + "binaryName": "Monochrome", + "resourcesPath": "/", + "binaryVersion": "6.5.0", + "clientVersion": "6.5.0" + }, + "extensions": [ + { + "id": "js.neutralino.discordrpc", + "commandLinux": "python3 \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.py\"", + "commandMac": "python3 \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.py\"", + "commandWindows": "powershell.exe -ExecutionPolicy Bypass -File \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.ps1\"" + } + ], + "nativeAllowList": ["app.exit", "window.*", "extensions.*", "filesystem.*", "events.*", "os.*"] +} \ No newline at end of file diff --git a/package.json b/package.json index d022cec..478d6eb 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,9 @@ "main": "sw.js", "scripts": { "dev": "vite", + "dev:desktop": "start npm run dev & node scripts/dev-runner.js", "build": "vite build --mode neutralino && bun x neu build", "postbuild": "node -e \"const fs = require('fs'); const path = require('path'); const src = 'extensions'; const dest = path.join('dist', 'Monochrome', 'extensions'); if (fs.existsSync(src)) { fs.mkdirSync(dest, { recursive: true }); fs.cpSync(src, dest, { recursive: true }); console.log('Extensions manually copied to ' + dest); }\"", - "preview": "vite preview", - "start": "vite preview", "lint:js": "eslint .", "lint:css": "stylelint \"**/*.css\"", "lint:html": "htmlhint \"**/*.html\" --ignore=\"dist/**,legacy/**,node_modules/**\"", diff --git a/public/neutralino_loader.html b/public/neutralino_loader.html index 3b46bc5..a3bdb30 100644 --- a/public/neutralino_loader.html +++ b/public/neutralino_loader.html @@ -25,8 +25,8 @@ - - + + @@ -45,22 +45,29 @@ // Neutralino.init() usually populates window.NL_PORT or we read it from sessionStorage const initFrame = async () => { - // Wait a tick for globals - await new Promise((r) => setTimeout(r, 100)); + // Simplified Dev Mode Detection using Neutralino's internal args + // 'neu run' adds --neu-dev-auto-reload, which we can use to detect dev environment. + const args = window.NL_ARGS || []; + const isDev = args.some(arg => arg.includes('--neu-dev-auto-reload') || arg.includes('--debug-mode')); + + // Static Dev Port + const DEV_PORT = '5173'; - let port = window.NL_PORT || sessionStorage.getItem('NL_PORT'); - // Fallback if missing (shouldn't happen after init) - if (!port) { - // Try reading from window.location if passed (it isn't in shell mode usually) - // But Neutralino fills globals. - // If not, default to 5050 - port = '5050'; + let port = window.NL_PORT || sessionStorage.getItem('NL_PORT') || '5050'; + const iframe = document.getElementById('app-frame'); + + const targetPort = isDev ? DEV_PORT : port; + const targetUrl = `http://localhost:${targetPort}/?mode=neutralino`; + + if (isDev) { + console.log(`[Shell] Dev mode detected via NL_ARGS. Waiting 2s for Vite on port ${targetPort}...`); + await new Promise(r => setTimeout(r, 2000)); + } else { + console.log(`[Shell] Production mode detected.`); } - const iframe = document.getElementById('app-frame'); - // Load the local index.html - iframe.src = `http://localhost:${port}/?mode=neutralino`; - console.log(`[Shell] Loading local app from http://localhost:${port}/?mode=neutralino`); + console.log(`[Shell] Loading app from: ${targetUrl}`); + iframe.src = targetUrl; }; initFrame(); diff --git a/scripts/dev-runner.js b/scripts/dev-runner.js new file mode 100644 index 0000000..f156c61 --- /dev/null +++ b/scripts/dev-runner.js @@ -0,0 +1,66 @@ +import fs from 'fs'; +import { spawn } from 'child_process'; +import path from 'path'; + +const CONFIG_FILE = 'neutralino.config.json'; +const DEV_CONFIG_FILE = 'neutralino.config.dev.json'; +const BACKUP_CONFIG_FILE = 'neutralino.config.prod.bak'; + +function restoreConfig() { + if (fs.existsSync(BACKUP_CONFIG_FILE)) { + try { + // If the current config is the dev one (we can check via content or assume), remove it + if (fs.existsSync(CONFIG_FILE)) { + fs.unlinkSync(CONFIG_FILE); + } + fs.renameSync(BACKUP_CONFIG_FILE, CONFIG_FILE); + console.log('Restored production configuration.'); + } catch (e) { + console.error('Failed to restore configuration:', e); + } + } +} + +// Ensure we clean up on exit +process.on('SIGINT', () => { + restoreConfig(); + process.exit(); +}); + +process.on('exit', () => { + restoreConfig(); +}); + +async function run() { + if (!fs.existsSync(DEV_CONFIG_FILE)) { + console.error('Error: neutralino.config.dev.json not found.'); + process.exit(1); + } + + try { + // Backup production config + if (fs.existsSync(CONFIG_FILE)) { + fs.renameSync(CONFIG_FILE, BACKUP_CONFIG_FILE); + } + + // Copy dev config to main + fs.copyFileSync(DEV_CONFIG_FILE, CONFIG_FILE); + console.log('Switched to development configuration.'); + + // Run neu + const neu = spawn('npx', ['neu', 'run'], { stdio: 'inherit', shell: true }); + + neu.on('close', (code) => { + console.log(`Neutralino process exited with code ${code}`); + restoreConfig(); + process.exit(code); + }); + + } catch (e) { + console.error('Error running dev environment:', e); + restoreConfig(); + process.exit(1); + } +} + +run();