/** * Copyright 2013 (c) Anna Schumaker. */ #include #include #include #include class LibraryQueue : public Queue { private: file f; public: LibraryQueue() : Queue(Q_ENABLED | Q_REPEAT) { file_init(&f, "library.q", 0); Queue :: sort(SORT_ARTIST, true); Queue :: sort(SORT_YEAR, false); Queue :: sort(SORT_TRACK, false); } void save() { std::vector::iterator it; file_open(&f, OPEN_WRITE); file_writef(&f, "%u %u", _flags, _sort_order.size()); for (it = _sort_order.begin(); it != _sort_order.end(); it++) file_writef(&f, " %u %d", it->field, it->ascending); 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", &_flags, &n); for (unsigned int i = 0; i < n; i++) { file_readf(&f, "%u %d", &field, &ascending); Queue :: sort((sort_t)field, (i == 0) ? true : false); if (ascending == false) Queue :: sort((sort_t)field, false); } file_close(&f); } void set_flag(queue_flags f) { Queue :: set_flag(f); save(); } void unset_flag(queue_flags f) { Queue :: unset_flag(f); save(); } void sort(sort_t field, bool ascending) { Queue :: sort(field, ascending); save(); }; }; static LibraryQueue library_q; struct scan_info { struct library *library; std :: string path; }; static void scan_path(struct scan_info &); /* * Scanning functions are here */ static void tag_track(struct library *library, const std::string &filepath) { struct track *track = track_add(library, filepath); if (track) library_q.add(track); } static void process_path(struct library *library, const std :: string &dir, const std :: string &name) { struct scan_info scan = { .library = library, .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); } static void scan_path(struct scan_info &scan) { GDir *dir; const char *name; 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(); } static void validate_library(struct library *&library) { struct track *track, *next; db_for_each(track, next, track_db_get()) { if (track->tr_library != library) continue; if (g_file_test(track_path(track).c_str(), G_FILE_TEST_EXISTS) == false) { library_q.del(track); track_remove(track); } } } /* * External API begins here */ void collection :: init() { struct track *track, *next; library_q.load(); db_for_each(track, next, track_db_get()) { if (track->tr_library->li_enabled) library_q.add(track); } } 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); 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 = { .library = library, }; if (library) { scan.path = library->primary_key(); idle :: schedule(validate_library, library); idle :: schedule(scan_path, scan); } } void collection :: update_all() { struct library *library, *next; db_for_each(library, next, library_db_get()) update(library); } void collection :: set_enabled(struct library *library, bool enabled) { struct track *track, *next; if (!library || (library->li_enabled == enabled)) return; library_set_enabled(library, enabled); db_for_each(track, next, track_db_get()) { if (track->tr_library == library) { if (enabled) library_q.add(track); else library_q.del(track); } } } Queue *collection :: get_queue() { return &library_q; }