/** * Copyright 2013 (c) Anna Schumaker. */ extern "C" { #include } #include #include #include class LibraryQueue : public queue { private: file f; public: LibraryQueue() { file_init(&f, "library.q", 0); } void save() { GSList *cur = q_sort; int field; if (!file_open(&f, OPEN_WRITE)) return; file_writef(&f, "%u %u", q_flags, g_slist_length(q_sort)); while (cur) { field = GPOINTER_TO_INT(cur->data); file_writef(&f, " %u %d", abs(field) - 1, field > 0); cur = g_slist_next(cur); } file_writef(&f, "\n"); file_close(&f); } void load() { unsigned int field; int ascending; unsigned int n; if (!file_open(&f, OPEN_READ)) return; file_readf(&f, "%u %u", &q_flags, &n); for (unsigned int i = 0; i < n; i++) { file_readf(&f, "%u %d", &field, &ascending); queue_sort(this, (compare_t)(field + 1), (i == 0) ? true : false); if (ascending == false) queue_sort(this, (compare_t)(field + 1), false); } file_close(&f); } }; static LibraryQueue library_q; struct scan_info { struct library *library; std :: string path; }; static void scan_path(void *); /* * Scanning functions are here */ static void tag_track(struct library *library, const std::string &filepath) { struct track *track = track_add(library, filepath.c_str()); if (track) queue_add(&library_q, track); } static void process_path(struct library *library, const std :: string &dir, const std :: string &name) { struct scan_info *scan = new struct scan_info; scan->library = library; scan->path = dir + "/" + name; if (g_file_test(scan->path.c_str(), G_FILE_TEST_IS_DIR) == true) idle_schedule (scan_path, scan); else { tag_track(library, scan->path); delete scan; } } static void scan_path(void *data) { GDir *dir; const char *name; struct scan_info *scan = (struct scan_info *)data; dir = g_dir_open(scan->path.c_str(), 0, NULL); if (dir == NULL) return; name = g_dir_read_name(dir); while (name != NULL) { process_path(scan->library, scan->path, name); name = g_dir_read_name(dir); } track_db_commit(); g_dir_close(dir); delete scan; } static void validate_library(void *data) { struct library *library = (struct library *)data; struct db_entry *dbe, *next; struct track *track; gchar *path; db_for_each(dbe, next, track_db_get()) { track = TRACK(dbe); if (track->tr_library != library) continue; path = track_path(track); if (g_file_test(path, G_FILE_TEST_EXISTS) == false) { queue_remove_all(&library_q, track); track_remove(track); } g_free(path); } } /* * External API begins here */ void collection_init(struct queue_ops *ops) { struct db_entry *track, *next; queue_init(&library_q, Q_ENABLED | Q_REPEAT | Q_ADD_FRONT, ops); db_for_each(track, next, track_db_get()) { if (TRACK(track)->tr_library->li_enabled) queue_add(&library_q, TRACK(track)); } queue_unset_flag(&library_q, Q_ADD_FRONT); library_q.load(); if (!library_q.q_sort) { queue_sort(&library_q, COMPARE_ARTIST, true); queue_sort(&library_q, COMPARE_YEAR, false); queue_sort(&library_q, COMPARE_TRACK, false); } queue_set_flag(&library_q, Q_SAVE_SORT); queue_set_flag(&library_q, Q_SAVE_FLAGS); } void collection :: save(struct queue *queue, enum queue_flags flag) { library_q.save(); } struct library *collection :: add(const std::string &dir) { struct library *library = NULL; if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false) return library; library = library_find(dir.c_str()); if (library) update(library); return library; } void collection :: remove(struct library *library) { if (library) { set_enabled(library, false); track_remove_all(library); library_remove(library); } } void collection :: update(struct library *library) { struct scan_info *scan = new struct scan_info; scan->library = library; if (library) { scan->path = library->li_path; idle_schedule(validate_library, library); idle_schedule(scan_path, scan); } } void collection :: update_all() { struct db_entry *library, *next; db_for_each(library, next, library_db_get()) update(LIBRARY(library)); } void collection :: set_enabled(struct library *library, bool enabled) { struct db_entry *dbe, *next; struct track *track; if (!library || (library->li_enabled == enabled)) return; library_set_enabled(library, enabled); queue_set_flag(&library_q, Q_ADD_FRONT); db_for_each(dbe, next, track_db_get()) { track = TRACK(dbe); if (track->tr_library == library) { if (enabled) queue_add(&library_q, track); else queue_remove_all(&library_q, track); } } queue_unset_flag(&library_q, Q_ADD_FRONT); queue_resort(&library_q); } queue *collection :: get_queue() { return &library_q; }