diff options
-rw-r--r-- | SConstruct | 1 | ||||
-rw-r--r-- | music.c | 4 | ||||
-rw-r--r-- | music.h | 4 | ||||
-rw-r--r-- | tag.c | 72 | ||||
-rw-r--r-- | tag.h | 24 |
5 files changed, 105 insertions, 0 deletions
@@ -16,6 +16,7 @@ else: env.ParseConfig('pkg-config --cflags --libs glib-2.0') env.ParseConfig('pkg-config --cflags --libs gio-2.0') env.ParseConfig('pkg-config --cflags --libs libmpg123') +env.ParseConfig('pkg-config --cflags --libs id3tag') env.Program('foo', Glob('*.c') + Glob('decoders/*.c') + Glob('encoders/*.c')) @@ -43,6 +43,10 @@ gboolean music_scan(struct directory *directory) { directory->files = g_slist_prepend(directory->files, f); g_debug("added file %s to %s", entry, directory->path); + struct tag *tag = tag_read(fullpath); + if(tag) { + f->tag = tag; + } } else if(S_ISDIR(st.st_mode)) { struct directory *d = g_new0(struct directory, 1); d->path = g_build_filename(directory->path, entry, NULL); @@ -1,11 +1,15 @@ #ifndef _MUSIC_H_ #define _MUSIC_H_ +#include "tag.h" + #include <glib.h> struct file { gchar *name; gssize size; + + struct tag *tag; }; struct directory { @@ -0,0 +1,72 @@ +#include "tag.h" + +#include <id3tag.h> + +static void tag_add(struct tag *tag, enum tag_type type, const gchar *value) { + struct tag_field *field = g_new0(struct tag_field, 1); + if(field == 0) { + g_error("tag_add: g_new0 returned NULL"); + } + + field->type = type; + field->string = g_strdup(value); + tag->fields = g_slist_prepend(tag->fields, field); +} + +static void tag_add_string(struct tag *tag, struct id3_tag *id3tag, + enum tag_type type, const gchar *id) { + struct id3_frame *frame = id3_tag_findframe(id3tag, id, 0); + + if(frame == NULL) { + return; + } + + if(frame->nfields != 2) { + g_debug("unexpected nfields value"); + return; + } + + const union id3_field *field = id3_frame_field(frame, 1); + guint nstrings = id3_field_getnstrings(field); + + for(guint i = 0; i < nstrings; i++) { + const id3_ucs4_t *ucs4 = id3_field_getstrings(field, i); + + if(ucs4 == NULL) { + g_warning("ucs4 is NULL"); + continue; + } + + id3_utf8_t *utf8 = id3_ucs4_utf8duplicate(ucs4); + tag_add(tag, type, (gchar*)utf8); + g_free(utf8); + } +} + +/* TODO: support other tag formats beside ID3 */ +struct tag *tag_read(const gchar *path) { + struct id3_file *file = id3_file_open(path, ID3_FILE_MODE_READONLY); + + if(file == NULL) { + g_warning("file is NULL"); + return NULL; + } + + struct id3_tag *id3tag = id3_file_tag(file); + + if(id3tag == NULL) { + g_debug("tag is NULL"); + return NULL; + } + + struct tag *tag = g_new0(struct tag, 1); + + /* TODO: add more interesting data */ + tag_add_string(tag, id3tag, TAG_TYPE_ARTIST, ID3_FRAME_ARTIST); + tag_add_string(tag, id3tag, TAG_TYPE_ALBUM, ID3_FRAME_ALBUM); + tag_add_string(tag, id3tag, TAG_TYPE_TITLE, ID3_FRAME_TITLE); + + id3_file_close(file); + + return tag; +} @@ -0,0 +1,24 @@ +#ifndef _TAG_H_ +#define _TAG_H_ + +#include <glib.h> + +enum tag_type { + TAG_TYPE_ARTIST, + TAG_TYPE_ALBUM, + TAG_TYPE_TITLE, +}; + +struct tag_field { + enum tag_type type; + gchar *string; +}; + +struct tag { + GSList *fields; +}; + +void tag_list_all(const gchar *path); +struct tag *tag_read(const gchar *path); + +#endif |