mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-18 18:05:20 -04:00
[web] Merge from main branch
This commit is contained in:
commit
42564905e0
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -219,6 +219,9 @@ static cfg_opt_t sec_spotify[] =
|
||||
CFG_BOOL("artist_override", cfg_false, CFGF_NONE),
|
||||
CFG_BOOL("album_override", cfg_false, CFGF_NONE),
|
||||
CFG_BOOL("disable_legacy_mode", cfg_false, CFGF_NONE),
|
||||
// Issued by Spotify on developer.spotify.com for forked-daapd/OwnTone
|
||||
CFG_STR("webapi_client_id", "0e684a5422384114a8ae7ac020f01789", CFGF_NONE),
|
||||
CFG_STR("webapi_client_secret", "232af95f39014c9ba218285a5c11a239", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,9 @@ PKG_CHECK_MODULES([JSON_C], [json-c])
|
||||
PKG_CHECK_MODULES([LIBGCRYPT], [libgcrypt], [], [
|
||||
AM_PATH_LIBGCRYPT([], [], [AC_MSG_ERROR([[libgcrypt is required]])])
|
||||
])
|
||||
PKG_CHECK_MODULES([LIBCURL], [libcurl])
|
||||
|
||||
dnl Need 7.83.0 for curl_easy_nextheader()
|
||||
PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.83.0])
|
||||
PKG_CHECK_MODULES([LIBPROTOBUF_C], [libprotobuf-c])
|
||||
|
||||
AC_CONFIG_FILES([Makefile tests/Makefile])
|
||||
|
@ -147,10 +147,10 @@ static int spotify_base_plid;
|
||||
// Flag to avoid triggering playlist change events while the (re)scan is running
|
||||
static bool scanning;
|
||||
|
||||
|
||||
// Endpoints and credentials for the web api
|
||||
static const char *spotify_client_id = "0e684a5422384114a8ae7ac020f01789";
|
||||
static const char *spotify_client_secret = "232af95f39014c9ba218285a5c11a239";
|
||||
static const char *spotify_client_id;
|
||||
static const char *spotify_client_secret;
|
||||
|
||||
static const char *spotify_scope = "playlist-read-private playlist-read-collaborative user-library-read user-read-private streaming";
|
||||
|
||||
static const char *spotify_auth_uri = "https://accounts.spotify.com/authorize";
|
||||
@ -2067,6 +2067,9 @@ spotifywebapi_library_init()
|
||||
{
|
||||
int ret;
|
||||
|
||||
spotify_client_id = cfg_getstr(cfg_getsec(cfg, "spotify"), "webapi_client_id");
|
||||
spotify_client_secret = cfg_getstr(cfg_getsec(cfg, "spotify"), "webapi_client_secret");
|
||||
|
||||
ret = spotify_init();
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
@ -182,6 +182,7 @@ int mpd_lex_parse(struct mpd_result *result, const char *input);
|
||||
#include <assert.h>
|
||||
|
||||
#define INVERT_MASK 0x80000000
|
||||
#define RECURSION_MAX 64
|
||||
}
|
||||
|
||||
/* Dependencies, mocked or real */
|
||||
@ -225,6 +226,8 @@ struct mpd_result {
|
||||
|
||||
int err;
|
||||
char errmsg[128];
|
||||
|
||||
int recursion_level;
|
||||
};
|
||||
|
||||
enum mpd_type {
|
||||
@ -416,6 +419,15 @@ static void sql_append_recursive(struct mpd_result *result, struct mpd_result_pa
|
||||
{
|
||||
char escape_char;
|
||||
|
||||
if (result->recursion_level > RECURSION_MAX)
|
||||
{
|
||||
snprintf(result->errmsg, sizeof(result->errmsg), "Recursion maximum exceeded");
|
||||
result->err = -2;
|
||||
return;
|
||||
}
|
||||
|
||||
result->recursion_level++;
|
||||
|
||||
switch (append_type)
|
||||
{
|
||||
case SQL_APPEND_OPERATOR:
|
||||
@ -477,6 +489,8 @@ static void sql_append_recursive(struct mpd_result *result, struct mpd_result_pa
|
||||
sql_append(result, part, ")");
|
||||
break;
|
||||
}
|
||||
|
||||
result->recursion_level--;
|
||||
}
|
||||
|
||||
/* Creates the parsing result from the AST. Errors are set via result->err. */
|
||||
|
@ -178,6 +178,7 @@ int rsp_lex_parse(struct rsp_result *result, const char *input);
|
||||
#include <assert.h>
|
||||
|
||||
#define INVERT_MASK 0x80000000
|
||||
#define RECURSION_MAX 64
|
||||
}
|
||||
|
||||
/* Dependencies, mocked or real */
|
||||
@ -197,6 +198,8 @@ struct rsp_result {
|
||||
int offset;
|
||||
int err;
|
||||
char errmsg[128];
|
||||
|
||||
int recursion_level;
|
||||
};
|
||||
}
|
||||
|
||||
@ -272,6 +275,15 @@ static void sql_append_recursive(struct rsp_result *result, struct ast *a, const
|
||||
{
|
||||
char escape_char;
|
||||
|
||||
if (result->recursion_level > RECURSION_MAX)
|
||||
{
|
||||
snprintf(result->errmsg, sizeof(result->errmsg), "Recursion maximum exceeded");
|
||||
result->err = -2;
|
||||
return;
|
||||
}
|
||||
|
||||
result->recursion_level++;
|
||||
|
||||
switch (append_type)
|
||||
{
|
||||
case SQL_APPEND_OPERATOR:
|
||||
@ -317,6 +329,8 @@ static void sql_append_recursive(struct rsp_result *result, struct ast *a, const
|
||||
sql_append(result, ")");
|
||||
break;
|
||||
}
|
||||
|
||||
result->recursion_level--;
|
||||
}
|
||||
|
||||
static void sql_from_ast(struct rsp_result *result, struct ast *a)
|
||||
|
@ -182,6 +182,7 @@ int smartpl_lex_parse(struct smartpl_result *result, const char *input);
|
||||
#include <assert.h>
|
||||
|
||||
#define INVERT_MASK 0x80000000
|
||||
#define RECURSION_MAX 64
|
||||
}
|
||||
|
||||
/* Dependencies, mocked or real */
|
||||
@ -215,6 +216,8 @@ struct smartpl_result {
|
||||
int limit;
|
||||
int err;
|
||||
char errmsg[128];
|
||||
|
||||
int recursion_level;
|
||||
};
|
||||
}
|
||||
|
||||
@ -289,6 +292,15 @@ static void sql_append_recursive(struct smartpl_result *result, struct result_pa
|
||||
{
|
||||
char escape_char;
|
||||
|
||||
if (result->recursion_level > RECURSION_MAX)
|
||||
{
|
||||
snprintf(result->errmsg, sizeof(result->errmsg), "Recursion maximum exceeded");
|
||||
result->err = -2;
|
||||
return;
|
||||
}
|
||||
|
||||
result->recursion_level++;
|
||||
|
||||
switch (append_type)
|
||||
{
|
||||
case SQL_APPEND_OPERATOR:
|
||||
@ -359,6 +371,8 @@ static void sql_append_recursive(struct smartpl_result *result, struct result_pa
|
||||
sql_append(result, part, "', ");
|
||||
break;
|
||||
}
|
||||
|
||||
result->recursion_level--;
|
||||
}
|
||||
|
||||
/* Creates the parsing result from the AST. Errors are set via result->err. */
|
||||
|
@ -10,7 +10,8 @@
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
class="media is-align-items-center mb-0"
|
||||
:class="{ 'is-clickable': isPlayable, 'is-not-allowed': !isPlayable }"
|
||||
@click="open"
|
||||
>
|
||||
<mdicon v-if="icon" class="media-left icon" :name="icon" />
|
||||
@ -28,10 +29,14 @@
|
||||
'is-size-6': position === 0,
|
||||
'is-size-7': position !== 0,
|
||||
'has-text-weight-bold': position !== 2,
|
||||
'has-text-grey': position !== 0 || isRead
|
||||
'has-text-grey': (position !== 0 || isRead) && isPlayable,
|
||||
'has-text-grey-light': !isPlayable
|
||||
}"
|
||||
v-text="line"
|
||||
/>
|
||||
<div v-if="!isPlayable" class="is-size-7 has-text-grey">
|
||||
<slot name="reason" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="progress" class="media-right">
|
||||
<control-progress :value="progress" />
|
||||
@ -56,6 +61,7 @@ export default {
|
||||
image: { default: null, type: Object },
|
||||
index: { default: null, type: [String, Number] },
|
||||
isItem: { default: true, type: Boolean },
|
||||
isPlayable: { default: true, type: Boolean },
|
||||
isRead: { default: false, type: Boolean },
|
||||
lines: { default: null, type: Array },
|
||||
progress: { default: null, type: Number }
|
||||
@ -71,3 +77,9 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.is-not-allowed {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,29 +1,13 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.id">
|
||||
<div class="media is-align-items-center mb-0">
|
||||
<div
|
||||
class="media-content"
|
||||
:class="{
|
||||
'is-clickable': item.is_playable,
|
||||
'is-not-allowed': !item.is_playable
|
||||
}"
|
||||
@click="play(item)"
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:is-playable="item.is_playable"
|
||||
:lines="[item.name, item.artists[0].name, item.album.name]"
|
||||
@open="open(item)"
|
||||
@open-details="openDetails(item)"
|
||||
>
|
||||
<div
|
||||
class="is-size-6 has-text-weight-bold"
|
||||
:class="{ 'has-text-grey-light': !item.is_playable }"
|
||||
v-text="item.name"
|
||||
/>
|
||||
<div
|
||||
class="is-size-7 has-text-weight-bold"
|
||||
:class="{
|
||||
'has-text-grey': item.is_playable,
|
||||
'has-text-grey-light': !item.is_playable
|
||||
}"
|
||||
v-text="item.artists[0].name"
|
||||
/>
|
||||
<div class="is-size-7 has-text-grey" v-text="item.album.name" />
|
||||
<div v-if="!item.is_playable" class="is-size-7 has-text-grey">
|
||||
<template v-if="!item.is_playable" #reason>
|
||||
(<span v-text="$t('list.spotify.not-playable-track')" />
|
||||
<span
|
||||
v-if="item.restrictions?.reason"
|
||||
@ -33,15 +17,8 @@
|
||||
})
|
||||
"
|
||||
/>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDetails(item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</list-item>
|
||||
<modal-dialog-track-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@ -50,12 +27,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogTrackSpotify from '@/components/ModalDialogTrackSpotify.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ListTracksSpotify',
|
||||
components: { ModalDialogTrackSpotify },
|
||||
components: { ListItem, ModalDialogTrackSpotify },
|
||||
props: {
|
||||
contextUri: { default: '', type: String },
|
||||
items: { required: true, type: Object }
|
||||
@ -64,11 +42,7 @@ export default {
|
||||
return { selectedItem: {}, showDetailsModal: false }
|
||||
},
|
||||
methods: {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play(item) {
|
||||
open(item) {
|
||||
if (item.is_playable) {
|
||||
webapi.player_play_uri(
|
||||
this.contextUri || item.uri,
|
||||
@ -76,13 +50,11 @@ export default {
|
||||
item.position || 0
|
||||
)
|
||||
}
|
||||
},
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.is-not-allowed {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user