From 2c165d71481821b623f15b138c1984a8dd83c446 Mon Sep 17 00:00:00 2001 From: Julien Maille Date: Tue, 10 Feb 2026 12:02:26 +0100 Subject: [PATCH 1/2] FIX: clean my own mess --- .github/workflows/desktop-build.yml | 2 +- .gitignore | Bin 117 -> 137 bytes index.html | 1 + js/app.js | 47 ++++++++++++++++++---------- js/discord-rpc.js | 1 + neutralino.config.json | 2 +- package.json | 3 +- vite.config.js | 24 ++++++++------ 8 files changed, 50 insertions(+), 30 deletions(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 603115b..ff7a028 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -50,7 +50,7 @@ jobs: run: npx neu update - name: Build application - run: npm run build + run: npm run build:desktop - name: Prepare Release run: | diff --git a/.gitignore b/.gitignore index 5282d6b0d6ee447cc951754653964fb3a2f31ce9..c1b2e4dac6afd184522430e77dacca4aeeffe2e2 100644 GIT binary patch literal 137 zcmYMsK?;R13ZK;;O9n KtCx9#2FwlY5+<(z literal 117 zcmX}kI}XDj5Jl1ct-?~e6vHN{)35+U%*a8(OaudL-=8AoDef&2+3ym2=7yM>f~@mS zr81tBWepiLk}~jEtgK(IATHzLi@Vm4QxTBvKZAEF=B_qSI~QSNgV6Qk|H7OT2iZ?0 A=>Px# diff --git a/index.html b/index.html index 400a4a6..f0c6a26 100644 --- a/index.html +++ b/index.html @@ -4324,6 +4324,7 @@ + diff --git a/js/app.js b/js/app.js index d399923..bdb80cd 100644 --- a/js/app.js +++ b/js/app.js @@ -1,4 +1,5 @@ //js/app.js +console.log('[App] Script loaded'); import { LosslessAPI } from './api.js'; import { apiSettings, @@ -25,7 +26,7 @@ import * as Neutralino from '@neutralinojs/lib'; import './smooth-scrolling.js'; // Assign Neutralino to window for global access -if (typeof window !== 'undefined') { +if (typeof window !== 'undefined' && window.NL_MODE) { window.Neutralino = Neutralino; } @@ -237,6 +238,31 @@ async function disablePwaForAuthGate() { } document.addEventListener('DOMContentLoaded', async () => { + // Initialize desktop environment (Neutralino) + const isDesktop = typeof window !== 'undefined' && (window.NL_MODE || window.location.port === '5050'); + if (typeof window !== 'undefined' && window.Neutralino) { + console.log('[App] Neutralino object detected. Environment:', isDesktop ? 'Desktop' : 'Web'); + if (isDesktop) { + console.log('[App] Initializing Neutralino desktop environment...'); + try { + Neutralino.init(); + console.log('[App] Neutralino.init() called successfully.'); + + // Register events immediately + Neutralino.events.on('windowClose', () => { + console.log('[App] Window close event triggered.'); + Neutralino.app.exit(); + }); + } catch (error) { + console.error('[App] Failed to initialize desktop environment:', error); + } + } else { + console.log('[App] Skipping Neutralino.init() on regular web environment.'); + } + } else { + console.log('[App] Neutralino object NOT detected.'); + } + const api = new LosslessAPI(apiSettings); const audioPlayer = document.getElementById('audio-player'); @@ -385,22 +411,9 @@ document.addEventListener('DOMContentLoaded', async () => { // Initialize tracker initTracker(player); - // Initialize desktop environment (Neutralino) - if (window.Neutralino) { - console.log('Initializing Neutralino desktop environment (Lite Mode)...'); - try { - Neutralino.init(); - - // Register events immediately - Neutralino.events.on('windowClose', () => { - Neutralino.app.exit(); - }); - - // Start RPC immediately after init - initializeDiscordRPC(player); - } catch (error) { - console.error('Failed to initialize desktop environment:', error); - } + if (typeof window !== 'undefined' && window.Neutralino && (window.NL_MODE || window.location.port === '5050')) { + console.log('[App] Starting Discord RPC...'); + initializeDiscordRPC(player); } const castBtn = document.getElementById('cast-btn'); diff --git a/js/discord-rpc.js b/js/discord-rpc.js index 49e91db..eb2708f 100644 --- a/js/discord-rpc.js +++ b/js/discord-rpc.js @@ -42,6 +42,7 @@ export function initializeDiscordRPC(player) { if (player.currentTrack) { sendUpdate(player.currentTrack, player.audio.paused); } else { + console.log('[DiscordRPC] Sending idling heartbeat...'); const idlingData = { details: 'Idling', state: 'Monochrome', diff --git a/neutralino.config.json b/neutralino.config.json index 1fee33d..fdbcf61 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -45,4 +45,4 @@ } ], "nativeAllowList": ["app.exit", "window.*", "extensions.*", "events.*"] -} +} \ No newline at end of file diff --git a/package.json b/package.json index 93f99a1..4a7b39b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "main": "sw.js", "scripts": { "dev": "vite", - "build": "vite build && npx neu build", + "build": "vite build", + "build:desktop": "vite build --mode neutralino && npx neu build && node -e \"const fs = require('fs'); fs.cpSync('extensions', 'dist/Monochrome/extensions', {recursive: true}); fs.copyFileSync('neutralino.config.json', 'dist/Monochrome/neutralino.config.json')\"", "preview": "vite preview", "start": "vite preview", "lint:js": "eslint .", diff --git a/vite.config.js b/vite.config.js index e631736..c71c6f0 100644 --- a/vite.config.js +++ b/vite.config.js @@ -3,16 +3,19 @@ import { VitePWA } from 'vite-plugin-pwa'; import neutralino from 'vite-plugin-neutralino'; import authGatePlugin from './vite-plugin-auth-gate.js'; -export default defineConfig({ - base: './', - build: { - outDir: 'www', - emptyOutDir: true, - }, - plugins: [ - neutralino(), - authGatePlugin(), - VitePWA({ +export default defineConfig(({ mode }) => { + const IS_NEUTRALINO = mode === 'neutralino'; + + return { + base: './', + build: { + outDir: IS_NEUTRALINO ? 'www' : 'dist', + emptyOutDir: IS_NEUTRALINO, + }, + plugins: [ + IS_NEUTRALINO && neutralino(), + authGatePlugin(), + VitePWA({ registerType: 'prompt', workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg,json}'], @@ -49,4 +52,5 @@ export default defineConfig({ manifest: false, // Use existing public/manifest.json }), ], + }; }); From 4c5b201b617b8bf63fc971be87392a4505c32b31 Mon Sep 17 00:00:00 2001 From: JulienMaille <182520+JulienMaille@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:20:16 +0000 Subject: [PATCH 2/2] style: auto-fix linting issues --- neutralino.config.json | 2 +- vite.config.js | 65 +++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/neutralino.config.json b/neutralino.config.json index fdbcf61..1fee33d 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -45,4 +45,4 @@ } ], "nativeAllowList": ["app.exit", "window.*", "extensions.*", "events.*"] -} \ No newline at end of file +} diff --git a/vite.config.js b/vite.config.js index c71c6f0..827ce43 100644 --- a/vite.config.js +++ b/vite.config.js @@ -16,41 +16,42 @@ export default defineConfig(({ mode }) => { IS_NEUTRALINO && neutralino(), authGatePlugin(), VitePWA({ - registerType: 'prompt', - workbox: { - globPatterns: ['**/*.{js,css,html,ico,png,svg,json}'], - cleanupOutdatedCaches: true, - maximumFileSizeToCacheInBytes: 3 * 1024 * 1024, // 3 MiB limit - // Define runtime caching strategies - runtimeCaching: [ - { - urlPattern: ({ request }) => request.destination === 'image', - handler: 'CacheFirst', - options: { - cacheName: 'images', - expiration: { - maxEntries: 100, - maxAgeSeconds: 60 * 24 * 60 * 60, // 60 Days + registerType: 'prompt', + workbox: { + globPatterns: ['**/*.{js,css,html,ico,png,svg,json}'], + cleanupOutdatedCaches: true, + maximumFileSizeToCacheInBytes: 3 * 1024 * 1024, // 3 MiB limit + // Define runtime caching strategies + runtimeCaching: [ + { + urlPattern: ({ request }) => request.destination === 'image', + handler: 'CacheFirst', + options: { + cacheName: 'images', + expiration: { + maxEntries: 100, + maxAgeSeconds: 60 * 24 * 60 * 60, // 60 Days + }, }, }, - }, - { - urlPattern: ({ request }) => request.destination === 'audio' || request.destination === 'video', - handler: 'CacheFirst', - options: { - cacheName: 'media', - expiration: { - maxEntries: 50, - maxAgeSeconds: 60 * 24 * 60 * 60, // 60 Days + { + urlPattern: ({ request }) => + request.destination === 'audio' || request.destination === 'video', + handler: 'CacheFirst', + options: { + cacheName: 'media', + expiration: { + maxEntries: 50, + maxAgeSeconds: 60 * 24 * 60 * 60, // 60 Days + }, + rangeRequests: true, // Support scrubbing }, - rangeRequests: true, // Support scrubbing }, - }, - ], - }, - includeAssets: ['instances.json', 'discord.html'], - manifest: false, // Use existing public/manifest.json - }), - ], + ], + }, + includeAssets: ['instances.json', 'discord.html'], + manifest: false, // Use existing public/manifest.json + }), + ], }; });