loukai-app 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +558 -0
- package/bin/loukai.js +32 -0
- package/package.json +243 -0
- package/src/main/appState.js +250 -0
- package/src/main/audioEngine.js +478 -0
- package/src/main/creator/conversionService.js +503 -0
- package/src/main/creator/downloadManager.js +1128 -0
- package/src/main/creator/ffmpegService.js +487 -0
- package/src/main/creator/installLogger.js +51 -0
- package/src/main/creator/keyDetection.js +212 -0
- package/src/main/creator/llmService.js +370 -0
- package/src/main/creator/lrclibService.js +340 -0
- package/src/main/creator/python/crepe_runner.py +189 -0
- package/src/main/creator/python/demucs_runner.py +158 -0
- package/src/main/creator/python/whisper_runner.py +172 -0
- package/src/main/creator/pythonRunner.js +268 -0
- package/src/main/creator/stemBuilder.js +491 -0
- package/src/main/creator/systemChecker.js +474 -0
- package/src/main/handlers/appHandlers.js +45 -0
- package/src/main/handlers/audioHandlers.js +33 -0
- package/src/main/handlers/autotuneHandlers.js +28 -0
- package/src/main/handlers/canvasHandlers.js +84 -0
- package/src/main/handlers/creatorHandlers.js +159 -0
- package/src/main/handlers/editorHandlers.js +98 -0
- package/src/main/handlers/effectsHandlers.js +100 -0
- package/src/main/handlers/fileHandlers.js +45 -0
- package/src/main/handlers/index.js +78 -0
- package/src/main/handlers/libraryHandlers.js +96 -0
- package/src/main/handlers/mixerHandlers.js +64 -0
- package/src/main/handlers/playerHandlers.js +39 -0
- package/src/main/handlers/preferencesHandlers.js +46 -0
- package/src/main/handlers/queueHandlers.js +81 -0
- package/src/main/handlers/rendererHandlers.js +63 -0
- package/src/main/handlers/settingsHandlers.js +42 -0
- package/src/main/handlers/webServerHandlers.js +105 -0
- package/src/main/main.js +2351 -0
- package/src/main/preload.js +252 -0
- package/src/main/settingsManager.js +139 -0
- package/src/main/statePersistence.js +193 -0
- package/src/main/utils/pathValidator.js +112 -0
- package/src/main/webServer.js +2535 -0
- package/src/native/autotune.js +417 -0
- package/src/renderer/adapters/ElectronBridge.js +677 -0
- package/src/renderer/canvas.html +80 -0
- package/src/renderer/components/App.jsx +303 -0
- package/src/renderer/components/AppRoot.jsx +37 -0
- package/src/renderer/components/AudioDeviceSettings.jsx +145 -0
- package/src/renderer/components/EffectsPanelWrapper.jsx +267 -0
- package/src/renderer/components/MixerTab.jsx +233 -0
- package/src/renderer/components/MixerTabWrapper.jsx +31 -0
- package/src/renderer/components/PortalSelect.jsx +239 -0
- package/src/renderer/components/QueueTab.jsx +116 -0
- package/src/renderer/components/RequestsListWrapper.jsx +78 -0
- package/src/renderer/components/ServerTab.jsx +472 -0
- package/src/renderer/components/SongInfoBarWrapper.jsx +77 -0
- package/src/renderer/components/StatusBar.jsx +92 -0
- package/src/renderer/components/TabNavigation.jsx +77 -0
- package/src/renderer/components/TransportControlsWrapper.jsx +69 -0
- package/src/renderer/components/creator/CreateTab.jsx +1236 -0
- package/src/renderer/dist/assets/kaiPlayer-CoMx__a_.js +2 -0
- package/src/renderer/dist/assets/kaiPlayer-CoMx__a_.js.map +1 -0
- package/src/renderer/dist/assets/microphoneEngine-BaCUhhQc.js +2 -0
- package/src/renderer/dist/assets/microphoneEngine-BaCUhhQc.js.map +1 -0
- package/src/renderer/dist/assets/player-DVrqp7N5.js +3 -0
- package/src/renderer/dist/assets/player-DVrqp7N5.js.map +1 -0
- package/src/renderer/dist/assets/songLoaders-BaTgGib4.js +2 -0
- package/src/renderer/dist/assets/songLoaders-BaTgGib4.js.map +1 -0
- package/src/renderer/dist/assets/webrtcManager-BhCHWceK.js +2 -0
- package/src/renderer/dist/assets/webrtcManager-BhCHWceK.js.map +1 -0
- package/src/renderer/dist/js/autoTuneWorklet.js +224 -0
- package/src/renderer/dist/js/micPitchDetectorWorklet.js +137 -0
- package/src/renderer/dist/js/musicAnalysisWorklet.js +216 -0
- package/src/renderer/dist/js/phaseVocoderWorklet.js +341 -0
- package/src/renderer/dist/js/soundtouch-worklet.js +1395 -0
- package/src/renderer/dist/renderer.css +1 -0
- package/src/renderer/dist/renderer.js +62 -0
- package/src/renderer/dist/renderer.js.map +1 -0
- package/src/renderer/dist/renderer.woff2 +0 -0
- package/src/renderer/hooks/useKeyboardShortcuts.js +154 -0
- package/src/renderer/index.html +24 -0
- package/src/renderer/index.html.backup +372 -0
- package/src/renderer/js/PlayerInterface.js +267 -0
- package/src/renderer/js/autoTuneWorklet.js +224 -0
- package/src/renderer/js/butterchurnVerify.js +46 -0
- package/src/renderer/js/canvas-app.js +114 -0
- package/src/renderer/js/cdgPlayer.js +685 -0
- package/src/renderer/js/kaiPlayer.js +1200 -0
- package/src/renderer/js/karaokeRenderer.js +3392 -0
- package/src/renderer/js/micPitchDetectorWorklet.js +137 -0
- package/src/renderer/js/microphoneEngine.js +656 -0
- package/src/renderer/js/musicAnalysisWorklet.js +216 -0
- package/src/renderer/js/phaseVocoderWorklet.js +341 -0
- package/src/renderer/js/player.js +232 -0
- package/src/renderer/js/referencePitchTracker.js +130 -0
- package/src/renderer/js/songLoaders.js +334 -0
- package/src/renderer/js/soundtouch-worklet.js +1395 -0
- package/src/renderer/js/webrtcManager.js +511 -0
- package/src/renderer/lib/butterchurn.min.js +6739 -0
- package/src/renderer/lib/butterchurnPresets.min.js +1 -0
- package/src/renderer/lib/cdgraphics-wrapper.js +16 -0
- package/src/renderer/lib/cdgraphics.js +299 -0
- package/src/renderer/public/js/autoTuneWorklet.js +224 -0
- package/src/renderer/public/js/micPitchDetectorWorklet.js +137 -0
- package/src/renderer/public/js/musicAnalysisWorklet.js +216 -0
- package/src/renderer/public/js/phaseVocoderWorklet.js +341 -0
- package/src/renderer/public/js/soundtouch-worklet.js +1395 -0
- package/src/renderer/react-entry.jsx +44 -0
- package/src/renderer/styles/tailwind.css +106 -0
- package/src/renderer/utils/qrCodeGenerator.js +98 -0
- package/src/renderer/vite.config.js +31 -0
- package/src/shared/adapters/BridgeInterface.js +195 -0
- package/src/shared/components/EffectsPanel.jsx +177 -0
- package/src/shared/components/LibraryPanel.jsx +701 -0
- package/src/shared/components/LineDetailCanvas.jsx +167 -0
- package/src/shared/components/LyricLine.jsx +505 -0
- package/src/shared/components/LyricRejection.jsx +84 -0
- package/src/shared/components/LyricSuggestion.jsx +80 -0
- package/src/shared/components/LyricsEditorCanvas.jsx +271 -0
- package/src/shared/components/MixerPanel.jsx +94 -0
- package/src/shared/components/PlayerControls.jsx +206 -0
- package/src/shared/components/PortalSelect.jsx +239 -0
- package/src/shared/components/QueueList.jsx +365 -0
- package/src/shared/components/QuickSearch.jsx +126 -0
- package/src/shared/components/RequestsList.jsx +121 -0
- package/src/shared/components/SongEditor.jsx +1362 -0
- package/src/shared/components/SongInfoBar.jsx +81 -0
- package/src/shared/components/ThemeToggle.jsx +106 -0
- package/src/shared/components/Toast.jsx +30 -0
- package/src/shared/components/VisualizationSettings.jsx +243 -0
- package/src/shared/constants.js +95 -0
- package/src/shared/context/BridgeContext.jsx +32 -0
- package/src/shared/contexts/AudioContext.jsx +37 -0
- package/src/shared/contexts/PlayerContext.jsx +66 -0
- package/src/shared/contexts/SettingsContext.jsx +50 -0
- package/src/shared/defaults.js +158 -0
- package/src/shared/formatUtils.js +59 -0
- package/src/shared/formatUtils.test.js +207 -0
- package/src/shared/hooks/useAppState.js +97 -0
- package/src/shared/hooks/useAudioEngine.js +264 -0
- package/src/shared/hooks/usePlayer.js +89 -0
- package/src/shared/hooks/useSettingsPersistence.js +74 -0
- package/src/shared/hooks/useWebRTC.js +118 -0
- package/src/shared/ipcContracts.js +299 -0
- package/src/shared/package.json +3 -0
- package/src/shared/services/creatorService.js +373 -0
- package/src/shared/services/creatorService.test.js +413 -0
- package/src/shared/services/editorService.js +213 -0
- package/src/shared/services/editorService.test.js +219 -0
- package/src/shared/services/effectsService.js +271 -0
- package/src/shared/services/effectsService.test.js +418 -0
- package/src/shared/services/libraryService.js +438 -0
- package/src/shared/services/libraryService.test.js +474 -0
- package/src/shared/services/mixerService.js +172 -0
- package/src/shared/services/mixerService.test.js +399 -0
- package/src/shared/services/playerService.js +221 -0
- package/src/shared/services/playerService.test.js +357 -0
- package/src/shared/services/preferencesService.js +219 -0
- package/src/shared/services/queueService.js +226 -0
- package/src/shared/services/queueService.test.js +430 -0
- package/src/shared/services/requestsService.js +155 -0
- package/src/shared/services/requestsService.test.js +362 -0
- package/src/shared/services/serverSettingsService.js +151 -0
- package/src/shared/services/settingsService.js +257 -0
- package/src/shared/services/settingsService.test.js +295 -0
- package/src/shared/state/StateManager.js +263 -0
- package/src/shared/utils/audio.js +42 -0
- package/src/shared/utils/format.js +32 -0
- package/src/shared/utils/lyricsUtils.js +162 -0
- package/src/test/setup.js +40 -0
- package/src/utils/cdgLoader.js +180 -0
- package/src/utils/m4aLoader.js +333 -0
- package/src/web/App.jsx +578 -0
- package/src/web/adapters/WebBridge.js +428 -0
- package/src/web/components/PlayerSettingsPanel.jsx +231 -0
- package/src/web/components/SongSearch.jsx +180 -0
- package/src/web/dist/assets/index-0H-RnRrV.js +51 -0
- package/src/web/dist/assets/index-0H-RnRrV.js.map +1 -0
- package/src/web/dist/assets/index-DYW2zB0u.css +1 -0
- package/src/web/dist/index.html +15 -0
- package/src/web/index.html +14 -0
- package/src/web/main.jsx +10 -0
- package/src/web/package-lock.json +1765 -0
- package/src/web/pages/SongRequestPage.jsx +619 -0
- package/src/web/styles/tailwind.css +68 -0
- package/src/web/vite.config.js +27 -0
- package/static/fonts/material-icons.woff2 +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi - Potion of Spirits.png +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi - Songflower _Moss Posy_.png +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi - Storm of the Eye _Thunder_ - mash0000 - quasi pseudo meta concentrics.png +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi _ Geiss - Airhandler _Kali Mix_ - Canvas Mix.png +0 -0
- package/static/images/butterchurn-screenshots/An AdamFX n Martin Infusion 2 flexi - Why The Sky Looks Diffrent Today - AdamFx n Martin Infusion - Tack Tile Disfunction B.png +0 -0
- package/static/images/butterchurn-screenshots/Cope - The Neverending Explosion of Red Liquid Fire.png +0 -0
- proton lights __Krash_s beat code_ _Phat_remix02b.png +0 -0
- package/static/images/butterchurn-screenshots/Eo_S_ _ Phat - cubetrace - v2.png +0 -0
- package/static/images/butterchurn-screenshots/Eo_S_ _ Zylot - skylight _Stained Glass Majesty mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - alien fish pond.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - area 51.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - infused with the spiral.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - mindblob _shiny mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - mindblob mix.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - predator-prey-spirals.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - smashing fractals _acid etching mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - truly soft piece of software - this is generic texturing _Jelly_ .png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ Martin - astral projection.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ Martin - cascading decay swing.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ amandio c - piercing 05 - Kopie _2_ - Kopie.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ stahlregen - jelly showoff parade.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi_ fishbrain_ Geiss _ Martin - tokamak witchery.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi_ martin _ geiss - dedicated to the sherwin maxawow.png +0 -0
- package/static/images/butterchurn-screenshots/Fumbling_Foo _ Flexi_ Martin_ Orb_ Unchained - Star Nova v7b.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Cauldron - painterly 2 _saturation remix_.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Reaction Diffusion 2.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Spiral Artifact.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Thumb Drum.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss _ Flexi _ Martin - disconnected.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss_ Flexi _ Stahlregen - Thumbdrum Tokamak _crossfiring aftermath jelly mashup_.png +0 -0
- package/static/images/butterchurn-screenshots/Goody - The Wild Vort.png +0 -0
- package/static/images/butterchurn-screenshots/Idiot - Star Of Annon.png +0 -0
- package/static/images/butterchurn-screenshots/Krash _ Illusion - Spiral Movement.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - QBikal - Surface Turbulence IIb.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - acid wiring.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - charisma.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - liquid arrows.png +0 -0
- package/static/images/butterchurn-screenshots/Milk Artist At our Best - FED - SlowFast Ft AdamFX n Martin - HD CosmoFX.png +0 -0
- package/static/images/butterchurn-screenshots/ORB - Waaa.png +0 -0
- package/static/images/butterchurn-screenshots/Phat_fiShbRaiN_Eo_S_Mandala_Chasers_remix.png +0 -0
- package/static/images/butterchurn-screenshots/Rovastar - Oozing Resistance.png +0 -0
- package/static/images/butterchurn-screenshots/Rovastar _ Loadus _ Geiss - FractalDrop _Triple Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/TonyMilkdrop - Leonardo Da Vinci_s Balloon _Flexi - merry-go-round _ techstyle_.png +0 -0
- package/static/images/butterchurn-screenshots/TonyMilkdrop - Magellan_s Nebula _Flexi - you enter first _ multiverse_.png +0 -0
- package/static/images/butterchurn-screenshots/Unchained - Rewop.png +0 -0
- package/static/images/butterchurn-screenshots/Unchained - Unified Drag 2.png +0 -0
- package/static/images/butterchurn-screenshots/Unchained _ Rovastar - Wormhole Pillars _Hall of Shadows mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Zylot - Paint Spill _Music Reactive Paint Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Zylot - Star Ornament.png +0 -0
- package/static/images/butterchurn-screenshots/Zylot - True Visionary _Final Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/_Aderrasi - Wanderer in Curved Space - mash0000 - faclempt kibitzing meshuggana schmaltz _Geiss color mix_.png +0 -0
- package/static/images/butterchurn-screenshots/_Geiss - Artifact 01.png +0 -0
- package/static/images/butterchurn-screenshots/_Geiss - Desert Rose 2.png +0 -0
- package/static/images/butterchurn-screenshots/_Geiss - untitled.png +0 -0
- package/static/images/butterchurn-screenshots/_Mig_049.png +0 -0
- package/static/images/butterchurn-screenshots/_Mig_085.png +0 -0
- package/static/images/butterchurn-screenshots/_Rovastar _ Geiss - Hurricane Nightmare _Posterize Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/___ Royal - Mashup _197_.png +0 -0
- package/static/images/butterchurn-screenshots/___ Royal - Mashup _220_.png +0 -0
- package/static/images/butterchurn-screenshots/___ Royal - Mashup _431_.png +0 -0
- package/static/images/butterchurn-screenshots/cope _ martin - mother-of-pearl.png +0 -0
- package/static/images/butterchurn-screenshots/fiShbRaiN _ Flexi - witchcraft 2_0.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - bouncing balls _double mindblob neon mix_.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - mom_ why the sky looks different today.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - patternton_ district of media_ capitol of the united abstractions of fractopia.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - swing out on the spiral.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - what is the matrix.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ amandio c - organic _random mashup_.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ amandio c - organic12-3d-2_milk.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ fishbrain - neon mindblob grafitti.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ geiss - pogo cubes vs_ tokamak vs_ game of life _stahls jelly 4_5 finish_.png +0 -0
- package/static/images/butterchurn-screenshots/high-altitude basket unraveling - singh grooves nitrogen argon nz_.png +0 -0
- package/static/images/butterchurn-screenshots/martin - The Bridge of Khazad-Dum.png +0 -0
- package/static/images/butterchurn-screenshots/martin - angel flight.png +0 -0
- package/static/images/butterchurn-screenshots/martin - another kind of groove.png +0 -0
- package/static/images/butterchurn-screenshots/martin - bombyx mori.png +0 -0
- package/static/images/butterchurn-screenshots/martin - castle in the air.png +0 -0
- package/static/images/butterchurn-screenshots/martin - chain breaker.png +0 -0
- package/static/images/butterchurn-screenshots/martin - disco mix 4.png +0 -0
- package/static/images/butterchurn-screenshots/martin - extreme heat.png +0 -0
- package/static/images/butterchurn-screenshots/martin - frosty caves 2.png +0 -0
- package/static/images/butterchurn-screenshots/martin - fruit machine.png +0 -0
- package/static/images/butterchurn-screenshots/martin - ghost city.png +0 -0
- package/static/images/butterchurn-screenshots/martin - glass corridor.png +0 -0
- package/static/images/butterchurn-screenshots/martin - infinity _2010 update_.png +0 -0
- package/static/images/butterchurn-screenshots/martin - mandelbox explorer - high speed demo version.png +0 -0
- package/static/images/butterchurn-screenshots/martin - mucus cervix.png +0 -0
- package/static/images/butterchurn-screenshots/martin - reflections on black tiles.png +0 -0
- package/static/images/butterchurn-screenshots/martin - stormy sea _2010 update_.png +0 -0
- package/static/images/butterchurn-screenshots/martin - witchcraft reloaded.png +0 -0
- package/static/images/butterchurn-screenshots/martin _ flexi - diamond cutter _prismaticvortex_com_ - camille - i wish i wish i wish i was constrained.png +0 -0
- package/static/images/butterchurn-screenshots/martin _shadow harlequins shape code_ - fata morgana.png +0 -0
- package/static/images/butterchurn-screenshots/martin_ flexi_ fishbrain _ sto - enterstate _random mashup_.png +0 -0
- package/static/images/butterchurn-screenshots/sawtooth grin roam.png +0 -0
- package/static/images/butterchurn-screenshots/shifter - dark tides bdrv mix 2.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - Rovastar - Sunflower Passion _Enlightment Mix__Phat_edit _ flexi und martin shaders - circumflex in character classes in regular expression.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - heretical crosscut playpen.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - uninitialized variabowl _hydroponic chronic_.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - vector exp 1 - couldn_t not.png +0 -0
- package/static/images/butterchurn-screenshots/yin - 191 - Temporal singularities.png +0 -0
- package/static/images/logo-512.png +0 -0
- package/static/images/logo.png +0 -0
- package/static/loukai-logo.png +0 -0
- package/static/screenshot-generator.html +610 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creator IPC Handlers
|
|
3
|
+
* Handles AI tool installation and karaoke file creation
|
|
4
|
+
*
|
|
5
|
+
* Uses shared creatorService for logic - same service is used by HTTP routes
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ipcMain, dialog } from 'electron';
|
|
9
|
+
import { CREATOR_CHANNELS } from '../../shared/ipcContracts.js';
|
|
10
|
+
import * as creatorService from '../../shared/services/creatorService.js';
|
|
11
|
+
import * as llmService from '../creator/llmService.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Register all creator-related IPC handlers
|
|
15
|
+
* @param {Object} mainApp - Main application instance
|
|
16
|
+
*/
|
|
17
|
+
export function registerCreatorHandlers(mainApp) {
|
|
18
|
+
// Check all components
|
|
19
|
+
ipcMain.handle(CREATOR_CHANNELS.CHECK_COMPONENTS, () => {
|
|
20
|
+
return creatorService.checkComponents();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Get installation status
|
|
24
|
+
ipcMain.handle(CREATOR_CHANNELS.GET_STATUS, () => {
|
|
25
|
+
return creatorService.getStatus();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Install components
|
|
29
|
+
ipcMain.handle(CREATOR_CHANNELS.INSTALL_COMPONENTS, async () => {
|
|
30
|
+
const result = await creatorService.installComponents((progress) => {
|
|
31
|
+
mainApp.sendToRenderer(CREATOR_CHANNELS.INSTALL_PROGRESS, progress);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (!result.success) {
|
|
35
|
+
mainApp.sendToRenderer(CREATOR_CHANNELS.INSTALL_ERROR, {
|
|
36
|
+
error: result.error,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return result;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Cancel installation
|
|
44
|
+
ipcMain.handle(CREATOR_CHANNELS.CANCEL_INSTALL, () => {
|
|
45
|
+
return creatorService.cancelInstall();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Search lyrics from LRCLIB
|
|
49
|
+
ipcMain.handle(CREATOR_CHANNELS.SEARCH_LYRICS, (_event, title, artist) => {
|
|
50
|
+
return creatorService.findLyrics(title, artist);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Prepare Whisper context with vocabulary hints
|
|
54
|
+
ipcMain.handle(
|
|
55
|
+
CREATOR_CHANNELS.PREPARE_WHISPER_CONTEXT,
|
|
56
|
+
(_event, title, artist, existingLyrics) => {
|
|
57
|
+
return creatorService.getWhisperContext(title, artist, existingLyrics);
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Select audio/video file (Electron-only - uses native dialog)
|
|
62
|
+
ipcMain.handle(CREATOR_CHANNELS.SELECT_FILE, async () => {
|
|
63
|
+
try {
|
|
64
|
+
const result = await dialog.showOpenDialog(mainApp.mainWindow, {
|
|
65
|
+
title: 'Select Audio or Video File',
|
|
66
|
+
properties: ['openFile'],
|
|
67
|
+
filters: [
|
|
68
|
+
{
|
|
69
|
+
name: 'Audio/Video Files',
|
|
70
|
+
extensions: [
|
|
71
|
+
'mp3',
|
|
72
|
+
'wav',
|
|
73
|
+
'flac',
|
|
74
|
+
'ogg',
|
|
75
|
+
'm4a',
|
|
76
|
+
'aac',
|
|
77
|
+
'mp4',
|
|
78
|
+
'mkv',
|
|
79
|
+
'avi',
|
|
80
|
+
'mov',
|
|
81
|
+
'webm',
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{ name: 'Audio Files', extensions: ['mp3', 'wav', 'flac', 'ogg', 'm4a', 'aac'] },
|
|
85
|
+
{ name: 'Video Files', extensions: ['mp4', 'mkv', 'avi', 'mov', 'webm'] },
|
|
86
|
+
{ name: 'All Files', extensions: ['*'] },
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (result.canceled || result.filePaths.length === 0) {
|
|
91
|
+
return { success: false, cancelled: true };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Use shared service to get file info
|
|
95
|
+
return creatorService.getFileInfo(result.filePaths[0]);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error('File selection failed:', error);
|
|
98
|
+
return { success: false, error: error.message };
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Start conversion
|
|
103
|
+
ipcMain.handle(CREATOR_CHANNELS.START_CONVERSION, async (_event, options) => {
|
|
104
|
+
// Track if we're saving to songs folder (outputDir is set)
|
|
105
|
+
const savedToSongsFolder = Boolean(options.outputDir);
|
|
106
|
+
|
|
107
|
+
const result = await creatorService.startConversion(
|
|
108
|
+
options,
|
|
109
|
+
(progress) => {
|
|
110
|
+
mainApp.sendToRenderer(CREATOR_CHANNELS.CONVERSION_PROGRESS, progress);
|
|
111
|
+
},
|
|
112
|
+
(consoleLine) => {
|
|
113
|
+
mainApp.sendToRenderer(CREATOR_CHANNELS.CONVERSION_CONSOLE, { line: consoleLine });
|
|
114
|
+
},
|
|
115
|
+
mainApp.settings // Pass settings manager for LLM
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (result.success) {
|
|
119
|
+
mainApp.sendToRenderer(CREATOR_CHANNELS.CONVERSION_COMPLETE, {
|
|
120
|
+
outputPath: result.outputPath,
|
|
121
|
+
duration: result.duration,
|
|
122
|
+
stems: result.stems,
|
|
123
|
+
hasLyrics: result.hasLyrics,
|
|
124
|
+
hasPitch: result.hasPitch,
|
|
125
|
+
llmStats: result.llmStats,
|
|
126
|
+
savedToSongsFolder,
|
|
127
|
+
});
|
|
128
|
+
} else if (!result.cancelled) {
|
|
129
|
+
mainApp.sendToRenderer(CREATOR_CHANNELS.CONVERSION_ERROR, {
|
|
130
|
+
error: result.error,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return result;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Cancel conversion
|
|
138
|
+
ipcMain.handle(CREATOR_CHANNELS.CANCEL_CONVERSION, () => {
|
|
139
|
+
return creatorService.stopConversion();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Get LLM settings
|
|
143
|
+
ipcMain.handle(CREATOR_CHANNELS.GET_LLM_SETTINGS, () => {
|
|
144
|
+
return llmService.getLLMSettings(mainApp.settings);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Save LLM settings
|
|
148
|
+
ipcMain.handle(CREATOR_CHANNELS.SAVE_LLM_SETTINGS, (_event, settings) => {
|
|
149
|
+
llmService.saveLLMSettings(mainApp.settings, settings);
|
|
150
|
+
return { success: true };
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Test LLM connection
|
|
154
|
+
ipcMain.handle(CREATOR_CHANNELS.TEST_LLM_CONNECTION, (_event, settings) => {
|
|
155
|
+
return llmService.testLLMConnection(settings);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
console.log('✅ Creator handlers registered');
|
|
159
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor IPC Handlers
|
|
3
|
+
* Handles song editing operations (KAI and M4A formats)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ipcMain } from 'electron';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Register all editor-related IPC handlers
|
|
10
|
+
* @param {Object} mainApp - Main application instance
|
|
11
|
+
*/
|
|
12
|
+
export function registerEditorHandlers(mainApp) {
|
|
13
|
+
// Load song file for editing (KAI or M4A)
|
|
14
|
+
ipcMain.handle('editor:loadKai', async (event, filePath) => {
|
|
15
|
+
try {
|
|
16
|
+
console.log('Load song file for editing:', filePath);
|
|
17
|
+
|
|
18
|
+
const editorService = await import('../../shared/services/editorService.js');
|
|
19
|
+
const result = await editorService.loadSong(filePath);
|
|
20
|
+
|
|
21
|
+
console.log(
|
|
22
|
+
`${result.format.toUpperCase()} file loaded for editing, has lyrics:`,
|
|
23
|
+
result.kaiData.lyrics?.length || 0
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
success: true,
|
|
28
|
+
data: result.kaiData,
|
|
29
|
+
format: result.format, // Include format in response
|
|
30
|
+
};
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error('Failed to load song file for editing:', error);
|
|
33
|
+
return { success: false, error: error.message };
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Save song file (KAI or M4A)
|
|
38
|
+
ipcMain.handle('editor:saveKai', async (event, kaiData, originalPath) => {
|
|
39
|
+
try {
|
|
40
|
+
console.log('Save song file request:', originalPath);
|
|
41
|
+
console.log('Updated lyrics:', kaiData.lyrics?.length || 0, 'lines');
|
|
42
|
+
|
|
43
|
+
// Determine format from file extension
|
|
44
|
+
const lowerPath = originalPath.toLowerCase();
|
|
45
|
+
let format;
|
|
46
|
+
if (lowerPath.endsWith('.kai')) {
|
|
47
|
+
format = 'kai';
|
|
48
|
+
} else if (lowerPath.endsWith('.m4a') || lowerPath.endsWith('.mp4')) {
|
|
49
|
+
format = 'm4a-stems';
|
|
50
|
+
} else {
|
|
51
|
+
throw new Error('Unsupported file format');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const editorService = await import('../../shared/services/editorService.js');
|
|
55
|
+
const _result = await editorService.saveSong(originalPath, {
|
|
56
|
+
format: format,
|
|
57
|
+
metadata: kaiData.song || kaiData.metadata || {},
|
|
58
|
+
lyrics: kaiData.lyrics,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.log(`${format.toUpperCase()} file saved successfully`);
|
|
62
|
+
return { success: true };
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('Failed to save song file:', error);
|
|
65
|
+
return { success: false, error: error.message };
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Reload song file in player (KAI or M4A)
|
|
70
|
+
ipcMain.handle('editor:reloadKai', async (event, filePath) => {
|
|
71
|
+
try {
|
|
72
|
+
console.log('Reload song file request:', filePath);
|
|
73
|
+
|
|
74
|
+
// Determine format and call appropriate loader
|
|
75
|
+
const lowerPath = filePath.toLowerCase();
|
|
76
|
+
let result;
|
|
77
|
+
|
|
78
|
+
if (lowerPath.endsWith('.kai')) {
|
|
79
|
+
result = await mainApp.loadKaiFile(filePath);
|
|
80
|
+
} else if (lowerPath.endsWith('.m4a') || lowerPath.endsWith('.mp4')) {
|
|
81
|
+
result = await mainApp.loadM4AFile(filePath);
|
|
82
|
+
} else {
|
|
83
|
+
throw new Error('Unsupported file format');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (result && result.success) {
|
|
87
|
+
console.log('Song file reloaded successfully');
|
|
88
|
+
return { success: true };
|
|
89
|
+
} else {
|
|
90
|
+
console.error('Failed to reload song file');
|
|
91
|
+
return { success: false, error: 'Failed to reload file' };
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('Failed to reload song file:', error);
|
|
95
|
+
return { success: false, error: error.message };
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effects IPC Handlers
|
|
3
|
+
* Handles all visual effects management operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ipcMain } from 'electron';
|
|
7
|
+
import * as effectsService from '../../shared/services/effectsService.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Register all effects-related IPC handlers
|
|
11
|
+
* @param {Object} mainApp - Main application instance
|
|
12
|
+
*/
|
|
13
|
+
export function registerEffectsHandlers(mainApp) {
|
|
14
|
+
// Get list of all effects
|
|
15
|
+
ipcMain.handle('effects:getList', async () => {
|
|
16
|
+
try {
|
|
17
|
+
// Send message to renderer to get effects list
|
|
18
|
+
return await mainApp.sendToRendererAndWait('effects:getList');
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error('Failed to get effects list:', error);
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Get currently selected effect
|
|
26
|
+
ipcMain.handle('effects:getCurrent', async () => {
|
|
27
|
+
try {
|
|
28
|
+
return await mainApp.sendToRendererAndWait('effects:getCurrent');
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error('Failed to get current effect:', error);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Get list of disabled effects
|
|
36
|
+
ipcMain.handle('effects:getDisabled', async () => {
|
|
37
|
+
try {
|
|
38
|
+
return await mainApp.sendToRendererAndWait('effects:getDisabled');
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('Failed to get disabled effects:', error);
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Select an effect
|
|
46
|
+
ipcMain.handle('effects:select', (event, effectName) => {
|
|
47
|
+
try {
|
|
48
|
+
// Update AppState so web admin and other clients can see current effect
|
|
49
|
+
mainApp.appState.updateEffectsState({ current: effectName });
|
|
50
|
+
return { success: true };
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('Failed to select effect:', error);
|
|
53
|
+
return { success: false, error: error.message };
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Toggle effect enabled/disabled
|
|
58
|
+
ipcMain.handle('effects:toggle', (event, effectName, enabled) => {
|
|
59
|
+
try {
|
|
60
|
+
mainApp.sendToRenderer('effects:toggle', { effectName, enabled });
|
|
61
|
+
return { success: true };
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('Failed to toggle effect:', error);
|
|
64
|
+
return { success: false, error: error.message };
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Go to next effect
|
|
69
|
+
ipcMain.handle('effects:next', async () => {
|
|
70
|
+
try {
|
|
71
|
+
const result = await effectsService.nextEffect(mainApp);
|
|
72
|
+
return result;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error('Failed to go to next effect:', error);
|
|
75
|
+
return { success: false, error: error.message };
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Go to previous effect
|
|
80
|
+
ipcMain.handle('effects:previous', async () => {
|
|
81
|
+
try {
|
|
82
|
+
const result = await effectsService.previousEffect(mainApp);
|
|
83
|
+
return result;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('Failed to go to previous effect:', error);
|
|
86
|
+
return { success: false, error: error.message };
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Select random effect
|
|
91
|
+
ipcMain.handle('effects:random', async () => {
|
|
92
|
+
try {
|
|
93
|
+
const result = await effectsService.randomEffect(mainApp);
|
|
94
|
+
return result;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('Failed to select random effect:', error);
|
|
97
|
+
return { success: false, error: error.message };
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File IPC Handlers
|
|
3
|
+
* Handles file operations like open dialogs and file loading
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ipcMain, dialog } from 'electron';
|
|
7
|
+
import { validateSongPath } from '../utils/pathValidator.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Register all file-related IPC handlers
|
|
11
|
+
* @param {Object} mainApp - Main application instance
|
|
12
|
+
*/
|
|
13
|
+
export function registerFileHandlers(mainApp) {
|
|
14
|
+
// Open file dialog to select karaoke file (M4A or KAI)
|
|
15
|
+
ipcMain.handle('file:openKai', async () => {
|
|
16
|
+
const result = await dialog.showOpenDialog(mainApp.mainWindow, {
|
|
17
|
+
filters: [
|
|
18
|
+
{ name: 'Karaoke Files', extensions: ['m4a', 'kai'] },
|
|
19
|
+
{ name: 'M4A Stems (recommended)', extensions: ['m4a'] },
|
|
20
|
+
{ name: 'KAI Files (legacy)', extensions: ['kai'] },
|
|
21
|
+
],
|
|
22
|
+
properties: ['openFile'],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!result.canceled && result.filePaths.length > 0) {
|
|
26
|
+
return await mainApp.loadKaiFile(result.filePaths[0]);
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Load KAI file from path (with path traversal protection)
|
|
32
|
+
ipcMain.handle('file:loadKaiFromPath', async (event, filePath) => {
|
|
33
|
+
// Get the songs folder from settings
|
|
34
|
+
const songsFolder = mainApp.settings?.getSongsFolder?.();
|
|
35
|
+
|
|
36
|
+
// Validate the path is within the songs directory
|
|
37
|
+
const validation = validateSongPath(filePath, songsFolder);
|
|
38
|
+
if (!validation.valid) {
|
|
39
|
+
console.error('🚫 Path validation failed:', validation.error, filePath);
|
|
40
|
+
return { error: validation.error };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return await mainApp.loadKaiFile(validation.resolvedPath);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IPC Handler Registration
|
|
3
|
+
* Central registration point for all IPC handlers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
console.log('📦 Loading handler modules...');
|
|
7
|
+
|
|
8
|
+
import { registerAudioHandlers } from './audioHandlers.js';
|
|
9
|
+
console.log('✓ audioHandlers');
|
|
10
|
+
import { registerMixerHandlers } from './mixerHandlers.js';
|
|
11
|
+
console.log('✓ mixerHandlers');
|
|
12
|
+
import { registerPlayerHandlers } from './playerHandlers.js';
|
|
13
|
+
console.log('✓ playerHandlers');
|
|
14
|
+
import { registerLibraryHandlers } from './libraryHandlers.js';
|
|
15
|
+
console.log('✓ libraryHandlers');
|
|
16
|
+
import { registerSettingsHandlers } from './settingsHandlers.js';
|
|
17
|
+
console.log('✓ settingsHandlers');
|
|
18
|
+
import { registerQueueHandlers } from './queueHandlers.js';
|
|
19
|
+
console.log('✓ queueHandlers');
|
|
20
|
+
import { registerWebServerHandlers } from './webServerHandlers.js';
|
|
21
|
+
console.log('✓ webServerHandlers');
|
|
22
|
+
import { registerCanvasHandlers } from './canvasHandlers.js';
|
|
23
|
+
console.log('✓ canvasHandlers');
|
|
24
|
+
import { registerEffectsHandlers } from './effectsHandlers.js';
|
|
25
|
+
console.log('✓ effectsHandlers');
|
|
26
|
+
import { registerEditorHandlers } from './editorHandlers.js';
|
|
27
|
+
console.log('✓ editorHandlers');
|
|
28
|
+
import { registerPreferencesHandlers } from './preferencesHandlers.js';
|
|
29
|
+
console.log('✓ preferencesHandlers');
|
|
30
|
+
import { registerFileHandlers } from './fileHandlers.js';
|
|
31
|
+
console.log('✓ fileHandlers');
|
|
32
|
+
import { registerRendererHandlers } from './rendererHandlers.js';
|
|
33
|
+
console.log('✓ rendererHandlers');
|
|
34
|
+
import { registerAppHandlers } from './appHandlers.js';
|
|
35
|
+
console.log('✓ appHandlers');
|
|
36
|
+
import { registerAutotuneHandlers } from './autotuneHandlers.js';
|
|
37
|
+
console.log('✓ autotuneHandlers');
|
|
38
|
+
import { registerCreatorHandlers } from './creatorHandlers.js';
|
|
39
|
+
console.log('✓ creatorHandlers');
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Register all IPC handlers
|
|
43
|
+
* @param {Object} mainApp - Main application instance
|
|
44
|
+
*/
|
|
45
|
+
export function registerAllHandlers(mainApp) {
|
|
46
|
+
console.log('📡 Registering IPC handlers...');
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// Core handlers
|
|
50
|
+
registerAudioHandlers(mainApp);
|
|
51
|
+
registerMixerHandlers(mainApp);
|
|
52
|
+
registerPlayerHandlers(mainApp);
|
|
53
|
+
registerLibraryHandlers(mainApp);
|
|
54
|
+
registerSettingsHandlers(mainApp);
|
|
55
|
+
registerQueueHandlers(mainApp);
|
|
56
|
+
|
|
57
|
+
// Feature handlers
|
|
58
|
+
registerWebServerHandlers(mainApp);
|
|
59
|
+
registerCanvasHandlers(mainApp);
|
|
60
|
+
registerEffectsHandlers(mainApp);
|
|
61
|
+
registerEditorHandlers(mainApp);
|
|
62
|
+
registerPreferencesHandlers(mainApp);
|
|
63
|
+
registerAutotuneHandlers(mainApp);
|
|
64
|
+
|
|
65
|
+
// System handlers
|
|
66
|
+
registerFileHandlers(mainApp);
|
|
67
|
+
registerRendererHandlers(mainApp);
|
|
68
|
+
registerAppHandlers(mainApp);
|
|
69
|
+
|
|
70
|
+
// Creator handlers
|
|
71
|
+
registerCreatorHandlers(mainApp);
|
|
72
|
+
|
|
73
|
+
console.log('✅ All IPC handlers registered');
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('❌ Failed to register IPC handlers:', error);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library IPC Handlers
|
|
3
|
+
* Handles song library management operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ipcMain, dialog } from 'electron';
|
|
7
|
+
import fsPromises from 'fs/promises';
|
|
8
|
+
import { LIBRARY_CHANNELS } from '../../shared/ipcContracts.js';
|
|
9
|
+
import * as libraryService from '../../shared/services/libraryService.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Register all library-related IPC handlers
|
|
13
|
+
* @param {Object} mainApp - Main application instance
|
|
14
|
+
*/
|
|
15
|
+
export function registerLibraryHandlers(mainApp) {
|
|
16
|
+
// Get songs folder
|
|
17
|
+
ipcMain.handle(LIBRARY_CHANNELS.GET_SONGS_FOLDER, () => {
|
|
18
|
+
return libraryService.getSongsFolder(mainApp);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Set songs folder
|
|
22
|
+
ipcMain.handle(LIBRARY_CHANNELS.SET_SONGS_FOLDER, async () => {
|
|
23
|
+
const result = await dialog.showOpenDialog(mainApp.mainWindow, {
|
|
24
|
+
properties: ['openDirectory'],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (result.canceled || result.filePaths.length === 0) {
|
|
28
|
+
return { success: false, folder: null };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const folder = result.filePaths[0];
|
|
32
|
+
await mainApp.setSongsFolderAndScan(folder);
|
|
33
|
+
|
|
34
|
+
return { success: true, folder };
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Scan folder (with cache updates)
|
|
38
|
+
ipcMain.handle(LIBRARY_CHANNELS.SCAN_FOLDER, async () => {
|
|
39
|
+
const result = await libraryService.scanLibrary(mainApp, (progress) => {
|
|
40
|
+
mainApp.sendToRenderer('library:scanProgress', progress);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (result.success) {
|
|
44
|
+
// Update all caches (mainApp, webServer, disk)
|
|
45
|
+
await libraryService.updateLibraryCache(mainApp, result.files);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return result;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Sync library (with cache updates)
|
|
52
|
+
ipcMain.handle(LIBRARY_CHANNELS.SYNC_LIBRARY, async () => {
|
|
53
|
+
const result = await libraryService.syncLibrary(mainApp, (progress) => {
|
|
54
|
+
mainApp.sendToRenderer('library:scanProgress', progress);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (result.success) {
|
|
58
|
+
// Update all caches (mainApp, webServer, disk)
|
|
59
|
+
await libraryService.updateLibraryCache(mainApp, result.files);
|
|
60
|
+
|
|
61
|
+
// Return with 'songs' key for renderer compatibility
|
|
62
|
+
return {
|
|
63
|
+
...result,
|
|
64
|
+
songs: result.files,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Get cached songs
|
|
72
|
+
ipcMain.handle(LIBRARY_CHANNELS.GET_CACHED_SONGS, () => {
|
|
73
|
+
return libraryService.getCachedSongs(mainApp);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Get song info (with file size)
|
|
77
|
+
ipcMain.handle(LIBRARY_CHANNELS.GET_SONG_INFO, async (event, filePath) => {
|
|
78
|
+
const result = await libraryService.getSongInfo(mainApp, filePath);
|
|
79
|
+
|
|
80
|
+
// For compatibility with existing code, wrap result if needed
|
|
81
|
+
if (result.success && result.song) {
|
|
82
|
+
// Get file size if not already present
|
|
83
|
+
if (!result.song.fileSize) {
|
|
84
|
+
try {
|
|
85
|
+
const stats = await fsPromises.stat(filePath);
|
|
86
|
+
result.song.fileSize = stats.size;
|
|
87
|
+
} catch {
|
|
88
|
+
result.song.fileSize = 0;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return result.song;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mixer IPC Handlers
|
|
3
|
+
* Handles all mixer control operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ipcMain } from 'electron';
|
|
7
|
+
import { MIXER_CHANNELS } from '../../shared/ipcContracts.js';
|
|
8
|
+
import * as mixerService from '../../shared/services/mixerService.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Register all mixer-related IPC handlers
|
|
12
|
+
* @param {Object} mainApp - Main application instance
|
|
13
|
+
*/
|
|
14
|
+
export function registerMixerHandlers(mainApp) {
|
|
15
|
+
// Set master gain
|
|
16
|
+
ipcMain.handle(MIXER_CHANNELS.SET_MASTER_GAIN, (event, bus, gainDb) => {
|
|
17
|
+
return mixerService.setMasterGain(mainApp, bus, gainDb);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Toggle master mute
|
|
21
|
+
ipcMain.handle(MIXER_CHANNELS.TOGGLE_MASTER_MUTE, (event, bus) => {
|
|
22
|
+
return mixerService.toggleMasterMute(mainApp, bus);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Toggle stem mute
|
|
26
|
+
ipcMain.handle('mixer:toggleMute', (event, stemId, bus) => {
|
|
27
|
+
if (mainApp.audioEngine) {
|
|
28
|
+
return mainApp.audioEngine.toggleMute(stemId, bus);
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Toggle stem solo
|
|
34
|
+
ipcMain.handle('mixer:toggleSolo', (event, stemId) => {
|
|
35
|
+
if (mainApp.audioEngine) {
|
|
36
|
+
return mainApp.audioEngine.toggleSolo(stemId);
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Set stem gain
|
|
42
|
+
ipcMain.handle('mixer:setGain', (event, stemId, gainDb) => {
|
|
43
|
+
if (mainApp.audioEngine) {
|
|
44
|
+
return mainApp.audioEngine.setGain(stemId, gainDb);
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Apply mixer preset
|
|
50
|
+
ipcMain.handle('mixer:applyPreset', (event, presetId) => {
|
|
51
|
+
if (mainApp.audioEngine) {
|
|
52
|
+
return mainApp.audioEngine.applyPreset(presetId);
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Recall mixer scene
|
|
58
|
+
ipcMain.handle('mixer:recallScene', (event, sceneId) => {
|
|
59
|
+
if (mainApp.audioEngine) {
|
|
60
|
+
return mainApp.audioEngine.recallScene(sceneId);
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Player IPC Handlers
|
|
3
|
+
* Handles playback control operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ipcMain } from 'electron';
|
|
7
|
+
import { PLAYER_CHANNELS } from '../../shared/ipcContracts.js';
|
|
8
|
+
import * as playerService from '../../shared/services/playerService.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Register all player-related IPC handlers
|
|
12
|
+
* @param {Object} mainApp - Main application instance
|
|
13
|
+
*/
|
|
14
|
+
export function registerPlayerHandlers(mainApp) {
|
|
15
|
+
// Play
|
|
16
|
+
ipcMain.handle(PLAYER_CHANNELS.PLAY, () => {
|
|
17
|
+
return playerService.play(mainApp);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Pause
|
|
21
|
+
ipcMain.handle(PLAYER_CHANNELS.PAUSE, () => {
|
|
22
|
+
return playerService.pause(mainApp);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Seek
|
|
26
|
+
ipcMain.handle(PLAYER_CHANNELS.SEEK, (event, positionSec) => {
|
|
27
|
+
return playerService.seek(mainApp, positionSec);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Restart
|
|
31
|
+
ipcMain.handle(PLAYER_CHANNELS.RESTART, () => {
|
|
32
|
+
return playerService.restart(mainApp);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Next
|
|
36
|
+
ipcMain.handle(PLAYER_CHANNELS.NEXT, () => {
|
|
37
|
+
return playerService.playNext(mainApp);
|
|
38
|
+
});
|
|
39
|
+
}
|