Skip to content
Snippets Groups Projects
PlaylistSelector.vue 7.86 KiB
Newer Older
  • Learn to ignore specific revisions
  • Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
      <div>
        <b-modal
          ref="modalPlaylistSelector"
          :title="$t('playlistSelector.title')"
          :cancel-title="$t('cancel')"
          size="lg"
        >
          <p v-if="loaded">
            {{ $t('playlistSelector.currentPlaylistLabel') }}:
    
            <span v-if="timeslot === null || timeslot.playlist_id === null">
              <i
                ><small>{{ $t('noneSetFeminine') }}</small></i
              >
            </span>
            <span v-else>
              {{ timeslot.playlist_id }}<br />
              <span v-if="currentPlaylistDescription">
                {{ $t('showMeta.description') }}: <b>{{ currentPlaylistDescription }}</b></span
              >
            </span>
          </p>
    
          <div v-if="loaded">
            <div v-if="playlists.length">
              <b-table ref="playlistsTable" striped :fields="playlistsTableFields" :items="playlists">
                <!-- Column: Entries
    
                            This column displays the number of entries of the playlist.
                            -->
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                <template #cell(entries)="data">
                  <span
                    v-b-tooltip.html="playlistToolTip(data.value)"
                    class="tw-underline hover:tw-no-underline tw-cursor-help"
                  >
                    {{ $t('playlistTable.items', { smart_count: data.value.length }) }}
                  </span>
                </template>
    
                <!-- Column: Duration
    
                            This column displays the number of entries of the playlist.
                            -->
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                <template #cell(duration)="data">
                  <span :class="{ 'is-mismatched': isMismatchedLength(data) }">
                    {{ playlistDuration(data.item) }}
                    <abbr v-if="isMismatchedLength(data)" :title="title(data)"> (?) </abbr>
                  </span>
                </template>
    
                <!-- Column: Actions
    
                            This column displays the available buttons for actions the user can
                            take on this playlist (e.g. editing and deleting).
                            -->
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                <template #cell(actions)="data">
                  <b-button-group size="sm">
                    <b-button
                      v-if="data.item.id !== timeslot.playlist_id"
                      variant="info"
                      @click="choose(data)"
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                      {{ $t('playlistTable.assign') }}
                    </b-button>
                    <b-button v-else variant="danger" @click="choose(null)">
                      {{ $t('playlistTable.unset') }}
                    </b-button>
                  </b-button-group>
                </template>
              </b-table>
            </div>
    
            <!-- If no playlists are available -->
            <div v-else class="tw-mb-4">
              {{ $t('playlistSelector.noPlaylistsAvailable') }}
            </div>
          </div>
    
          <div v-else>
            <img src="/assets/radio.gif" :alt="$t('loading')" />
          </div>
    
          <div>
            <div class="tw-space-x-2">
              <b-button :to="'files'">
                {{ $t('playlistSelector.goToFiles') }}
              </b-button>
    
              <b-button v-if="!audioUpload" v-model="audioFile" @click="toggleAudioUpload">
                {{ $t('playlistSelector.uploadAudio') }}
              </b-button>
            </div>
    
            <div v-if="audioUpload" class="tw-mt-4 tw-space-x-2 tw-flex">
              <b-form-file v-model="audioFile" accept="audio/*" />
    
              <b-button :disabled="!audioFile" @click="upload">
                {{ $t('playlistSelector.upload') }}
              </b-button>
            </div>
          </div>
        </b-modal>
      </div>
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    import { mapGetters } from 'vuex'
    
    import prettyDate from '@/mixins/prettyDate'
    import playlist from '@/mixins/playlist'
    
    export default {
      mixins: [prettyDate, playlist],
    
      data() {
        return {
          scheduleId: null,
          timeslot: null,
    
          audioFile: null,
          audioUpload: false,
          audioUploadError: '',
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
      },
    
      computed: {
        loaded() {
          return this.$store.state.playlists.loaded.playlists
        },
    
        playlistsTableFields() {
          return [
            { key: 'id', label: this.$t('playlistTable.index') },
            { key: 'description', label: this.$t('playlistTable.description') },
            { key: 'entries', label: this.$t('playlistTable.entries') },
            { key: 'duration', label: this.$t('playlistTable.duration') },
            { key: 'actions', label: this.$t('playlistTable.actions'), class: 'text-right' },
          ]
        },
    
        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).minutes, 10)
        },
    
        currentPlaylistDescription() {
          let description = false
          if (this.timeslot && this.timeslot.playlist_id !== null) {
    
            const choosenList = this.playlists.find((list) => list.id === this.timeslot.playlist_id)
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            if (choosenList && choosenList.description.length > 0) {
              description = choosenList.description
            }
          }
          return description
        },
    
        ...mapGetters({
          selectedShow: 'shows/selectedShow',
          timeslots: 'shows/timeslots',
          playlists: 'playlists/playlists',
          getTimeslotById: 'shows/getTimeslotById',
        }),
      },
    
      methods: {
        upload(event) {
          event.preventDefault()
          event.stopPropagation()
    
          if (!this.audioFile) {
            this.audioUploadError = this.$t('playlistSelector.missingFile')
            return
          }
    
          this.audioUpload = false
          this.$store.dispatch('files/addFile', {
            show: this.selectedShow.slug,
            uploadSourceFile: this.audioFile,
            callback: this.handleUploadedFile,
          })
        },
    
        handleUploadedFile() {
          this.$store.dispatch('files/fetchFiles', {
            slug: this.selectedShow.slug,
            callback: this.createPlaylistForUploadedFile,
          })
        },
    
        createPlaylistForUploadedFile(files) {
          const file = files.slice(-1)[0]
          const { slug } = this.selectedShow
          const playlist = {
            description: 'Automatisch erstellt durch Dateiupload',
            entries: [{ file }],
          }
    
          this.$store.dispatch('playlists/add', {
            slug,
            playlist,
          })
        },
    
        toggleAudioUpload() {
          this.audioUpload = !this.audioUpload
        },
    
        open(scheduleId, timeslotId) {
          this.audioFile = null
          this.audioUpload = false
          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(this.$t('playlistSelector.mismatchedLengthConfirmation'))
          }
    
          if (confirmed) {
    
            const ts = { ...this.timeslot }
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            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 this.$t('playlistSelector.mismatchedLength')
          }
    
          return ''
        },
    
        playlistToolTip(entries) {
          let text = '<div style="white-space: nowrap;" align="left">'
    
          for (const i in entries) {
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            text += i + ': ' + entries[i].uri + '<br>'
          }
          text += '</div>'
          return text
        },
    
        isMismatchedLength(playlist) {
          const totalDuration = this.playlistDuration(playlist.item)
          let delta = 0
    
    
          const unknowns = (playlist.item.entries ?? []).filter((entry) => !entry.duration)
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          if (unknowns.length === 1) {
            delta = this.timeslotDurationInNs - totalDuration
          }
    
          return this.timeslotDurationInNs !== totalDuration + delta
        },
      },
    }