diff --git a/forked-daapd.conf.in b/forked-daapd.conf.in index aa9bb84d..94f84dfb 100644 --- a/forked-daapd.conf.in +++ b/forked-daapd.conf.in @@ -157,6 +157,10 @@ library { # to trigger a rescan. # filescan_disable = false + # Should metadata from m3u playlists, e.g. artist and title in EXTINF, + # override the metadata we get from radio streams? +# m3u_overrides = false + # Should iTunes metadata override ours? # itunes_overrides = false diff --git a/src/conffile.c b/src/conffile.c index 139ec774..4e40405c 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -95,6 +95,7 @@ static cfg_opt_t sec_library[] = CFG_STR_LIST("filetypes_ignore", "{.db,.ini,.db-journal,.pdf,.metadata}", CFGF_NONE), CFG_STR_LIST("filepath_ignore", NULL, CFGF_NONE), CFG_BOOL("filescan_disable", cfg_false, CFGF_NONE), + CFG_BOOL("m3u_overrides", cfg_false, CFGF_NONE), CFG_BOOL("itunes_overrides", cfg_false, CFGF_NONE), CFG_BOOL("itunes_smartpl", cfg_false, CFGF_NONE), CFG_STR_LIST("no_decode", NULL, CFGF_NONE), diff --git a/src/library/filescanner_playlist.c b/src/library/filescanner_playlist.c index 34e7f419..cd79b85d 100644 --- a/src/library/filescanner_playlist.c +++ b/src/library/filescanner_playlist.c @@ -32,6 +32,7 @@ #include #include +#include "conffile.h" #include "logger.h" #include "db.h" #include "library/filescanner.h" @@ -63,34 +64,73 @@ playlist_type(const char *path) return PLAYLIST_UNKNOWN; } -// Get metadata from the EXTINF tag static int -extinf_get(char *string, struct media_file_info *mfi, int *extinf) +extinf_read(char **artist, char **title, const char *tag) { char *ptr; - if (strncmp(string, "#EXTINF:", strlen("#EXTINF:")) != 0) - return 0; - - ptr = strchr(string, ','); + ptr = strchr(tag, ','); if (!ptr || strlen(ptr) < 2) - return 0; + return -1; - // New extinf found, so clear old data - free_mfi(mfi, 1); + *artist = strdup(ptr + 1); - *extinf = 1; - mfi->artist = strdup(ptr + 1); - - ptr = strstr(mfi->artist, " -"); + ptr = strstr(*artist, " -"); if (ptr && strlen(ptr) > 3) - mfi->title = strdup(ptr + 3); + *title = strdup(ptr + 3); else - mfi->title = strdup(""); + *title = strdup(""); if (ptr) *ptr = '\0'; - return 1; + return 0; +} + +static int +extval_read(char **val, const char *tag) +{ + char *ptr; + + ptr = strchr(tag, ':'); + if (!ptr || strlen(ptr) < 2) + return -1; + + *val = strdup(ptr + 1); + return 0; +} + +// Get metadata from a EXTINF or EXTALB tag +static int +exttag_read(struct media_file_info *mfi, const char *tag) +{ + char *artist; + char *title; + char *val; + + if (strncmp(tag, "#EXTINF:", strlen("#EXTINF:")) == 0 && extinf_read(&artist, &title, tag) == 0) + { + free(mfi->artist); + free(mfi->title); + mfi->artist = artist; + mfi->title = title; + if (!mfi->album_artist) + mfi->album_artist = strdup(artist); + return 0; + } + if (strncmp(tag, "#EXTALB:", strlen("#EXTALB:")) == 0 && extval_read(&val, tag) == 0) + { + free(mfi->album); + mfi->album = val; + return 0; + } + if (strncmp(tag, "#EXTART:", strlen("#EXTART:")) == 0 && extval_read(&val, tag) == 0) + { + free(mfi->album_artist); + mfi->album_artist = val; + return 0; + } + + return -1; } void @@ -173,11 +213,35 @@ process_nested_playlist(int parent_id, const char *path) static int process_url(int pl_id, const char *path, struct media_file_info *mfi) { + struct media_file_info m3u; int ret; mfi->id = db_file_id_bypath(path); - scan_metadata_stream(mfi, path); + if (cfg_getbool(cfg_getsec(cfg, "library"), "m3u_overrides")) + { + memset(&m3u, 0, sizeof(struct media_file_info)); + + m3u.artist = safe_strdup(mfi->artist); + m3u.album_artist = safe_strdup(mfi->album_artist); + m3u.album = safe_strdup(mfi->album); + m3u.title = safe_strdup(mfi->title); + + scan_metadata_stream(mfi, path); + + if (m3u.artist) + swap_pointers(&mfi->artist, &m3u.artist); + if (m3u.album_artist) + swap_pointers(&mfi->album_artist, &m3u.album_artist); + if (m3u.album) + swap_pointers(&mfi->album, &m3u.album); + if (m3u.title) + swap_pointers(&mfi->title, &m3u.title); + + free_mfi(&m3u, 1); + } + else + scan_metadata_stream(mfi, path); ret = library_media_save(mfi); if (ret < 0) @@ -329,7 +393,6 @@ scan_playlist(const char *file, time_t mtime, int dir_id) char buf[PATH_MAX]; char *path; size_t len; - int extinf; int pl_id; int pl_format; int ntracks; @@ -361,7 +424,6 @@ scan_playlist(const char *file, time_t mtime, int dir_id) db_transaction_begin(); - extinf = 0; memset(&mfi, 0, sizeof(struct media_file_info)); ntracks = 0; nadded = 0; @@ -379,8 +441,8 @@ scan_playlist(const char *file, time_t mtime, int dir_id) if (len < 1) continue; - // Saves metadata in mfi if EXTINF metadata line - if ((pl_format == PLAYLIST_M3U) && extinf_get(buf, &mfi, &extinf)) + // Saves metadata in mfi if EXT metadata line + if ((pl_format == PLAYLIST_M3U) && (exttag_read(&mfi, buf) == 0)) continue; // For pls files we are only interested in the part after the FileX= entry @@ -417,15 +479,14 @@ scan_playlist(const char *file, time_t mtime, int dir_id) nadded++; // Clean up in preparation for next item - extinf = 0; free_mfi(&mfi, 1); } db_transaction_end(); - // We had some extinf that we never got to use, free it now - if (extinf) - free_mfi(&mfi, 1); + // In case we had some m3u ext metadata that we never got to use, free it now + // (no risk of double free when the free_mfi()'s are content_only) + free_mfi(&mfi, 1); if (!feof(fp)) DPRINTF(E_LOG, L_SCAN, "Error reading playlist '%s' (only added %d tracks): %s\n", file, nadded, strerror(errno));