PlaylistSelector.vue 5.84 KB
Newer Older
1
2
3
<template>
  <div>
    <b-modal
4
      ref="modalPlaylistSelector"
5
6
7
      title="Edit playlist for this timeslot"
      size="lg"
    >
8
      <p v-if="loaded">
9
        Currently chosen playlist ID:
10
        <span v-if="timeslot === null || timeslot.playlist_id === null">
11
12
13
          <i><small>(none set)</small></i>
        </span>
        <span v-else>
14
          {{ timeslot.playlist_id }}
15
16
17
18
19
20
21
          <span v-if="currentPlaylistDescription">
            , Description: <b>{{ currentPlaylistDescription }}</b>
          </span>
        </span>
      </p>

      <p>Available playlists:</p>
22
      <div v-if="loaded">
23
24
25
26
27
28
29
30
31
        <b-table
          ref="playlistsTable"
          striped
          :fields="playlistsTableFields"
          :items="playlists"
        >
          <!-- Column: Entries
          This column displays the number of entries of the playlist.
          -->
32
          <template v-slot:cell(entries)="data">
33
34
35
36
37
38
39
40
41
42
            {{ data.value.length }} items
            <b-button
              v-b-tooltip.html="playlistToolTip(data.value)"
              variant="outline-success"
              size="sm"
            >
              show entries
            </b-button>
          </template>

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

          <!-- Column: Duration
          This column displays the number of entries of the playlist.
          -->
          <template v-slot:cell(duration)="data">
            <span
              :class="{'is-mismatched': isMismatchedLength(data) }"
            >
              {{ playlistDuration(data) }}

              <abbr
                v-if="isMismatchedLength(data)"
                :title="title(data)"
              >
                (?)
              </abbr>
            </span>
          </template>

62
63
64
65
          <!-- Column: Actions
          This column displays the available buttons for actions the user can
          take on this playlist (e.g. editing and deleting).
          -->
66
          <template v-slot:cell(actions)="data">
67
68
            <b-button-group size="sm">
              <b-button
69
                v-if="data.item.id !== timeslot.playlist_id"
70
                variant="info"
71
                @click="choose(data)"
72
73
74
              >
                Take it!
              </b-button>
75
76
77
78
79
80
81
              <b-button
                v-else
                variant="danger"
                @click="choose(null)"
              >
                Unset
              </b-button>
82
83
84
85
86
87
            </b-button-group>
          </template>
        </b-table>
      </div>
      <div v-else>
        <img
88
          src="../../assets/radio.gif"
89
90
91
          alt="loading playlists"
        >
      </div>
92
93
94
95
96
97

      <div align="center">
        <b-button :to="'files'">
          Go to FileManager
        </b-button>
      </div>
98
99
100
101
102
    </b-modal>
  </div>
</template>

<script>
103
import { mapGetters } from 'vuex'
104
import prettyDate from '../../mixins/prettyDate'
105
106
107
108
109
110

export default {
  mixins: [ prettyDate ],

  data () {
    return {
111
      scheduleId: null,
112
113
114
115
116
117
      timeslot: null,

      playlistsTableFields: [
        { key: 'id', label: 'Index' },
        { key: 'description', label: 'Description' },
        { key: 'entries', label: 'Entries' },
118
        { key: 'duration', label: 'Duration' },
119
120
121
122
123
124
        { key: 'actions', label: 'Actions', class: 'text-right' },
      ],
    }
  },

  computed: {
125
126
    loaded () { return this.$store.state.playlists.loaded.playlists },

127
128
129
130
131
132
133
134
135
    timeslotDuration() {
      const { start, end } = this.timeslot

      return parseInt(
        this.prettyDuration(start, end),
        10
      )
    },

136
137
    currentPlaylistDescription () {
      let description = false
138
139
      if (this.timeslot && this.timeslot.playlist_id !== null) {
        let choosenList = this.playlists.find(list => list.id === this.timeslot.playlist_id)
140
141
142
143
144
        if (choosenList && choosenList.description.length > 0) {
          description = choosenList.description
        }
      }
      return description
145
146
147
148
149
150
151
152
153
    },

    ...mapGetters({
      selectedShow: 'shows/selectedShow',
      timeslots: 'shows/timeslots',
      notes: 'shows/notes',
      playlists: 'playlists/playlists',
      getTimeslotById: 'shows/getTimeslotById',
    })
154
155
156
  },

  methods: {
157
158
159
160
    open (scheduleId, timeslotId) {
      this.scheduleId = scheduleId
      this.timeslot = this.getTimeslotById(timeslotId)
      this.$refs.modalPlaylistSelector.show()
161
162
    },

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    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 ""
190
191
192
193
194
195
196
197
198
199
    },

    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
    },
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

    playlistDuration({ item }) {
      const totalDuration = item.entries.reduce((acc, entry) => acc + entry.duration, 0);
      return this.prettyNanoseconds(totalDuration)
    },

    isMismatchedLength({ item }) {
      const totalDuration = this.calculatePlaylistDuration(item)
      const durationInMinutes = this.nanosecondsToMinutes(totalDuration)

      return this.timeslotDuration !== durationInMinutes
    },

    calculatePlaylistDuration(item) {
      return item.entries.reduce((acc, entry) => acc + entry.duration, 0)
    }
216
217
218
219
220
  }
}
</script>

<style scoped>
221
222
223
  .is-mismatched {
    color: var(--orange);
  }
224
</style>