up
This commit is contained in:
@@ -177,6 +177,9 @@ export class Controller {
|
||||
}
|
||||
private measured = new Map<Channel, { operation: number; startedAt: number }>()
|
||||
private timerDeadline: number | null = null
|
||||
private applyingRemote = false
|
||||
private musicAutoPaused = false
|
||||
private musicOverride = false
|
||||
constructor(
|
||||
private publish: (state: State) => void,
|
||||
private now: () => number = () => performance.now(),
|
||||
@@ -184,6 +187,7 @@ export class Controller {
|
||||
this.state.channels.main.source = this.state.catalog.media[0]!
|
||||
}
|
||||
private broadcast() {
|
||||
if (this.applyingRemote) return
|
||||
this.state.revision++
|
||||
this.publish(structuredClone(this.state))
|
||||
}
|
||||
@@ -199,6 +203,8 @@ export class Controller {
|
||||
this.measured.delete(channel)
|
||||
}
|
||||
private newSession() {
|
||||
this.musicAutoPaused = false
|
||||
this.musicOverride = false
|
||||
this.updateTimer()
|
||||
this.state.session = randomUUID()
|
||||
this.state.sequence = 0
|
||||
@@ -314,6 +320,8 @@ export class Controller {
|
||||
this.state.scene.error = ''
|
||||
}
|
||||
private mode(mode: ScreenMode, stepIndex: number | null = null, text = this.state.scene.text) {
|
||||
if ([2, 4].includes(mode) && ![2, 4].includes(this.state.scene.mode))
|
||||
this.musicOverride = false
|
||||
this.state.scene = { ...this.state.scene, mode, stepIndex, text }
|
||||
const c = this.state.channels.main
|
||||
const kind = mode === 2 ? 'audio' : mode === 4 ? 'video' : null
|
||||
@@ -327,6 +335,36 @@ export class Controller {
|
||||
})
|
||||
this.invalidateScene()
|
||||
}
|
||||
private overrideMusic() {
|
||||
this.musicAutoPaused = false
|
||||
this.musicOverride = [2, 4].includes(this.state.scene.mode)
|
||||
}
|
||||
private reconcileSceneMusic() {
|
||||
const music = this.state.channels.music
|
||||
if ([2, 4].includes(this.state.scene.mode)) {
|
||||
if (!this.musicOverride && music.source && music.desired === 'playing') {
|
||||
this.musicAutoPaused = true
|
||||
this.change('music', { desired: 'paused', status: 'pending' })
|
||||
}
|
||||
} else {
|
||||
if (this.musicAutoPaused && music.source && music.desired === 'paused')
|
||||
this.change('music', { desired: 'playing', status: 'pending' })
|
||||
this.musicAutoPaused = false
|
||||
this.musicOverride = false
|
||||
}
|
||||
}
|
||||
synchronizeRemote(apply: () => void, musicChanged: boolean) {
|
||||
// Применить снимок целиком, прежде чем публиковать локальную автопаузу.
|
||||
this.applyingRemote = true
|
||||
try {
|
||||
apply()
|
||||
} finally {
|
||||
this.applyingRemote = false
|
||||
if (musicChanged) this.overrideMusic()
|
||||
this.reconcileSceneMusic()
|
||||
this.broadcast()
|
||||
}
|
||||
}
|
||||
private configureTimer(label: string, seconds: number) {
|
||||
this.timerDeadline = null
|
||||
this.state.timer = {
|
||||
@@ -598,6 +636,10 @@ export class Controller {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.applyingRemote) {
|
||||
if ('channel' in command && command.channel === 'music') this.overrideMusic()
|
||||
this.reconcileSceneMusic()
|
||||
}
|
||||
this.state.sequence = command.sequence
|
||||
this.broadcast()
|
||||
}
|
||||
@@ -645,6 +687,7 @@ export class Controller {
|
||||
this.measured.delete(report.channel)
|
||||
}
|
||||
if (report.status === 'error') {
|
||||
if (report.channel === 'music') this.overrideMusic()
|
||||
c.desired = 'paused'
|
||||
if (report.channel === 'main' && [2, 4].includes(this.state.scene.mode)) {
|
||||
this.state.scene.status = 'error'
|
||||
|
||||
Reference in New Issue
Block a user