00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <dirent.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <sys/stat.h>
00026
00027 #include <gtk/gtk.h>
00028
00029 #include <libaudcore/audstrings.h>
00030
00031 #include "audconfig.h"
00032 #include "config.h"
00033 #include "glib-compat.h"
00034 #include "i18n.h"
00035 #include "misc.h"
00036 #include "playback.h"
00037 #include "playlist.h"
00038
00039 typedef struct {
00040 gchar * filename;
00041 PluginHandle * decoder;
00042 } AddFile;
00043
00044 typedef struct {
00045 gint playlist_id, at;
00046 GQueue folders;
00047 gboolean play;
00048 } AddGroup;
00049
00050 static GQueue add_queue = G_QUEUE_INIT;
00051 static gint add_source = 0;
00052 static GtkWidget * add_window = NULL, * add_progress_path, * add_progress_count;
00053
00054 static void show_progress (const gchar * path, gint count)
00055 {
00056 if (add_window == NULL)
00057 {
00058 GtkWidget * vbox;
00059
00060 add_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
00061 gtk_window_set_type_hint (GTK_WINDOW(add_window),
00062 GDK_WINDOW_TYPE_HINT_DIALOG);
00063 gtk_window_set_title (GTK_WINDOW(add_window), _("Searching ..."));
00064 gtk_window_set_resizable (GTK_WINDOW(add_window), FALSE);
00065 gtk_container_set_border_width (GTK_CONTAINER(add_window), 6);
00066
00067 vbox = gtk_vbox_new (FALSE, 6);
00068 gtk_container_add (GTK_CONTAINER(add_window), vbox);
00069
00070 add_progress_path = gtk_label_new ("");
00071 gtk_widget_set_size_request (add_progress_path, 320, -1);
00072 gtk_label_set_ellipsize (GTK_LABEL(add_progress_path),
00073 PANGO_ELLIPSIZE_MIDDLE);
00074 gtk_box_pack_start (GTK_BOX(vbox), add_progress_path, FALSE, FALSE, 0);
00075
00076 add_progress_count = gtk_label_new ("");
00077 gtk_widget_set_size_request (add_progress_count, 320, -1);
00078 gtk_box_pack_start (GTK_BOX(vbox), add_progress_count, FALSE, FALSE, 0);
00079
00080 gtk_widget_show_all (add_window);
00081
00082 g_signal_connect (G_OBJECT(add_window), "destroy",
00083 G_CALLBACK(gtk_widget_destroyed), & add_window);
00084 }
00085
00086 gtk_label_set_text (GTK_LABEL(add_progress_path), path);
00087
00088 gchar scratch[128];
00089 snprintf (scratch, sizeof scratch, dngettext (PACKAGE, "%d file found",
00090 "%d files found", count), count);
00091 gtk_label_set_text (GTK_LABEL(add_progress_count), scratch);
00092 }
00093
00094 static void show_done (void)
00095 {
00096 gtk_widget_destroy (add_window);
00097 }
00098
00099 static gint sort_cb (const AddFile * a, const AddFile * b)
00100 {
00101 return string_compare_encoded (a->filename, b->filename);
00102 }
00103
00104 static gboolean add_cb (void * unused)
00105 {
00106 static GList * stack = NULL;
00107 static GList * big_list = NULL, * little_list = NULL;
00108
00109 if (! stack)
00110 {
00111 AddGroup * group = g_queue_peek_head (& add_queue);
00112 g_return_val_if_fail (group, FALSE);
00113 gchar * folder = g_queue_pop_head (& group->folders);
00114 g_return_val_if_fail (folder, FALSE);
00115 stack = g_list_prepend (NULL, folder);
00116 }
00117
00118 show_progress (stack->data, g_list_length (big_list) + g_list_length
00119 (little_list));
00120
00121 for (gint count = 0; count < 30; count ++)
00122 {
00123 struct stat info;
00124
00125
00126
00127 if (! stat (stack->data, & info))
00128 {
00129 if (S_ISREG (info.st_mode))
00130 {
00131 gchar * filename = filename_to_uri (stack->data);
00132 PluginHandle * decoder = (filename == NULL) ? NULL :
00133 file_find_decoder (filename, TRUE);
00134
00135 if (decoder)
00136 {
00137 AddFile * file = g_slice_new (AddFile);
00138 file->filename = filename;
00139 file->decoder = decoder;
00140 little_list = g_list_prepend (little_list, file);
00141 }
00142 else
00143 g_free (filename);
00144 }
00145 else if (S_ISDIR (info.st_mode))
00146 {
00147 DIR * folder = opendir (stack->data);
00148
00149 if (folder)
00150 {
00151 stack = g_list_prepend (stack, folder);
00152 goto READ;
00153 }
00154 }
00155 }
00156
00157 g_free (stack->data);
00158 stack = g_list_delete_link (stack, stack);
00159
00160 READ:
00161 if (! stack)
00162 break;
00163
00164
00165
00166 struct dirent * entry = readdir (stack->data);
00167
00168 if (entry)
00169 {
00170 if (entry->d_name[0] == '.')
00171 goto READ;
00172
00173 stack = g_list_prepend (stack, g_strdup_printf ("%s"
00174 G_DIR_SEPARATOR_S "%s", (gchar *) stack->next->data, entry->d_name));
00175 }
00176 else
00177 {
00178 closedir (stack->data);
00179 stack = g_list_delete_link (stack, stack);
00180 g_free (stack->data);
00181 stack = g_list_delete_link (stack, stack);
00182 goto READ;
00183 }
00184 }
00185
00186 if (stack)
00187 return TRUE;
00188
00189 AddGroup * group = g_queue_peek_head (& add_queue);
00190 g_return_val_if_fail (group, FALSE);
00191
00192 little_list = g_list_sort (little_list, (GCompareFunc) sort_cb);
00193 big_list = g_list_concat (big_list, little_list);
00194 little_list = NULL;
00195
00196 if (! g_queue_is_empty (& group->folders))
00197 return TRUE;
00198
00199 gint playlist = playlist_by_unique_id (group->playlist_id);
00200
00201 if (playlist < 0)
00202 {
00203 for (GList * node = big_list; node; node = node->next)
00204 {
00205 AddFile * file = node->data;
00206 g_free (file->filename);
00207 g_slice_free (AddFile, file);
00208 }
00209
00210 g_list_free (big_list);
00211 big_list = NULL;
00212 goto ADDED;
00213 }
00214
00215 struct index * filenames = index_new ();
00216 struct index * decoders = index_new ();
00217
00218 for (GList * node = big_list; node; node = node->next)
00219 {
00220 AddFile * file = node->data;
00221 index_append (filenames, file->filename);
00222 index_append (decoders, file->decoder);
00223 g_slice_free (AddFile, file);
00224 }
00225
00226 g_list_free (big_list);
00227 big_list = NULL;
00228
00229 gint count = playlist_entry_count (playlist);
00230 if (group->at < 0 || group->at > count)
00231 group->at = count;
00232
00233 playlist_entry_insert_batch_with_decoders (playlist, group->at,
00234 filenames, decoders, NULL);
00235
00236 if (group->play && playlist_entry_count (playlist) > count)
00237 {
00238 playlist_set_playing (playlist);
00239 if (! cfg.shuffle)
00240 playlist_set_position (playlist, group->at);
00241 playback_play (0, FALSE);
00242 }
00243
00244 ADDED:
00245 g_slice_free (AddGroup, group);
00246 g_queue_pop_head (& add_queue);
00247
00248 if (! g_queue_is_empty (& add_queue))
00249 return TRUE;
00250
00251 show_done ();
00252 add_source = 0;
00253 return FALSE;
00254 }
00255
00256 void playlist_insert_folder (gint playlist, gint at, const gchar * folder,
00257 gboolean play)
00258 {
00259 gint playlist_id = playlist_get_unique_id (playlist);
00260 g_return_if_fail (playlist_id >= 0);
00261
00262 gchar * unix_name = uri_to_filename (folder);
00263 g_return_if_fail (unix_name);
00264
00265 if (unix_name[strlen (unix_name) - 1] == '/')
00266 unix_name[strlen (unix_name) - 1] = 0;
00267
00268 AddGroup * group = NULL;
00269
00270 for (GList * node = g_queue_peek_head_link (& add_queue); node; node =
00271 node->next)
00272 {
00273 AddGroup * test = node->data;
00274 if (test->playlist_id == playlist_id && test->at == at)
00275 {
00276 group = test;
00277 break;
00278 }
00279 }
00280
00281 if (! group)
00282 {
00283 group = g_slice_new (AddGroup);
00284 group->playlist_id = playlist_id;
00285 group->at = at;
00286 g_queue_init (& group->folders);
00287 group->play = FALSE;
00288 g_queue_push_tail (& add_queue, group);
00289 }
00290
00291 g_queue_push_tail (& group->folders, unix_name);
00292 group->play |= play;
00293
00294 if (! add_source)
00295 add_source = g_idle_add (add_cb, NULL);
00296 }