Newer
Older
import {
APICreate,
APIListPaginated,
APIRemove,
APIRetrieve,
APIUpdate,
createExtendableAPI,
} from '@rokoli/bnb/drf'
import { defineStore } from 'pinia'
import { createTankURL } from '@/api'
import { tankAuthInit } from '@/stores/auth'
import { Playlist } from '@/types'
import { URLBuilder } from '@rokoli/bnb'
import { useShowStore } from '@/stores/shows'
import { computed, MaybeRefOrGetter, toValue } from 'vue'
export function calculatePlaylistDurationInSeconds(playlist: Playlist, skipUnknown?: true): number
export function calculatePlaylistDurationInSeconds(
playlist: Playlist,
skipUnknown?: false,
): number | null
/**
* Calculates the duration of a playlist.
* May return null if the playlist contains entries with an invalid duration.
* @param playlist
* @param skipUnknown Whether unknown length entries should be skipped
export function calculatePlaylistDurationInSeconds(playlist: Playlist, skipUnknown = false) {
let duration = 0
for (const entry of playlist.entries) {
// entry.duration may be null/NaN if the entry references
// a stream or other resources without an inherent duration
if (typeof entry.duration !== 'number' || isNaN(entry.duration)) {
if (skipUnknown) continue
else return null
duration += entry.duration
export function countUnknownDurations(entries: Playlist['entries']) {
let counter = 0
for (const entry of entries) {
if (typeof entry.duration !== 'number' || isNaN(entry.duration)) counter += 1
return counter
}
export function usePlaylistState(
playlist: MaybeRefOrGetter<Playlist | null>,
targetDurationSeconds: MaybeRefOrGetter<number>,
) {
return computed(() => {
const _playlist = toValue(playlist)
if (!_playlist) return { state: 'missing' as const }
const _targetDuration = Math.round(toValue(targetDurationSeconds))
const unknownDurationCount = countUnknownDurations(_playlist.entries)
let playlistDuration = Math.round(calculatePlaylistDurationInSeconds(_playlist, true))
// If the playlist contains just one record of unknown length
// the playout will automatically expand that entry to the remaining
// time that is needed to fill the timeslot.
// We can therefore consider a single entry of unknown duration to fit the required time.
if (unknownDurationCount === 1 && playlistDuration < _targetDuration) {
playlistDuration = _targetDuration
}
if (unknownDurationCount > 1)
return {
state: 'indeterminate' as const,
duration: playlistDuration,
offset: Math.abs(_targetDuration - playlistDuration),
}
if (playlistDuration < _targetDuration)
return {
state: 'tooShort' as const,
duration: playlistDuration,
offset: _targetDuration - playlistDuration,
}
if (playlistDuration > _targetDuration)
return {
state: 'tooLong' as const,
duration: playlistDuration,
offset: playlistDuration - _targetDuration,
}
return { state: 'ok' as const }
})
}
const playlistsShowEndpoint: URLBuilder = (...subPaths) => {
const showStore = useShowStore()
return createTankURL.prefix(
'shows',
showStore.selectedShow?.slug as string,
'playlists',
)(...subPaths)
}
export const usePlaylistStore = defineStore('playlists', () => {
const endpoint = createTankURL.prefix('playlists')
const { api, base } = createExtendableAPI<Playlist>(endpoint, tankAuthInit)
const { list } = APIListPaginated(api)
const { update } = APIUpdate({ ...api, endpoint: playlistsShowEndpoint })
...APICreate({ ...api, endpoint: playlistsShowEndpoint }),
...APIRemove({ ...api, endpoint: playlistsShowEndpoint }),