95 lines
1.8 KiB
Vue
95 lines
1.8 KiB
Vue
<template>
|
|
<view class="player">
|
|
<image
|
|
v-if="currentItem?.type === 'image'"
|
|
:key="currentItem.id"
|
|
class="media"
|
|
:src="currentItem.url"
|
|
mode="aspectFill"
|
|
@error="next"
|
|
/>
|
|
<video
|
|
v-else-if="currentItem?.type === 'video'"
|
|
:key="currentItem.id"
|
|
class="media video"
|
|
:src="currentItem.url"
|
|
:autoplay="true"
|
|
:controls="false"
|
|
:show-center-play-btn="false"
|
|
:show-play-btn="false"
|
|
:enable-progress-gesture="false"
|
|
object-fit="cover"
|
|
@ended="next"
|
|
@error="next"
|
|
/>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
|
import type { PlaylistItem } from '@/types/terminal'
|
|
|
|
const props = defineProps<{
|
|
items: PlaylistItem[]
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
cycleEnd: []
|
|
}>()
|
|
|
|
const currentIndex = ref(0)
|
|
let imageTimer: ReturnType<typeof setTimeout> | undefined
|
|
|
|
const currentItem = computed(() => props.items[currentIndex.value])
|
|
|
|
const clearImageTimer = () => {
|
|
if (!imageTimer) return
|
|
clearTimeout(imageTimer)
|
|
imageTimer = undefined
|
|
}
|
|
|
|
const scheduleImage = () => {
|
|
clearImageTimer()
|
|
if (currentItem.value?.type !== 'image') return
|
|
imageTimer = setTimeout(next, Math.max(currentItem.value.duration || 8, 1) * 1000)
|
|
}
|
|
|
|
const next = () => {
|
|
clearImageTimer()
|
|
if (!props.items.length) return
|
|
|
|
const isLast = currentIndex.value >= props.items.length - 1
|
|
currentIndex.value = isLast ? 0 : currentIndex.value + 1
|
|
if (isLast) emit('cycleEnd')
|
|
scheduleImage()
|
|
}
|
|
|
|
watch(
|
|
() => props.items,
|
|
() => {
|
|
currentIndex.value = 0
|
|
scheduleImage()
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
onBeforeUnmount(clearImageTimer)
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.player,
|
|
.media {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
}
|
|
|
|
.player {
|
|
background: #111111;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.media {
|
|
display: block;
|
|
}
|
|
</style>
|