mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-12 07:23:24 -05:00
Add support for .pls playlists
This commit is contained in:
parent
1b51fcf07c
commit
ae3b5077ec
11
README
11
README
@ -237,11 +237,14 @@ them. Watch out for that.
|
|||||||
Playlists and internet radio
|
Playlists and internet radio
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
forked-daapd supports M3U playlists. Just drop your playlist somewhere in
|
forked-daapd supports M3U and PLS playlists. Just drop your playlist somewhere
|
||||||
your library with an .m3u extension and it will pick it up.
|
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,
|
If the playlist contains an http URL it will be added as an internet radio
|
||||||
and the URL will be probed for Shoutcast (ICY) metadata.
|
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
|
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
|
option. By default, metadata from our parsers is preferred over what's in
|
||||||
|
@ -460,9 +460,9 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
|
|||||||
ext = strrchr(path, '.');
|
ext = strrchr(path, '.');
|
||||||
if (ext)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@ -599,7 +599,9 @@ process_playlist(char *file, time_t mtime)
|
|||||||
if (ext)
|
if (ext)
|
||||||
{
|
{
|
||||||
if (strcasecmp(ext, ".m3u") == 0)
|
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
|
#ifdef ITUNES
|
||||||
else if (strcasecmp(ext, ".xml") == 0)
|
else if (strcasecmp(ext, ".xml") == 0)
|
||||||
scan_itunes_itml(file);
|
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 (ext)
|
||||||
{
|
{
|
||||||
if ((strcasecmp(ext, ".m3u") == 0)
|
if ((strcasecmp(ext, ".m3u") == 0)
|
||||||
|
|| (strcasecmp(ext, ".pls") == 0)
|
||||||
#ifdef ITUNES
|
#ifdef ITUNES
|
||||||
|| (strcasecmp(ext, ".xml") == 0)
|
|| (strcasecmp(ext, ".xml") == 0)
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,7 +32,7 @@ int
|
|||||||
scan_metadata_icy(char *url, struct media_file_info *mfi);
|
scan_metadata_icy(char *url, struct media_file_info *mfi);
|
||||||
|
|
||||||
void
|
void
|
||||||
scan_m3u_playlist(char *file, time_t mtime);
|
scan_playlist(char *file, time_t mtime);
|
||||||
|
|
||||||
#ifdef ITUNES
|
#ifdef ITUNES
|
||||||
void
|
void
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
#include "filescanner.h"
|
#include "filescanner.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
/* Formats we can read so far */
|
||||||
|
#define PLAYLIST_PLS 1
|
||||||
|
#define PLAYLIST_M3U 2
|
||||||
|
|
||||||
/* Get metadata from the EXTINF tag */
|
/* Get metadata from the EXTINF tag */
|
||||||
static int
|
static int
|
||||||
@ -71,19 +74,21 @@ extinf_get(char *string, struct media_file_info *mfi, int *extinf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scan_m3u_playlist(char *file, time_t mtime)
|
scan_playlist(char *file, time_t mtime)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct media_file_info mfi;
|
struct media_file_info mfi;
|
||||||
struct playlist_info *pli;
|
struct playlist_info *pli;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
char *path;
|
||||||
char *entry;
|
char *entry;
|
||||||
char *filename;
|
char *filename;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
size_t len;
|
size_t len;
|
||||||
int extinf;
|
int extinf;
|
||||||
int pl_id;
|
int pl_id;
|
||||||
|
int pl_format;
|
||||||
int mfi_id;
|
int mfi_id;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
@ -98,6 +103,17 @@ scan_m3u_playlist(char *file, time_t mtime)
|
|||||||
return;
|
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, '/');
|
filename = strrchr(file, '/');
|
||||||
if (!filename)
|
if (!filename)
|
||||||
filename = file;
|
filename = file;
|
||||||
@ -145,7 +161,7 @@ scan_m3u_playlist(char *file, time_t mtime)
|
|||||||
ret = db_pl_add(buf, file, &pl_id);
|
ret = db_pl_add(buf, file, &pl_id);
|
||||||
if (ret < 0)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@ -159,12 +175,6 @@ scan_m3u_playlist(char *file, time_t mtime)
|
|||||||
while (fgets(buf, sizeof(buf), fp) != NULL)
|
while (fgets(buf, sizeof(buf), fp) != NULL)
|
||||||
{
|
{
|
||||||
len = strlen(buf);
|
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) */
|
/* rtrim and check that length is sane (ignore blank lines) */
|
||||||
while ((len > 0) && isspace(buf[len - 1]))
|
while ((len > 0) && isspace(buf[len - 1]))
|
||||||
@ -176,19 +186,29 @@ scan_m3u_playlist(char *file, time_t mtime)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Saves metadata in mfi if EXTINF metadata line */
|
/* 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;
|
continue;
|
||||||
|
|
||||||
/* Check that first char is sane for a path */
|
/* 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;
|
continue;
|
||||||
|
|
||||||
/* Check if line is an URL, will be added to library */
|
/* 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");
|
DPRINTF(E_DBG, L_SCAN, "Playlist contains URL entry\n");
|
||||||
|
|
||||||
filename = strdup(buf);
|
filename = strdup(path);
|
||||||
if (!filename)
|
if (!filename)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SCAN, "Out of memory for playlist filename\n");
|
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 */
|
/* Regular file, should already be in library */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* m3u might be from Windows so we change backslash to forward slash */
|
/* Playlist might be from Windows so we change backslash to forward slash */
|
||||||
for (i = 0; i < strlen(buf); i++)
|
for (i = 0; i < strlen(path); i++)
|
||||||
{
|
{
|
||||||
if (buf[i] == '\\')
|
if (path[i] == '\\')
|
||||||
buf[i] = '/';
|
path[i] = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now search for the library item where the path has closest match to playlist item */
|
/* 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;
|
entry = NULL;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
ptr = strrchr(buf, '/');
|
ptr = strrchr(path, '/');
|
||||||
if (entry)
|
if (entry)
|
||||||
*(entry - 1) = '/';
|
*(entry - 1) = '/';
|
||||||
if (ptr)
|
if (ptr)
|
||||||
@ -226,7 +246,7 @@ scan_m3u_playlist(char *file, time_t mtime)
|
|||||||
entry = ptr + 1;
|
entry = ptr + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
entry = buf;
|
entry = path;
|
||||||
|
|
||||||
DPRINTF(E_SPAM, L_SCAN, "Playlist entry is now %s\n", entry);
|
DPRINTF(E_SPAM, L_SCAN, "Playlist entry is now %s\n", entry);
|
||||||
ret = db_files_get_count_bymatch(entry);
|
ret = db_files_get_count_bymatch(entry);
|
||||||
|
Loading…
Reference in New Issue
Block a user