Skip to content
Snippets Groups Projects
playlists.ts 3.73 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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
    
    }
    
    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
        }
    
          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 })
    
      return {
        ...base,
        list,
    
        ...APIRetrieve(api),
    
        ...APICreate({ ...api, endpoint: playlistsShowEndpoint }),
        ...APIRemove({ ...api, endpoint: playlistsShowEndpoint }),