up
This commit is contained in:
+80
-7
@@ -1,3 +1,4 @@
|
||||
import { nextMusicTrack } from '../src/utils/musicGroups.js'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import { isDeepStrictEqual } from 'node:util'
|
||||
@@ -104,6 +105,11 @@ export function parseCommand(value: unknown): Command {
|
||||
throw new Error('Некорректный плейлист')
|
||||
intent = { action: 'playlist', channel, playlistId: c.playlistId }
|
||||
break
|
||||
case 'group':
|
||||
if (channel !== 'music' || !number(c.groupId, 0) || !Number.isSafeInteger(c.groupId))
|
||||
throw new Error('Некорректная группа')
|
||||
intent = { action: 'group', channel, groupId: c.groupId }
|
||||
break
|
||||
case 'track':
|
||||
if (channel !== 'music' || !number(c.trackIndex, 0) || !Number.isSafeInteger(c.trackIndex))
|
||||
throw new Error('Некорректный трек')
|
||||
@@ -159,6 +165,7 @@ function initialChannel(): ChannelState {
|
||||
error: '',
|
||||
playlistId: null,
|
||||
trackIndex: 0,
|
||||
groupId: 0,
|
||||
loop: false,
|
||||
}
|
||||
}
|
||||
@@ -276,9 +283,11 @@ export class Controller {
|
||||
playlists: pkg.package.playlists.map((p) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
...(p.groups ? { groups: p.groups } : {}),
|
||||
tracks: p.tracks.map((t) => ({
|
||||
id: t.id,
|
||||
name: t.name,
|
||||
...(t.groupId ? { groupId: t.groupId } : {}),
|
||||
source: source(`track-${p.id}-${t.id}`, t.assetId, t.name, 'audio'),
|
||||
})),
|
||||
})),
|
||||
@@ -291,6 +300,22 @@ export class Controller {
|
||||
const tracks = catalog.playlists.find((p) => p.id === music.playlistId)?.tracks
|
||||
const index = tracks?.findIndex((t) => t.source.url === music.source?.url) ?? -1
|
||||
if (index >= 0) music.trackIndex = index
|
||||
const playlist = catalog.playlists.find((p) => p.id === music.playlistId)
|
||||
if (
|
||||
music.groupId &&
|
||||
(!playlist?.groups?.some((g) => g.id === music.groupId) ||
|
||||
playlist.tracks[index]?.groupId !== music.groupId)
|
||||
) {
|
||||
this.change('music', {
|
||||
groupId: 0,
|
||||
desired: 'stopped',
|
||||
status: 'stopped',
|
||||
position: 0,
|
||||
trackIndex: Math.max(index, 0),
|
||||
source: tracks?.[index]?.source ?? null,
|
||||
duration: null,
|
||||
})
|
||||
}
|
||||
this.state.catalog = catalog
|
||||
this.broadcast()
|
||||
return
|
||||
@@ -576,17 +601,34 @@ export class Controller {
|
||||
}
|
||||
private advance() {
|
||||
const c = this.state.channels.music
|
||||
const tracks = this.state.catalog.playlists.find((p) => p.id === c.playlistId)?.tracks ?? []
|
||||
if (!tracks.length) throw new Error('Плейлист пуст')
|
||||
const next = c.trackIndex + 1
|
||||
if (next < tracks.length || c.loop) this.track(next % tracks.length)
|
||||
else
|
||||
const playlist = this.state.catalog.playlists.find((p) => p.id === c.playlistId)
|
||||
if (!playlist?.tracks.length) throw new Error('Плейлист пуст')
|
||||
const next = nextMusicTrack(playlist, c.trackIndex, c.groupId, c.loop)
|
||||
if (next) {
|
||||
c.groupId = next.groupId
|
||||
this.track(next.index)
|
||||
} else if (c.groupId) {
|
||||
this.change('music', { desired: 'stopped', status: 'stopped', position: 0 })
|
||||
} else {
|
||||
this.change('music', {
|
||||
desired: 'paused',
|
||||
status: 'ended',
|
||||
position: c.duration ?? c.position,
|
||||
})
|
||||
}
|
||||
}
|
||||
synchronizeMusicGroup(groupId: number) {
|
||||
const c = this.state.channels.music
|
||||
const playlist = this.state.catalog.playlists.find((p) => p.id === c.playlistId)
|
||||
if (
|
||||
groupId &&
|
||||
(!playlist?.groups?.some((group) => group.id === groupId) ||
|
||||
playlist.tracks[c.trackIndex]?.groupId !== groupId)
|
||||
)
|
||||
throw new Error('Группа ожидает подготовки локальных материалов')
|
||||
c.groupId = groupId
|
||||
}
|
||||
|
||||
command(input: unknown) {
|
||||
const command = parseCommand(input)
|
||||
if (command.session !== this.state.session || command.sequence <= this.state.sequence) return
|
||||
@@ -615,6 +657,7 @@ export class Controller {
|
||||
if (!playlist) throw new Error('Плейлист не найден в выбранном пакете')
|
||||
this.change(channel, {
|
||||
playlistId: playlist.id,
|
||||
groupId: 0,
|
||||
trackIndex: 0,
|
||||
source: playlist.tracks[0]?.source ?? null,
|
||||
position: 0,
|
||||
@@ -624,9 +667,38 @@ export class Controller {
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'track':
|
||||
case 'group': {
|
||||
const playlist = this.state.catalog.playlists.find((p) => p.id === c.playlistId)
|
||||
if (
|
||||
!playlist ||
|
||||
(command.groupId && !playlist.groups?.some((group) => group.id === command.groupId))
|
||||
)
|
||||
throw new Error('Группа не найдена')
|
||||
const index = command.groupId
|
||||
? playlist.tracks.findIndex((track) => track.groupId === command.groupId)
|
||||
: 0
|
||||
const track = playlist.tracks[index]
|
||||
if (!track) throw new Error('Группа пуста')
|
||||
this.change('music', {
|
||||
groupId: command.groupId,
|
||||
trackIndex: index,
|
||||
source: track.source,
|
||||
desired: 'playing',
|
||||
status: 'pending',
|
||||
position: 0,
|
||||
duration: null,
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'track': {
|
||||
const track = this.state.catalog.playlists.find((p) => p.id === c.playlistId)?.tracks[
|
||||
command.trackIndex
|
||||
]
|
||||
if (!track) throw new Error('Трек не найден')
|
||||
c.groupId = track.groupId ?? 0
|
||||
this.track(command.trackIndex)
|
||||
break
|
||||
}
|
||||
case 'next':
|
||||
this.advance()
|
||||
break
|
||||
@@ -724,7 +796,8 @@ export class Controller {
|
||||
}
|
||||
if (report.status === 'error') {
|
||||
if (report.channel === 'music') this.overrideMusic()
|
||||
c.desired = 'paused'
|
||||
c.desired = report.channel === 'music' && c.groupId ? 'stopped' : 'paused'
|
||||
if (report.channel === 'music' && c.groupId) c.position = 0
|
||||
if (report.channel === 'main' && [2, 4].includes(this.state.scene.mode)) {
|
||||
this.state.scene.status = 'error'
|
||||
this.state.scene.error = c.error
|
||||
|
||||
Reference in New Issue
Block a user