IMP: cleanup and add npm run dev:desktop to test neutralino app locally

This commit is contained in:
Julien Maille 2026-02-12 16:00:19 +01:00
parent 64a9171f79
commit 952da07230
5 changed files with 137 additions and 35 deletions

View file

@ -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);
});

View file

@ -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.*"]
}

View file

@ -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/**\"",

View file

@ -25,8 +25,8 @@
</head>
<body>
<script src="/__neutralino_globals.js"></script>
<script src="/neutralino.js"></script>
<script src="__neutralino_globals.js"></script>
<script src="neutralino.js"></script>
<!-- Load the app from the local Neutralino server -->
<iframe id="app-frame" allow="autoplay; fullscreen; microphone; clipboard-read; clipboard-write"></iframe>
@ -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();

66
scripts/dev-runner.js Normal file
View file

@ -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();