Merge pull request #703 from chme/json_web

Small JSON API fixes + small web interface updates (v0.5.1)
This commit is contained in:
Christian Meffert 2019-02-24 07:30:47 +01:00 committed by GitHub
commit fb98eb68ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 896 additions and 267 deletions

View File

@ -600,6 +600,7 @@ POST /api/queue/items/add
| expression | A smart playlist query expression identifying the tracks that will be added to the queue. |
| position | *(Optional)* If a position is given, new items are inserted starting from this position into the queue. |
| playback | *(Optional)* If the `playback` parameter is set to `start`, playback will be started after adding the new items. |
| playback_from_position | *(Optional)* If the `playback` parameter is set to `start`, playback will be started with the queue item at the position given in `playback_from_position`. |
| clear | *(Optional)* If the `clear` parameter is set to `true`, the queue will be cleared before adding the new items. |
| shuffle | *(Optional)* If the `shuffle` parameter is set to `true`, the shuffle mode is activated. If it is set to something else, the shuffle mode is deactivated. To leave the shuffle mode untouched the parameter should be ommited. |
@ -2048,7 +2049,7 @@ curl --include \
| date_released | string | Date in the format `yyyy-mm-dd` |
| seek_ms | integer | Resume point in milliseconds (available only for podcasts and audiobooks) |
| media_kind | string | Media type of this track: `music`, `movie`, `podcast`, `audiobook`, `musicvideo`, `tvshow` |
| data_kind | string | Data type of this track: `file`, `stream`, `spotify`, `pipe` |
| data_kind | string | Data type of this track: `file`, `url`, `spotify`, `pipe` |
| path | string | Path |
| uri | string | Resource identifier |
| artwork_url | string | *(optional)* [Artwork url](#artwork-urls) |

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1893,7 +1893,7 @@ queue_tracks_add_byexpression(const char *param, int pos, int *total_count)
memset(&query_params, 0, sizeof(struct query_params));
query_params.type = Q_ITEMS;
query_params.sort = S_ALBUM;
query_params.sort = S_NAME;
query_params.idx_type = I_NONE;
memset(&smartpl_expression, 0, sizeof(struct smartpl));
@ -1905,13 +1905,14 @@ queue_tracks_add_byexpression(const char *param, int pos, int *total_count)
return -1;
query_params.filter = strdup(smartpl_expression.query_where);
query_params.order = safe_strdup(smartpl_expression.order);
free_smartpl(&smartpl_expression, 1);
player_get_status(&status);
ret = db_queue_add_by_query(&query_params, status.shuffle, status.item_id, pos, total_count, NULL);
free(query_params.filter);
free_query_params(&query_params, 1);
return ret;
@ -1995,7 +1996,10 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
param = evhttp_find_header(hreq->query, "playback");
if (param && strcmp(param, "start") == 0)
{
player_playback_start();
if ((param = evhttp_find_header(hreq->query, "playback_from_position")))
play_item_at_position(param);
else
player_playback_start();
}
return HTTP_OK;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "forked-daapd-web",
"version": "0.5.0",
"version": "0.5.1",
"description": "forked-daapd web interface",
"author": "chme <christian.meffert@googlemail.com>",
"license": "GPL-2.0",
@ -20,7 +20,7 @@
"npm": "^6.8.0",
"reconnectingwebsocket": "^1.0.0",
"spotify-web-api-js": "^1.2.0",
"vue": "^2.6.6",
"vue": "^2.6.7",
"vue-infinite-loading": "^2.4.3",
"vue-progressbar": "^0.7.4",
"vue-range-slider": "^0.6.0",
@ -29,10 +29,10 @@
"vuex": "^3.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.4.0",
"@vue/cli-plugin-eslint": "^3.4.0",
"@vue/cli-service": "^3.4.0",
"@vue/cli-plugin-babel": "^3.4.1",
"@vue/cli-plugin-eslint": "^3.4.1",
"@vue/cli-service": "^3.4.1",
"@vue/eslint-config-standard": "^3.0.5",
"vue-template-compiler": "^2.6.6"
"vue-template-compiler": "^2.6.7"
}
}

