From ab3d89f484d7997e3f6dc0d4bb42c1da9377ba40 Mon Sep 17 00:00:00 2001 From: Jochen Keil Date: Sun, 8 Mar 2009 20:16:53 +0100 Subject: [PATCH] decoder_plugin: added method container_scan() [mk: fixed whitespace errors; use delete_song() instead of songvec_delete()] --- src/decoder/sidplay_plugin.cxx | 1 + src/decoder_plugin.h | 23 +++++++ src/directory.h | 1 + src/input/file_input_plugin.c | 23 +++++-- src/update.c | 110 ++++++++++++++++++++++++++++----- 5 files changed, 137 insertions(+), 21 deletions(-) diff --git a/src/decoder/sidplay_plugin.cxx b/src/decoder/sidplay_plugin.cxx index cea7f84db..06ac9493d 100644 --- a/src/decoder/sidplay_plugin.cxx +++ b/src/decoder/sidplay_plugin.cxx @@ -156,6 +156,7 @@ const struct decoder_plugin sidplay_decoder_plugin = { NULL, /* stream_decode() */ sidplay_file_decode, sidplay_tag_dup, + NULL, /* container_scan */ sidplay_suffixes, NULL, /* mime_types */ }; diff --git a/src/decoder_plugin.h b/src/decoder_plugin.h index 35a76bb38..c118a5ec3 100644 --- a/src/decoder_plugin.h +++ b/src/decoder_plugin.h @@ -74,6 +74,18 @@ struct decoder_plugin { */ struct tag *(*tag_dup)(const char *file); + /** + * @brief Return a "virtual" filename for subtracks in + * container formats like flac + * @param const char* pathname full pathname for the file on fs + * @param const unsigned int tnum track number + * + * @return NULL if there are no multiple files + * a filename for every single track according to tnum (param 2) + * do not include full pathname here, just the "virtual" file + */ + char* (*container_scan)(const char* pathname, const unsigned int tnum); + /* last element in these arrays must always be a NULL: */ const char *const*suffixes; const char *const*mime_types; @@ -136,4 +148,15 @@ decoder_plugin_tag_dup(const struct decoder_plugin *plugin, return plugin->tag_dup(path_fs); } +/** + * return "virtual" tracks in a container + */ +static inline char * +decoder_plugin_container_scan( const struct decoder_plugin *plugin, + const char* pathname, + const unsigned int tnum) +{ + return plugin->container_scan(pathname, tnum); +} + #endif diff --git a/src/directory.h b/src/directory.h index 9321e9530..d0126609f 100644 --- a/src/directory.h +++ b/src/directory.h @@ -28,6 +28,7 @@ #define DIRECTORY_DIR "directory: " #define DEVICE_INARCHIVE (unsigned)(-1) +#define DEVICE_CONTAINER (unsigned)(-2) struct directory { struct dirvec children; diff --git a/src/input/file_input_plugin.c b/src/input/file_input_plugin.c index c8a5053f8..6dc815df9 100644 --- a/src/input/file_input_plugin.c +++ b/src/input/file_input_plugin.c @@ -35,12 +35,23 @@ input_file_open(struct input_stream *is, const char *filename) int fd, ret; struct stat st; - if (filename[0] != '/') - return false; + char* pathname = g_strdup(filename); - fd = open(filename, O_RDONLY); + if (filename[0] != '/') + { + g_free(pathname); + return false; + } + + if (stat(filename, &st) < 0) { + char* slash = strrchr(pathname, '/'); + *slash = '\0'; + } + + fd = open(pathname, O_RDONLY); if (fd < 0) { is->error = errno; + g_free(pathname); return false; } @@ -50,13 +61,15 @@ input_file_open(struct input_stream *is, const char *filename) if (ret < 0) { is->error = errno; close(fd); + g_free(pathname); return false; } if (!S_ISREG(st.st_mode)) { - g_debug("Not a regular file: %s\n", filename); + g_debug("Not a regular file: %s", pathname); is->error = EINVAL; close(fd); + g_free(pathname); return false; } @@ -70,6 +83,8 @@ input_file_open(struct input_stream *is, const char *filename) is->data = GINT_TO_POINTER(fd); is->ready = true; + g_free(pathname); + return true; } diff --git a/src/update.c b/src/update.c index e72c2e26d..493e97da9 100644 --- a/src/update.c +++ b/src/update.c @@ -52,6 +52,8 @@ #include #include +#include "decoder_plugin.h" + #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "update" @@ -213,7 +215,8 @@ directory_exists(const struct directory *directory) /* invalid path: cannot exist */ return false; - test = directory->device == DEVICE_INARCHIVE + test = directory->device == DEVICE_INARCHIVE || + directory->device == DEVICE_CONTAINER ? G_FILE_TEST_IS_REGULAR : G_FILE_TEST_IS_DIR; @@ -423,32 +426,105 @@ static void update_regular_file(struct directory *directory, const char *name, const struct stat *st) { + bool no_container = true; const char *suffix = uri_get_suffix(name); + const struct decoder_plugin* plugin; #ifdef ENABLE_ARCHIVE const struct archive_plugin *archive; #endif if (suffix == NULL) return; + else + plugin = decoder_plugin_from_suffix(suffix, false); - if (decoder_plugin_from_suffix(suffix, false) != NULL) { - struct song *song = songvec_find(&directory->songs, name); + if (plugin != NULL) { + if (plugin->container_scan != NULL) + { + unsigned int tnum = 0; + char* vtrack = NULL; + struct song *song = songvec_find(&directory->songs, name); + const char* pathname = map_directory_child_fs(directory, name); + struct directory* contdir = dirvec_find(&directory->children, name); - if (song == NULL) { - song = song_file_load(name, directory); - if (song == NULL) - return; - - songvec_add(&directory->songs, song); - modified = true; - g_message("added %s/%s", - directory_get_path(directory), name); - } else if (st->st_mtime != song->mtime) { - g_message("updating %s/%s", - directory_get_path(directory), name); - if (!song_file_update(song)) + // is there already a song for this file? + if (song != NULL) + { delete_song(directory, song); - modified = true; + song = NULL; + } + + // directory exists already + if (contdir != NULL) + { + no_container = false; + + // modification time not eq. file mod. time + if (contdir->mtime != st->st_mtime) + { + g_message("removing directory: %s", pathname); + delete_directory(contdir); + contdir = NULL; + } + } + + // contdir doesn't yet exist + if (contdir == NULL) + { + // reset flag if there are no vtracks + no_container = true; + + contdir = make_subdir(directory, name); + contdir->mtime = st->st_mtime; + contdir->device = DEVICE_CONTAINER; + + while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL) + { + song = songvec_find(&contdir->songs, vtrack); + + if (song == NULL) + { + song = song_file_new(vtrack, contdir); + if (song == NULL) + return; + + // shouldn't be necessary but it's there.. + song->mtime = st->st_mtime; + + song->tag = plugin->tag_dup( + map_directory_child_fs(contdir, vtrack)); + + songvec_add(&contdir->songs, song); + song = NULL; + + modified = true; + } + no_container = false; + g_free(vtrack); + } + } + } + + if (no_container == true) + { + struct song *song = songvec_find(&directory->songs, name); + + if (song == NULL) { + song = song_file_load(name, directory); + if (song == NULL) + return; + + songvec_add(&directory->songs, song); + modified = true; + g_message("added %s/%s", + directory_get_path(directory), name); + } else if (st->st_mtime != song->mtime) { + g_message("updating %s/%s", + directory_get_path(directory), name); + if (!song_file_update(song)) + delete_song(directory, song); + modified = true; + } } #ifdef ENABLE_ARCHIVE } else if ((archive = archive_plugin_from_suffix(suffix))) {