diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2009-11-06 21:12:38 +0100 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2009-11-06 21:12:38 +0100 |
commit | 39b8fe4b2c864247e0004d2a8c0ca55bab0fdf32 (patch) | |
tree | 6a5a4daf957a6522ba7342c6ca376b2722768fcb | |
parent | 63a606b4592acacf7adb76587c3177b0676d3886 (diff) |
rewrote icy header parser
shoutcast title is being read from icy headers
-rw-r--r-- | deadbeef.h | 4 | ||||
-rw-r--r-- | plugins.c | 2 | ||||
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 14 | ||||
-rw-r--r-- | plugins/vfs_curl/vfs_curl.c | 137 | ||||
-rw-r--r-- | vfs.c | 15 | ||||
-rw-r--r-- | vfs.h | 2 |
6 files changed, 160 insertions, 14 deletions
@@ -236,6 +236,8 @@ typedef struct { void (*rewind) (DB_FILE *stream); int64_t (*fgetlength) (DB_FILE *stream); const char *(*fget_content_type) (DB_FILE *stream); + const char *(*fget_content_name) (DB_FILE *stream); + const char *(*fget_content_genre) (DB_FILE *stream); // message passing int (*sendmessage) (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2); // configuration access @@ -393,6 +395,8 @@ typedef struct DB_vfs_s { void (*rewind) (DB_FILE *stream); int64_t (*getlength)(DB_FILE *stream); const char * (*get_content_type) (DB_FILE *stream); + const char * (*get_content_name) (DB_FILE *stream); + const char * (*get_content_genre) (DB_FILE *stream); const char **scheme_names; // NULL-terminated list of supported schemes, e.g. {"http", "ftp", NULL} unsigned streaming : 1; } DB_vfs_t; @@ -111,6 +111,8 @@ static DB_functions_t deadbeef_api = { .rewind = vfs_rewind, .fgetlength = vfs_fgetlength, .fget_content_type = vfs_get_content_type, + .fget_content_name = vfs_get_content_name, + .fget_content_genre = vfs_get_content_genre, // message passing .sendmessage = messagepump_push, // configuration access diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 21d3b8fb..8e54b6c8 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -498,6 +498,8 @@ cmp3_init (DB_playItem_t *it) { } else { int len = deadbeef->fgetlength (buffer.file); + const char *name = deadbeef->fget_content_name (buffer.file); + const char *genre = deadbeef->fget_content_genre (buffer.file); if (len > 0) { deadbeef->pl_delete_all_meta (it); int v2err = deadbeef->junk_read_id3v2 (it, buffer.file); @@ -506,6 +508,18 @@ cmp3_init (DB_playItem_t *it) { deadbeef->fseek (buffer.file, 0, SEEK_SET); } } + else { + deadbeef->pl_delete_all_meta (it); + if (name) { + deadbeef->pl_add_meta (it, "title", name); + } + else { + deadbeef->pl_add_meta (it, "title", NULL); + } + if (genre) { + deadbeef->pl_add_meta (it, "genre", genre); + } + } int res = cmp3_scan_stream (&buffer, 0); if (res < 0) { trace ("mpgmad: cmp3_init: initial cmp3_scan_stream failed\n"); diff --git a/plugins/vfs_curl/vfs_curl.c b/plugins/vfs_curl/vfs_curl.c index e467692e..1ac15c93 100644 --- a/plugins/vfs_curl/vfs_curl.c +++ b/plugins/vfs_curl/vfs_curl.c @@ -58,6 +58,8 @@ typedef struct { int icyheader; int nheaderpackets; char *content_type; + char *content_name; + char *content_genre; uint8_t status; } HTTP_FILE; @@ -170,28 +172,91 @@ http_size_header_handler (void *ptr, size_t size, size_t nmemb, void *stream) { return size * nmemb; } +static const uint8_t * +parse_header (const uint8_t *p, const uint8_t *e, uint8_t *key, int keysize, uint8_t *value, int valuesize) { + int sz; // will hold lenght of extracted string + const uint8_t *v; // pointer to current character + keysize--; + valuesize--; + *key = 0; + *value = 0; + v = p; + // find : + while (v < e && *v != 0x0d && *v != 0x0a && *v != ':') { + v++; + } + if (*v != ':') { + // skip linebreaks + while (v < e && (*v == 0x0d || *v == 0x0a)) { + v++; + } + return v; + } + // copy key + sz = v-p; + sz = min (keysize, sz); + memcpy (key, p, sz); + key[sz] = 0; + + // skip whitespace + v++; + while (v < e && (*v == 0x20 || *v == 0x08)) { + v++; + } + if (*v == 0x0d || *v == 0x0a) { + // skip linebreaks + while (v < e && (*v == 0x0d || *v == 0x0a)) { + v++; + } + return v; + } + p = v; + + // find linebreak + while (v < e && *v != 0x0d || *v == 0x0a) { + v++; + } + + // copy value + sz = v-p; + sz = min (valuesize, sz); + memcpy (value, p, sz); + value[sz] = 0; + + // skip linebreaks + while (v < e && (*v == 0x0d || *v == 0x0a)) { + v++; + } + return v; +} + static size_t http_content_header_handler (void *ptr, size_t size, size_t nmemb, void *stream) { trace ("http_content_header_handler\n"); assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; const uint8_t c_type_str[] ="Content-Type:"; - const uint8_t *cl = strcasestr (ptr, c_type_str); - if (cl) { - fp->gotheader = 1; - cl += sizeof (c_type_str)-1; - while (*cl <= 0x20) { - cl++; + const uint8_t icy_name_str[] ="icy-name:"; + const uint8_t icy_genre_str[] ="icy-genre:"; + const uint8_t *p = ptr; + const uint8_t *end = p + size*nmemb; + uint8_t key[256]; + uint8_t value[256]; + while (p < end) { + p = parse_header (p, end, key, sizeof (key), value, sizeof (value)); + trace ("%skey=%s value=%s\n", fp->icyheader ? "[icy] " : "", key, value); + if (!strcasecmp (key, "Content-Type")) { + fp->content_type = strdup (value); + } + else if (!strcasecmp (key, "icy-name")) { + fp->content_name = strdup (value); } - const uint8_t *p = (const uint8_t *)cl; - while (*p >= 0x20) { - p++; + else if (!strcasecmp (key, "icy-genre")) { + fp->content_genre = strdup (value); } - int len = (const uint8_t *)p-cl; - char str[len+1]; - strncpy (str, cl, len); - str[len] = 0; - fp->content_type = strdup (str); + } + if (!fp->icyheader) { + fp->gotheader = 1; } return size * nmemb; } @@ -300,6 +365,12 @@ http_close (DB_FILE *stream) { if (fp->content_type) { free (fp->content_type); } + if (fp->content_name) { + free (fp->content_name); + } + if (fp->content_genre) { + free (fp->content_genre); + } if (fp->url) { free (fp->url); } @@ -476,6 +547,42 @@ http_get_content_type (DB_FILE *stream) { return fp->content_type; } +static const char * +http_get_content_name (DB_FILE *stream) { + trace ("http_get_content_name\n"); + assert (stream); + HTTP_FILE *fp = (HTTP_FILE *)stream; + if (fp->gotheader) { + return fp->content_name; + } + if (!fp->tid) { + http_start_streamer (fp); + } + trace ("http_get_content_name waiting for response...\n"); + while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader) { + usleep (3000); + } + return fp->content_name; +} + +static const char * +http_get_content_genre (DB_FILE *stream) { + trace ("http_get_content_genre\n"); + assert (stream); + HTTP_FILE *fp = (HTTP_FILE *)stream; + if (fp->gotheader) { + return fp->content_genre; + } + if (!fp->tid) { + http_start_streamer (fp); + } + trace ("http_get_content_genre waiting for response...\n"); + while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader) { + usleep (3000); + } + return fp->content_genre; +} + static const char *scheme_names[] = { "http://", "ftp://", NULL }; // standard stdio vfs @@ -497,6 +604,8 @@ static DB_vfs_t plugin = { .rewind = http_rewind, .getlength = http_getlength, .get_content_type = http_get_content_type, + .get_content_name = http_get_content_name, + .get_content_genre = http_get_content_type, .scheme_names = scheme_names, .streaming = 1 }; @@ -84,3 +84,18 @@ const char * vfs_get_content_type (DB_FILE *stream) { return stream->vfs->get_content_type (stream); } + +const char * +vfs_get_content_name (DB_FILE *stream) { + if (stream->vfs->get_content_name) { + return stream->vfs->get_content_name (stream); + } + return NULL; +} +const char * +vfs_get_content_genre (DB_FILE *stream) { + if (stream->vfs->get_content_genre) { + return stream->vfs->get_content_genre (stream); + } + return NULL; +} @@ -30,5 +30,7 @@ int64_t vfs_ftell (DB_FILE *stream); void vfs_rewind (DB_FILE *stream); int64_t vfs_fgetlength (DB_FILE *stream); const char *vfs_get_content_type (DB_FILE *stream); +const char *vfs_get_content_name (DB_FILE *stream); +const char *vfs_get_content_genre (DB_FILE *stream); #endif // __VFS_H |