Merge pull request #915 from chme/web_pl_folders

Show playlist folders in player web interface
This commit is contained in:
ejurgensen 2020-03-08 22:58:23 +01:00 committed by GitHub
commit 9452d3d8d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 61 additions and 17 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -531,7 +531,7 @@ fetch_playlists(struct query_params *query_params, json_object *items, int *tota
} }
static json_object * static json_object *
fetch_playlist(const char *playlist_id) fetch_playlist(uint32_t playlist_id)
{ {
struct query_params query_params; struct query_params query_params;
json_object *playlist; json_object *playlist;
@ -543,7 +543,7 @@ fetch_playlist(const char *playlist_id)
query_params.type = Q_PL; query_params.type = Q_PL;
query_params.sort = S_PLAYLIST; query_params.sort = S_PLAYLIST;
query_params.filter = db_mprintf("(f.id = %s)", playlist_id); query_params.filter = db_mprintf("(f.id = %d)", playlist_id);
ret = db_query_start(&query_params); ret = db_query_start(&query_params);
if (ret < 0) if (ret < 0)
@ -3185,16 +3185,34 @@ jsonapi_reply_library_playlists(struct httpd_request *hreq)
static int static int
jsonapi_reply_library_playlist(struct httpd_request *hreq) jsonapi_reply_library_playlist(struct httpd_request *hreq)
{ {
const char *playlist_id; uint32_t playlist_id;
json_object *reply; json_object *reply = NULL;
int ret = 0; int ret = 0;
if (!is_modified(hreq->req, DB_ADMIN_DB_UPDATE)) if (!is_modified(hreq->req, DB_ADMIN_DB_UPDATE))
return HTTP_NOTMODIFIED; return HTTP_NOTMODIFIED;
playlist_id = hreq->uri_parsed->path_parts[3]; ret = safe_atou32(hreq->uri_parsed->path_parts[3], &playlist_id);
if (ret < 0)
{
DPRINTF(E_LOG, L_WEB, "Could not parse playlist id to integer\n");
goto error;
}
if (playlist_id == 0)
{
reply = json_object_new_object();
json_object_object_add(reply, "id", json_object_new_int(0));
json_object_object_add(reply, "name", json_object_new_string("Playlists"));
json_object_object_add(reply, "type", json_object_new_string(db_pl_type_label(PL_FOLDER)));
json_object_object_add(reply, "smart_playlist", json_object_new_boolean(false));
json_object_object_add(reply, "folder", json_object_new_boolean(true));
}
else
{
reply = fetch_playlist(playlist_id);
}
reply = fetch_playlist(playlist_id);
if (!reply) if (!reply)
{ {
ret = -1; ret = -1;

View File

@ -14,9 +14,13 @@
<span class="heading">Path</span> <span class="heading">Path</span>
<span class="title is-6">{{ playlist.path }}</span> <span class="title is-6">{{ playlist.path }}</span>
</p> </p>
<p>
<span class="heading">Type</span>
<span class="title is-6">{{ playlist.type }}</span>
</p>
</div> </div>
</div> </div>
<footer class="card-footer"> <footer class="card-footer" v-if="!playlist.folder">
<a class="card-footer-item has-text-dark" @click="queue_add"> <a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus"></i></span> <span class="is-size-7">Add</span> <span class="icon"><i class="mdi mdi-playlist-plus"></i></span> <span class="is-size-7">Add</span>
</a> </a>
@ -60,7 +64,7 @@ export default {
open_playlist: function () { open_playlist: function () {
this.$emit('close') this.$emit('close')
this.$router.push({ path: '/playlists/' + this.playlist.id }) this.$router.push({ path: '/playlists/' + this.playlist.id + '/tracks' })
} }
} }
} }

View File

@ -166,7 +166,7 @@ export default {
}, },
open_playlist: function (playlist) { open_playlist: function (playlist) {
this.$router.push({ path: '/playlists/' + playlist.id }) this.$router.push({ path: '/playlists/' + playlist.id + '/tracks' })
}, },
open_playlist_dialog: function (playlist) { open_playlist_dialog: function (playlist) {

View File

@ -1,11 +1,16 @@
<template> <template>
<content-with-heading> <content-with-heading>
<template slot="heading-left"> <template slot="heading-left">
<p class="title is-4">Playlists</p> <p class="title is-4">{{ playlist.name }}</p>
<p class="heading">{{ playlists.total }} playlists</p> <p class="heading">{{ playlists.total }} playlists</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-playlist v-for="playlist in playlists.items" :key="playlist.id" :playlist="playlist" @click="open_playlist(playlist)"> <list-item-playlist v-for="playlist in playlists.items" :key="playlist.id" :playlist="playlist" @click="open_playlist(playlist)">
<template slot="icon">
<span class="icon">
<i class="mdi" :class="{ 'mdi-library-music': playlist.type !== 'folder', 'mdi-folder': playlist.type === 'folder' }"></i>
</span>
</template>
<template slot="actions"> <template slot="actions">
<a @click="open_dialog(playlist)"> <a @click="open_dialog(playlist)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span> <span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
@ -27,11 +32,15 @@ import webapi from '@/webapi'
const playlistsData = { const playlistsData = {
load: function (to) { load: function (to) {
return webapi.library_playlists() return Promise.all([
webapi.library_playlist(to.params.playlist_id),
webapi.library_playlist_folder(to.params.playlist_id)
])
}, },
set: function (vm, response) { set: function (vm, response) {
vm.playlists = response.data vm.playlist = response[0].data
vm.playlists = response[1].data
} }
} }
@ -42,6 +51,7 @@ export default {
data () { data () {
return { return {
playlist: {},
playlists: {}, playlists: {},
show_details_modal: false, show_details_modal: false,
@ -51,7 +61,11 @@ export default {
methods: { methods: {
open_playlist: function (playlist) { open_playlist: function (playlist) {
this.$router.push({ path: '/playlists/' + playlist.id }) if (playlist.type !== 'folder') {
this.$router.push({ path: '/playlists/' + playlist.id + '/tracks' })
} else {
this.$router.push({ path: '/playlists/' + playlist.id })
}
}, },
open_dialog: function (playlist) { open_dialog: function (playlist) {

View File

@ -295,7 +295,7 @@ export default {
}, },
open_playlist: function (playlist) { open_playlist: function (playlist) {
this.$router.push({ path: '/playlists/' + playlist.id }) this.$router.push({ path: '/playlists/' + playlist.id + '/tracks' })
}, },
open_recent_search: function (query) { open_recent_search: function (query) {

View File

@ -156,12 +156,16 @@ export const router = new VueRouter({
}, },
{ {
path: '/playlists', path: '/playlists',
redirect: '/playlists/0'
},
{
path: '/playlists/:playlist_id',
name: 'Playlists', name: 'Playlists',
component: PagePlaylists, component: PagePlaylists,
meta: { show_progress: true } meta: { show_progress: true }
}, },
{ {
path: '/playlists/:playlist_id', path: '/playlists/:playlist_id/tracks',
name: 'Playlist', name: 'Playlist',
component: PagePlaylist, component: PagePlaylist,
meta: { show_progress: true } meta: { show_progress: true }

View File

@ -287,6 +287,10 @@ export default {
return axios.get('/api/library/playlists') return axios.get('/api/library/playlists')
}, },
library_playlist_folder (playlistId = 0) {
return axios.get('/api/library/playlists/' + playlistId + '/playlists')
},
library_playlist (playlistId) { library_playlist (playlistId) {
return axios.get('/api/library/playlists/' + playlistId) return axios.get('/api/library/playlists/' + playlistId)
}, },