From a810621762ba58adea3ed01d2d0fdc09ef971a96 Mon Sep 17 00:00:00 2001 From: JellyBrick Date: Sat, 21 Oct 2023 10:45:21 +0900 Subject: [PATCH] feat: http api --- src/config/defaults.ts | 1 + src/index.ts | 2 + src/plugins/http-api/back.ts | 112 +++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 src/plugins/http-api/back.ts diff --git a/src/config/defaults.ts b/src/config/defaults.ts index 6b49c36a..6818b9c4 100644 --- a/src/config/defaults.ts +++ b/src/config/defaults.ts @@ -128,6 +128,7 @@ const defaultConfig = { skipExisting: false, playlistMaxItems: undefined as number | undefined, }, + 'http-api': {}, 'exponential-volume': {}, 'in-app-menu': { /** diff --git a/src/index.ts b/src/index.ts index f5eaaaed..cf59b34d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,6 +24,7 @@ import captionsSelector from './plugins/captions-selector/back'; import crossfade from './plugins/crossfade/back'; import discord from './plugins/discord/back'; import downloader from './plugins/downloader/back'; +import httpApi from './plugins/http-api/back'; import inAppMenu from './plugins/in-app-menu/back'; import lastFm from './plugins/last-fm/back'; import lumiaStream from './plugins/lumiastream/back'; @@ -109,6 +110,7 @@ const mainPlugins = { 'crossfade': crossfade, 'discord': discord, 'downloader': downloader, + 'http-api': httpApi, 'in-app-menu': inAppMenu, 'last-fm': lastFm, 'lumiastream': lumiaStream, diff --git a/src/plugins/http-api/back.ts b/src/plugins/http-api/back.ts new file mode 100644 index 00000000..d6143b28 --- /dev/null +++ b/src/plugins/http-api/back.ts @@ -0,0 +1,112 @@ +import http from 'node:http'; + +import { BrowserWindow, ipcMain } from 'electron'; +import is from 'electron-is'; + +import registerCallback, { SongInfo } from '../../providers/song-info'; +import getSongControls from '../../providers/song-controls'; +import { isEnabled } from '../../config/plugins'; + +const port = 9669; // Choose a port number + +export default (win: BrowserWindow) => { + let songInfo: (SongInfo & { loopStatus?: string, volume?: number }) | undefined; + + if (!is.linux() || (is.linux() && !isEnabled('shortcuts'))) { + ipcMain.on('apiLoaded', () => { + win.webContents.send('setupSeekedListener', 'webinterface'); + win.webContents.send('setupTimeChangedListener', 'webinterface'); + win.webContents.send('setupRepeatChangedListener', 'webinterface'); + win.webContents.send('setupVolumeChangedListener', 'webinterface'); + }); + } + + // updations + ipcMain.on('seeked', (_, t: number) => { + if (songInfo) { + songInfo.elapsedSeconds = t; + } + }); + + ipcMain.on('timeChanged', (_, t: number) => { + if (songInfo) { + songInfo.elapsedSeconds = t; + } + }); + + ipcMain.on('repeatChanged', (_, mode: string) => { + if (songInfo) { + songInfo.loopStatus = mode; + } + }); + + ipcMain.on('volumeChanged', (_, newVolume: number) => { + if(songInfo) { + songInfo.volume = newVolume; + } + }); + + registerCallback((info) => songInfo = info as SongInfo & { loopStatus?: string, volume?: number }); + + const doAction = (action: URLSearchParams) => { + //actions + const songControls = getSongControls(win); + const { playPause, next, previous, volumeMinus10, volumePlus10, shuffle } = songControls; + switch (action.get('action')) { + case 'play': + case 'pause': + case 'playpause': + if (songInfo) { + songInfo.isPaused = !songInfo.isPaused; + } + playPause(); + break; + case 'next': + next(); + break; + case 'previous': + previous(); + break; + case 'shuffle': + shuffle(); + break; + case 'looptoggle': + songControls.switchRepeat(1); + break; + case 'volumeplus10': + volumePlus10(); + break; + case 'volumeminus10': + volumeMinus10(); + break; + case 'seek': + console.log('seek', action.get('value')); + win.webContents.send('seekBy', action.get('value')); + break; + default: + throw Error(`web-interface: Requested action "${action.get('action')}" not found`); + } + }; + + const server = http.createServer((req,res) => { + if (req?.url?.slice(0,4) === '/api') { + const url = new URL(req.url, `http://${req.headers.host}`); + if (url.searchParams.has('action')) { + console.log('webinterface: received and trying action ' + url.searchParams.get('action')); + try { + doAction(url.searchParams); + } catch (e) { + res.statusCode = 404; + res.write(e); + return; + } + } + res.setHeader('Content-Type','application/json'); + res.write(JSON.stringify(songInfo)); + } + res.end(); + }); + server.listen(port, () => { + console.log(`web-interface API Server is running on port ${port}`); + }); +};