Merge pull request #689 from chme/web_podcasts
Improve podcasts views in player web interface
This commit is contained in:
commit
90a7c120c3
|
@ -85,6 +85,7 @@ STRTAG : 'artist'
|
|||
| 'artist_id'
|
||||
| 'album_id'
|
||||
| 'songartistid'
|
||||
| 'songalbumid'
|
||||
;
|
||||
|
||||
INTTAG : 'play_count'
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<template functional>
|
||||
<div class="media" :id="'index_' + props.track.title_sort.charAt(0).toUpperCase()">
|
||||
<div class="media" :id="'index_' + props.track.title_sort.charAt(0).toUpperCase()" :class="{ 'with-progress': slots().progress }">
|
||||
<figure class="media-left fd-has-action" v-if="slots().icon" @click="listeners.click">
|
||||
<slot name="icon"></slot>
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped" @click="listeners.click">
|
||||
<h1 class="title is-6">{{ props.track.title }}</h1>
|
||||
<h1 class="title is-6" :class="{ 'has-text-grey': props.track.media_kind === 'podcast' && props.track.play_count > 0 }">{{ props.track.title }}</h1>
|
||||
<h2 class="subtitle is-7 has-text-grey"><b>{{ props.track.artist }}</b></h2>
|
||||
<h2 class="subtitle is-7 has-text-grey">{{ props.track.album }}</h2>
|
||||
<slot name="progress"></slot>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions"></slot>
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
<p class="subtitle">
|
||||
{{ track.artist }}
|
||||
</p>
|
||||
<div class="buttons" v-if="track.media_kind === 'podcast'">
|
||||
<a class="button is-small" v-if="track.play_count > 0" @click="mark_new">Mark as new</a>
|
||||
<a class="button is-small" v-if="track.play_count === 0" @click="mark_played">Mark as played</a>
|
||||
</div>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album</span>
|
||||
|
@ -125,6 +129,20 @@ export default {
|
|||
open_artist: function () {
|
||||
this.$emit('close')
|
||||
this.$router.push({ path: '/music/artists/' + this.track.album_artist_id })
|
||||
},
|
||||
|
||||
mark_new: function () {
|
||||
webapi.library_track_update(this.track.id, { 'play_count': 'reset' }).then(() => {
|
||||
this.$emit('play_count_changed')
|
||||
this.$emit('close')
|
||||
})
|
||||
},
|
||||
|
||||
mark_played: function () {
|
||||
webapi.library_track_update(this.track.id, { 'play_count': 'increment' }).then(() => {
|
||||
this.$emit('play_count_changed')
|
||||
this.$emit('close')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,34 @@
|
|||
background-color: hsl(0, 0%, 21%);
|
||||
}
|
||||
|
||||
.track-progress {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 250px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.track-progress .range-slider-knob {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.track-progress .range-slider-fill {
|
||||
background-color: hsl(217, 71%, 53%);
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.track-progress .range-slider-rail {
|
||||
background-color: hsl(0, 0%, 100%);
|
||||
}
|
||||
|
||||
.media.with-progress h2:last-of-type {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.media.with-progress {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
a.navbar-item {
|
||||
outline: 0;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -67,8 +67,8 @@ import webapi from '@/webapi'
|
|||
const browseData = {
|
||||
load: function (to) {
|
||||
return Promise.all([
|
||||
webapi.search({ type: 'album', expression: 'time_added after 8 weeks ago having track_count > 3 order by time_added desc', limit: 3 }),
|
||||
webapi.search({ type: 'track', expression: 'time_played after 8 weeks ago order by time_played desc', limit: 3 })
|
||||
webapi.search({ type: 'album', expression: 'time_added after 8 weeks ago and media_kind is music having track_count > 3 order by time_added desc', limit: 3 }),
|
||||
webapi.search({ type: 'track', expression: 'time_played after 8 weeks ago and media_kind is music order by time_played desc', limit: 3 })
|
||||
])
|
||||
},
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ const browseData = {
|
|||
load: function (to) {
|
||||
return webapi.search({
|
||||
type: 'album',
|
||||
expression: 'time_added after 8 weeks ago having track_count > 3 order by time_added desc',
|
||||
expression: 'time_added after 8 weeks ago and media_kind is music having track_count > 3 order by time_added desc',
|
||||
limit: 50
|
||||
})
|
||||
},
|
||||
|
|
|
@ -33,7 +33,7 @@ const browseData = {
|
|||
load: function (to) {
|
||||
return webapi.search({
|
||||
type: 'track',
|
||||
expression: 'time_played after 8 weeks ago order by time_played desc',
|
||||
expression: 'time_played after 8 weeks ago and media_kind is music order by time_played desc',
|
||||
limit: 50
|
||||
})
|
||||
},
|
||||
|
|
|
@ -14,13 +14,23 @@
|
|||
<template slot="content">
|
||||
<p class="heading has-text-centered-mobile">{{ album.track_count }} tracks</p>
|
||||
<list-item-track v-for="track in tracks" :key="track.id" :track="track" @click="play_track(track)">
|
||||
<template slot="progress">
|
||||
<range-slider
|
||||
class="track-progress"
|
||||
min="0"
|
||||
:max="track.length_ms"
|
||||
step="1"
|
||||
:disabled="true"
|
||||
:value="track.seek_ms" >
|
||||
</range-slider>
|
||||
</template>
|
||||
<template slot="actions">
|
||||
<a @click="open_dialog(track)">
|
||||
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-track>
|
||||
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
|
||||
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" @play_count_changed="reload_tracks" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</template>
|
||||
|
@ -30,26 +40,27 @@ import { LoadDataBeforeEnterMixin } from './mixin'
|
|||
import ContentWithHeading from '@/templates/ContentWithHeading'
|
||||
import ListItemTrack from '@/components/ListItemTrack'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack'
|
||||
import RangeSlider from 'vue-range-slider'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const albumData = {
|
||||
load: function (to) {
|
||||
return Promise.all([
|
||||
webapi.library_album(to.params.album_id),
|
||||
webapi.library_album_tracks(to.params.album_id)
|
||||
webapi.library_podcast_episodes(to.params.album_id)
|
||||
])
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.album = response[0].data
|
||||
vm.tracks = response[1].data.items
|
||||
vm.tracks = response[1].data.tracks.items
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'PagePodcast',
|
||||
mixins: [ LoadDataBeforeEnterMixin(albumData) ],
|
||||
components: { ContentWithHeading, ListItemTrack, ModalDialogTrack },
|
||||
components: { ContentWithHeading, ListItemTrack, ModalDialogTrack, RangeSlider },
|
||||
|
||||
data () {
|
||||
return {
|
||||
|
@ -73,6 +84,12 @@ export default {
|
|||
open_dialog: function (track) {
|
||||
this.selected_track = track
|
||||
this.show_details_modal = true
|
||||
},
|
||||
|
||||
reload_tracks: function () {
|
||||
webapi.library_podcast_episodes(this.album.id).then(({ data }) => {
|
||||
this.tracks = data.tracks.items
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,31 @@
|
|||
<template>
|
||||
<div>
|
||||
<content-with-heading v-if="new_episodes.items.length > 0">
|
||||
<template slot="heading-left">
|
||||
<p class="title is-4">New episodes</p>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<list-item-track v-for="track in new_episodes.items" :key="track.id" :track="track" @click="play_track(track)">
|
||||
<template slot="progress">
|
||||
<range-slider
|
||||
class="track-progress"
|
||||
min="0"
|
||||
:max="track.length_ms"
|
||||
step="1"
|
||||
:disabled="true"
|
||||
:value="track.seek_ms" >
|
||||
</range-slider>
|
||||
</template>
|
||||
<template slot="actions">
|
||||
<a @click="open_track_dialog(track)">
|
||||
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-track>
|
||||
<modal-dialog-track :show="show_track_details_modal" :track="selected_track" @close="show_track_details_modal = false" @play_count_changed="reload_new_episodes" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template slot="heading-left">
|
||||
<p class="title is-4">Podcasts</p>
|
||||
|
@ -8,12 +34,12 @@
|
|||
<template slot="content">
|
||||
<list-item-album v-for="album in albums.items" :key="album.id" :album="album" :media_kind="'podcast'" @click="open_album(album)">
|
||||
<template slot="actions">
|
||||
<a @click="open_dialog(album)">
|
||||
<a @click="open_album_dialog(album)">
|
||||
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-album>
|
||||
<modal-dialog-album :show="show_details_modal" :album="selected_album" :media_kind="'podcast'" @close="show_details_modal = false" />
|
||||
<modal-dialog-album :show="show_album_details_modal" :album="selected_album" :media_kind="'podcast'" @close="show_album_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -22,31 +48,42 @@
|
|||
<script>
|
||||
import { LoadDataBeforeEnterMixin } from './mixin'
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading'
|
||||
import ListItemTrack from '@/components/ListItemTrack'
|
||||
import ListItemAlbum from '@/components/ListItemAlbum'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack'
|
||||
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
|
||||
import RangeSlider from 'vue-range-slider'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const albumsData = {
|
||||
load: function (to) {
|
||||
return webapi.library_podcasts()
|
||||
return Promise.all([
|
||||
webapi.library_podcasts(),
|
||||
webapi.library_podcasts_new_episodes()
|
||||
])
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.albums = response.data
|
||||
vm.albums = response[0].data
|
||||
vm.new_episodes = response[1].data.tracks
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'PagePodcasts',
|
||||
mixins: [ LoadDataBeforeEnterMixin(albumsData) ],
|
||||
components: { ContentWithHeading, ListItemAlbum, ModalDialogAlbum },
|
||||
components: { ContentWithHeading, ListItemTrack, ListItemAlbum, ModalDialogTrack, ModalDialogAlbum, RangeSlider },
|
||||
|
||||
data () {
|
||||
return {
|
||||
albums: {},
|
||||
new_episodes: { items: [] },
|
||||
|
||||
show_details_modal: false,
|
||||
selected_album: {}
|
||||
show_album_details_modal: false,
|
||||
selected_album: {},
|
||||
|
||||
show_track_details_modal: false,
|
||||
selected_track: {}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -55,9 +92,24 @@ export default {
|
|||
this.$router.push({ path: '/podcasts/' + album.id })
|
||||
},
|
||||
|
||||
open_dialog: function (album) {
|
||||
play_track: function (track) {
|
||||
webapi.player_play_uri(track.uri, false)
|
||||
},
|
||||
|
||||
open_track_dialog: function (track) {
|
||||
this.selected_track = track
|
||||
this.show_track_details_modal = true
|
||||
},
|
||||
|
||||
open_album_dialog: function (album) {
|
||||
this.selected_album = album
|
||||
this.show_details_modal = true
|
||||
this.show_album_details_modal = true
|
||||
},
|
||||
|
||||
reload_new_episodes: function () {
|
||||
webapi.library_podcasts_new_episodes().then(({ data }) => {
|
||||
this.new_episodes = data.tracks
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,6 +202,26 @@ export default {
|
|||
return axios.get('/api/library/albums?media_kind=podcast')
|
||||
},
|
||||
|
||||
library_podcasts_new_episodes () {
|
||||
var episodesParams = {
|
||||
'type': 'tracks',
|
||||
'expression': 'media_kind is podcast and play_count = 0 ORDER BY time_added DESC'
|
||||
}
|
||||
return axios.get('/api/search', {
|
||||
params: episodesParams
|
||||
})
|
||||
},
|
||||
|
||||
library_podcast_episodes (albumId) {
|
||||
var episodesParams = {
|
||||
'type': 'tracks',
|
||||
'expression': 'media_kind is podcast and songalbumid is "' + albumId + '" ORDER BY time_added DESC'
|
||||
}
|
||||
return axios.get('/api/search', {
|
||||
params: episodesParams
|
||||
})
|
||||
},
|
||||
|
||||
library_audiobooks () {
|
||||
return axios.get('/api/library/albums?media_kind=audiobook')
|
||||
},
|
||||
|
@ -218,6 +238,14 @@ export default {
|
|||
return axios.get('/api/library/playlists/' + playlistId + '/tracks')
|
||||
},
|
||||
|
||||
library_track (trackId) {
|
||||
return axios.get('/api/library/tracks/' + trackId)
|
||||
},
|
||||
|
||||
library_track_update (trackId, attributes = {}) {
|
||||
return axios.put('/api/library/tracks/' + trackId, undefined, { params: attributes })
|
||||
},
|
||||
|
||||
library_files (directory = undefined) {
|
||||
var filesParams = { 'directory': directory }
|
||||
return axios.get('/api/library/files', {
|
||||
|
|
Loading…
Reference in New Issue