From: Dave H. <da...@sr...> - 2009-06-15 18:57:28
|
I keep my music organized like this: |-- Metallica | |-- S_&_M | | |-- Disc_1 | | | |-- Metallica - S & M (Disc 1)[01] - The Ecstacy Of Gold.mp3 | | | |-- Metallica - S & M (Disc 1)[02] - The Call Of Ktulu.mp3 ... | | |-- Disc_2 | | | |-- Metallica - S&M (Disc 2)[01] - Nothing Else Matters.mp3 | | | |-- Metallica - S&M (Disc 2)[02] - Until it Sleeps.mp3 ... If I ever try to create a playlist that's auto-sync'ed with either Metallica/ or Metallica/S_&_M/, the add_files() function will see either S_&_M/ or Disc_* and 'break;' out of the case:, ignoring them. I don't like this. :) The following patch will allow add_files() to recurse into subdirectories. It does this first by using the 'value' void* argument to pass the updated variable back up through several layers of calls. In the case where add_files() encounters a directory, it simply calls itself recursively on that directory. The only complication is that the sync_playlist() code also tries to remove *old* files from the auto-generated playlist. It does this by seeing if a file's parent directory is in the hash table of added directories. Since we're recursing, we don't actually add any of the child subdirectories into this hash. The auto-removal code thus does not find them, and removes them right after we add them. To fix this up, we not only search the hash for a file's immediate parent directory but also all of the ancestors. --- trunk-dave/src/syncdir.c | 56 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 15 deletions(-) diff -puN src/syncdir.c~recurse-dirs-for-auto-playlist-gen src/syncdir.c --- trunk/src/syncdir.c~recurse-dirs-for-auto-playlist-gen 2009-06-15 11:33:10.000000000 -0700 +++ trunk-dave/src/syncdir.c 2009-06-15 11:33:24.000000000 -0700 @@ -367,6 +367,7 @@ static void add_files (gpointer key, gpo struct add_files_data *afd = user_data; Playlist *pl; gchar *dirname; + gboolean updated = FALSE; g_return_if_fail (key); g_return_if_fail (afd); @@ -387,13 +388,14 @@ static void add_files (gpointer key, gpo { gchar *filename = g_build_filename (dirname, next, NULL); FileType filetype = determine_file_type (filename); - gboolean updated = FALSE; Track *tr=NULL; switch (filetype) { - case FILE_TYPE_UNKNOWN: case FILE_TYPE_DIRECTORY: + add_files(filename, &updated, user_data); + break; + case FILE_TYPE_UNKNOWN: case FILE_TYPE_IMAGE: case FILE_TYPE_M3U: case FILE_TYPE_PLS: @@ -466,8 +468,38 @@ printf ("%ld %ld (%s)\n, %ld %d\n", } g_dir_close (dir); } + if (value) + *(gboolean *)value = updated; } +/** + * file_under_dir_in_hash: + * + * @file: file (or dir) for which we search for parent dirs + * @dirs_hash: hash of directories to query + * + * In the dirs_hash, we only keep the actual directories from + * which the user as asked to add files. These do not explicitly + * include subdirectories. So, here we search to see if any + * parent directories of the file are contained in the hash. + * The recursion here is limited by the limits on path lengths in + * the OS. + */ +gboolean file_under_dir_in_hash(gchar *file, GHashTable *dirs_hash) +{ + gboolean ret = FALSE; + gchar *parent_dirname = g_path_get_dirname (file); + if (g_hash_table_lookup_extended (dirs_hash, parent_dirname, + NULL, NULL)) { + ret = TRUE; + } else { + if (strcmp("/", parent_dirname) && + strcmp(".", parent_dirname)) + ret = file_under_dir_in_hash(parent_dirname, dirs_hash); + } + g_free (parent_dirname); + return ret; +} @@ -661,22 +693,16 @@ void sync_playlist (Playlist *playlist, if (etr->pc_path_locale && *etr->pc_path_locale) { gchar *dirname_local; - - dirname_local = g_path_get_dirname (etr->pc_path_locale); - if (!g_hash_table_lookup_extended (dirs_hash, dirname_local, - NULL, NULL)) - { /* file is not in one of the specified directories */ - remove = TRUE; - } - else - { /* check if file exists */ - if (g_file_test (etr->pc_path_locale, - G_FILE_TEST_EXISTS) == FALSE) + remove = FALSE; + if (!file_under_dir_in_hash(etr->pc_path_locale, dirs_hash)) + { /* no -- remove */ + remove = TRUE; + } + if (g_file_test (etr->pc_path_locale, + G_FILE_TEST_EXISTS) == FALSE) { /* no -- remove */ remove = TRUE; } - } - g_free (dirname_local); } if (remove) _ |