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.
Files changed (290) hide show
  1. package/README.md +558 -0
  2. package/bin/loukai.js +32 -0
  3. package/package.json +243 -0
  4. package/src/main/appState.js +250 -0
  5. package/src/main/audioEngine.js +478 -0
  6. package/src/main/creator/conversionService.js +503 -0
  7. package/src/main/creator/downloadManager.js +1128 -0
  8. package/src/main/creator/ffmpegService.js +487 -0
  9. package/src/main/creator/installLogger.js +51 -0
  10. package/src/main/creator/keyDetection.js +212 -0
  11. package/src/main/creator/llmService.js +370 -0
  12. package/src/main/creator/lrclibService.js +340 -0
  13. package/src/main/creator/python/crepe_runner.py +189 -0
  14. package/src/main/creator/python/demucs_runner.py +158 -0
  15. package/src/main/creator/python/whisper_runner.py +172 -0
  16. package/src/main/creator/pythonRunner.js +268 -0
  17. package/src/main/creator/stemBuilder.js +491 -0
  18. package/src/main/creator/systemChecker.js +474 -0
  19. package/src/main/handlers/appHandlers.js +45 -0
  20. package/src/main/handlers/audioHandlers.js +33 -0
  21. package/src/main/handlers/autotuneHandlers.js +28 -0
  22. package/src/main/handlers/canvasHandlers.js +84 -0
  23. package/src/main/handlers/creatorHandlers.js +159 -0
  24. package/src/main/handlers/editorHandlers.js +98 -0
  25. package/src/main/handlers/effectsHandlers.js +100 -0
  26. package/src/main/handlers/fileHandlers.js +45 -0
  27. package/src/main/handlers/index.js +78 -0
  28. package/src/main/handlers/libraryHandlers.js +96 -0
  29. package/src/main/handlers/mixerHandlers.js +64 -0
  30. package/src/main/handlers/playerHandlers.js +39 -0
  31. package/src/main/handlers/preferencesHandlers.js +46 -0
  32. package/src/main/handlers/queueHandlers.js +81 -0
  33. package/src/main/handlers/rendererHandlers.js +63 -0
  34. package/src/main/handlers/settingsHandlers.js +42 -0
  35. package/src/main/handlers/webServerHandlers.js +105 -0
  36. package/src/main/main.js +2351 -0
  37. package/src/main/preload.js +252 -0
  38. package/src/main/settingsManager.js +139 -0
  39. package/src/main/statePersistence.js +193 -0
  40. package/src/main/utils/pathValidator.js +112 -0
  41. package/src/main/webServer.js +2535 -0
  42. package/src/native/autotune.js +417 -0
  43. package/src/renderer/adapters/ElectronBridge.js +677 -0
  44. package/src/renderer/canvas.html +80 -0
  45. package/src/renderer/components/App.jsx +303 -0
  46. package/src/renderer/components/AppRoot.jsx +37 -0
  47. package/src/renderer/components/AudioDeviceSettings.jsx +145 -0
  48. package/src/renderer/components/EffectsPanelWrapper.jsx +267 -0
  49. package/src/renderer/components/MixerTab.jsx +233 -0
  50. package/src/renderer/components/MixerTabWrapper.jsx +31 -0
  51. package/src/renderer/components/PortalSelect.jsx +239 -0
  52. package/src/renderer/components/QueueTab.jsx +116 -0
  53. package/src/renderer/components/RequestsListWrapper.jsx +78 -0
  54. package/src/renderer/components/ServerTab.jsx +472 -0
  55. package/src/renderer/components/SongInfoBarWrapper.jsx +77 -0
  56. package/src/renderer/components/StatusBar.jsx +92 -0
  57. package/src/renderer/components/TabNavigation.jsx +77 -0
  58. package/src/renderer/components/TransportControlsWrapper.jsx +69 -0
  59. package/src/renderer/components/creator/CreateTab.jsx +1236 -0
  60. package/src/renderer/dist/assets/kaiPlayer-CoMx__a_.js +2 -0
  61. package/src/renderer/dist/assets/kaiPlayer-CoMx__a_.js.map +1 -0
  62. package/src/renderer/dist/assets/microphoneEngine-BaCUhhQc.js +2 -0
  63. package/src/renderer/dist/assets/microphoneEngine-BaCUhhQc.js.map +1 -0
  64. package/src/renderer/dist/assets/player-DVrqp7N5.js +3 -0
  65. package/src/renderer/dist/assets/player-DVrqp7N5.js.map +1 -0
  66. package/src/renderer/dist/assets/songLoaders-BaTgGib4.js +2 -0
  67. package/src/renderer/dist/assets/songLoaders-BaTgGib4.js.map +1 -0
  68. package/src/renderer/dist/assets/webrtcManager-BhCHWceK.js +2 -0
  69. package/src/renderer/dist/assets/webrtcManager-BhCHWceK.js.map +1 -0
  70. package/src/renderer/dist/js/autoTuneWorklet.js +224 -0
  71. package/src/renderer/dist/js/micPitchDetectorWorklet.js +137 -0
  72. package/src/renderer/dist/js/musicAnalysisWorklet.js +216 -0
  73. package/src/renderer/dist/js/phaseVocoderWorklet.js +341 -0
  74. package/src/renderer/dist/js/soundtouch-worklet.js +1395 -0
  75. package/src/renderer/dist/renderer.css +1 -0
  76. package/src/renderer/dist/renderer.js +62 -0
  77. package/src/renderer/dist/renderer.js.map +1 -0
  78. package/src/renderer/dist/renderer.woff2 +0 -0
  79. package/src/renderer/hooks/useKeyboardShortcuts.js +154 -0
  80. package/src/renderer/index.html +24 -0
  81. package/src/renderer/index.html.backup +372 -0
  82. package/src/renderer/js/PlayerInterface.js +267 -0
  83. package/src/renderer/js/autoTuneWorklet.js +224 -0
  84. package/src/renderer/js/butterchurnVerify.js +46 -0
  85. package/src/renderer/js/canvas-app.js +114 -0
  86. package/src/renderer/js/cdgPlayer.js +685 -0
  87. package/src/renderer/js/kaiPlayer.js +1200 -0
  88. package/src/renderer/js/karaokeRenderer.js +3392 -0
  89. package/src/renderer/js/micPitchDetectorWorklet.js +137 -0
  90. package/src/renderer/js/microphoneEngine.js +656 -0
  91. package/src/renderer/js/musicAnalysisWorklet.js +216 -0
  92. package/src/renderer/js/phaseVocoderWorklet.js +341 -0
  93. package/src/renderer/js/player.js +232 -0
  94. package/src/renderer/js/referencePitchTracker.js +130 -0
  95. package/src/renderer/js/songLoaders.js +334 -0
  96. package/src/renderer/js/soundtouch-worklet.js +1395 -0
  97. package/src/renderer/js/webrtcManager.js +511 -0
  98. package/src/renderer/lib/butterchurn.min.js +6739 -0
  99. package/src/renderer/lib/butterchurnPresets.min.js +1 -0
  100. package/src/renderer/lib/cdgraphics-wrapper.js +16 -0
  101. package/src/renderer/lib/cdgraphics.js +299 -0
  102. package/src/renderer/public/js/autoTuneWorklet.js +224 -0
  103. package/src/renderer/public/js/micPitchDetectorWorklet.js +137 -0
  104. package/src/renderer/public/js/musicAnalysisWorklet.js +216 -0
  105. package/src/renderer/public/js/phaseVocoderWorklet.js +341 -0
  106. package/src/renderer/public/js/soundtouch-worklet.js +1395 -0
  107. package/src/renderer/react-entry.jsx +44 -0
  108. package/src/renderer/styles/tailwind.css +106 -0
  109. package/src/renderer/utils/qrCodeGenerator.js +98 -0
  110. package/src/renderer/vite.config.js +31 -0
  111. package/src/shared/adapters/BridgeInterface.js +195 -0
  112. package/src/shared/components/EffectsPanel.jsx +177 -0
  113. package/src/shared/components/LibraryPanel.jsx +701 -0
  114. package/src/shared/components/LineDetailCanvas.jsx +167 -0
  115. package/src/shared/components/LyricLine.jsx +505 -0
  116. package/src/shared/components/LyricRejection.jsx +84 -0
  117. package/src/shared/components/LyricSuggestion.jsx +80 -0
  118. package/src/shared/components/LyricsEditorCanvas.jsx +271 -0
  119. package/src/shared/components/MixerPanel.jsx +94 -0
  120. package/src/shared/components/PlayerControls.jsx +206 -0
  121. package/src/shared/components/PortalSelect.jsx +239 -0
  122. package/src/shared/components/QueueList.jsx +365 -0
  123. package/src/shared/components/QuickSearch.jsx +126 -0
  124. package/src/shared/components/RequestsList.jsx +121 -0
  125. package/src/shared/components/SongEditor.jsx +1362 -0
  126. package/src/shared/components/SongInfoBar.jsx +81 -0
  127. package/src/shared/components/ThemeToggle.jsx +106 -0
  128. package/src/shared/components/Toast.jsx +30 -0
  129. package/src/shared/components/VisualizationSettings.jsx +243 -0
  130. package/src/shared/constants.js +95 -0
  131. package/src/shared/context/BridgeContext.jsx +32 -0
  132. package/src/shared/contexts/AudioContext.jsx +37 -0
  133. package/src/shared/contexts/PlayerContext.jsx +66 -0
  134. package/src/shared/contexts/SettingsContext.jsx +50 -0
  135. package/src/shared/defaults.js +158 -0
  136. package/src/shared/formatUtils.js +59 -0
  137. package/src/shared/formatUtils.test.js +207 -0
  138. package/src/shared/hooks/useAppState.js +97 -0
  139. package/src/shared/hooks/useAudioEngine.js +264 -0
  140. package/src/shared/hooks/usePlayer.js +89 -0
  141. package/src/shared/hooks/useSettingsPersistence.js +74 -0
  142. package/src/shared/hooks/useWebRTC.js +118 -0
  143. package/src/shared/ipcContracts.js +299 -0
  144. package/src/shared/package.json +3 -0
  145. package/src/shared/services/creatorService.js +373 -0
  146. package/src/shared/services/creatorService.test.js +413 -0
  147. package/src/shared/services/editorService.js +213 -0
  148. package/src/shared/services/editorService.test.js +219 -0
  149. package/src/shared/services/effectsService.js +271 -0
  150. package/src/shared/services/effectsService.test.js +418 -0
  151. package/src/shared/services/libraryService.js +438 -0
  152. package/src/shared/services/libraryService.test.js +474 -0
  153. package/src/shared/services/mixerService.js +172 -0
  154. package/src/shared/services/mixerService.test.js +399 -0
  155. package/src/shared/services/playerService.js +221 -0
  156. package/src/shared/services/playerService.test.js +357 -0
  157. package/src/shared/services/preferencesService.js +219 -0
  158. package/src/shared/services/queueService.js +226 -0
  159. package/src/shared/services/queueService.test.js +430 -0
  160. package/src/shared/services/requestsService.js +155 -0
  161. package/src/shared/services/requestsService.test.js +362 -0
  162. package/src/shared/services/serverSettingsService.js +151 -0
  163. package/src/shared/services/settingsService.js +257 -0
  164. package/src/shared/services/settingsService.test.js +295 -0
  165. package/src/shared/state/StateManager.js +263 -0
  166. package/src/shared/utils/audio.js +42 -0
  167. package/src/shared/utils/format.js +32 -0
  168. package/src/shared/utils/lyricsUtils.js +162 -0
  169. package/src/test/setup.js +40 -0
  170. package/src/utils/cdgLoader.js +180 -0
  171. package/src/utils/m4aLoader.js +333 -0
  172. package/src/web/App.jsx +578 -0
  173. package/src/web/adapters/WebBridge.js +428 -0
  174. package/src/web/components/PlayerSettingsPanel.jsx +231 -0
  175. package/src/web/components/SongSearch.jsx +180 -0
  176. package/src/web/dist/assets/index-0H-RnRrV.js +51 -0
  177. package/src/web/dist/assets/index-0H-RnRrV.js.map +1 -0
  178. package/src/web/dist/assets/index-DYW2zB0u.css +1 -0
  179. package/src/web/dist/index.html +15 -0
  180. package/src/web/index.html +14 -0
  181. package/src/web/main.jsx +10 -0
  182. package/src/web/package-lock.json +1765 -0
  183. package/src/web/pages/SongRequestPage.jsx +619 -0
  184. package/src/web/styles/tailwind.css +68 -0
  185. package/src/web/vite.config.js +27 -0
  186. package/static/fonts/material-icons.woff2 +0 -0
  187. package/static/images/butterchurn-screenshots/Aderrasi - Potion of Spirits.png +0 -0
  188. package/static/images/butterchurn-screenshots/Aderrasi - Songflower _Moss Posy_.png +0 -0
  189. package/static/images/butterchurn-screenshots/Aderrasi - Storm of the Eye _Thunder_ - mash0000 - quasi pseudo meta concentrics.png +0 -0
  190. package/static/images/butterchurn-screenshots/Aderrasi _ Geiss - Airhandler _Kali Mix_ - Canvas Mix.png +0 -0
  191. 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
  192. package/static/images/butterchurn-screenshots/Cope - The Neverending Explosion of Red Liquid Fire.png +0 -0
  193. proton lights __Krash_s beat code_ _Phat_remix02b.png +0 -0
  194. package/static/images/butterchurn-screenshots/Eo_S_ _ Phat - cubetrace - v2.png +0 -0
  195. package/static/images/butterchurn-screenshots/Eo_S_ _ Zylot - skylight _Stained Glass Majesty mix_.png +0 -0
  196. package/static/images/butterchurn-screenshots/Flexi - alien fish pond.png +0 -0
  197. package/static/images/butterchurn-screenshots/Flexi - area 51.png +0 -0
  198. package/static/images/butterchurn-screenshots/Flexi - infused with the spiral.png +0 -0
  199. package/static/images/butterchurn-screenshots/Flexi - mindblob _shiny mix_.png +0 -0
  200. package/static/images/butterchurn-screenshots/Flexi - mindblob mix.png +0 -0
  201. package/static/images/butterchurn-screenshots/Flexi - predator-prey-spirals.png +0 -0
  202. package/static/images/butterchurn-screenshots/Flexi - smashing fractals _acid etching mix_.png +0 -0
  203. package/static/images/butterchurn-screenshots/Flexi - truly soft piece of software - this is generic texturing _Jelly_ .png +0 -0
  204. package/static/images/butterchurn-screenshots/Flexi _ Martin - astral projection.png +0 -0
  205. package/static/images/butterchurn-screenshots/Flexi _ Martin - cascading decay swing.png +0 -0
  206. package/static/images/butterchurn-screenshots/Flexi _ amandio c - piercing 05 - Kopie _2_ - Kopie.png +0 -0
  207. package/static/images/butterchurn-screenshots/Flexi _ stahlregen - jelly showoff parade.png +0 -0
  208. package/static/images/butterchurn-screenshots/Flexi_ fishbrain_ Geiss _ Martin - tokamak witchery.png +0 -0
  209. package/static/images/butterchurn-screenshots/Flexi_ martin _ geiss - dedicated to the sherwin maxawow.png +0 -0
  210. package/static/images/butterchurn-screenshots/Fumbling_Foo _ Flexi_ Martin_ Orb_ Unchained - Star Nova v7b.png +0 -0
  211. package/static/images/butterchurn-screenshots/Geiss - Cauldron - painterly 2 _saturation remix_.png +0 -0
  212. package/static/images/butterchurn-screenshots/Geiss - Reaction Diffusion 2.png +0 -0
  213. package/static/images/butterchurn-screenshots/Geiss - Spiral Artifact.png +0 -0
  214. package/static/images/butterchurn-screenshots/Geiss - Thumb Drum.png +0 -0
  215. package/static/images/butterchurn-screenshots/Geiss _ Flexi _ Martin - disconnected.png +0 -0
  216. package/static/images/butterchurn-screenshots/Geiss_ Flexi _ Stahlregen - Thumbdrum Tokamak _crossfiring aftermath jelly mashup_.png +0 -0
  217. package/static/images/butterchurn-screenshots/Goody - The Wild Vort.png +0 -0
  218. package/static/images/butterchurn-screenshots/Idiot - Star Of Annon.png +0 -0
  219. package/static/images/butterchurn-screenshots/Krash _ Illusion - Spiral Movement.png +0 -0
  220. package/static/images/butterchurn-screenshots/Martin - QBikal - Surface Turbulence IIb.png +0 -0
  221. package/static/images/butterchurn-screenshots/Martin - acid wiring.png +0 -0
  222. package/static/images/butterchurn-screenshots/Martin - charisma.png +0 -0
  223. package/static/images/butterchurn-screenshots/Martin - liquid arrows.png +0 -0
  224. package/static/images/butterchurn-screenshots/Milk Artist At our Best - FED - SlowFast Ft AdamFX n Martin - HD CosmoFX.png +0 -0
  225. package/static/images/butterchurn-screenshots/ORB - Waaa.png +0 -0
  226. package/static/images/butterchurn-screenshots/Phat_fiShbRaiN_Eo_S_Mandala_Chasers_remix.png +0 -0
  227. package/static/images/butterchurn-screenshots/Rovastar - Oozing Resistance.png +0 -0
  228. package/static/images/butterchurn-screenshots/Rovastar _ Loadus _ Geiss - FractalDrop _Triple Mix_.png +0 -0
  229. package/static/images/butterchurn-screenshots/TonyMilkdrop - Leonardo Da Vinci_s Balloon _Flexi - merry-go-round _ techstyle_.png +0 -0
  230. package/static/images/butterchurn-screenshots/TonyMilkdrop - Magellan_s Nebula _Flexi - you enter first _ multiverse_.png +0 -0
  231. package/static/images/butterchurn-screenshots/Unchained - Rewop.png +0 -0
  232. package/static/images/butterchurn-screenshots/Unchained - Unified Drag 2.png +0 -0
  233. package/static/images/butterchurn-screenshots/Unchained _ Rovastar - Wormhole Pillars _Hall of Shadows mix_.png +0 -0
  234. package/static/images/butterchurn-screenshots/Zylot - Paint Spill _Music Reactive Paint Mix_.png +0 -0
  235. package/static/images/butterchurn-screenshots/Zylot - Star Ornament.png +0 -0
  236. package/static/images/butterchurn-screenshots/Zylot - True Visionary _Final Mix_.png +0 -0
  237. package/static/images/butterchurn-screenshots/_Aderrasi - Wanderer in Curved Space - mash0000 - faclempt kibitzing meshuggana schmaltz _Geiss color mix_.png +0 -0
  238. package/static/images/butterchurn-screenshots/_Geiss - Artifact 01.png +0 -0
  239. package/static/images/butterchurn-screenshots/_Geiss - Desert Rose 2.png +0 -0
  240. package/static/images/butterchurn-screenshots/_Geiss - untitled.png +0 -0
  241. package/static/images/butterchurn-screenshots/_Mig_049.png +0 -0
  242. package/static/images/butterchurn-screenshots/_Mig_085.png +0 -0
  243. package/static/images/butterchurn-screenshots/_Rovastar _ Geiss - Hurricane Nightmare _Posterize Mix_.png +0 -0
  244. package/static/images/butterchurn-screenshots/___ Royal - Mashup _197_.png +0 -0
  245. package/static/images/butterchurn-screenshots/___ Royal - Mashup _220_.png +0 -0
  246. package/static/images/butterchurn-screenshots/___ Royal - Mashup _431_.png +0 -0
  247. package/static/images/butterchurn-screenshots/cope _ martin - mother-of-pearl.png +0 -0
  248. package/static/images/butterchurn-screenshots/fiShbRaiN _ Flexi - witchcraft 2_0.png +0 -0
  249. package/static/images/butterchurn-screenshots/flexi - bouncing balls _double mindblob neon mix_.png +0 -0
  250. package/static/images/butterchurn-screenshots/flexi - mom_ why the sky looks different today.png +0 -0
  251. package/static/images/butterchurn-screenshots/flexi - patternton_ district of media_ capitol of the united abstractions of fractopia.png +0 -0
  252. package/static/images/butterchurn-screenshots/flexi - swing out on the spiral.png +0 -0
  253. package/static/images/butterchurn-screenshots/flexi - what is the matrix.png +0 -0
  254. package/static/images/butterchurn-screenshots/flexi _ amandio c - organic _random mashup_.png +0 -0
  255. package/static/images/butterchurn-screenshots/flexi _ amandio c - organic12-3d-2_milk.png +0 -0
  256. package/static/images/butterchurn-screenshots/flexi _ fishbrain - neon mindblob grafitti.png +0 -0
  257. package/static/images/butterchurn-screenshots/flexi _ geiss - pogo cubes vs_ tokamak vs_ game of life _stahls jelly 4_5 finish_.png +0 -0
  258. package/static/images/butterchurn-screenshots/high-altitude basket unraveling - singh grooves nitrogen argon nz_.png +0 -0
  259. package/static/images/butterchurn-screenshots/martin - The Bridge of Khazad-Dum.png +0 -0
  260. package/static/images/butterchurn-screenshots/martin - angel flight.png +0 -0
  261. package/static/images/butterchurn-screenshots/martin - another kind of groove.png +0 -0
  262. package/static/images/butterchurn-screenshots/martin - bombyx mori.png +0 -0
  263. package/static/images/butterchurn-screenshots/martin - castle in the air.png +0 -0
  264. package/static/images/butterchurn-screenshots/martin - chain breaker.png +0 -0
  265. package/static/images/butterchurn-screenshots/martin - disco mix 4.png +0 -0
  266. package/static/images/butterchurn-screenshots/martin - extreme heat.png +0 -0
  267. package/static/images/butterchurn-screenshots/martin - frosty caves 2.png +0 -0
  268. package/static/images/butterchurn-screenshots/martin - fruit machine.png +0 -0
  269. package/static/images/butterchurn-screenshots/martin - ghost city.png +0 -0
  270. package/static/images/butterchurn-screenshots/martin - glass corridor.png +0 -0
  271. package/static/images/butterchurn-screenshots/martin - infinity _2010 update_.png +0 -0
  272. package/static/images/butterchurn-screenshots/martin - mandelbox explorer - high speed demo version.png +0 -0
  273. package/static/images/butterchurn-screenshots/martin - mucus cervix.png +0 -0
  274. package/static/images/butterchurn-screenshots/martin - reflections on black tiles.png +0 -0
  275. package/static/images/butterchurn-screenshots/martin - stormy sea _2010 update_.png +0 -0
  276. package/static/images/butterchurn-screenshots/martin - witchcraft reloaded.png +0 -0
  277. package/static/images/butterchurn-screenshots/martin _ flexi - diamond cutter _prismaticvortex_com_ - camille - i wish i wish i wish i was constrained.png +0 -0
  278. package/static/images/butterchurn-screenshots/martin _shadow harlequins shape code_ - fata morgana.png +0 -0
  279. package/static/images/butterchurn-screenshots/martin_ flexi_ fishbrain _ sto - enterstate _random mashup_.png +0 -0
  280. package/static/images/butterchurn-screenshots/sawtooth grin roam.png +0 -0
  281. package/static/images/butterchurn-screenshots/shifter - dark tides bdrv mix 2.png +0 -0
  282. 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
  283. package/static/images/butterchurn-screenshots/suksma - heretical crosscut playpen.png +0 -0
  284. package/static/images/butterchurn-screenshots/suksma - uninitialized variabowl _hydroponic chronic_.png +0 -0
  285. package/static/images/butterchurn-screenshots/suksma - vector exp 1 - couldn_t not.png +0 -0
  286. package/static/images/butterchurn-screenshots/yin - 191 - Temporal singularities.png +0 -0
  287. package/static/images/logo-512.png +0 -0
  288. package/static/images/logo.png +0 -0
  289. package/static/loukai-logo.png +0 -0
  290. 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
+ }