From 665c76de005c2088bd5c1c7045115b527da97e0b Mon Sep 17 00:00:00 2001 From: chme Date: Sat, 7 Mar 2015 19:31:24 +0100 Subject: [PATCH 1/6] [spotify] Add "sp_session_starred_create" api method and load the "starred" playlist on login --- src/spotify.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/spotify.c b/src/spotify.c index 1b9e92f8..7e79f3e2 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -184,6 +184,7 @@ typedef sp_error (*fptr_sp_session_login_t)(sp_session *session, const char typedef sp_error (*fptr_sp_session_relogin_t)(sp_session *session); typedef sp_error (*fptr_sp_session_logout_t)(sp_session *session); typedef sp_error (*fptr_sp_session_process_events_t)(sp_session *session, int *next_timeout); +typedef sp_playlist* (*fptr_sp_session_starred_create_t)(sp_session *session); typedef sp_playlistcontainer* (*fptr_sp_session_playlistcontainer_t)(sp_session *session); typedef sp_error (*fptr_sp_session_player_load_t)(sp_session *session, sp_track *track); typedef sp_error (*fptr_sp_session_player_unload_t)(sp_session *session); @@ -242,6 +243,7 @@ fptr_sp_session_release_t fptr_sp_session_release; fptr_sp_session_login_t fptr_sp_session_login; fptr_sp_session_relogin_t fptr_sp_session_relogin; fptr_sp_session_logout_t fptr_sp_session_logout; +fptr_sp_session_starred_create_t fptr_sp_session_starred_create; fptr_sp_session_playlistcontainer_t fptr_sp_session_playlistcontainer; fptr_sp_session_process_events_t fptr_sp_session_process_events; fptr_sp_session_player_load_t fptr_sp_session_player_load; @@ -320,6 +322,7 @@ fptr_assign_all() && (fptr_sp_session_preferred_bitrate = dlsym(h, "sp_session_preferred_bitrate")) && (fptr_sp_playlistcontainer_add_callbacks = dlsym(h, "sp_playlistcontainer_add_callbacks")) && (fptr_sp_playlistcontainer_num_playlists = dlsym(h, "sp_playlistcontainer_num_playlists")) + && (fptr_sp_session_starred_create = dlsym(h, "sp_session_starred_create")) && (fptr_sp_playlistcontainer_playlist = dlsym(h, "sp_playlistcontainer_playlist")) && (fptr_sp_playlist_add_callbacks = dlsym(h, "sp_playlist_add_callbacks")) && (fptr_sp_playlist_name = dlsym(h, "sp_playlist_name")) @@ -1179,6 +1182,9 @@ logged_in(sp_session *sess, sp_error error) db_spotify_purge(); + pl = fptr_sp_session_starred_create(sess); + fptr_sp_playlist_add_callbacks(pl, &pl_callbacks, NULL); + pc = fptr_sp_session_playlistcontainer(sess); fptr_sp_playlistcontainer_add_callbacks(pc, &pc_callbacks, NULL); From c984bcd1576553679620df655a26a0cabc288199 Mon Sep 17 00:00:00 2001 From: chme Date: Sun, 8 Mar 2015 09:05:21 +0100 Subject: [PATCH 2/6] [spotify] Set the name for the starred playlist --- src/spotify.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/spotify.c b/src/spotify.c index 7e79f3e2..72b4d3d3 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -596,7 +596,12 @@ spotify_playlist_save(sp_playlist *pl) // sleep(1); // Primitive way of preventing database locking (the mutex wasn't working) pli = db_pl_fetch_bypath(url); - snprintf(title, sizeof(title), "[s] %s", name); + + // The starred playlist has an empty name, set it manually to "Starred" + if (*name == '\0') + snprintf(title, sizeof(title), "[s] Starred"); + else + snprintf(title, sizeof(title), "[s] %s", name); snprintf(virtual_path, PATH_MAX, "/spotify:/%s", title); From 563195b8a7623bd136589d1543f8d53d3dde598b Mon Sep 17 00:00:00 2001 From: chme Date: Sat, 7 Mar 2015 18:30:32 +0100 Subject: [PATCH 3/6] [spotify] Add "sp_track_is_starred" api method and log metadata --- src/spotify.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/spotify.c b/src/spotify.c index 72b4d3d3..a2e20ec0 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -212,6 +212,7 @@ typedef int (*fptr_sp_track_index_t)(sp_track *track); typedef int (*fptr_sp_track_disc_t)(sp_track *track); typedef sp_album* (*fptr_sp_track_album_t)(sp_track *track); typedef sp_track_availability (*fptr_sp_track_get_availability_t)(sp_session *session, sp_track *track); +typedef bool (*fptr_sp_track_is_starred_t)(sp_session *session, sp_track *track); typedef sp_link* (*fptr_sp_link_create_from_playlist_t)(sp_playlist *playlist); typedef sp_link* (*fptr_sp_link_create_from_track_t)(sp_track *track, int offset); @@ -272,6 +273,7 @@ fptr_sp_track_index_t fptr_sp_track_index; fptr_sp_track_disc_t fptr_sp_track_disc; fptr_sp_track_album_t fptr_sp_track_album; fptr_sp_track_get_availability_t fptr_sp_track_get_availability; +fptr_sp_track_is_starred_t fptr_sp_track_is_starred; fptr_sp_link_create_from_playlist_t fptr_sp_link_create_from_playlist; fptr_sp_link_create_from_track_t fptr_sp_link_create_from_track; @@ -338,6 +340,7 @@ fptr_assign_all() && (fptr_sp_track_disc = dlsym(h, "sp_track_disc")) && (fptr_sp_track_album = dlsym(h, "sp_track_album")) && (fptr_sp_track_get_availability = dlsym(h, "sp_track_get_availability")) + && (fptr_sp_track_is_starred = dlsym(h, "sp_track_is_starred")) && (fptr_sp_link_create_from_playlist = dlsym(h, "sp_link_create_from_playlist")) && (fptr_sp_link_create_from_track = dlsym(h, "sp_link_create_from_track")) && (fptr_sp_link_create_from_string = dlsym(h, "sp_link_create_from_string")) @@ -467,6 +470,7 @@ spotify_metadata_get(sp_track *track, struct media_file_info *mfi) sp_album *album; sp_artist *artist; sp_albumtype albumtype; + bool starred; album = fptr_sp_track_album(track); if (!album) @@ -478,6 +482,8 @@ spotify_metadata_get(sp_track *track, struct media_file_info *mfi) albumtype = fptr_sp_album_type(album); + starred = fptr_sp_track_is_starred(g_sess, track); + mfi->title = strdup(fptr_sp_track_name(track)); mfi->album = strdup(fptr_sp_album_name(album)); mfi->artist = strdup(fptr_sp_artist_name(artist)); @@ -491,6 +497,24 @@ spotify_metadata_get(sp_track *track, struct media_file_info *mfi) mfi->codectype = strdup("wav"); mfi->description = strdup("Spotify audio"); + DPRINTF(E_SPAM, L_SPOTIFY, "Metadata for track:\n" + "Title: %s\n" + "Album: %s\n" + "Artist: %s\n" + "Year: %u\n" + "Track: %u\n" + "Disc: %u\n" + "Compilation: %d\n" + "Starred: %d\n", + mfi->title, + mfi->album, + mfi->artist, + mfi->year, + mfi->track, + mfi->disc, + mfi->compilation, + starred); + return 0; } From 7cc3659d427b41af102c0d54a94ea4f0d73e8da7 Mon Sep 17 00:00:00 2001 From: chme Date: Sun, 8 Mar 2015 09:04:26 +0100 Subject: [PATCH 4/6] [spotify] Added config options to use the compilation artist for spotify tracks --- forked-daapd.conf | 16 ++++++++++++++++ src/conffile.c | 2 ++ src/spotify.c | 21 +++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/forked-daapd.conf b/forked-daapd.conf index 870b3d16..15eb1dc8 100644 --- a/forked-daapd.conf +++ b/forked-daapd.conf @@ -163,6 +163,22 @@ spotify { # Set preferred bitrate for music streaming # 0: No preference (default), 1: 96kbps, 2: 160kbps, 3: 320kbps # bitrate = 0 + + # Compilations usually have many artists, and if you don't want every + # artist to be listed when artist browsing in Remote, you can set + # a single name which will be used for all music in the compilation dir + # (changing this setting only takes effect after rescan, see the README) + + # Spotify playlists usually have many artist, and if you don't want every + # artist to be listed when artist browsing in Remote, you can set the + # artist_override flag to true. This will use the compilation_artist as + # album artist for spotify items that are not in the starred playlist. +# artist_override = false + + # Like artist_override, the starre_artist_override flag can be set to true, + # in order to use the compilation_artist for items in the spotify starred + # playlist. +# starred_artist_override = false } # SQLite configuration (allows to modify the operation of the SQLite databases) diff --git a/src/conffile.c b/src/conffile.c index 03716167..1f929f60 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -113,6 +113,8 @@ static cfg_opt_t sec_spotify[] = CFG_STR("settings_dir", STATEDIR "/cache/" PACKAGE "/libspotify", CFGF_NONE), CFG_STR("cache_dir", "/tmp", CFGF_NONE), CFG_INT("bitrate", 0, CFGF_NONE), + CFG_BOOL("artist_override", cfg_false, CFGF_NONE), + CFG_BOOL("starred_artist_override", cfg_false, CFGF_NONE), CFG_END() }; diff --git a/src/spotify.c b/src/spotify.c index a2e20ec0..51fe3983 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -467,10 +467,18 @@ thread_exit(void) static int spotify_metadata_get(sp_track *track, struct media_file_info *mfi) { + cfg_t *spotify_cfg; + bool artist_override; + bool starred_artist_override; sp_album *album; sp_artist *artist; sp_albumtype albumtype; bool starred; + char compilation; + + spotify_cfg = cfg_getsec(cfg, "spotify"); + artist_override = cfg_getbool(spotify_cfg, "artist_override"); + starred_artist_override = cfg_getbool(spotify_cfg, "starred_artist_override"); album = fptr_sp_track_album(track); if (!album) @@ -481,9 +489,18 @@ spotify_metadata_get(sp_track *track, struct media_file_info *mfi) return -1; albumtype = fptr_sp_album_type(album); - starred = fptr_sp_track_is_starred(g_sess, track); + /* + * Treat album as compilation if one of the following conditions is true: + * - spotfy album type is compilation + * - artist_override in config is set to true and track is not part of the starred playlist + * - starred_artist_override in config is set to true and track is part of the starred playlist + */ + compilation = ((albumtype == SP_ALBUMTYPE_COMPILATION) + || (starred && starred_artist_override) + || (!starred && artist_override)); + mfi->title = strdup(fptr_sp_track_name(track)); mfi->album = strdup(fptr_sp_album_name(album)); mfi->artist = strdup(fptr_sp_artist_name(artist)); @@ -491,7 +508,7 @@ spotify_metadata_get(sp_track *track, struct media_file_info *mfi) mfi->song_length = fptr_sp_track_duration(track); mfi->track = fptr_sp_track_index(track); mfi->disc = fptr_sp_track_disc(track); - mfi->compilation = (albumtype == SP_ALBUMTYPE_COMPILATION); + mfi->compilation = compilation; mfi->artwork = ARTWORK_SPOTIFY; mfi->type = strdup("spotify"); mfi->codectype = strdup("wav"); From 988283c25dcbece939615c92a274be395fa67ce6 Mon Sep 17 00:00:00 2001 From: chme Date: Sun, 8 Mar 2015 09:24:23 +0100 Subject: [PATCH 5/6] [spotify] Added config options to use the playlist name as album name --- forked-daapd.conf | 14 +++++++++++++- src/conffile.c | 2 ++ src/spotify.c | 21 ++++++++++++++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/forked-daapd.conf b/forked-daapd.conf index 15eb1dc8..b4675013 100644 --- a/forked-daapd.conf +++ b/forked-daapd.conf @@ -175,10 +175,22 @@ spotify { # album artist for spotify items that are not in the starred playlist. # artist_override = false - # Like artist_override, the starre_artist_override flag can be set to true, + # Like artist_override, the starred_artist_override flag can be set to true, # in order to use the compilation_artist for items in the spotify starred # playlist. # starred_artist_override = false + + # Similar to the different artists in spotify playlists, the playlist items + # belong to different albums, and if you do not want every album to be listed + # when browsing in Remote, you can set the album_override flag to true. This + # will use the playlist name as album name for spotify items that are not in + # the starred playlist. Notice that if an item is in more than one playlist, + # it will only appear in one album when browsing (in which album is random). +# album_override = false + + # Like album_override, the starred_album_override flag can be set to true, + # in order to use the playlist name as album name. +# starred_album_override = false } # SQLite configuration (allows to modify the operation of the SQLite databases) diff --git a/src/conffile.c b/src/conffile.c index 1f929f60..af94ee0a 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -115,6 +115,8 @@ static cfg_opt_t sec_spotify[] = CFG_INT("bitrate", 0, CFGF_NONE), CFG_BOOL("artist_override", cfg_false, CFGF_NONE), CFG_BOOL("starred_artist_override", cfg_false, CFGF_NONE), + CFG_BOOL("album_override", cfg_false, CFGF_NONE), + CFG_BOOL("starred_album_override", cfg_false, CFGF_NONE), CFG_END() }; diff --git a/src/spotify.c b/src/spotify.c index 51fe3983..561d33e9 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -465,20 +465,25 @@ thread_exit(void) /* Should only be called from within the spotify thread */ static int -spotify_metadata_get(sp_track *track, struct media_file_info *mfi) +spotify_metadata_get(sp_track *track, struct media_file_info *mfi, char *pltitle) { cfg_t *spotify_cfg; bool artist_override; bool starred_artist_override; + bool album_override; + bool starred_album_override; sp_album *album; sp_artist *artist; sp_albumtype albumtype; bool starred; char compilation; + char *albumname; spotify_cfg = cfg_getsec(cfg, "spotify"); artist_override = cfg_getbool(spotify_cfg, "artist_override"); starred_artist_override = cfg_getbool(spotify_cfg, "starred_artist_override"); + album_override = cfg_getbool(spotify_cfg, "album_override"); + starred_album_override = cfg_getbool(spotify_cfg, "starred_album_override"); album = fptr_sp_track_album(track); if (!album) @@ -501,8 +506,14 @@ spotify_metadata_get(sp_track *track, struct media_file_info *mfi) || (starred && starred_artist_override) || (!starred && artist_override)); + if ((starred && starred_album_override) + || (!starred && album_override)) + albumname = strdup(pltitle); + else + albumname = strdup(fptr_sp_album_name(album)); + mfi->title = strdup(fptr_sp_track_name(track)); - mfi->album = strdup(fptr_sp_album_name(album)); + mfi->album = albumname; mfi->artist = strdup(fptr_sp_artist_name(artist)); mfi->year = fptr_sp_album_year(album); mfi->song_length = fptr_sp_track_duration(track); @@ -536,7 +547,7 @@ spotify_metadata_get(sp_track *track, struct media_file_info *mfi) } static int -spotify_track_save(int plid, sp_track *track) +spotify_track_save(int plid, sp_track *track, char *pltitle) { struct media_file_info mfi; sp_link *link; @@ -579,7 +590,7 @@ spotify_track_save(int plid, sp_track *track) memset(&mfi, 0, sizeof(struct media_file_info)); - ret = spotify_metadata_get(track, &mfi); + ret = spotify_metadata_get(track, &mfi, pltitle); if (ret < 0) { DPRINTF(E_LOG, L_SPOTIFY, "Metadata missing (but track should be loaded?): '%s'\n", fptr_sp_track_name(track)); @@ -687,7 +698,7 @@ spotify_playlist_save(sp_playlist *pl) continue; } - ret = spotify_track_save(plid, track); + ret = spotify_track_save(plid, track, title); if (ret < 0) { DPRINTF(E_LOG, L_SPOTIFY, "Error saving track %d to playlist '%s' (id %d)\n", i, name, plid); From 8e7ed7717b33a5e938939af2caa6304820b93e78 Mon Sep 17 00:00:00 2001 From: chme Date: Sun, 8 Mar 2015 10:56:57 +0100 Subject: [PATCH 6/6] fixup forked-daapd.conf --- forked-daapd.conf | 5 ----- 1 file changed, 5 deletions(-) diff --git a/forked-daapd.conf b/forked-daapd.conf index b4675013..b9891872 100644 --- a/forked-daapd.conf +++ b/forked-daapd.conf @@ -164,11 +164,6 @@ spotify { # 0: No preference (default), 1: 96kbps, 2: 160kbps, 3: 320kbps # bitrate = 0 - # Compilations usually have many artists, and if you don't want every - # artist to be listed when artist browsing in Remote, you can set - # a single name which will be used for all music in the compilation dir - # (changing this setting only takes effect after rescan, see the README) - # Spotify playlists usually have many artist, and if you don't want every # artist to be listed when artist browsing in Remote, you can set the # artist_override flag to true. This will use the compilation_artist as