decoder_plugin: added method container_scan()

[mk: fixed whitespace errors; use delete_song() instead of
songvec_delete()]
This commit is contained in:
Jochen Keil 2009-03-08 20:16:53 +01:00 committed by Max Kellermann
parent 94d1a87d04
commit ab3d89f484
5 changed files with 137 additions and 21 deletions

View File

@ -156,6 +156,7 @@ const struct decoder_plugin sidplay_decoder_plugin = {
NULL, /* stream_decode() */ NULL, /* stream_decode() */
sidplay_file_decode, sidplay_file_decode,
sidplay_tag_dup, sidplay_tag_dup,
NULL, /* container_scan */
sidplay_suffixes, sidplay_suffixes,
NULL, /* mime_types */ NULL, /* mime_types */
}; };

View File

@ -74,6 +74,18 @@ struct decoder_plugin {
*/ */
struct tag *(*tag_dup)(const char *file); 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: */ /* last element in these arrays must always be a NULL: */
const char *const*suffixes; const char *const*suffixes;
const char *const*mime_types; 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 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 #endif

View File

@ -28,6 +28,7 @@
#define DIRECTORY_DIR "directory: " #define DIRECTORY_DIR "directory: "
#define DEVICE_INARCHIVE (unsigned)(-1) #define DEVICE_INARCHIVE (unsigned)(-1)
#define DEVICE_CONTAINER (unsigned)(-2)
struct directory { struct directory {
struct dirvec children; struct dirvec children;

View File

@ -35,12 +35,23 @@ input_file_open(struct input_stream *is, const char *filename)
int fd, ret; int fd, ret;
struct stat st; struct stat st;
if (filename[0] != '/') char* pathname = g_strdup(filename);
return false;
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) { if (fd < 0) {
is->error = errno; is->error = errno;
g_free(pathname);
return false; return false;
} }
@ -50,13 +61,15 @@ input_file_open(struct input_stream *is, const char *filename)
if (ret < 0) { if (ret < 0) {
is->error = errno; is->error = errno;
close(fd); close(fd);
g_free(pathname);
return false; return false;
} }
if (!S_ISREG(st.st_mode)) { 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; is->error = EINVAL;
close(fd); close(fd);
g_free(pathname);
return false; return false;
} }
@ -70,6 +83,8 @@ input_file_open(struct input_stream *is, const char *filename)
is->data = GINT_TO_POINTER(fd); is->data = GINT_TO_POINTER(fd);
is->ready = true; is->ready = true;
g_free(pathname);
return true; return true;
} }

View File

@ -52,6 +52,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include "decoder_plugin.h"
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "update" #define G_LOG_DOMAIN "update"
@ -213,7 +215,8 @@ directory_exists(const struct directory *directory)
/* invalid path: cannot exist */ /* invalid path: cannot exist */
return false; 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_REGULAR
: G_FILE_TEST_IS_DIR; : G_FILE_TEST_IS_DIR;
@ -423,32 +426,105 @@ static void
update_regular_file(struct directory *directory, update_regular_file(struct directory *directory,
const char *name, const struct stat *st) const char *name, const struct stat *st)
{ {
bool no_container = true;
const char *suffix = uri_get_suffix(name); const char *suffix = uri_get_suffix(name);
const struct decoder_plugin* plugin;
#ifdef ENABLE_ARCHIVE #ifdef ENABLE_ARCHIVE
const struct archive_plugin *archive; const struct archive_plugin *archive;
#endif #endif
if (suffix == NULL) if (suffix == NULL)
return; return;
else
plugin = decoder_plugin_from_suffix(suffix, false);
if (decoder_plugin_from_suffix(suffix, false) != NULL) { if (plugin != NULL) {
struct song *song = songvec_find(&directory->songs, name); 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) { // is there already a song for this file?
song = song_file_load(name, directory); if (song != NULL)
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); 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 #ifdef ENABLE_ARCHIVE
} else if ((archive = archive_plugin_from_suffix(suffix))) { } else if ((archive = archive_plugin_from_suffix(suffix))) {