mirror of
https://github.com/streamwall/streamwall.git
synced 2025-12-06 01:45:37 -05:00
Persist wall assignments across restarts
This commit is contained in:
1
package-lock.json
generated
1
package-lock.json
generated
@@ -14348,6 +14348,7 @@
|
|||||||
"esbuild-register": "^3.6.0",
|
"esbuild-register": "^3.6.0",
|
||||||
"hls.js": "^1.5.18",
|
"hls.js": "^1.5.18",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lowdb": "^7.0.1",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"react-hotkeys-hook": "^4.6.1",
|
"react-hotkeys-hook": "^4.6.1",
|
||||||
"react-icons": "^5.4.0",
|
"react-icons": "^5.4.0",
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
"esbuild-register": "^3.6.0",
|
"esbuild-register": "^3.6.0",
|
||||||
"hls.js": "^1.5.18",
|
"hls.js": "^1.5.18",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lowdb": "^7.0.1",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"react-hotkeys-hook": "^4.6.1",
|
"react-hotkeys-hook": "^4.6.1",
|
||||||
"react-icons": "^5.4.0",
|
"react-icons": "^5.4.0",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import * as Sentry from '@sentry/electron/main'
|
|||||||
import { BrowserWindow, app, session } from 'electron'
|
import { BrowserWindow, app, session } from 'electron'
|
||||||
import started from 'electron-squirrel-startup'
|
import started from 'electron-squirrel-startup'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import { throttle } from 'lodash-es'
|
||||||
import EventEmitter from 'node:events'
|
import EventEmitter from 'node:events'
|
||||||
import { join } from 'node:path'
|
import { join } from 'node:path'
|
||||||
import ReconnectingWebSocket from 'reconnecting-websocket'
|
import ReconnectingWebSocket from 'reconnecting-websocket'
|
||||||
@@ -22,6 +23,7 @@ import {
|
|||||||
pollDataURL,
|
pollDataURL,
|
||||||
watchDataFile,
|
watchDataFile,
|
||||||
} from './data'
|
} from './data'
|
||||||
|
import { loadStorage } from './storage'
|
||||||
import StreamdelayClient from './StreamdelayClient'
|
import StreamdelayClient from './StreamdelayClient'
|
||||||
import StreamWindow from './StreamWindow'
|
import StreamWindow from './StreamWindow'
|
||||||
import TwitchBot from './TwitchBot'
|
import TwitchBot from './TwitchBot'
|
||||||
@@ -281,16 +283,7 @@ async function main(argv: ReturnType<typeof parseArgs>) {
|
|||||||
streamdelay: null,
|
streamdelay: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateDoc = new Y.Doc()
|
function updateViewsFromStateDoc() {
|
||||||
const viewsState = stateDoc.getMap<Y.Map<string | undefined>>('views')
|
|
||||||
stateDoc.transact(() => {
|
|
||||||
for (let i = 0; i < argv.grid.count ** 2; i++) {
|
|
||||||
const data = new Y.Map<string | undefined>()
|
|
||||||
data.set('streamId', undefined)
|
|
||||||
viewsState.set(String(i), data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
viewsState.observeDeep(() => {
|
|
||||||
try {
|
try {
|
||||||
const viewContentMap = new Map()
|
const viewContentMap = new Map()
|
||||||
for (const [key, viewData] of viewsState) {
|
for (const [key, viewData] of viewsState) {
|
||||||
@@ -308,8 +301,47 @@ async function main(argv: ReturnType<typeof parseArgs>) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error updating views', err)
|
console.error('Error updating views', err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateDoc = new Y.Doc()
|
||||||
|
const viewsState = stateDoc.getMap<Y.Map<string | undefined>>('views')
|
||||||
|
|
||||||
|
const db = await loadStorage(
|
||||||
|
join(app.getPath('userData'), 'streamwall-storage.json'),
|
||||||
|
)
|
||||||
|
if (db.data.stateDoc) {
|
||||||
|
console.log('Loading stateDoc from storage...')
|
||||||
|
try {
|
||||||
|
Y.applyUpdate(stateDoc, Buffer.from(db.data.stateDoc, 'base64'))
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Failed to restore stateDoc', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stateDoc.on(
|
||||||
|
'update',
|
||||||
|
throttle(() => {
|
||||||
|
db.update((data) => {
|
||||||
|
const fullDoc = Y.encodeStateAsUpdate(stateDoc)
|
||||||
|
data.stateDoc = Buffer.from(fullDoc).toString('base64')
|
||||||
|
})
|
||||||
|
}, 1000),
|
||||||
|
)
|
||||||
|
|
||||||
|
stateDoc.transact(() => {
|
||||||
|
for (let i = 0; i < argv.grid.count ** 2; i++) {
|
||||||
|
if (viewsState.has(String(i))) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const data = new Y.Map<string | undefined>()
|
||||||
|
data.set('streamId', undefined)
|
||||||
|
viewsState.set(String(i), data)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
updateViewsFromStateDoc()
|
||||||
|
viewsState.observeDeep(updateViewsFromStateDoc)
|
||||||
|
|
||||||
const onCommand = async (msg: ControlCommand) => {
|
const onCommand = async (msg: ControlCommand) => {
|
||||||
console.debug('Received message:', msg)
|
console.debug('Received message:', msg)
|
||||||
if (msg.type === 'set-listening-view') {
|
if (msg.type === 'set-listening-view') {
|
||||||
@@ -506,6 +538,7 @@ async function main(argv: ReturnType<typeof parseArgs>) {
|
|||||||
console.debug('Processing streams:', rawStreams)
|
console.debug('Processing streams:', rawStreams)
|
||||||
const streams = idGen.process(rawStreams)
|
const streams = idGen.process(rawStreams)
|
||||||
updateState({ streams })
|
updateState({ streams })
|
||||||
|
updateViewsFromStateDoc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user