mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-25 04:19:15 -05:00
Merge pull request #530 from chme/spotify_rework
Allow playing arbitrary spotify tracks
This commit is contained in:
commit
f5d7477ddb
@ -1072,6 +1072,9 @@ artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h)
|
|||||||
|
|
||||||
DPRINTF(E_DBG, L_ART, "Artwork request for item %d\n", id);
|
DPRINTF(E_DBG, L_ART, "Artwork request for item %d\n", id);
|
||||||
|
|
||||||
|
if (id == DB_MEDIA_FILE_NON_PERSISTENT_ID)
|
||||||
|
return -1;
|
||||||
|
|
||||||
memset(&ctx, 0, sizeof(struct artwork_ctx));
|
memset(&ctx, 0, sizeof(struct artwork_ctx));
|
||||||
|
|
||||||
ctx.qp.type = Q_ITEMS;
|
ctx.qp.type = Q_ITEMS;
|
||||||
|
@ -1499,6 +1499,9 @@ artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h)
|
|||||||
|
|
||||||
DPRINTF(E_DBG, L_ART, "Artwork request for item %d\n", id);
|
DPRINTF(E_DBG, L_ART, "Artwork request for item %d\n", id);
|
||||||
|
|
||||||
|
if (id == DB_MEDIA_FILE_NON_PERSISTENT_ID)
|
||||||
|
return -1;
|
||||||
|
|
||||||
memset(&ctx, 0, sizeof(struct artwork_ctx));
|
memset(&ctx, 0, sizeof(struct artwork_ctx));
|
||||||
|
|
||||||
ctx.qp.type = Q_ITEMS;
|
ctx.qp.type = Q_ITEMS;
|
||||||
|
@ -627,6 +627,7 @@ jsonapi_reply_spotify(struct httpd_request *hreq)
|
|||||||
char *oauth_uri;
|
char *oauth_uri;
|
||||||
struct spotify_status_info info;
|
struct spotify_status_info info;
|
||||||
struct spotifywebapi_status_info webapi_info;
|
struct spotifywebapi_status_info webapi_info;
|
||||||
|
struct spotifywebapi_access_token webapi_token;
|
||||||
|
|
||||||
json_object_object_add(jreply, "enabled", json_object_new_boolean(true));
|
json_object_object_add(jreply, "enabled", json_object_new_boolean(true));
|
||||||
|
|
||||||
@ -647,11 +648,16 @@ jsonapi_reply_spotify(struct httpd_request *hreq)
|
|||||||
spotify_status_info_get(&info);
|
spotify_status_info_get(&info);
|
||||||
json_object_object_add(jreply, "libspotify_installed", json_object_new_boolean(info.libspotify_installed));
|
json_object_object_add(jreply, "libspotify_installed", json_object_new_boolean(info.libspotify_installed));
|
||||||
json_object_object_add(jreply, "libspotify_logged_in", json_object_new_boolean(info.libspotify_logged_in));
|
json_object_object_add(jreply, "libspotify_logged_in", json_object_new_boolean(info.libspotify_logged_in));
|
||||||
json_object_object_add(jreply, "libspotify_user", json_object_new_string(info.libspotify_user));
|
safe_json_add_string(jreply, "libspotify_user", info.libspotify_user);
|
||||||
|
|
||||||
spotifywebapi_status_info_get(&webapi_info);
|
spotifywebapi_status_info_get(&webapi_info);
|
||||||
json_object_object_add(jreply, "webapi_token_valid", json_object_new_boolean(webapi_info.token_valid));
|
json_object_object_add(jreply, "webapi_token_valid", json_object_new_boolean(webapi_info.token_valid));
|
||||||
json_object_object_add(jreply, "webapi_user", json_object_new_string(webapi_info.user));
|
safe_json_add_string(jreply, "webapi_user", webapi_info.user);
|
||||||
|
safe_json_add_string(jreply, "webapi_country", webapi_info.country);
|
||||||
|
|
||||||
|
spotifywebapi_access_token_get(&webapi_token);
|
||||||
|
safe_json_add_string(jreply, "webapi_token", webapi_token.token);
|
||||||
|
json_object_object_add(jreply, "webapi_token_expires_in", json_object_new_int(webapi_token.expires_in));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
json_object_object_add(jreply, "enabled", json_object_new_boolean(false));
|
json_object_object_add(jreply, "enabled", json_object_new_boolean(false));
|
||||||
@ -1611,8 +1617,13 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
|
|||||||
queue_tracks_add_playlist(id);
|
queue_tracks_add_playlist(id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
ret = library_queue_add(uri);
|
||||||
|
if (ret != LIBRARY_OK)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_WEB, "Invalid uri '%s'\n", uri);
|
DPRINTF(E_LOG, L_WEB, "Invalid uri '%s'\n", uri);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while ((uri = strtok(NULL, ",")));
|
while ((uri = strtok(NULL, ",")));
|
||||||
|
@ -22,14 +22,30 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "spotify.h"
|
#include "spotify.h"
|
||||||
|
|
||||||
|
// How many retries to start playback if resource is still loading
|
||||||
|
#define SPOTIFY_SETUP_RETRIES 5
|
||||||
|
// How long to wait between retries in microseconds (500000 = 0.5 seconds)
|
||||||
|
#define SPOTIFY_SETUP_RETRY_WAIT 500000
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setup(struct player_source *ps)
|
setup(struct player_source *ps)
|
||||||
{
|
{
|
||||||
|
int i = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = spotify_playback_setup(ps->path);
|
while((ret = spotify_playback_setup(ps->path)) == SPOTIFY_SETUP_ERROR_IS_LOADING)
|
||||||
|
{
|
||||||
|
if (i >= SPOTIFY_SETUP_RETRIES)
|
||||||
|
break;
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_SPOTIFY, "Resource still loading (%d)\n", i);
|
||||||
|
usleep(SPOTIFY_SETUP_RETRY_WAIT);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -604,7 +604,7 @@ playback_setup(void *arg, int *retval)
|
|||||||
if (SP_ERROR_OK != err)
|
if (SP_ERROR_OK != err)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SPOTIFY, "Playback setup failed: %s\n", fptr_sp_error_message(err));
|
DPRINTF(E_LOG, L_SPOTIFY, "Playback setup failed: %s\n", fptr_sp_error_message(err));
|
||||||
*retval = -1;
|
*retval = (SP_ERROR_IS_LOADING == err) ? SPOTIFY_SETUP_ERROR_IS_LOADING : -1;
|
||||||
return COMMAND_END;
|
return COMMAND_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ struct spotify_status_info
|
|||||||
char libspotify_user[100];
|
char libspotify_user[100];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SPOTIFY_SETUP_ERROR_IS_LOADING -2
|
||||||
|
|
||||||
int
|
int
|
||||||
spotify_playback_setup(const char *path);
|
spotify_playback_setup(const char *path);
|
||||||
|
|
||||||
|
@ -119,9 +119,13 @@ static const char *spotify_client_secret = "232af95f39014c9ba218285a5c11a239";
|
|||||||
static const char *spotify_auth_uri = "https://accounts.spotify.com/authorize";
|
static const char *spotify_auth_uri = "https://accounts.spotify.com/authorize";
|
||||||
static const char *spotify_token_uri = "https://accounts.spotify.com/api/token";
|
static const char *spotify_token_uri = "https://accounts.spotify.com/api/token";
|
||||||
static const char *spotify_playlist_uri = "https://api.spotify.com/v1/users/%s/playlists/%s";
|
static const char *spotify_playlist_uri = "https://api.spotify.com/v1/users/%s/playlists/%s";
|
||||||
|
static const char *spotify_track_uri = "https://api.spotify.com/v1/tracks/%s";
|
||||||
static const char *spotify_me_uri = "https://api.spotify.com/v1/me";
|
static const char *spotify_me_uri = "https://api.spotify.com/v1/me";
|
||||||
static const char *spotify_albums_uri = "https://api.spotify.com/v1/me/albums?limit=50";
|
static const char *spotify_albums_uri = "https://api.spotify.com/v1/me/albums?limit=50";
|
||||||
|
static const char *spotify_album_uri = "https://api.spotify.com/v1/albums/%s";
|
||||||
|
static const char *spotify_album_tracks_uri = "https://api.spotify.com/v1/albums/%s/tracks";
|
||||||
static const char *spotify_playlists_uri = "https://api.spotify.com/v1/me/playlists?limit=50";
|
static const char *spotify_playlists_uri = "https://api.spotify.com/v1/me/playlists?limit=50";
|
||||||
|
static const char *spotify_playlist_tracks_uri = "https://api.spotify.com/v1/users/%s/playlists/%s/tracks";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -716,6 +720,7 @@ get_owner_plid_from_uri(const char *uri, char **owner, char **plid)
|
|||||||
if (!ptr1)
|
if (!ptr1)
|
||||||
{
|
{
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
*owner = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ptr1++;
|
ptr1++;
|
||||||
@ -731,6 +736,22 @@ get_owner_plid_from_uri(const char *uri, char **owner, char **plid)
|
|||||||
* @param uri Playlist uri (e. g. "spotify:user:username:playlist:59ZbFPES4DQwEjBpWHzrtC")
|
* @param uri Playlist uri (e. g. "spotify:user:username:playlist:59ZbFPES4DQwEjBpWHzrtC")
|
||||||
* @return Playlist endpoint uri (e. g. "https://api.spotify.com/v1/users/username/playlists/59ZbFPES4DQwEjBpWHzrtC")
|
* @return Playlist endpoint uri (e. g. "https://api.spotify.com/v1/users/username/playlists/59ZbFPES4DQwEjBpWHzrtC")
|
||||||
*/
|
*/
|
||||||
|
static int
|
||||||
|
get_id_from_uri(const char *uri, char **id)
|
||||||
|
{
|
||||||
|
char *tmp;
|
||||||
|
tmp = strrchr(uri, ':');
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tmp++;
|
||||||
|
|
||||||
|
*id = strdup(tmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_playlist_endpoint_uri(const char *uri)
|
get_playlist_endpoint_uri(const char *uri)
|
||||||
{
|
{
|
||||||
@ -754,6 +775,105 @@ get_playlist_endpoint_uri(const char *uri)
|
|||||||
return endpoint_uri;
|
return endpoint_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_playlist_tracks_endpoint_uri(const char *uri)
|
||||||
|
{
|
||||||
|
char *endpoint_uri = NULL;
|
||||||
|
char *owner = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_owner_plid_from_uri(uri, &owner, &id);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SPOTIFY, "Error extracting owner and id from playlist uri '%s'\n", uri);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_uri = safe_asprintf(spotify_playlist_tracks_uri, owner, id);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(owner);
|
||||||
|
free(id);
|
||||||
|
return endpoint_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_album_endpoint_uri(const char *uri)
|
||||||
|
{
|
||||||
|
char *endpoint_uri = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_id_from_uri(uri, &id);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SPOTIFY, "Error extracting id from uri '%s'\n", uri);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_uri = safe_asprintf(spotify_album_uri, id);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(id);
|
||||||
|
return endpoint_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_album_tracks_endpoint_uri(const char *uri)
|
||||||
|
{
|
||||||
|
char *endpoint_uri = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_id_from_uri(uri, &id);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SPOTIFY, "Error extracting id from uri '%s'\n", uri);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_uri = safe_asprintf(spotify_album_tracks_uri, id);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(id);
|
||||||
|
return endpoint_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_track_endpoint_uri(const char *uri)
|
||||||
|
{
|
||||||
|
char *endpoint_uri = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_id_from_uri(uri, &id);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SPOTIFY, "Error extracting id from track uri '%s'\n", uri);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_uri = safe_asprintf(spotify_track_uri, id);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(id);
|
||||||
|
return endpoint_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_object *
|
||||||
|
request_track(const char *path)
|
||||||
|
{
|
||||||
|
char *endpoint_uri;
|
||||||
|
json_object *response;
|
||||||
|
|
||||||
|
endpoint_uri = get_track_endpoint_uri(path);
|
||||||
|
response = request_endpoint_with_token_refresh(endpoint_uri);
|
||||||
|
free(endpoint_uri);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
/* Thread: httpd */
|
/* Thread: httpd */
|
||||||
char *
|
char *
|
||||||
spotifywebapi_oauth_uri_get(const char *redirect_uri)
|
spotifywebapi_oauth_uri_get(const char *redirect_uri)
|
||||||
@ -841,6 +961,217 @@ transaction_end(void *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
map_track_to_queueitem(struct db_queue_item *item, const struct spotify_track *track, const struct spotify_album *album)
|
||||||
|
{
|
||||||
|
char virtual_path[PATH_MAX];
|
||||||
|
|
||||||
|
memset(item, 0, sizeof(struct db_queue_item));
|
||||||
|
|
||||||
|
item->file_id = DB_MEDIA_FILE_NON_PERSISTENT_ID;
|
||||||
|
item->title = safe_strdup(track->name);
|
||||||
|
item->artist = safe_strdup(track->artist);
|
||||||
|
|
||||||
|
if (album)
|
||||||
|
{
|
||||||
|
item->album_artist = safe_strdup(album->artist);
|
||||||
|
item->album = safe_strdup(album->name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item->album_artist = safe_strdup(track->album_artist);
|
||||||
|
item->album = safe_strdup(track->album);
|
||||||
|
}
|
||||||
|
|
||||||
|
item->disc = track->disc_number;
|
||||||
|
item->song_length = track->duration_ms;
|
||||||
|
item->track = track->track_number;
|
||||||
|
|
||||||
|
item->data_kind = DATA_KIND_SPOTIFY;
|
||||||
|
item->media_kind = MEDIA_KIND_MUSIC;
|
||||||
|
|
||||||
|
item->path = safe_strdup(track->uri);
|
||||||
|
|
||||||
|
snprintf(virtual_path, PATH_MAX, "/%s", track->uri);
|
||||||
|
item->virtual_path = strdup(virtual_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
queue_add_track(const char *uri)
|
||||||
|
{
|
||||||
|
json_object *response;
|
||||||
|
struct spotify_track track;
|
||||||
|
struct db_queue_item item;
|
||||||
|
struct db_queue_add_info queue_add_info;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
response = request_track(uri);
|
||||||
|
if (!response)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
parse_metadata_track(response, &track);
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_SPOTIFY, "Got track: '%s' (%s) \n", track.name, track.uri);
|
||||||
|
|
||||||
|
map_track_to_queueitem(&item, &track, NULL);
|
||||||
|
|
||||||
|
ret = db_queue_add_start(&queue_add_info);
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
ret = db_queue_add_item(&queue_add_info, &item);
|
||||||
|
db_queue_add_end(&queue_add_info, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_queue_item(&item, 1);
|
||||||
|
jparse_free(response);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct queue_add_album_param {
|
||||||
|
struct spotify_album album;
|
||||||
|
struct db_queue_add_info queue_add_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
queue_add_album_tracks(json_object *item, int index, int total, void *arg)
|
||||||
|
{
|
||||||
|
struct queue_add_album_param *param;
|
||||||
|
struct spotify_track track;
|
||||||
|
struct db_queue_item queue_item;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
param = arg;
|
||||||
|
|
||||||
|
parse_metadata_track(item, &track);
|
||||||
|
|
||||||
|
if (!track.uri || !track.is_playable)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SPOTIFY, "Track not available for playback: '%s' - '%s' (%s) (restrictions: %s)\n", track.artist, track.name, track.uri, track.restrictions);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_track_to_queueitem(&queue_item, &track, ¶m->album);
|
||||||
|
|
||||||
|
ret = db_queue_add_item(¶m->queue_add_info, &queue_item);
|
||||||
|
|
||||||
|
free_queue_item(&queue_item, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
queue_add_album(const char *uri)
|
||||||
|
{
|
||||||
|
char *album_endpoint_uri = NULL;
|
||||||
|
char *endpoint_uri = NULL;
|
||||||
|
json_object *json_album;
|
||||||
|
struct queue_add_album_param param;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
album_endpoint_uri = get_album_endpoint_uri(uri);
|
||||||
|
json_album = request_endpoint_with_token_refresh(album_endpoint_uri);
|
||||||
|
parse_metadata_album(json_album, ¶m.album);
|
||||||
|
|
||||||
|
ret = db_queue_add_start(¶m.queue_add_info);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
endpoint_uri = get_album_tracks_endpoint_uri(uri);
|
||||||
|
|
||||||
|
ret = request_pagingobject_endpoint(endpoint_uri, queue_add_album_tracks, NULL, NULL, true, ¶m);
|
||||||
|
|
||||||
|
db_queue_add_end(¶m.queue_add_info, ret);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(album_endpoint_uri);
|
||||||
|
free(endpoint_uri);
|
||||||
|
jparse_free(json_album);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
queue_add_playlist_tracks(json_object *item, int index, int total, void *arg)
|
||||||
|
{
|
||||||
|
struct db_queue_add_info *queue_add_info;
|
||||||
|
struct spotify_track track;
|
||||||
|
json_object *jsontrack;
|
||||||
|
struct db_queue_item queue_item;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
queue_add_info = arg;
|
||||||
|
|
||||||
|
if (!(item && json_object_object_get_ex(item, "track", &jsontrack)))
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SPOTIFY, "Unexpected JSON: missing 'track' in JSON object at index %d\n", index);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_metadata_track(jsontrack, &track);
|
||||||
|
track.added_at = jparse_str_from_obj(item, "added_at");
|
||||||
|
track.mtime = jparse_time_from_obj(item, "added_at");
|
||||||
|
|
||||||
|
if (!track.uri || !track.is_playable)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SPOTIFY, "Track not available for playback: '%s' - '%s' (%s) (restrictions: %s)\n", track.artist, track.name, track.uri, track.restrictions);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_track_to_queueitem(&queue_item, &track, NULL);
|
||||||
|
|
||||||
|
ret = db_queue_add_item(queue_add_info, &queue_item);
|
||||||
|
|
||||||
|
free_queue_item(&queue_item, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
queue_add_playlist(const char *uri)
|
||||||
|
{
|
||||||
|
char *endpoint_uri;
|
||||||
|
struct db_queue_add_info queue_add_info;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = db_queue_add_start(&queue_add_info);
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
endpoint_uri = get_playlist_tracks_endpoint_uri(uri);
|
||||||
|
|
||||||
|
ret = request_pagingobject_endpoint(endpoint_uri, queue_add_playlist_tracks, NULL, NULL, true, &queue_add_info);
|
||||||
|
|
||||||
|
db_queue_add_end(&queue_add_info, ret);
|
||||||
|
|
||||||
|
free(endpoint_uri);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
queue_add(const char *uri)
|
||||||
|
{
|
||||||
|
if (strncasecmp(uri, "spotify:track:", strlen("spotify:track:")) == 0)
|
||||||
|
{
|
||||||
|
queue_add_track(uri);
|
||||||
|
return LIBRARY_OK;
|
||||||
|
}
|
||||||
|
else if (strncasecmp(uri, "spotify:album:", strlen("spotify:album:")) == 0)
|
||||||
|
{
|
||||||
|
queue_add_album(uri);
|
||||||
|
return LIBRARY_OK;
|
||||||
|
}
|
||||||
|
else if (strncasecmp(uri, "spotify:", strlen("spotify:")) == 0)
|
||||||
|
{
|
||||||
|
queue_add_playlist(uri);
|
||||||
|
return LIBRARY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBRARY_PATH_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the directory id for /spotify:/<artist>/<album>, if the directory (or the parent
|
* Returns the directory id for /spotify:/<artist>/<album>, if the directory (or the parent
|
||||||
* directories) does not yet exist, they will be created.
|
* directories) does not yet exist, they will be created.
|
||||||
@ -1449,6 +1780,29 @@ spotifywebapi_status_info_get(struct spotifywebapi_status_info *info)
|
|||||||
{
|
{
|
||||||
memcpy(info->user, spotify_user, (sizeof(info->user) - 1));
|
memcpy(info->user, spotify_user, (sizeof(info->user) - 1));
|
||||||
}
|
}
|
||||||
|
if (spotify_user_country)
|
||||||
|
{
|
||||||
|
memcpy(info->country, spotify_user_country, (sizeof(info->country) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&token_lck));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
spotifywebapi_access_token_get(struct spotifywebapi_access_token *info)
|
||||||
|
{
|
||||||
|
token_refresh();
|
||||||
|
|
||||||
|
memset(info, 0, sizeof(struct spotifywebapi_access_token));
|
||||||
|
|
||||||
|
CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&token_lck));
|
||||||
|
|
||||||
|
if (token_requested > 0)
|
||||||
|
info->expires_in = expires_in - difftime(time(NULL), token_requested);
|
||||||
|
else
|
||||||
|
info->expires_in = 0;
|
||||||
|
|
||||||
|
info->token = safe_strdup(spotify_access_token);
|
||||||
|
|
||||||
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&token_lck));
|
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&token_lck));
|
||||||
}
|
}
|
||||||
@ -1481,5 +1835,6 @@ struct library_source spotifyscanner =
|
|||||||
.rescan = rescan,
|
.rescan = rescan,
|
||||||
.initscan = initscan,
|
.initscan = initscan,
|
||||||
.fullrescan = fullrescan,
|
.fullrescan = fullrescan,
|
||||||
|
.queue_add = queue_add,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +30,13 @@ struct spotifywebapi_status_info
|
|||||||
{
|
{
|
||||||
bool token_valid;
|
bool token_valid;
|
||||||
char user[100];
|
char user[100];
|
||||||
|
char country[3]; // ISO 3166-1 alpha-2 country code
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spotifywebapi_access_token
|
||||||
|
{
|
||||||
|
int expires_in;
|
||||||
|
char *token;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -49,5 +56,7 @@ spotifywebapi_pl_remove(const char *uri);
|
|||||||
|
|
||||||
void
|
void
|
||||||
spotifywebapi_status_info_get(struct spotifywebapi_status_info *info);
|
spotifywebapi_status_info_get(struct spotifywebapi_status_info *info);
|
||||||
|
void
|
||||||
|
spotifywebapi_access_token_get(struct spotifywebapi_access_token *info);
|
||||||
|
|
||||||
#endif /* SRC_SPOTIFY_WEBAPI_H_ */
|
#endif /* SRC_SPOTIFY_WEBAPI_H_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user