index.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. import { contextBridge, ipcRenderer } from 'electron'
  2. import { IpcChannels } from '../shared/ipc-channels'
  3. import type {
  4. WorkshopQueryParams,
  5. WorkshopQueryResult,
  6. WorkshopItem,
  7. CreatorWorkshopQueryParams,
  8. WallpaperMeta,
  9. WallpaperFolder,
  10. LibraryFilters,
  11. WorkshopAuthorInfo,
  12. ApplyWallpaperOptions,
  13. DownloadProgressEvent,
  14. WallpaperEnvironment,
  15. LweStatus,
  16. LweInstallProgress,
  17. LinuxDistro,
  18. LweSceneObject,
  19. LweProperty,
  20. LweAudioObject,
  21. LweSceneEffect,
  22. BackupProgressEvent,
  23. Playlist,
  24. PlaylistSettings,
  25. PlaylistPlaybackState,
  26. SteamIdentity,
  27. EngineFlags,
  28. EngineFlagPreset,
  29. DisplayMode,
  30. ScreenTarget,
  31. ScreenAssignment,
  32. ScheduleRule,
  33. CrashEvent
  34. } from '../shared/types'
  35. const api = {
  36. workshop: {
  37. query: (params: WorkshopQueryParams): Promise<WorkshopQueryResult> =>
  38. ipcRenderer.invoke(IpcChannels.WORKSHOP_QUERY, params),
  39. getItem: (publishedFileId: string): Promise<WorkshopItem | null> =>
  40. ipcRenderer.invoke(IpcChannels.WORKSHOP_GET_ITEM, publishedFileId),
  41. queryByCreator: (
  42. creatorSteamId: string,
  43. params?: CreatorWorkshopQueryParams
  44. ): Promise<WorkshopQueryResult> =>
  45. ipcRenderer.invoke(IpcChannels.WORKSHOP_QUERY_BY_CREATOR, creatorSteamId, params)
  46. },
  47. steam: {
  48. isRunning: (): Promise<boolean> => ipcRenderer.invoke(IpcChannels.STEAM_IS_RUNNING),
  49. subscribe: (itemId: string): Promise<{ ok: boolean }> =>
  50. ipcRenderer.invoke(IpcChannels.STEAM_SUBSCRIBE, itemId),
  51. unsubscribe: (itemId: string): Promise<{ ok: boolean }> =>
  52. ipcRenderer.invoke(IpcChannels.STEAM_UNSUBSCRIBE, itemId),
  53. redownload: (itemId: string): Promise<{ ok: boolean }> =>
  54. ipcRenderer.invoke(IpcChannels.STEAM_REDOWNLOAD, itemId),
  55. getSubscribedItems: (): Promise<string[]> =>
  56. ipcRenderer.invoke(IpcChannels.STEAM_GET_SUBSCRIBED),
  57. downloadInfo: (itemId: string): Promise<DownloadProgressEvent | null> =>
  58. ipcRenderer.invoke(IpcChannels.STEAM_DOWNLOAD_INFO, itemId),
  59. itemState: (itemId: string): Promise<number> =>
  60. ipcRenderer.invoke(IpcChannels.STEAM_ITEM_STATE, itemId),
  61. vote: (itemId: string, voteUp: boolean): Promise<{ ok: boolean; confirmed: boolean }> =>
  62. ipcRenderer.invoke(IpcChannels.STEAM_VOTE, itemId, voteUp),
  63. openWorkshopItem: (itemId: string): Promise<{ ok: boolean }> =>
  64. ipcRenderer.invoke(IpcChannels.STEAM_OPEN_WORKSHOP, itemId),
  65. getVotedIds: (): Promise<string[]> =>
  66. ipcRenderer.invoke(IpcChannels.STEAM_GET_VOTED_IDS),
  67. checkVote: (itemId: string): Promise<boolean | null> =>
  68. ipcRenderer.invoke(IpcChannels.STEAM_CHECK_VOTE, itemId),
  69. getAuthorInfo: (steamId: string): Promise<WorkshopAuthorInfo | null> =>
  70. ipcRenderer.invoke(IpcChannels.STEAM_GET_AUTHOR_INFO, steamId)
  71. },
  72. library: {
  73. getAll: (filters?: LibraryFilters): Promise<WallpaperMeta[]> =>
  74. ipcRenderer.invoke(IpcChannels.LIBRARY_GET_ALL, filters),
  75. getOne: (id: string): Promise<WallpaperMeta | null> =>
  76. ipcRenderer.invoke(IpcChannels.LIBRARY_GET_ONE, id),
  77. update: (id: string, patch: Partial<WallpaperMeta>): Promise<WallpaperMeta | null> =>
  78. ipcRenderer.invoke(IpcChannels.LIBRARY_UPDATE, id, patch),
  79. delete: (id: string): Promise<{ ok: boolean }> =>
  80. ipcRenderer.invoke(IpcChannels.LIBRARY_DELETE, id),
  81. addTag: (id: string, tag: string): Promise<WallpaperMeta | null> =>
  82. ipcRenderer.invoke(IpcChannels.LIBRARY_ADD_TAG, id, tag),
  83. removeTag: (id: string, tag: string): Promise<WallpaperMeta | null> =>
  84. ipcRenderer.invoke(IpcChannels.LIBRARY_REMOVE_TAG, id, tag),
  85. getTags: (): Promise<string[]> => ipcRenderer.invoke(IpcChannels.LIBRARY_GET_TAGS),
  86. search: (query: string): Promise<WallpaperMeta[]> =>
  87. ipcRenderer.invoke(IpcChannels.LIBRARY_SEARCH, query),
  88. scan: (): Promise<{ imported: number; skipped: number; removed: number }> =>
  89. ipcRenderer.invoke(IpcChannels.LIBRARY_SCAN),
  90. distinctTags: (): Promise<string[]> =>
  91. ipcRenderer.invoke(IpcChannels.LIBRARY_DISTINCT_TAGS),
  92. resetFpsOverrides: (): Promise<{ count: number }> =>
  93. ipcRenderer.invoke(IpcChannels.LIBRARY_RESET_FPS_OVERRIDES),
  94. checkUnavailable: (): Promise<{ checked: number; unavailable: number; changed: boolean }> =>
  95. ipcRenderer.invoke(IpcChannels.LIBRARY_CHECK_UNAVAILABLE)
  96. },
  97. config: {
  98. get: (): Promise<{
  99. workshopPath: string | null
  100. defaultWorkshopPath: string
  101. isConfigured: boolean
  102. defaultFps: number | null
  103. recommendedFpsEnabled: boolean
  104. recommendedWebFpsEnabled: boolean
  105. lweRepoUrl: string | null
  106. lweRepoBranch: string | null
  107. lweCmakeArgs: string | null
  108. defaultLweRepoUrl: string
  109. backupPath: string | null
  110. isBackupConfigured: boolean
  111. autoUnsubscribeAfterBackup: boolean
  112. trayEnabled: boolean
  113. autostartSupported: boolean
  114. autostartEnabled: boolean
  115. autostartMinimized: boolean
  116. autostartPlaylistId: string | null
  117. killLweOnQuit: boolean
  118. audioScreen: string | null
  119. ambientVolume: number | null
  120. defaultAudioSensitivity: number
  121. disablePuppetAnimation: boolean
  122. disableAnimations: boolean
  123. steamIdentity: SteamIdentity
  124. ignoredCreators: string[]
  125. engineFlags: EngineFlags
  126. engineFlagPresets: EngineFlagPreset[]
  127. displayMode: DisplayMode
  128. }> => ipcRenderer.invoke(IpcChannels.CONFIG_GET),
  129. setEngineFlags: (flags: EngineFlags): Promise<{ ok: boolean }> =>
  130. ipcRenderer.invoke(IpcChannels.CONFIG_SET_ENGINE_FLAGS, flags),
  131. setEnginePresets: (presets: EngineFlagPreset[]): Promise<{ ok: boolean }> =>
  132. ipcRenderer.invoke(IpcChannels.CONFIG_SET_ENGINE_PRESETS, presets),
  133. setDisplayMode: (mode: DisplayMode): Promise<{ ok: boolean }> =>
  134. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DISPLAY_MODE, mode),
  135. setWorkshopPath: (p: string): Promise<{ ok: boolean }> =>
  136. ipcRenderer.invoke(IpcChannels.CONFIG_SET_WORKSHOP_PATH, p),
  137. setDefaultFps: (fps: number | null): Promise<{ ok: boolean }> =>
  138. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DEFAULT_FPS, fps),
  139. setRecommendedFpsEnabled: (enabled: boolean): Promise<{ ok: boolean }> =>
  140. ipcRenderer.invoke(IpcChannels.CONFIG_SET_RECOMMENDED_FPS, enabled),
  141. setRecommendedWebFpsEnabled: (enabled: boolean): Promise<{ ok: boolean }> =>
  142. ipcRenderer.invoke(IpcChannels.CONFIG_SET_RECOMMENDED_WEB_FPS, enabled),
  143. setLweRepo: (url: string | null, branch: string | null): Promise<{ ok: boolean }> =>
  144. ipcRenderer.invoke(IpcChannels.CONFIG_SET_LWE_REPO, url, branch),
  145. setLweCmakeArgs: (args: string | null): Promise<{ ok: boolean }> =>
  146. ipcRenderer.invoke(IpcChannels.CONFIG_SET_LWE_CMAKE_ARGS, args),
  147. setBackupPath: (p: string): Promise<{ ok: boolean }> =>
  148. ipcRenderer.invoke(IpcChannels.CONFIG_SET_BACKUP_PATH, p),
  149. setAutoUnsubscribeAfterBackup: (enabled: boolean): Promise<{ ok: boolean }> =>
  150. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUTO_UNSUBSCRIBE, enabled),
  151. pickFolder: (): Promise<string | null> =>
  152. ipcRenderer.invoke(IpcChannels.CONFIG_PICK_FOLDER),
  153. pickFile: (): Promise<string | null> =>
  154. ipcRenderer.invoke(IpcChannels.CONFIG_PICK_FILE),
  155. importWE: (sourcePath: string): Promise<{ folders: number; playlists: number; configPath: string }> =>
  156. ipcRenderer.invoke(IpcChannels.CONFIG_IMPORT_WE, sourcePath),
  157. createFresh: (): Promise<{ configPath: string }> =>
  158. ipcRenderer.invoke(IpcChannels.CONFIG_CREATE_FRESH),
  159. setTrayEnabled: (enabled: boolean): Promise<{ ok: boolean }> =>
  160. ipcRenderer.invoke(IpcChannels.CONFIG_SET_TRAY_ENABLED, enabled),
  161. setKillLweOnQuit: (enabled: boolean): Promise<{ ok: boolean }> =>
  162. ipcRenderer.invoke(IpcChannels.CONFIG_SET_KILL_LWE_ON_QUIT, enabled),
  163. setAutostart: (
  164. enabled: boolean,
  165. minimized: boolean,
  166. playlistId: string | null
  167. ): Promise<{ ok: boolean }> =>
  168. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUTOSTART, enabled, minimized, playlistId),
  169. getAutostartSupported: (): Promise<boolean> =>
  170. ipcRenderer.invoke(IpcChannels.CONFIG_GET_AUTOSTART_SUPPORTED),
  171. setAudioScreen: (screen: string | null): Promise<{ ok: boolean }> =>
  172. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUDIO_SCREEN, screen),
  173. setAmbientVolume: (volume: number | null): Promise<{ ok: boolean }> =>
  174. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AMBIENT_VOLUME, volume),
  175. setDefaultAudioSensitivity: (multiplier: number): Promise<{ ok: boolean }> =>
  176. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DEFAULT_AUDIO_SENSITIVITY, multiplier),
  177. setDisablePuppetAnimation: (disabled: boolean): Promise<{ ok: boolean }> =>
  178. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DISABLE_PUPPET_ANIMATION, disabled),
  179. setSteamIdentity: (identity: SteamIdentity): Promise<{ ok: boolean }> =>
  180. ipcRenderer.invoke(IpcChannels.CONFIG_SET_STEAM_IDENTITY, identity),
  181. ignoreCreator: (steamId: string): Promise<{ ok: boolean }> =>
  182. ipcRenderer.invoke(IpcChannels.CONFIG_IGNORE_CREATOR, steamId),
  183. unignoreCreator: (steamId: string): Promise<{ ok: boolean }> =>
  184. ipcRenderer.invoke(IpcChannels.CONFIG_UNIGNORE_CREATOR, steamId)
  185. },
  186. playlist: {
  187. getAll: (): Promise<Playlist[]> => ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_ALL),
  188. getOne: (id: string): Promise<Playlist | null> =>
  189. ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_ONE, id),
  190. create: (title: string): Promise<Playlist> =>
  191. ipcRenderer.invoke(IpcChannels.PLAYLIST_CREATE, title),
  192. rename: (id: string, title: string): Promise<Playlist | null> =>
  193. ipcRenderer.invoke(IpcChannels.PLAYLIST_RENAME, id, title),
  194. delete: (id: string): Promise<{ ok: boolean }> =>
  195. ipcRenderer.invoke(IpcChannels.PLAYLIST_DELETE, id),
  196. updateSettings: (id: string, patch: Partial<PlaylistSettings>): Promise<Playlist | null> =>
  197. ipcRenderer.invoke(IpcChannels.PLAYLIST_UPDATE_SETTINGS, id, patch),
  198. addItems: (id: string, wallpaperIds: string[]): Promise<Playlist | null> =>
  199. ipcRenderer.invoke(IpcChannels.PLAYLIST_ADD_ITEMS, id, wallpaperIds),
  200. removeItems: (id: string, wallpaperIds: string[]): Promise<Playlist | null> =>
  201. ipcRenderer.invoke(IpcChannels.PLAYLIST_REMOVE_ITEMS, id, wallpaperIds),
  202. reorderItems: (id: string, orderedWallpaperIds: string[]): Promise<Playlist | null> =>
  203. ipcRenderer.invoke(IpcChannels.PLAYLIST_REORDER_ITEMS, id, orderedWallpaperIds),
  204. updateItem: (
  205. id: string,
  206. wallpaperId: string,
  207. patch: { volume?: number; durationSec?: number }
  208. ): Promise<Playlist | null> =>
  209. ipcRenderer.invoke(IpcChannels.PLAYLIST_UPDATE_ITEM, id, wallpaperId, patch),
  210. start: (id: string, screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  211. ipcRenderer.invoke(IpcChannels.PLAYLIST_START, id, screen),
  212. playItem: (id: string, wallpaperId: string, screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  213. ipcRenderer.invoke(IpcChannels.PLAYLIST_PLAY_ITEM, id, wallpaperId, screen),
  214. stop: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  215. ipcRenderer.invoke(IpcChannels.PLAYLIST_STOP, screen),
  216. pause: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  217. ipcRenderer.invoke(IpcChannels.PLAYLIST_PAUSE, screen),
  218. resume: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  219. ipcRenderer.invoke(IpcChannels.PLAYLIST_RESUME, screen),
  220. next: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  221. ipcRenderer.invoke(IpcChannels.PLAYLIST_NEXT, screen),
  222. previous: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  223. ipcRenderer.invoke(IpcChannels.PLAYLIST_PREVIOUS, screen),
  224. getState: (): Promise<PlaylistPlaybackState[]> =>
  225. ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_STATE)
  226. },
  227. folders: {
  228. getAll: (): Promise<WallpaperFolder[]> =>
  229. ipcRenderer.invoke(IpcChannels.FOLDERS_GET_ALL),
  230. create: (title: string): Promise<WallpaperFolder> =>
  231. ipcRenderer.invoke(IpcChannels.FOLDERS_CREATE, title),
  232. rename: (id: string, title: string): Promise<WallpaperFolder | null> =>
  233. ipcRenderer.invoke(IpcChannels.FOLDERS_RENAME, id, title),
  234. delete: (id: string): Promise<{ ok: boolean }> =>
  235. ipcRenderer.invoke(IpcChannels.FOLDERS_DELETE, id),
  236. addItems: (folderId: string, itemIds: string[]): Promise<WallpaperFolder | null> =>
  237. ipcRenderer.invoke(IpcChannels.FOLDERS_ADD_ITEMS, folderId, itemIds),
  238. removeItems: (folderId: string, itemIds: string[]): Promise<WallpaperFolder | null> =>
  239. ipcRenderer.invoke(IpcChannels.FOLDERS_REMOVE_ITEMS, folderId, itemIds),
  240. importWEConfig: (configPath: string): Promise<{ folders: number; playlists: number }> =>
  241. ipcRenderer.invoke(IpcChannels.FOLDERS_IMPORT_WE_CONFIG, configPath),
  242. cleanup: (): Promise<{ removed: number }> =>
  243. ipcRenderer.invoke(IpcChannels.FOLDERS_CLEANUP)
  244. },
  245. wallpaper: {
  246. apply: (options: ApplyWallpaperOptions): Promise<{ ok: boolean; appliedPath: string }> =>
  247. ipcRenderer.invoke(IpcChannels.WALLPAPER_APPLY, options),
  248. getActive: (): Promise<WallpaperMeta | null> =>
  249. ipcRenderer.invoke(IpcChannels.WALLPAPER_GET_ACTIVE),
  250. getAssignments: (): Promise<ScreenAssignment[]> =>
  251. ipcRenderer.invoke(IpcChannels.WALLPAPER_GET_ASSIGNMENTS),
  252. getTargets: (): Promise<ScreenTarget[]> =>
  253. ipcRenderer.invoke(IpcChannels.WALLPAPER_GET_TARGETS),
  254. stop: (screen?: ScreenTarget): Promise<{ ok: boolean }> =>
  255. ipcRenderer.invoke(IpcChannels.WALLPAPER_STOP, screen),
  256. testLaunch: (wallpaperId: string, screen?: ScreenTarget): Promise<{ ok: boolean }> =>
  257. ipcRenderer.invoke(IpcChannels.WALLPAPER_TEST_LAUNCH, wallpaperId, screen),
  258. generateThumbnail: (wallpaperId: string): Promise<WallpaperMeta> =>
  259. ipcRenderer.invoke(IpcChannels.WALLPAPER_GENERATE_THUMBNAIL, wallpaperId),
  260. pickThumbnail: (wallpaperId: string): Promise<WallpaperMeta | null> =>
  261. ipcRenderer.invoke(IpcChannels.WALLPAPER_PICK_THUMBNAIL, wallpaperId),
  262. deleteThumbnail: (wallpaperId: string): Promise<WallpaperMeta> =>
  263. ipcRenderer.invoke(IpcChannels.WALLPAPER_DELETE_THUMBNAIL, wallpaperId),
  264. detectEnvironment: (): Promise<WallpaperEnvironment> =>
  265. ipcRenderer.invoke(IpcChannels.WALLPAPER_DETECT_ENV)
  266. },
  267. lwe: {
  268. status: (): Promise<LweStatus> =>
  269. ipcRenderer.invoke(IpcChannels.LWE_STATUS),
  270. detectDistro: (): Promise<LinuxDistro> =>
  271. ipcRenderer.invoke(IpcChannels.LWE_DETECT_DISTRO),
  272. installDeps: (): Promise<{ ok: boolean }> =>
  273. ipcRenderer.invoke(IpcChannels.LWE_INSTALL_DEPS),
  274. install: (): Promise<LweStatus> =>
  275. ipcRenderer.invoke(IpcChannels.LWE_INSTALL),
  276. uninstall: (): Promise<{ ok: boolean; message: string }> =>
  277. ipcRenderer.invoke(IpcChannels.LWE_UNINSTALL),
  278. launch: (wallpaperPath: string, options?: { screen?: ScreenTarget; fps?: number }): Promise<{ ok: boolean; running: boolean }> =>
  279. ipcRenderer.invoke(IpcChannels.LWE_LAUNCH, wallpaperPath, options),
  280. stop: (): Promise<{ ok: boolean }> =>
  281. ipcRenderer.invoke(IpcChannels.LWE_STOP),
  282. killAll: (): Promise<{ ok: boolean; message: string }> =>
  283. ipcRenderer.invoke(IpcChannels.LWE_KILL_ALL),
  284. listObjects: (wallpaperPath: string): Promise<LweSceneObject[]> =>
  285. ipcRenderer.invoke(IpcChannels.LWE_LIST_OBJECTS, wallpaperPath),
  286. hotswapSettings: (options: {
  287. disabledObjects?: string[]
  288. enabledObjects?: string[]
  289. volume?: number
  290. xray?: boolean
  291. scaling?: string
  292. zoom?: number
  293. offsetX?: number
  294. offsetY?: number
  295. disableParallax?: boolean
  296. expandCanvas?: boolean
  297. cornerColor?: string
  298. speed?: number
  299. propertyOverrides?: Record<string, string>
  300. audioScreen?: string
  301. ambientVolume?: number
  302. audioSensitivity?: Record<string, number>
  303. soundVolume?: Record<string, number>
  304. }, wallpaperPath?: string): Promise<{ ok: boolean }> =>
  305. ipcRenderer.invoke(IpcChannels.LWE_HOTSWAP_SETTINGS, options, wallpaperPath),
  306. listProperties: (wallpaperPath: string): Promise<LweProperty[]> =>
  307. ipcRenderer.invoke(IpcChannels.LWE_LIST_PROPERTIES, wallpaperPath),
  308. listScreens: (): Promise<string[]> =>
  309. ipcRenderer.invoke(IpcChannels.LWE_LIST_SCREENS),
  310. listAudioObjects: (wallpaperPath: string): Promise<LweAudioObject[]> =>
  311. ipcRenderer.invoke(IpcChannels.LWE_LIST_AUDIO_OBJECTS, wallpaperPath),
  312. listEffects: (wallpaperPath: string): Promise<LweSceneEffect[]> =>
  313. ipcRenderer.invoke(IpcChannels.LWE_LIST_EFFECTS, wallpaperPath)
  314. },
  315. schedule: {
  316. getAll: (): Promise<ScheduleRule[]> => ipcRenderer.invoke(IpcChannels.SCHEDULE_GET_ALL),
  317. save: (rule: Omit<ScheduleRule, 'id'> & { id?: string }): Promise<ScheduleRule> =>
  318. ipcRenderer.invoke(IpcChannels.SCHEDULE_SAVE, rule),
  319. delete: (id: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.SCHEDULE_DELETE, id),
  320. run: (id: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.SCHEDULE_RUN, id)
  321. },
  322. backup: {
  323. item: (itemId: string): Promise<{ ok: boolean; unsubscribed: boolean }> =>
  324. ipcRenderer.invoke(IpcChannels.BACKUP_ITEM, itemId),
  325. selection: (itemIds: string[]): Promise<{ backedUp: number; failed: number; unsubscribed: number }> =>
  326. ipcRenderer.invoke(IpcChannels.BACKUP_SELECTION, itemIds),
  327. scan: (): Promise<{ imported: number; skipped: number; linked: number }> =>
  328. ipcRenderer.invoke(IpcChannels.BACKUP_SCAN)
  329. },
  330. desktopIcons: {
  331. setEnabled: (enabled: boolean): Promise<{ ok: boolean; enabled: boolean }> =>
  332. ipcRenderer.invoke(IpcChannels.DESKTOP_ICONS_SET_ENABLED, enabled),
  333. getEnabled: (): Promise<boolean> =>
  334. ipcRenderer.invoke(IpcChannels.DESKTOP_ICONS_GET_ENABLED)
  335. },
  336. shell: {
  337. openInFileManager: (folderPath: string): Promise<{ ok: boolean; error?: string }> =>
  338. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_IN_FILE_MANAGER, folderPath),
  339. openWithDefault: (filePath: string): Promise<{ ok: boolean; error?: string }> =>
  340. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_WITH_DEFAULT, filePath),
  341. openPath: (targetPath: string): Promise<{ ok: boolean; error?: string }> =>
  342. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_PATH, targetPath),
  343. openPaths: (targetPaths: string[]): Promise<{ ok: boolean; error?: string }> =>
  344. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_PATHS, targetPaths),
  345. openExternal: (url: string): Promise<{ ok: boolean; error?: string }> =>
  346. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_EXTERNAL, url)
  347. },
  348. on: {
  349. downloadProgress: (cb: (info: DownloadProgressEvent) => void): (() => void) => {
  350. const listener = (_: Electron.IpcRendererEvent, info: DownloadProgressEvent) => cb(info)
  351. ipcRenderer.on(IpcChannels.EVENT_DOWNLOAD_PROGRESS, listener)
  352. return () => ipcRenderer.off(IpcChannels.EVENT_DOWNLOAD_PROGRESS, listener)
  353. },
  354. wallpaperImported: (cb: (meta: WallpaperMeta) => void): (() => void) => {
  355. const listener = (_: Electron.IpcRendererEvent, meta: WallpaperMeta) => cb(meta)
  356. ipcRenderer.on(IpcChannels.EVENT_WALLPAPER_IMPORTED, listener)
  357. return () => ipcRenderer.off(IpcChannels.EVENT_WALLPAPER_IMPORTED, listener)
  358. },
  359. steamStatus: (cb: (running: boolean) => void): (() => void) => {
  360. const listener = (_: Electron.IpcRendererEvent, running: boolean) => cb(running)
  361. ipcRenderer.on(IpcChannels.EVENT_STEAM_STATUS, listener)
  362. return () => ipcRenderer.off(IpcChannels.EVENT_STEAM_STATUS, listener)
  363. },
  364. lweInstallProgress: (cb: (progress: LweInstallProgress) => void): (() => void) => {
  365. const listener = (_: Electron.IpcRendererEvent, progress: LweInstallProgress) => cb(progress)
  366. ipcRenderer.on(IpcChannels.EVENT_LWE_INSTALL_PROGRESS, listener)
  367. return () => ipcRenderer.off(IpcChannels.EVENT_LWE_INSTALL_PROGRESS, listener)
  368. },
  369. backupProgress: (cb: (progress: BackupProgressEvent) => void): (() => void) => {
  370. const listener = (_: Electron.IpcRendererEvent, progress: BackupProgressEvent) => cb(progress)
  371. ipcRenderer.on(IpcChannels.EVENT_BACKUP_PROGRESS, listener)
  372. return () => ipcRenderer.off(IpcChannels.EVENT_BACKUP_PROGRESS, listener)
  373. },
  374. playlistStateChanged: (cb: (states: PlaylistPlaybackState[]) => void): (() => void) => {
  375. const listener = (_: Electron.IpcRendererEvent, states: PlaylistPlaybackState[]) => cb(states)
  376. ipcRenderer.on(IpcChannels.EVENT_PLAYLIST_STATE_CHANGED, listener)
  377. return () => ipcRenderer.off(IpcChannels.EVENT_PLAYLIST_STATE_CHANGED, listener)
  378. },
  379. votedIdsChanged: (cb: (ids: string[]) => void): (() => void) => {
  380. const listener = (_: Electron.IpcRendererEvent, ids: string[]) => cb(ids)
  381. ipcRenderer.on(IpcChannels.EVENT_VOTED_IDS_CHANGED, listener)
  382. return () => ipcRenderer.off(IpcChannels.EVENT_VOTED_IDS_CHANGED, listener)
  383. },
  384. libraryChanged: (cb: () => void): (() => void) => {
  385. const listener = () => cb()
  386. ipcRenderer.on(IpcChannels.EVENT_LIBRARY_CHANGED, listener)
  387. return () => ipcRenderer.off(IpcChannels.EVENT_LIBRARY_CHANGED, listener)
  388. },
  389. displayChanged: (cb: () => void): (() => void) => {
  390. const listener = () => cb()
  391. ipcRenderer.on(IpcChannels.EVENT_DISPLAY_CHANGED, listener)
  392. return () => ipcRenderer.off(IpcChannels.EVENT_DISPLAY_CHANGED, listener)
  393. },
  394. wallpaperCrashed: (cb: (event: CrashEvent) => void): (() => void) => {
  395. const listener = (_: Electron.IpcRendererEvent, event: CrashEvent) => cb(event)
  396. ipcRenderer.on(IpcChannels.EVENT_WALLPAPER_CRASHED, listener)
  397. return () => ipcRenderer.off(IpcChannels.EVENT_WALLPAPER_CRASHED, listener)
  398. },
  399. scheduleFired: (cb: (ruleName: string) => void): (() => void) => {
  400. const listener = (_: Electron.IpcRendererEvent, ruleName: string) => cb(ruleName)
  401. ipcRenderer.on(IpcChannels.EVENT_SCHEDULE_FIRED, listener)
  402. return () => ipcRenderer.off(IpcChannels.EVENT_SCHEDULE_FIRED, listener)
  403. }
  404. }
  405. }
  406. contextBridge.exposeInMainWorld('electronAPI', api)
  407. export type ElectronAPI = typeof api