/** * Copyright 2013 (c) Anna Schumaker. */ #include #include #include #include #include #include class LibraryQueue : public Queue { private: File f; public: LibraryQueue() : Queue(Q_ENABLED | Q_REPEAT), 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; f.open(OPEN_WRITE); f << _flags << " " << _sort_order.size(); for (it = _sort_order.begin(); it != _sort_order.end(); it++) f << " " << it->field << " " << it->ascending; f << std::endl; f.close(); } void load() { unsigned int field; bool ascending; unsigned int n; if (!f.open(OPEN_READ)) return; f >> _flags >> n; for (unsigned int i = 0; i < n; i++) { f >> field >> ascending; Queue :: sort((sort_t)field, (i == 0) ? true : false); if (ascending == false) Queue :: sort((sort_t)field, false); } } 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 { Library *library; std :: string path; }; static void scan_path(struct scan_info &); /* * Scanning functions are here */ static void tag_track(Library *library, const std::string &filepath) { Track *track; TagLib :: Tag *tag; TagLib :: AudioProperties *audio; TagLib :: FileRef ref(filepath.c_str(), true, TagLib::AudioProperties::Fast); if (ref.isNull()) { print("WARNING: Could not read tags for file %s\n", filepath.c_str()); return; } tag = ref.tag(); audio = ref.audioProperties(); track = tags :: add_track( tags :: get_album(tag->album().stripWhiteSpace().to8Bit(true), tag->year()), tags :: get_artist(tag->artist().stripWhiteSpace().to8Bit(true)), tags :: get_genre(tag->genre().stripWhiteSpace().to8Bit(true)), library, filepath, tag->title().stripWhiteSpace().to8Bit(true), audio->length(), tag->track() ); if (track) library_q.add(track); } static void process_path(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); } tags :: commit_track_db(); } static void validate_library(Library *&library) { Track *track; for (unsigned int i = 0; i < tags :: track_size(); i++) { track = tags :: get_track(i); if (!track || (track->library() != library)) continue; if (g_file_test(track->path().c_str(), G_FILE_TEST_EXISTS) == false) { library_q.del(track); tags :: remove_track(track); } } } /* * External API begins here */ void library :: init() { Track *track; library_q.load(); for (unsigned int i = 0; i < tags :: track_size(); i++) { track = tags :: get_track(i); if (track && (track->library()->enabled())) library_q.add(track); } } Library *library :: add(const std::string &dir) { Library *library = NULL; if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false) return library; library = tags :: get_library(dir); if (library) update(library); return library; } void library :: remove(Library *library) { if (library) { set_enabled(library, false); tags :: remove_library_tracks(library); tags :: remove_library(library); } } void library :: update(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 library :: update_all() { Library *library; for (unsigned int i = 0; i < tags :: library_size(); i++) { library = tags :: get_library(i); if (library) update(library); } } void library :: set_enabled(Library *library, bool enabled) { Track *track; if (!library || (library->enabled() == enabled)) return; library->set_enabled(enabled); for (unsigned int i = 0; i < tags :: track_size(); i++) { track = tags :: get_track(i); if (track && (track->library() == library)) { if (enabled) library_q.add(track); else library_q.del(track); } } } Queue *library :: get_queue() { return &library_q; }