Skip to content
Snippets Groups Projects
PlaylistSelector.vue 8.49 KiB
Newer Older
  • Learn to ignore specific revisions
  •     <div>
            <b-modal
                    ref="modalPlaylistSelector"
                    title="Edit playlist for this timeslot"
                    size="lg"
            >
                <p v-if="loaded">
                    Currently chosen playlist ID:
                    <span v-if="timeslot === null || timeslot.playlist_id === null">
    
              <i><small>(none set)</small></i>
            </span>
    
                    <span v-else>
    
              <span v-if="currentPlaylistDescription">
                , Description: <b>{{ currentPlaylistDescription }}</b>
              </span>
            </span>
    
                </p>
    
                <p>Available playlists:</p>
                <div v-if="loaded">
                    <b-table
                            ref="playlistsTable"
                            striped
                            :fields="playlistsTableFields"
                            :items="playlists"
                    >
                        <!-- Column: Entries
                        This column displays the number of entries of the playlist.
                        -->
                        <template v-slot:cell(entries)="data">
    
                        v-b-tooltip.html="playlistToolTip(data.value)"
                        class="tw-underline hover:tw-no-underline tw-cursor-help"
    
                  {{ data.value.length }} items
                </span>
    
                        </template>
    
                        <!-- Column: Duration
                        This column displays the number of entries of the playlist.
                        -->
                        <template v-slot:cell(duration)="data">
    
                        :class="{'is-mismatched': isMismatchedLength(data) }"
    
                  {{ playlistDuration(data) }}
    
                          v-if="isMismatchedLength(data)"
                          :title="title(data)"
    
                        </template>
    
                        <!-- Column: Actions
                        This column displays the available buttons for actions the user can
                        take on this playlist (e.g. editing and deleting).
                        -->
                        <template v-slot:cell(actions)="data">
                            <b-button-group size="sm">
                                <b-button
                                        v-if="data.item.id !== timeslot.playlist_id"
                                        variant="info"
                                        @click="choose(data)"
                                >
                                    Take it!
                                </b-button>
                                <b-button
                                        v-else
                                        variant="danger"
                                        @click="choose(null)"
                                >
                                    Unset
                                </b-button>
                            </b-button-group>
                        </template>
                    </b-table>
                </div>
                <div v-else>
                    <img
                            src="/assets/radio.gif"
                            alt="loading playlists"
                    >
                </div>
    
                <div align="center">
                    <b-button :to="'files'">
                        Go to FileManager
                    </b-button>
                </div>
            </b-modal>
        </div>
    
        import {mapGetters} from 'vuex'
        import prettyDate from '../../mixins/prettyDate'
    
        export default {
            mixins: [prettyDate],
    
            data() {
                return {
                    scheduleId: null,
                    timeslot: null,
    
                    playlistsTableFields: [
                        {key: 'id', label: 'Index'},
                        {key: 'description', label: 'Description'},
                        {key: 'entries', label: 'Entries'},
                        {key: 'duration', label: 'Duration'},
                        {key: 'actions', label: 'Actions', class: 'text-right'},
                    ],
                }
            },
    
            computed: {
                loaded() {
                    return this.$store.state.playlists.loaded.playlists
                },
    
                timeslotDurationInNs() {
                    const mm = this.timeslotDuration % 60;
                    const hh = (this.timeslotDuration - mm) / 60;
    
                    return this.hmsToNanoseconds(
                        `${this.leadingZero(hh)}:${this.leadingZero(mm)}:00`
                    );
                },
    
                timeslotDuration() {
                    const {start, end} = this.timeslot
    
                    return parseInt(
                        this.prettyDuration(start, end),
                        10
                    )
                },
    
                currentPlaylistDescription() {
                    let description = false
                    if (this.timeslot && this.timeslot.playlist_id !== null) {
                        let choosenList = this.playlists.find(list => list.id === this.timeslot.playlist_id)
                        if (choosenList && choosenList.description.length > 0) {
                            description = choosenList.description
                        }
                    }
                    return description
                },
    
                ...mapGetters({
                    selectedShow: 'shows/selectedShow',
                    timeslots: 'shows/timeslots',
                    notes: 'shows/notes',
                    playlists: 'playlists/playlists',
                    getTimeslotById: 'shows/getTimeslotById',
                })
            },
    
            methods: {
                open(scheduleId, timeslotId) {
                    this.scheduleId = scheduleId
                    this.timeslot = this.getTimeslotById(timeslotId)
                    this.$refs.modalPlaylistSelector.show()
                },
    
                choose(data) {
                    const {item} = data || {}
                    const {id} = item || {}
                    let confirmed = true
    
                    if (data && this.isMismatchedLength(data)) {
                        confirmed = confirm("The playlist you have selected has a different length than the timeslot. Proceed?")
                    }
    
                    if (confirmed) {
                        let ts = {...this.timeslot}
                        ts.playlist_id = id
                        this.$store.dispatch('shows/updateTimeslot', {
                            show: this.selectedShow.id,
                            schedule: this.scheduleId,
                            timeslot: ts,
                            callback: () => {
                                this.timeslot = this.getTimeslotById(ts.id)
                            }
                        })
                    }
                },
    
                title(data) {
                    if (this.isMismatchedLength(data)) {
                        return "Playlist is not the same length as the timeslot"
                    }
    
                    return ""
                },
    
                playlistToolTip(entries) {
                    let text = '<div style="white-space: nowrap;" align="left">'
                    for (let i in entries) {
                        text += i + ': ' + entries[i].uri + '<br>'
                    }
                    text += '</div>'
                    return text
                },
    
                playlistDuration({item}) {
                    if (!item.entries) {
                        return 0;
                    }
    
                    let delta = 0;
                    const totalDuration = item.entries.reduce((acc, entry) => {
                        const newDuration = acc + this.durationInSeconds(entry.duration);
    
                        if (Number.isNaN(newDuration)) {
                            return acc;
                        }
    
                        return newDuration
                    }, 0)
    
                    const unknowns = item.entries.filter(entry => !entry.duration);
                    if (unknowns.length === 1) {
                        delta = this.durationInSeconds(this.timeslotDurationInNs) - totalDuration;
                    }
    
                    const totalDurationInNanoseconds = (totalDuration + delta) * 1000 * 1000 * 1000
                    return this.prettyNanoseconds(totalDurationInNanoseconds)
                },
    
                isMismatchedLength(playlist) {
                    const totalDuration = this.playlistDuration(playlist);
                    let delta = 0;
    
                    const unknowns = playlist.item.entries.filter(entry => !entry.duration);
                    if (unknowns.length === 1) {
                        delta = this.timeslotDurationInNs - totalDuration;
                    }
    
                    return this.timeslotDurationInNs !== totalDuration + delta;
                },
    
        .is-mismatched {
            color: var(--orange);
        }