Add support for .pls playlists

This commit is contained in:
ejurgensen 2014-08-27 21:57:16 +02:00
parent 1b51fcf07c
commit ae3b5077ec
4 changed files with 52 additions and 26 deletions

11
README
View File

@ -237,11 +237,14 @@ them. Watch out for that.
Playlists and internet radio
----------------------------
forked-daapd supports M3U playlists. Just drop your playlist somewhere in
your library with an .m3u extension and it will pick it up.
forked-daapd supports M3U and PLS playlists. Just drop your playlist somewhere
in your library with an .m3u or .pls extension and it will pick it up.
If the m3u contains an http URL it will be added as an internet radio station,
and the URL will be probed for Shoutcast (ICY) metadata.
If the playlist contains an http URL it will be added as an internet radio
station, and the URL will be probed for Shoutcast (ICY) metadata.
forked-daapd does not support playlists in playlists (so for instance a .m3u
where one of the items is another .m3u or .pls).
Support for iTunes Music Library XML format is available as a compile-time
option. By default, metadata from our parsers is preferred over what's in

View File

@ -460,9 +460,9 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
ext = strrchr(path, '.');
if (ext)
{
if ((strcasecmp(ext, ".pls") == 0) || (strcasecmp(ext, ".url") == 0))
if (strcasecmp(ext, ".url") == 0)
{
DPRINTF(E_INFO, L_SCAN, "No support for .url and .pls in this version, use .m3u\n");
DPRINTF(E_INFO, L_SCAN, "No support for .url in this version, use .m3u or .pls\n");
return;
}
@ -599,7 +599,9 @@ process_playlist(char *file, time_t mtime)
if (ext)
{
if (strcasecmp(ext, ".m3u") == 0)
scan_m3u_playlist(file, mtime);
scan_playlist(file, mtime);
else if (strcasecmp(ext, ".pls") == 0)
scan_playlist(file, mtime);
#ifdef ITUNES
else if (strcasecmp(ext, ".xml") == 0)
scan_itunes_itml(file);
@ -672,6 +674,7 @@ process_file(char *file, time_t mtime, off_t size, int type, int flags)
if (ext)
{
if ((strcasecmp(ext, ".m3u") == 0)
|| (strcasecmp(ext, ".pls") == 0)
#ifdef ITUNES
|| (strcasecmp(ext, ".xml") == 0)
#endif

View File

@ -32,7 +32,7 @@ int
scan_metadata_icy(char *url, struct media_file_info *mfi);
void
scan_m3u_playlist(char *file, time_t mtime);
scan_playlist(char *file, time_t mtime);
#ifdef ITUNES
void

View File

@ -39,6 +39,9 @@
#include "filescanner.h"
#include "misc.h"
/* Formats we can read so far */
#define PLAYLIST_PLS 1
#define PLAYLIST_M3U 2
/* Get metadata from the EXTINF tag */
static int
@ -71,19 +74,21 @@ extinf_get(char *string, struct media_file_info *mfi, int *extinf)
}
void
scan_m3u_playlist(char *file, time_t mtime)
scan_playlist(char *file, time_t mtime)
{
FILE *fp;
struct media_file_info mfi;
struct playlist_info *pli;
struct stat sb;
char buf[PATH_MAX];
char *path;
char *entry;
char *filename;
char *ptr;
size_t len;
int extinf;
int pl_id;
int pl_format;
int mfi_id;
int ret;
int i;
@ -98,6 +103,17 @@ scan_m3u_playlist(char *file, time_t mtime)
return;
}
ptr = strrchr(file, '.');
if (!ptr)
return;
if (strcasecmp(ptr, ".m3u") == 0)
pl_format = PLAYLIST_M3U;
else if (strcasecmp(ptr, ".pls") == 0)
pl_format = PLAYLIST_PLS;
else
return;
filename = strrchr(file, '/');
if (!filename)
filename = file;
@ -145,7 +161,7 @@ scan_m3u_playlist(char *file, time_t mtime)
ret = db_pl_add(buf, file, &pl_id);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Error adding m3u playlist '%s'\n", file);
DPRINTF(E_LOG, L_SCAN, "Error adding playlist '%s'\n", file);
return;
}
@ -159,12 +175,6 @@ scan_m3u_playlist(char *file, time_t mtime)
while (fgets(buf, sizeof(buf), fp) != NULL)
{
len = strlen(buf);
if (len >= (sizeof(buf) - 1))
{
DPRINTF(E_LOG, L_SCAN, "Playlist entry exceeds PATH_MAX, discarding\n");
continue;
}
/* rtrim and check that length is sane (ignore blank lines) */
while ((len > 0) && isspace(buf[len - 1]))
@ -176,19 +186,29 @@ scan_m3u_playlist(char *file, time_t mtime)
continue;
/* Saves metadata in mfi if EXTINF metadata line */
if (extinf_get(buf, &mfi, &extinf))
if ((pl_format == PLAYLIST_M3U) && extinf_get(buf, &mfi, &extinf))
continue;
/* For pls files we are only interested in the part after the FileX= entry */
path = NULL;
if ((pl_format == PLAYLIST_PLS) && (strncasecmp(buf, "file", strlen("file")) == 0))
path = strchr(buf, '=') + 1;
else if (pl_format == PLAYLIST_M3U)
path = buf;
if (!path)
continue;
/* Check that first char is sane for a path */
if ((!isalnum(buf[0])) && (buf[0] != '/') && (buf[0] != '.'))
if ((!isalnum(path[0])) && (path[0] != '/') && (path[0] != '.'))
continue;
/* Check if line is an URL, will be added to library */
if (strcmp(buf, "http://") > 0)
if (strncasecmp(path, "http://", strlen("http://")) == 0)
{
DPRINTF(E_DBG, L_SCAN, "Playlist contains URL entry\n");
filename = strdup(buf);
filename = strdup(path);
if (!filename)
{
DPRINTF(E_LOG, L_SCAN, "Out of memory for playlist filename\n");
@ -204,11 +224,11 @@ scan_m3u_playlist(char *file, time_t mtime)
/* Regular file, should already be in library */
else
{
/* m3u might be from Windows so we change backslash to forward slash */
for (i = 0; i < strlen(buf); i++)
/* Playlist might be from Windows so we change backslash to forward slash */
for (i = 0; i < strlen(path); i++)
{
if (buf[i] == '\\')
buf[i] = '/';
if (path[i] == '\\')
path[i] = '/';
}
/* Now search for the library item where the path has closest match to playlist item */
@ -217,7 +237,7 @@ scan_m3u_playlist(char *file, time_t mtime)
entry = NULL;
do
{
ptr = strrchr(buf, '/');
ptr = strrchr(path, '/');
if (entry)
*(entry - 1) = '/';
if (ptr)
@ -226,7 +246,7 @@ scan_m3u_playlist(char *file, time_t mtime)
entry = ptr + 1;
}
else
entry = buf;
entry = path;
DPRINTF(E_SPAM, L_SCAN, "Playlist entry is now %s\n", entry);
ret = db_files_get_count_bymatch(entry);