View File

@ -39,23 +39,17 @@ export default {
methods: {
play: function () {
this.$emit('close')
webapi.search({ 'type': 'tracks', 'expression': 'path starts with "' + this.directory.path + '" order by path asc' }).then(({ data }) => {
webapi.player_play_uri(data.tracks.items.map(a => a.uri).join(','), false)
})
webapi.player_play_expression('path starts with "' + this.directory.path + '" order by path asc', false)
},
queue_add: function () {
this.$emit('close')
webapi.search({ 'type': 'tracks', 'expression': 'path starts with "' + this.directory.path + '" order by path asc' }).then(({ data }) => {
webapi.queue_add(data.tracks.items.map(a => a.uri).join(','))
})
webapi.queue_expression_add('path starts with "' + this.directory.path + '" order by path asc')
},
queue_add_next: function () {
this.$emit('close')
webapi.search({ 'type': 'tracks', 'expression': 'path starts with "' + this.directory.path + '" order by path asc' }).then(({ data }) => {
webapi.queue_add_next(data.tracks.items.map(a => a.uri).join(','))
})
webapi.queue_expression_add_next('path starts with "' + this.directory.path + '" order by path asc')
}
}
}

View File

@ -39,23 +39,17 @@ export default {
methods: {
play: function () {
this.$emit('close')
webapi.library_genre_tracks(this.genre.name).then(({ data }) =>
webapi.player_play_uri(data.tracks.items.map(a => a.uri).join(','), false)
)
webapi.player_play_expression('genre is "' + this.genre.name + '" and media_kind is music', false)
},
queue_add: function () {
this.$emit('close')
webapi.library_genre_tracks(this.genre.name).then(({ data }) =>
webapi.queue_add(data.tracks.items.map(a => a.uri).join(','))
)
webapi.queue_expression_add('genre is "' + this.genre.name + '" and media_kind is music')
},
queue_add_next: function () {
this.$emit('close')
webapi.library_genre_tracks(this.genre.name).then(({ data }) =>
webapi.queue_add_next(data.tracks.items.map(a => a.uri).join(','))
)
webapi.queue_expression_add_next('genre is "' + this.genre.name + '" and media_kind is music')
},
open_genre: function () {

View File

@ -47,6 +47,10 @@
<span class="heading">Path</span>
<span class="title is-6">{{ item.path }}</span>
</p>
<p>
<span class="heading">Type</span>
<span class="title is-6">{{ item.media_kind }} - {{ item.data_kind }} <span class="has-text-weight-normal" v-if="item.data_kind === 'spotify'">(<a @click="open_spotify_artist">artist</a>, <a @click="open_spotify_album">album</a>)</span></span>
</p>
</div>
</div>
<footer class="card-footer">
@ -67,11 +71,18 @@
<script>
import webapi from '@/webapi'
import SpotifyWebApi from 'spotify-web-api-js'
export default {
name: 'ModalDialogQueueItem',
props: [ 'show', 'item' ],
data () {
return {
spotify_track: {}
}
},
methods: {
remove: function () {
this.$emit('close')
@ -99,6 +110,30 @@ export default {
open_genre: function () {
this.$router.push({ name: 'Genre', params: { genre: this.item.genre } })
},
open_spotify_artist: function () {
this.$emit('close')
this.$router.push({ path: '/music/spotify/artists/' + this.spotify_track.artists[0].id })
},
open_spotify_album: function () {
this.$emit('close')
this.$router.push({ path: '/music/spotify/albums/' + this.spotify_track.album.id })
}
},
watch: {
'item' () {
if (this.item && this.item.data_kind === 'spotify') {
const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(this.$store.state.spotify.webapi_token)
spotifyApi.getTrack(this.item.path.slice(this.item.path.lastIndexOf(':') + 1)).then((response) => {
this.spotify_track = response
})
} else {
this.spotify_track = {}
}
}
}
}

View File

@ -8,7 +8,7 @@
<div>
<p class="is-size-7 fd-is-text-clipped">
<strong>{{ now_playing.title }}</strong><br>
{{ now_playing.artist }}
{{ now_playing.artist }}<span v-if="now_playing.data_kind === 'url'"> - {{ now_playing.album }}</span>
</p>
</div>
</router-link>

View File

@ -153,9 +153,7 @@ export default {
},
play: function () {
webapi.search({ 'type': 'tracks', 'expression': 'path starts with "' + this.current_directory + '" order by path asc' }).then(({ data }) => {
webapi.player_play_uri(data.tracks.items.map(a => a.uri).join(','), false)
})
webapi.player_play_expression('path starts with "' + this.current_directory + '" order by path asc', false)
},
play_track: function (position) {

View File

@ -85,9 +85,7 @@ export default {
},
play: function () {
webapi.library_genre_tracks(this.name).then(({ data }) =>
webapi.player_play_uri(data.tracks.items.map(a => a.uri).join(','), true)
)
webapi.player_play_expression('genre is "' + this.name + '" and media_kind is music', true)
},
open_album: function (album) {

View File

@ -84,11 +84,11 @@ export default {
},
play: function () {
webapi.player_play_uri(this.tracks.items.map(a => a.uri).join(','), true)
webapi.player_play_expression('genre is "' + this.genre + '" and media_kind is music', true)
},
play_track: function (position) {
webapi.player_play_uri(this.tracks.items.map(a => a.uri).join(','), false, position)
webapi.player_play_expression('genre is "' + this.genre + '" and media_kind is music', false, position)
},
open_dialog: function (track) {

View File

@ -41,11 +41,9 @@ export default {
return axios.put('/api/queue/items/' + itemId + '?new_position=' + newPosition)
},
queue_add (uri, showNotification = true) {
queue_add (uri) {
return axios.post('/api/queue/items/add?uris=' + uri).then((response) => {
if (showNotification) {
store.dispatch('add_notification', { text: response.data.count + ' tracks appended to queue', type: 'info', timeout: 2000 })
}
store.dispatch('add_notification', { text: response.data.count + ' tracks appended to queue', type: 'info', timeout: 2000 })
return Promise.resolve(response)
})
},
@ -61,18 +59,54 @@ export default {
})
},
queue_expression_add (expression) {
var options = {}
options.expression = expression
return axios.post('/api/queue/items/add', undefined, { params: options }).then((response) => {
store.dispatch('add_notification', { text: response.data.count + ' tracks appended to queue', type: 'info', timeout: 2000 })
return Promise.resolve(response)
})
},
queue_expression_add_next (expression) {
var options = {}
options.expression = expression
options.position = 0
if (store.getters.now_playing && store.getters.now_playing.id) {
options.position = store.getters.now_playing.position + 1
}
return axios.post('/api/queue/items/add', undefined, { params: options }).then((response) => {
store.dispatch('add_notification', { text: response.data.count + ' tracks appended to queue', type: 'info', timeout: 2000 })
return Promise.resolve(response)
})
},
player_status () {
return axios.get('/api/player')
},
player_play_uri (uris, shuffle, position = undefined) {
return this.queue_clear().then(() =>
this.player_shuffle(shuffle).then(() =>
this.queue_add(uris, false).then(() =>
this.player_play({ 'position': position })
)
)
)
var options = {}
options.uris = uris
options.shuffle = shuffle ? 'true' : 'false'
options.clear = 'true'
options.playback = 'start'
options.playback_from_position = position
return axios.post('/api/queue/items/add', undefined, { params: options })
},
player_play_expression (expression, shuffle, position = undefined) {
var options = {}
options.expression = expression
options.shuffle = shuffle ? 'true' : 'false'
options.clear = 'true'
options.playback = 'start'
options.playback_from_position = position
return axios.post('/api/queue/items/add', undefined, { params: options })
},
player_play (options = {}) {