Fix multiplayer responsiveness for viewer
All checks were successful
Deploy Feature / deploy-feature (push) Successful in 26s
All checks were successful
Deploy Feature / deploy-feature (push) Successful in 26s
This commit is contained in:
@@ -44,3 +44,13 @@ jobs:
|
|||||||
mkdir -p /www/jeopardy-test
|
mkdir -p /www/jeopardy-test
|
||||||
find /www/jeopardy-test -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
find /www/jeopardy-test -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
||||||
cp -r /repos/music-jeopardy/dist/. /www/jeopardy-test/
|
cp -r /repos/music-jeopardy/dist/. /www/jeopardy-test/
|
||||||
|
- name: Restart realtime service (if available)
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now music-jeopardy-realtime.service
|
||||||
|
systemctl restart music-jeopardy-realtime.service
|
||||||
|
else
|
||||||
|
echo "systemctl not available in this runner container. Restart on host manually."
|
||||||
|
fi
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ jobs:
|
|||||||
mkdir -p /www/jeopardy
|
mkdir -p /www/jeopardy
|
||||||
find /www/jeopardy -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
find /www/jeopardy -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
||||||
cp -r /repos/music-jeopardy/dist/. /www/jeopardy/
|
cp -r /repos/music-jeopardy/dist/. /www/jeopardy/
|
||||||
|
|
||||||
- name: Restart realtime service (if available)
|
- name: Restart realtime service (if available)
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
|
|||||||
65
src/App.vue
65
src/App.vue
@@ -540,22 +540,6 @@ export default {
|
|||||||
const socket = new WebSocket(wsUrl)
|
const socket = new WebSocket(wsUrl)
|
||||||
this.socket = socket
|
this.socket = socket
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
socket.onopen = () => {
|
|
||||||
if (this.socket !== socket) return
|
|
||||||
this.socketConnected = true
|
|
||||||
this.syncError = ''
|
|
||||||
if (this.isHost) this.publishState()
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
socket.onerror = () => {
|
|
||||||
if (this.socket !== socket) return
|
|
||||||
this.socketConnected = false
|
|
||||||
this.syncError = 'Realtime connection failed'
|
|
||||||
reject(new Error('Realtime connection failed'))
|
|
||||||
}
|
|
||||||
}).catch(() => {})
|
|
||||||
|
|
||||||
socket.onmessage = async (event) => {
|
socket.onmessage = async (event) => {
|
||||||
let message: RealtimeMessage | null = null
|
let message: RealtimeMessage | null = null
|
||||||
try {
|
try {
|
||||||
@@ -574,6 +558,22 @@ export default {
|
|||||||
this.socketConnected = false
|
this.socketConnected = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
socket.onopen = () => {
|
||||||
|
if (this.socket !== socket) return
|
||||||
|
this.socketConnected = true
|
||||||
|
this.syncError = ''
|
||||||
|
if (this.isHost) this.publishState()
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
socket.onerror = () => {
|
||||||
|
if (this.socket !== socket) return
|
||||||
|
this.socketConnected = false
|
||||||
|
this.syncError = 'Realtime connection failed'
|
||||||
|
reject(new Error('Realtime connection failed'))
|
||||||
|
}
|
||||||
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
buildRealtimeState(): RealtimeState {
|
buildRealtimeState(): RealtimeState {
|
||||||
return {
|
return {
|
||||||
@@ -611,6 +611,7 @@ export default {
|
|||||||
this.queuedRemoteState = state
|
this.queuedRemoteState = state
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const previousClipUrl = this.currentClipUrl
|
||||||
this.isApplyingRemote = true
|
this.isApplyingRemote = true
|
||||||
try {
|
try {
|
||||||
const selected = state.selectedGameName
|
const selected = state.selectedGameName
|
||||||
@@ -628,6 +629,38 @@ export default {
|
|||||||
} finally {
|
} finally {
|
||||||
this.isApplyingRemote = false
|
this.isApplyingRemote = false
|
||||||
}
|
}
|
||||||
|
await nextTick()
|
||||||
|
this.syncRemotePlayback(previousClipUrl !== this.currentClipUrl)
|
||||||
|
},
|
||||||
|
getCurrentTileStatus() {
|
||||||
|
if (!this.currentTileKey) return 'available'
|
||||||
|
return this.tiles[this.currentTileKey]?.status || 'available'
|
||||||
|
},
|
||||||
|
syncRemotePlayback(forceReload: boolean) {
|
||||||
|
if (this.canControlGame) return
|
||||||
|
const player = this.getPlayer()
|
||||||
|
if (!player) return
|
||||||
|
const tileStatus = this.getCurrentTileStatus()
|
||||||
|
|
||||||
|
if (!this.currentClipUrl || tileStatus === 'won' || tileStatus === 'void') {
|
||||||
|
player.pause()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceReload) {
|
||||||
|
player.currentTime = 0
|
||||||
|
player.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileStatus === 'paused') {
|
||||||
|
player.pause()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileStatus === 'playing' || tileStatus === 'guessed') {
|
||||||
|
this.ensureAudioContext()
|
||||||
|
player.play().catch(() => {})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
getPlayer() {
|
getPlayer() {
|
||||||
return this.$refs.player as HTMLAudioElement | undefined
|
return this.$refs.player as HTMLAudioElement | undefined
|
||||||
|
|||||||
Reference in New Issue
Block a user