mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-14 08:15:02 -05:00
Add support for M3U metadata (extinf)
This commit is contained in:
parent
6fb718b55e
commit
d710e6ee95
@ -296,7 +296,7 @@ fixup_tags(struct media_file_info *mfi)
|
||||
|
||||
|
||||
void
|
||||
process_media_file(char *file, time_t mtime, off_t size, int compilation, int url)
|
||||
process_media_file(char *file, time_t mtime, off_t size, int compilation, int url, struct extinf_ctx *extinf)
|
||||
{
|
||||
struct media_file_info mfi;
|
||||
char *filename;
|
||||
@ -305,6 +305,41 @@ process_media_file(char *file, time_t mtime, off_t size, int compilation, int ur
|
||||
int id;
|
||||
int ret;
|
||||
|
||||
filename = strrchr(file, '/');
|
||||
if (!filename)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Could not determine filename for %s\n", file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* File types which should never be processed */
|
||||
ext = strrchr(file, '.');
|
||||
if (ext)
|
||||
{
|
||||
if ((strcmp(ext, ".pls") == 0) || (strcmp(ext, ".url") == 0))
|
||||
{
|
||||
DPRINTF(E_INFO, L_SCAN, "No support for .url and .pls in this version, use .m3u\n");
|
||||
|
||||
return;
|
||||
}
|
||||
else if ((strcmp(ext, ".png") == 0) || (strcmp(ext, ".jpg") == 0))
|
||||
{
|
||||
/* Artwork files - don't scan */
|
||||
return;
|
||||
}
|
||||
else if ((strcmp(ext, ".db") == 0) || (strcmp(ext, ".ini") == 0))
|
||||
{
|
||||
/* System files - don't scan */
|
||||
return;
|
||||
}
|
||||
else if ((strlen(filename) > 1) && ((filename[1] == '_') || (filename[1] == '.')))
|
||||
{
|
||||
/* Hidden files - don't scan */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
db_file_stamp_bypath(file, &stamp, &id);
|
||||
|
||||
if (stamp >= mtime)
|
||||
@ -318,14 +353,6 @@ process_media_file(char *file, time_t mtime, off_t size, int compilation, int ur
|
||||
if (stamp)
|
||||
mfi.id = db_file_id_bypath(file);
|
||||
|
||||
filename = strrchr(file, '/');
|
||||
if (!filename)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Could not determine filename for %s\n", file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mfi.fname = strdup(filename + 1);
|
||||
if (!mfi.fname)
|
||||
{
|
||||
@ -346,54 +373,20 @@ process_media_file(char *file, time_t mtime, off_t size, int compilation, int ur
|
||||
mfi.time_modified = mtime;
|
||||
mfi.file_size = size;
|
||||
|
||||
ret = -1;
|
||||
|
||||
/* Special cases */
|
||||
ext = strrchr(file, '.');
|
||||
if (ext)
|
||||
if (!url)
|
||||
{
|
||||
if ((strcmp(ext, ".pls") == 0)
|
||||
|| (strcmp(ext, ".url") == 0))
|
||||
{
|
||||
DPRINTF(E_INFO, L_SCAN, "No support for .url and .pls in this version, use .m3u\n");
|
||||
|
||||
goto out;
|
||||
}
|
||||
else if ((strcmp(ext, ".png") == 0)
|
||||
|| (strcmp(ext, ".jpg") == 0))
|
||||
{
|
||||
/* Artwork - don't scan */
|
||||
goto out;
|
||||
}
|
||||
else if ((strcmp(ext, ".db") == 0)
|
||||
|| (strcmp(ext, ".ini") == 0))
|
||||
{
|
||||
/* System files - don't scan */
|
||||
goto out;
|
||||
}
|
||||
else if ((filename[1] == '_')
|
||||
|| (filename[1] == '.'))
|
||||
{
|
||||
/* Hidden files - don't scan */
|
||||
goto out;
|
||||
}
|
||||
mfi.data_kind = 0; /* real file */
|
||||
ret = scan_metadata_ffmpeg(file, &mfi);
|
||||
}
|
||||
|
||||
/* General case */
|
||||
if (ret < 0)
|
||||
else
|
||||
{
|
||||
if (url == 0)
|
||||
{
|
||||
mfi.data_kind = 0; /* real file */
|
||||
ret = scan_metadata_ffmpeg(file, &mfi);
|
||||
mfi.data_kind = 1; /* url/stream */
|
||||
if (extinf && extinf->found)
|
||||
{
|
||||
mfi.artist = strdup(extinf->artist);
|
||||
mfi.title = strdup(extinf->title);
|
||||
}
|
||||
else if (url == 1)
|
||||
{
|
||||
mfi.data_kind = 1; /* url/stream */
|
||||
ret = scan_metadata_icy(file, &mfi);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
ret = scan_metadata_icy(file, &mfi);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
@ -526,7 +519,7 @@ process_file(char *file, time_t mtime, off_t size, int compilation, int flags)
|
||||
}
|
||||
|
||||
/* Not any kind of special file, so let's see if it's a media file */
|
||||
process_media_file(file, mtime, size, compilation, 0);
|
||||
process_media_file(file, mtime, size, compilation, 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,8 +10,15 @@ filescanner_init(void);
|
||||
void
|
||||
filescanner_deinit(void);
|
||||
|
||||
struct extinf_ctx
|
||||
{
|
||||
char *artist;
|
||||
char *title;
|
||||
int found;
|
||||
};
|
||||
|
||||
void
|
||||
process_media_file(char *file, time_t mtime, off_t size, int compilation, int url);
|
||||
process_media_file(char *file, time_t mtime, off_t size, int compilation, int url, struct extinf_ctx *extinf);
|
||||
|
||||
/* Actual scanners */
|
||||
int
|
||||
|
@ -34,18 +34,92 @@
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "db.h"
|
||||
#include "filescanner.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
static int
|
||||
get_extinf(char *string, struct extinf_ctx *extinf)
|
||||
{
|
||||
regex_t *regex;
|
||||
regmatch_t *regmatch;
|
||||
size_t matchlen;
|
||||
|
||||
if (strcmp(string, "#EXTINF:") <= 0)
|
||||
{
|
||||
DPRINTF(E_DBG, L_SCAN, "Playlist line has no EXTINF data\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
regex = (regex_t*)malloc(sizeof(regex_t));
|
||||
if (!regex)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Out of memory for playlist regex.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
regcomp(regex, "^#EXTINF:.*,(.*?)-(.*)",REG_EXTENDED|REG_NEWLINE);
|
||||
regmatch = (regmatch_t*)malloc(sizeof(regmatch_t) * (1 + regex->re_nsub));
|
||||
if (!regmatch)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Out of memory for playlist regmatch.\n");
|
||||
|
||||
goto regexfail;
|
||||
}
|
||||
|
||||
if (regexec(regex, string, 1 + regex->re_nsub, regmatch, 0))
|
||||
{
|
||||
DPRINTF(E_DBG, L_SCAN, "Playlist line has no EXTINF data\n");
|
||||
|
||||
goto regmatchfail;
|
||||
}
|
||||
|
||||
/* Found extinf */
|
||||
if (regmatch[0].rm_so != -1)
|
||||
{
|
||||
DPRINTF(E_DBG, L_SCAN, "Playlist line has EXTINF data\n");
|
||||
|
||||
/* Artist */
|
||||
if (extinf->artist)
|
||||
free(extinf->artist);
|
||||
matchlen = regmatch[1].rm_eo - regmatch[1].rm_so;
|
||||
extinf->artist = (char*)malloc(matchlen + 1);
|
||||
strncpy(extinf->artist, string + regmatch[1].rm_so, matchlen + 1);
|
||||
extinf->artist[matchlen]='\0';
|
||||
|
||||
/* Title */
|
||||
if (extinf->title)
|
||||
free(extinf->title);
|
||||
matchlen = regmatch[1].rm_eo - regmatch[1].rm_so;
|
||||
extinf->title = (char*)malloc(matchlen + 1);
|
||||
strncpy(extinf->title, string + regmatch[1].rm_so, matchlen + 1);
|
||||
extinf->title[matchlen]='\0';
|
||||
|
||||
free(regmatch);
|
||||
regfree(regex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
regmatchfail:
|
||||
free(regmatch);
|
||||
regexfail:
|
||||
regfree(regex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
scan_m3u_playlist(char *file, time_t mtime)
|
||||
{
|
||||
FILE *fp;
|
||||
struct playlist_info *pli;
|
||||
struct stat sb;
|
||||
struct extinf_ctx extinf;
|
||||
char buf[PATH_MAX];
|
||||
char *entry;
|
||||
char *filename;
|
||||
@ -121,30 +195,36 @@ scan_m3u_playlist(char *file, time_t mtime)
|
||||
DPRINTF(E_INFO, L_SCAN, "Added playlist as id %d\n", pl_id);
|
||||
}
|
||||
|
||||
extinf.found = 0;
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL)
|
||||
{
|
||||
len = strlen(buf);
|
||||
if (buf[len - 1] != '\n')
|
||||
if (len >= (sizeof(buf) - 1))
|
||||
{
|
||||
DPRINTF(E_WARN, L_SCAN, "Entry exceeds PATH_MAX, discarding\n");
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL)
|
||||
{
|
||||
if (buf[strlen(buf) - 1] == '\n')
|
||||
break;
|
||||
}
|
||||
DPRINTF(E_LOG, L_SCAN, "Playlist entry exceeds PATH_MAX, discarding\n");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((!isalnum(buf[0])) && (buf[0] != '/'))
|
||||
continue;
|
||||
|
||||
while (isspace(buf[len - 1]))
|
||||
/* rtrim and check that length is sane (ignore blank lines) */
|
||||
while ((len > 0) && isspace(buf[len - 1]))
|
||||
{
|
||||
len--;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
if (len < 1)
|
||||
continue;
|
||||
|
||||
/* Saves metadata in extinf if EXTINF metadata line */
|
||||
if (get_extinf(buf, &extinf))
|
||||
{
|
||||
extinf.found = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check that first char is sane for a path */
|
||||
if ((!isalnum(buf[0])) && (buf[0] != '/') && (buf[0] != '.'))
|
||||
continue;
|
||||
|
||||
/* Check if line is an URL */
|
||||
if (strcmp(buf, "http://") > 0)
|
||||
@ -159,13 +239,13 @@ scan_m3u_playlist(char *file, time_t mtime)
|
||||
continue;
|
||||
}
|
||||
|
||||
process_media_file(filename, mtime, 0, 0, 1);
|
||||
process_media_file(filename, mtime, 0, 0, 1, &extinf);
|
||||
}
|
||||
/* Regular file */
|
||||
else
|
||||
{
|
||||
/* m3u might be from Windows so we change backslash to forward slash */
|
||||
for (i = 0; i < strlen(buf); i++)
|
||||
/* m3u might be from Windows so we change backslash to forward slash */
|
||||
for (i = 0; i < strlen(buf); i++)
|
||||
{
|
||||
if (buf[i] == '\\')
|
||||
buf[i] = '/';
|
||||
@ -218,6 +298,7 @@ scan_m3u_playlist(char *file, time_t mtime)
|
||||
if (ret < 0)
|
||||
DPRINTF(E_WARN, L_SCAN, "Could not add %s to playlist\n", filename);
|
||||
|
||||
extinf.found = 0;
|
||||
free(filename);
|
||||
}
|
||||
|
||||
@ -230,6 +311,10 @@ scan_m3u_playlist(char *file, time_t mtime)
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (extinf.artist)
|
||||
free(extinf.artist);
|
||||
if (extinf.title)
|
||||
free(extinf.title);
|
||||
|
||||
DPRINTF(E_INFO, L_SCAN, "Done processing playlist\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user