This commit is contained in:
2026-10-07 01:43:36 +07:00
parent 22c0b7ab4b
commit 71355777fd
7 changed files with 812 additions and 18 deletions
+43 -1
View File
@@ -38,6 +38,7 @@ const timerSyncedAt = ref(Date.now())
const timerStateAtSync = ref<string>()
const pollingReady = ref(false)
const introAudioElement = ref<HTMLAudioElement>()
const musicAudioElement = ref<HTMLAudioElement>()
const conclusionVideoElement = ref<HTMLVideoElement>()
let appliedCommandVersion = 0
let timerTick: number | null = null
@@ -68,6 +69,11 @@ const timerDisplay = computed(() => {
})
const introAudio = computed(() => applicationFileURL(state.value?.introAudio))
const conclusionVideo = computed(() => applicationFileURL(state.value?.conclusionVideo))
const musicTrack = computed(() => {
const tracks = state.value?.music?.playlist?.tracks || []
const index = state.value?.music?.trackIndex || 0
return applicationFileURL(tracks[index]?.filename)
})
const screenBackground = computed(() => {
const image = state.value?.backgroundImage || state.value?.coverImage
return image ? { backgroundImage: `linear-gradient(rgb(0 0 0 / 55%), rgb(0 0 0 / 55%)), url("${image}")` } : {}
@@ -188,6 +194,35 @@ watch(state, async (value) => {
}
})
watch(
() => state.value?.music,
async (value) => {
const media = musicAudioElement.value
if (!media || !value || !value.playlist?.tracks?.length) return
await nextTick()
media.volume = Math.max(0, Math.min(1, (value.volume ?? 100) / 100))
media.muted = !state.value?.soundEnabled
media.currentTime = (value.positionMs || 0) / 1000
if (value.playback === 'MUSIC_PLAYBACK_PLAYING') {
void media.play().catch(() => {
mediaError.value = 'Браузер заблокировал воспроизведение музыки. Нажмите «Подготовить экран».'
})
} else {
media.pause()
}
},
{ deep: true },
)
async function advanceMusic() {
if (!screenId.value || !accessToken.value) return
try {
await screenClient.AdvanceScreenMusic({ screenID: screenId.value, accessToken: accessToken.value })
} catch {
mediaError.value = 'Не удалось синхронизировать музыку. Повторная попытка выполняется автоматически.'
}
}
async function bind() {
if (!selectedGameId.value || !route.query.screenID || !route.query.accessToken) return
binding.value = true
@@ -213,7 +248,7 @@ async function prepareScreen() {
}
prepared.value = true
await nextTick()
for (const media of [introAudioElement.value, conclusionVideoElement.value]) {
for (const media of [introAudioElement.value, conclusionVideoElement.value, musicAudioElement.value]) {
if (!media) continue
media.muted = true
try {
@@ -288,6 +323,13 @@ onUnmounted(() => {
<div v-if="state.introAudio" v-show="screenMode === 'SCREEN_MODE_INTRO'" class="screen-media">
<audio ref="introAudioElement" :src="introAudio" :muted="!state.soundEnabled" controls />
</div>
<audio
v-if="state.music?.playlist?.tracks?.length"
ref="musicAudioElement"
:src="musicTrack"
:muted="!state.soundEnabled"
@ended="advanceMusic"
/>
<div v-if="state.conclusionVideo" v-show="screenMode === 'SCREEN_MODE_CONCLUSION'" class="conclusion-screen">
<video ref="conclusionVideoElement" :src="conclusionVideo" :muted="!state.soundEnabled" playsinline />
</div>