[spotify] Reintroduce libspotify support, change spotifyc to librespot-c

Select use of either libspotify or librespot-c as streaming backend via config
option.

librespot-c (renamed/improved spotifyc) impl has the following:
- sync interface
- seek support
- honor bitrate config, set client and thread name
- use web access token with "streaming" scope for login
- fix issue with podcast playback

Also say goodbye to file-based Spotify login.
This commit is contained in:
ejurgensen
2021-04-08 22:53:19 +02:00
parent 2bbc5f16c5
commit 6f0fef6179
77 changed files with 6007 additions and 3755 deletions

View File

@@ -67,9 +67,6 @@
#ifdef LASTFM
# include "lastfm.h"
#endif
#ifdef SPOTIFY
# include "spotify.h"
#endif
#define F_SCAN_BULK (1 << 0)
@@ -95,7 +92,6 @@ enum file_type {
FILE_CTRL_REMOTE,
FILE_CTRL_RAOP_VERIFICATION,
FILE_CTRL_LASTFM,
FILE_CTRL_SPOTIFY,
FILE_CTRL_INITSCAN,
FILE_CTRL_METASCAN, // forced scan for meta, preserves existing db records
FILE_CTRL_FULLSCAN,
@@ -350,9 +346,6 @@ file_type_get(const char *path) {
if (strcasecmp(ext, ".lastfm") == 0)
return FILE_CTRL_LASTFM;
if (strcasecmp(ext, ".spotify") == 0)
return FILE_CTRL_SPOTIFY;
if (strcasecmp(ext, ".init-rescan") == 0)
return FILE_CTRL_INITSCAN;
@@ -700,17 +693,6 @@ process_file(char *file, struct stat *sb, enum file_type file_type, int scan_typ
#endif
break;
case FILE_CTRL_SPOTIFY:
#ifdef SPOTIFY
if (flags & F_SCAN_BULK)
DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file);
else
kickoff(spotify_login, file, 2);
#else
DPRINTF(E_LOG, L_SCAN, "Found '%s', but this version was built without Spotify support\n", file);
#endif
break;
case FILE_CTRL_INITSCAN:
if (flags & F_SCAN_BULK)
break;

View File

@@ -35,6 +35,7 @@
#include "listener.h"
#include "logger.h"
#include "misc_json.h"
#include "inputs/spotify.h"
enum spotify_request_type {
@@ -134,7 +135,7 @@ 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_scope = "playlist-read-private playlist-read-collaborative user-library-read user-read-private";
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";
static const char *spotify_token_uri = "https://accounts.spotify.com/api/token";
@@ -974,10 +975,9 @@ spotifywebapi_oauth_uri_get(const char *redirect_uri)
/* Thread: httpd */
int
spotifywebapi_oauth_callback(struct evkeyvalq *param, const char *redirect_uri, char **errmsg)
spotifywebapi_oauth_callback(struct evkeyvalq *param, const char *redirect_uri, const char **errmsg)
{
const char *code;
const char *err;
int ret;
*errmsg = NULL;
@@ -985,18 +985,19 @@ spotifywebapi_oauth_callback(struct evkeyvalq *param, const char *redirect_uri,
code = evhttp_find_header(param, "code");
if (!code)
{
*errmsg = safe_asprintf("Error: Didn't receive a code from Spotify");
*errmsg = "Error: Didn't receive a code from Spotify";
return -1;
}
DPRINTF(E_DBG, L_SPOTIFY, "Received OAuth code: %s\n", code);
ret = token_get(code, redirect_uri, &err);
ret = token_get(code, redirect_uri, errmsg);
if (ret < 0)
{
*errmsg = safe_asprintf("Error: %s", err);
return -1;
}
return -1;
ret = spotify_login_token(spotify_credentials.user, spotify_credentials.access_token, errmsg);
if (ret < 0)
return -1;
// Trigger scan after successful access to spotifywebapi
spotifywebapi_fullrescan();
@@ -1470,6 +1471,9 @@ track_add(struct spotify_track *track, struct spotify_album *album, const char *
free_mfi(&mfi, 1);
}
// This is only required for the libspotify backend
spotify_uri_register(track->uri);
if (album && album->uri)
cache_artwork_ping(track->uri, album->mtime, 0);
else
@@ -1709,7 +1713,7 @@ scan_playlists(enum spotify_request_type request_type)
}
static void
create_saved_tracks_playlist()
create_saved_tracks_playlist(void)
{
struct playlist_info pli =
{
@@ -1735,7 +1739,7 @@ create_saved_tracks_playlist()
* Add or update playlist folder for all spotify playlists (if enabled in config)
*/
static void
create_base_playlist()
create_base_playlist(void)
{
cfg_t *spotify_cfg;
struct playlist_info pli =
@@ -1792,17 +1796,17 @@ scan(enum spotify_request_type request_type)
/* Thread: library */
static int
initscan()
initscan(void)
{
int ret;
/* Refresh access token for the spotify webapi */
ret = token_refresh();
ret = token_refresh();
if (ret < 0)
{
DPRINTF(E_LOG, L_SPOTIFY, "Spotify webapi token refresh failed. "
"In order to use the web api, authorize the server to access "
"your saved tracks by visiting http://owntone.local:3689\n");
"In order to use Spotify, authorize the server to access your saved "
"tracks by visiting http://owntone.local:3689\n");
db_spotify_purge();
@@ -1811,6 +1815,21 @@ initscan()
spotify_saved_plid = 0;
/*
* libspotify needs to be logged in before before scanning tracks from the web
* since scanned tracks need to be registered for playback
*/
ret = spotify_relogin();
if (ret < 0)
{
DPRINTF(E_LOG, L_SPOTIFY, "libspotify-login failed. In order to use Spotify, "
"provide valid credentials for libspotify by visiting http://owntone.local:3689\n");
db_spotify_purge();
return 0;
}
/*
* Scan saved tracks from the web api
*/
@@ -1821,7 +1840,7 @@ initscan()
/* Thread: library */
static int
rescan()
rescan(void)
{
scan(SPOTIFY_REQUEST_TYPE_RESCAN);
return 0;
@@ -1829,7 +1848,7 @@ rescan()
/* Thread: library */
static int
metarescan()
metarescan(void)
{
scan(SPOTIFY_REQUEST_TYPE_METARESCAN);
return 0;
@@ -1837,7 +1856,7 @@ metarescan()
/* Thread: library */
static int
fullrescan()
fullrescan(void)
{
db_spotify_purge();
scan(SPOTIFY_REQUEST_TYPE_RESCAN);
@@ -2050,7 +2069,8 @@ spotifywebapi_init()
{
CHECK_ERR(L_SPOTIFY, mutex_init(&token_lck));
return 0;
// Required for libspotify backend
return spotify_init();
}
static void
@@ -2058,6 +2078,8 @@ spotifywebapi_deinit()
{
CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&token_lck));
spotify_deinit();
free_credentials();
}

View File

@@ -45,7 +45,7 @@ struct spotifywebapi_access_token
char *
spotifywebapi_oauth_uri_get(const char *redirect_uri);
int
spotifywebapi_oauth_callback(struct evkeyvalq *param, const char *redirect_uri, char **errmsg);
spotifywebapi_oauth_callback(struct evkeyvalq *param, const char *redirect_uri, const char **errmsg);
void
spotifywebapi_fullrescan(void);