From a14f6145a51da12986b19239d85369c86eeb95e0 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Sat, 29 Mar 2014 11:44:39 -0400 Subject: [PATCH] Switch over to the new tagdb implementation Signed-off-by: Anna Schumaker --- gui/collection_mgr.cpp | 12 +- gui/gui.cpp | 14 +- gui/model.cpp | 38 ++-- include/callback.h | 6 +- include/library.h | 95 +------- include/ocarina.h | 4 +- include/playqueue.h | 14 +- include/tags.h | 2 + lib/audio.cpp | 29 ++- lib/callback.cpp | 4 +- lib/library.cpp | 504 +++++++---------------------------------- lib/playqueue.cpp | 95 ++------ lib/tags.cpp | 10 + 13 files changed, 174 insertions(+), 653 deletions(-) diff --git a/gui/collection_mgr.cpp b/gui/collection_mgr.cpp index 557b6426..cd17724f 100644 --- a/gui/collection_mgr.cpp +++ b/gui/collection_mgr.cpp @@ -96,19 +96,19 @@ void on_collection_toggled(const Glib::ustring &path) row[collection_cols.c_col_enabled]); } -static void on_library_add(unsigned int id, library :: Library *path) +static void on_library_add(unsigned int id, Library *library) { Gtk::TreeModel::Row row; Glib::RefPtr list = get_collection_list(); row = *(list->append()); row[collection_cols.c_col_id] = id; - row[collection_cols.c_col_enabled] = path->enabled; - row[collection_cols.c_col_size] = path->size; - row[collection_cols.c_col_path] = path->root_path; + row[collection_cols.c_col_enabled] = library->enabled; + row[collection_cols.c_col_size] = library->count; + row[collection_cols.c_col_path] = library->root_path; } -static void on_library_update(unsigned int id, library :: Library *path) +static void on_library_update(unsigned int id, Library *library) { Gtk::TreeModel::Row row; Glib::RefPtr list = get_collection_list(); @@ -118,7 +118,7 @@ static void on_library_update(unsigned int id, library :: Library *path) it != children.end(); it++) { row = *it; if (row[collection_cols.c_col_id] == id) - row[collection_cols.c_col_size] = path->size; + row[collection_cols.c_col_size] = library->count; } } diff --git a/gui/gui.cpp b/gui/gui.cpp index 9af95c46..959e62f0 100644 --- a/gui/gui.cpp +++ b/gui/gui.cpp @@ -64,7 +64,7 @@ static void set_label_text(Gtk::Label *label, const std::string &size, Glib::Markup::escape_text(text) + ""); } -static void on_track_loaded(library :: Song &song) +static void on_track_loaded(Track *track) { Gtk::ToggleButton *ban = get_widget("o_ban"); Gtk::ToggleButton *fav = get_widget("o_favorite"); @@ -73,16 +73,16 @@ static void on_track_loaded(library :: Song &song) Gtk::Label *album = get_widget("o_album"); Gtk::Label *duration = get_widget("o_total_time"); - set_label_text(title, "xx-large", song.track->title); - set_label_text(artist, "x-large", "By: " + song.artist->name); - set_label_text(album, "x-large", "From: " + song.album->name); - duration->set_text(song.track->length_str); + set_label_text(title, "xx-large", track->title); + set_label_text(artist, "x-large", "By: " + track->artist->name); + set_label_text(album, "x-large", "From: " + track->album->name); + duration->set_text(track->length_str); std::set ids = playlist :: get_tracks("Banned"); - bool banned = ids.find(song.track_id) != ids.end(); + bool banned = ids.find(track->id) != ids.end(); ids = playlist :: get_tracks("Favorites"); - bool favorite = ids.find(song.track_id) != ids.end(); + bool favorite = ids.find(track->id) != ids.end(); ban_connection.block(); fav_connection.block(); diff --git a/gui/model.cpp b/gui/model.cpp index 1d61bf10..07fee583 100644 --- a/gui/model.cpp +++ b/gui/model.cpp @@ -110,7 +110,7 @@ GType PlayqueueModel::get_column_type_vfunc(int index) const } } -void PlayqueueModel::get_value_uint(struct library::Song &song, int column, +void PlayqueueModel::get_value_uint(Track *track, int column, Glib::ValueBase &value) const { Glib::Value specific; @@ -118,20 +118,20 @@ void PlayqueueModel::get_value_uint(struct library::Song &song, int column, switch (column) { case 0: - specific.set(song.track->track); + specific.set(track->track); break; case 5: - specific.set(song.album->year); + specific.set(track->album->year); break; case 7: - specific.set(song.track->play_count); + specific.set(track->play_count); } value.init(Glib::Value::value_type()); value = specific; } -void PlayqueueModel::get_value_str(struct library::Song &song, int column, +void PlayqueueModel::get_value_str(Track *track, int column, Glib::ValueBase &value) const { std::stringstream ss; @@ -140,32 +140,32 @@ void PlayqueueModel::get_value_str(struct library::Song &song, int column, switch (column) { case 1: - specific.set(song.track->title); + specific.set(track->title); break; case 2: - specific.set(song.track->length_str); + specific.set(track->length_str); break; case 3: - specific.set(song.artist->name); + specific.set(track->artist->name); break; case 4: - specific.set(song.album->name); + specific.set(track->album->name); break; case 6: - specific.set(song.genre->name); + specific.set(track->genre->name); break; case 8: - if (song.track->play_count == 0) + if (track->play_count == 0) specific.set("Never"); else { - ss << song.track->last_month << " / "; - ss << song.track->last_day << " / "; - ss << song.track->last_year; + ss << track->last_month << " / "; + ss << track->last_day << " / "; + ss << track->last_year; specific.set(ss.str()); } break; case 9: - specific.set(Glib::Markup::escape_text(song.track->full_path)); + specific.set(Glib::Markup::escape_text(track->path())); } value.init(Glib::Value::value_type()); @@ -177,7 +177,7 @@ void PlayqueueModel::get_value_vfunc(const Gtk::TreeIter &iter, int column, Glib::ValueBase &value) const { unsigned int row; - struct library::Song song; + Track *track; if (!check_iter_validity(iter)) return; @@ -186,16 +186,16 @@ void PlayqueueModel::get_value_vfunc(const Gtk::TreeIter &iter, int column, return; row = GPOINTER_TO_UINT(iter.gobj()->user_data); - library :: lookup((*queue)[row], &song); + track = tagdb :: lookup((*queue)[row]); switch (column) { case 0: case 5: case 7: - get_value_uint(song, column, value); + get_value_uint(track, column, value); break; default: - get_value_str(song, column, value); + get_value_str(track, column, value); } } diff --git a/include/callback.h b/include/callback.h index 2a3a41e4..230643af 100644 --- a/include/callback.h +++ b/include/callback.h @@ -12,7 +12,7 @@ struct Callbacks { /* Audio callbacks */ void (*on_play)(); void (*on_pause)(); - void (*on_track_loaded)(library :: Song &); + void (*on_track_loaded)(Track *); void (*on_pause_count_changed)(bool, unsigned int); /* Deck callbacks */ @@ -20,8 +20,8 @@ struct Callbacks { void (*on_pq_removed)(Playqueue *); /* Library callbacks */ - void (*on_library_add)(unsigned int, library :: Library *); - void (*on_library_update)(unsigned int, library :: Library *); + void (*on_library_add)(unsigned int, Library *); + void (*on_library_update)(unsigned int, Library *); void (*on_library_track_add)(unsigned int); void (*on_library_track_del)(unsigned int); void (*on_library_track_updated)(unsigned int); diff --git a/include/library.h b/include/library.h index 003c8222..de7aded8 100644 --- a/include/library.h +++ b/include/library.h @@ -4,14 +4,9 @@ #ifndef OCARINA_LIBRARY_H #define OCARINA_LIBRARY_H -#include +#include #include -#include -#include - -struct ImportData; - namespace library { @@ -24,100 +19,12 @@ namespace library }; - class AGInfo : public DatabaseEntry { - public: - DB_Type db_type; - std :: string name; - std :: string key_lower; - - AGInfo(); - AGInfo(DB_Type, TagLib :: Tag *); - AGInfo(DB_Type, const std::string &); - const std::string primary_key() const; - void read(File &); - void write(File &); - }; - - - class Album : public DatabaseEntry { - public: - std :: string name; - std :: string name_lower; - unsigned int year; - - Album(); - Album(TagLib :: Tag *, unsigned int); - Album(const std::string &, unsigned int, unsigned int); - const std::string primary_key() const; - void read(File &); - void write(File &); - }; - - - class Library : public DatabaseEntry { - public: - std::string root_path; - unsigned int size; - bool enabled; - - Library(); - Library(const std::string &, bool); - const std::string primary_key() const; - void read(File &); - void write(File &); - }; - - - class Track : public DatabaseEntry { - public: - unsigned int library_id; - unsigned int artist_id; - unsigned int album_id; - unsigned int genre_id; - - unsigned int track; - unsigned int last_year; - unsigned int last_month; - unsigned int last_day; - unsigned int play_count; - unsigned int length; - - std :: string title; - std :: string title_lower; - std :: string length_str; - std :: string filepath; - std :: string full_path; - - Track(); - Track(TagLib :: Tag *, TagLib :: AudioProperties *, - unsigned int, unsigned int, unsigned int, - unsigned int, const std :: string &); - Track(ImportData *, unsigned int, unsigned int, - unsigned int, unsigned int); - const std::string primary_key() const; - void read(File &); - void write(File &); - }; - - - struct Song { - unsigned int track_id; - library :: Album *album; - library :: AGInfo *artist; - library :: AGInfo *genre; - library :: Library *library; - library :: Track *track; - }; - - void init(); void add_path(const std::string &); void del_path(unsigned int); void update_path(unsigned int); void update_all(); void set_enabled(unsigned int, bool); - void lookup(unsigned int, library :: Song *); - Library *lookup_path(unsigned int); void import(); void track_played(unsigned int); #ifdef CONFIG_TEST diff --git a/include/ocarina.h b/include/ocarina.h index c5a35f8d..7815c5ac 100644 --- a/include/ocarina.h +++ b/include/ocarina.h @@ -21,8 +21,8 @@ Gtk::Window *ocarina_init(int *, char ***); class PlayqueueModel : public Gtk::TreeModel, public Glib::Object { private: void increment_stamp(); - void get_value_uint(struct library::Song &, int, Glib::ValueBase &) const; - void get_value_str(struct library::Song &, int, Glib::ValueBase &) const; + void get_value_uint(Track *, int, Glib::ValueBase &) const; + void get_value_str(Track *, int, Glib::ValueBase &) const; bool check_iter_validity(const Gtk::TreeIter &) const; protected: diff --git a/include/playqueue.h b/include/playqueue.h index 857ede51..ec943163 100644 --- a/include/playqueue.h +++ b/include/playqueue.h @@ -17,18 +17,6 @@ enum playqueue_flags { PQ_DISABLE_CHANGED_SIZE = (1 << 31), }; -enum sort_t { - SORT_ARTIST, - SORT_ALBUM, - SORT_COUNT, - SORT_GENRE, - SORT_LENGTH, - SORT_PLAYED, - SORT_TITLE, - SORT_TRACK, - SORT_YEAR, -}; - struct sort_info { sort_t field; bool ascending; @@ -42,7 +30,7 @@ private: unsigned int cur; unsigned int length; - unsigned int find_sorted_id(library :: Song &); + unsigned int find_sorted_id(Track *); void _add_sort(sort_t, bool); public: diff --git a/include/tags.h b/include/tags.h index 6ebaa390..64ea6f27 100644 --- a/include/tags.h +++ b/include/tags.h @@ -121,6 +121,7 @@ namespace tagdb void init(); void commit(); + void commit_library(); Track *add_track(const std::string &, Library *); Track *import_track(const std::string &, Library *, const ImportData &); @@ -128,6 +129,7 @@ namespace tagdb void remove_track(unsigned int); void remove_library(unsigned int); Track *lookup(unsigned int); + Library *lookup_library(unsigned int); Database &get_track_db(); Database &get_library_db(); diff --git a/lib/audio.cpp b/lib/audio.cpp index 2610403a..eb06602a 100644 --- a/lib/audio.cpp +++ b/lib/audio.cpp @@ -26,11 +26,10 @@ static void parse_error(GstMessage *error) { GError *err; gchar *debug; - library :: Song song; + Track *track = tagdb :: lookup(cur_trackid); - library :: lookup(cur_trackid, &song); gst_message_parse_error(error, &err, &debug); - g_print("Error playing file: %s\n", song.track->primary_key().c_str()); + g_print("Error playing file: %s\n", track->path().c_str()); g_print("Error: %s\n", err->message); g_error_free(err); g_free(debug); @@ -91,11 +90,11 @@ static void save_state() f_cur_track.close(); } -static bool load_song(library :: Song &song) +static bool load_song(Track *track) { GstState state; gchar *uri; - std::string filepath = song.library->root_path + "/" + song.track->filepath; + std::string filepath = track->path(); if (o_should_pause == true) { state = GST_STATE_PAUSED; @@ -110,7 +109,7 @@ static bool load_song(library :: Song &song) g_object_set(G_OBJECT(ocarina_player), "uri", uri, NULL); g_free(uri); - get_callbacks()->on_track_loaded(song); + get_callbacks()->on_track_loaded(track); return change_state(state); } @@ -191,13 +190,13 @@ void audio :: seek_to(long pos) void audio :: next() { - library :: Song song; + Track *track; unsigned int id; track_loaded = false; id = deck :: next(); - library :: lookup(id, &song); - load_song(song); + track = tagdb :: lookup(id); + load_song(track); track_loaded = true; cur_trackid = id; @@ -209,33 +208,33 @@ void audio :: next() void audio :: previous() { - library :: Song song; + Track *track; unsigned int id; id = o_recently_played.next(); if (id == cur_trackid) return; - library :: lookup(id, &song); - load_song(song); + track = tagdb :: lookup(id); + load_song(track); cur_trackid = id; save_state(); } void audio :: load_trackid(unsigned int track_id) { - library :: Song song; + Track *track; if ((track_id == cur_trackid) && (track_loaded == true)) return; track_loaded = false; try { - library :: lookup(track_id, &song); + track = tagdb :: lookup(track_id); } catch (int err) { return; } - load_song(song); + load_song(track); track_loaded = true; cur_trackid = track_id; diff --git a/lib/callback.cpp b/lib/callback.cpp index 7d2394f5..d732934e 100644 --- a/lib/callback.cpp +++ b/lib/callback.cpp @@ -7,10 +7,10 @@ static void no_op() {} static void no_op(unsigned int) {} static void no_op(bool, unsigned int) {} -static void no_op(unsigned int id, library :: Library *path) {} +static void no_op(unsigned int id, Library *path) {} static void no_op(Playqueue *, unsigned int) {} static void no_op(Playqueue *) {} -static void no_op(library :: Song &) {} +static void no_op(Track *) {} static struct Callbacks callbacks = { diff --git a/lib/library.cpp b/lib/library.cpp index 4fd005ec..1cb0bb1f 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -11,319 +11,40 @@ #include #include -static Database album_db("album.db", false); -static Database artist_db("artist.db", false); -static Database genre_db("genre.db", false); -static Database track_db("track.db", false); -static Database library_db("library.db", false); - -struct ImportData { - std::string filepath; - std::string title; - unsigned int track; - unsigned int last_day; - unsigned int last_month; - unsigned int last_year; - unsigned int length; - unsigned int count; -}; - - -/* - * library :: Artist: Artist tag information - */ - -library :: AGInfo :: AGInfo() -{ -} - -library :: AGInfo :: AGInfo(DB_Type type, TagLib :: Tag *tag) - : db_type(type) -{ - if (db_type == DB_ARTIST) - name = tag->artist().stripWhiteSpace().to8Bit(true); - else if (db_type == DB_GENRE) - name = tag->genre().stripWhiteSpace().to8Bit(true); - else - throw -E_INVAL; - - key_lower = filter :: lowercase(name); -} - -library :: AGInfo :: AGInfo(DB_Type type, const std::string &str) - : db_type(type) -{ - if ((db_type == DB_ARTIST) || (db_type == DB_GENRE)) { - name = str; - key_lower = filter :: lowercase(name); - } else - throw -E_INVAL; -} - -const std::string library :: AGInfo :: primary_key() const -{ - return name; -} - -void library :: AGInfo :: read(File &f) -{ - name = f.getline(); - key_lower = filter :: lowercase(name); -} - -void library :: AGInfo :: write(File &f) -{ - f << name; -} - - - -/* - * library :: Album: Album tag information - */ - -library :: Album :: Album() - : name(""), year(0) -{ -} - -library :: Album :: Album(TagLib :: Tag *tag, unsigned int artist) - : name(tag->album().stripWhiteSpace().to8Bit(true)), - year(tag->year()) -{ - name_lower = filter :: lowercase(name); -} - -library :: Album :: Album(const std::string &str, unsigned int yr, unsigned int artist) - : name(str), year(yr) -{ - name_lower = filter :: lowercase(name); -} - -const std::string library :: Album :: primary_key() const -{ - std::stringstream ss; - ss << name << "." << year; - return ss.str(); -} - -void library :: Album :: read(File &f) -{ - f >> year; - name = f.getline(); - name_lower = filter :: lowercase(name); -} - -void library :: Album :: write(File &f) -{ - f << year << " " << name; -} - - - -/* - * library :: Library: Basic information about each directory in the library - */ - -library :: Library :: Library() - : root_path(""), size(0), enabled(false) -{ -} - -library :: Library :: Library(const std::string &path, bool is_enabled) - : root_path(path), size(0), enabled(is_enabled) -{ -} - -const std::string library :: Library :: primary_key() const -{ - return root_path; -} - -void library :: Library :: read(File &f) -{ - f >> enabled; - root_path = f.getline(); - size = 0; -} - -void library :: Library :: write(File &f) -{ - f << enabled << " " << root_path; -} - - - -/* - * library :: Track: Track tag information - */ - -library :: Track :: Track() - : library_id(0), artist_id(0), album_id(0), genre_id(0) -{ -} - -library :: Track :: Track(TagLib :: Tag *tag, TagLib :: AudioProperties *audio, - unsigned int lib, unsigned int artist, unsigned int album, - unsigned int genre, const std :: string &path) - : library_id(lib), artist_id(artist), album_id(album), genre_id(genre), - track(tag->track()), last_year(0), last_month(0), last_day(0), - play_count(0), length(audio->length()), - title(tag->title().stripWhiteSpace().to8Bit(true)) -{ - std::stringstream ss; - unsigned int minutes, seconds; - - full_path = path; - filepath = path.substr(library_db.at(library_id)->root_path.size() + 1); - title_lower = filter :: lowercase(title); - - minutes = length / 60; - seconds = length % 60; - ss << minutes << ":"; - if (seconds < 10) - ss << "0"; - ss << seconds; - length_str = ss.str(); -} - -library :: Track :: Track(struct ImportData *data, unsigned int lib, - unsigned int artist, unsigned int album, - unsigned int genre) - : library_id(lib), artist_id(artist), album_id(album), genre_id(genre), - track(data->track), last_year(data->last_year), last_month(data->last_month), - last_day(data->last_day), play_count(data->count), length(data->length), - title(data->title) -{ - std::stringstream ss; - unsigned int minutes, seconds; - - full_path = data->filepath; - filepath = full_path.substr(library_db.at(library_id)->root_path.size() + 1); - title_lower = filter :: lowercase(title); - - minutes = length / 60; - seconds = length % 60; - ss << minutes << ":"; - if (seconds < 10) - ss << "0"; - ss << seconds; - length_str = ss.str(); -} - -const std::string library :: Track :: primary_key() const -{ - return full_path; -} - -void library :: Track :: read(File &f) -{ - std::stringstream ss; - unsigned int minutes, seconds; - - f >> library_id >> artist_id >> album_id >> genre_id; - f >> track >> last_year >> last_month >> last_day; - f >> play_count >> length; - title = f.getline(); - filepath = f.getline(); - - title_lower = filter :: lowercase(title); - full_path = library_db.at(library_id)->root_path + "/" + filepath; - library_db.at(library_id)->size++; - - minutes = length / 60; - seconds = length % 60; - ss << minutes << ":"; - if (seconds < 10) - ss << "0"; - ss << seconds; - length_str = ss.str(); -} - -void library :: Track :: write(File &f) -{ - f << library_id << " " << artist_id << " " << album_id << " " << genre_id; - f << " " << track << " " << last_year << " " << last_month << " " << last_day; - f << " " << play_count << " " << length << " "; // << std :: endl; - f << title << std :: endl; - f << filepath; -} - - /* * Internal library functions */ struct scan_info { - unsigned int lib_id; + Library *library; std :: string path; }; static void do_scan_path(struct scan_info &); -static void read_tags(unsigned int lib_id, const std :: string &path) +static void read_tags(const std::string &path, Library *library) { - TagLib :: Tag *tag; - TagLib :: AudioProperties *audio; - TagLib :: FileRef ref(path.c_str(), true, TagLib :: AudioProperties :: Fast); - unsigned int artist_id, album_id, genre_id, track_id; - - if (ref.isNull()) { - print("ERROR: Could not read tags for file %s\n", path.c_str()); - return; - } - - tag = ref.tag(); - - audio = ref.audioProperties(); - - artist_id = artist_db.insert(library :: AGInfo(library :: DB_ARTIST, tag))->id; - album_id = album_db.insert(library :: Album(tag, artist_id))->id; - genre_id = genre_db.insert(library :: AGInfo(library :: DB_GENRE, tag))->id; - track_id = track_db.insert(library :: Track(tag, audio, lib_id, - artist_id, album_id, genre_id, path))->id; - - library_db.at(lib_id)->size++; - - filter::add(artist_db.at(artist_id)->name, track_id); - filter::add(album_db.at(album_id)->name, track_id); - filter::add(track_db.at(track_id)->title, track_id); - get_callbacks()->on_library_track_add(track_id); + Track *track = tagdb :: add_track(path, library); + get_callbacks()->on_library_track_add(track->id); } -static bool process_path(unsigned int lib_id, const std :: string &dir, +static void process_path(Library *library, const std :: string &dir, const std :: string &name) { struct scan_info scan; - bool changed = false; std :: string path = dir + "/" + name; if (g_file_test(path.c_str(), G_FILE_TEST_IS_DIR) == true) { - scan.lib_id = lib_id; + scan.library = library; scan.path = path; idle :: schedule (do_scan_path, scan); - } else { - if (track_db.find(path) == NULL) { - read_tags(lib_id, path); - changed = true; - } - } - - return changed; -} - -static void save_all_dbs() -{ - artist_db.save(); - album_db.save(); - genre_db.save(); - track_db.save(); + } else + read_tags(path, library); } static void do_scan_path(struct scan_info &scan) { GDir *dir; const char *name; - bool changed = false; dir = g_dir_open(scan.path.c_str(), 0, NULL); if (dir == NULL) @@ -331,86 +52,65 @@ static void do_scan_path(struct scan_info &scan) name = g_dir_read_name(dir); while (name != NULL) { - if (process_path(scan.lib_id, scan.path, name)) - changed = true; + process_path(scan.library, scan.path, name); name = g_dir_read_name(dir); } - if (changed == true) { - save_all_dbs(); - get_callbacks()->on_library_update(scan.lib_id, - &(*library_db.at(scan.lib_id))); - } + tagdb :: commit(); + get_callbacks()->on_library_update(scan.library->id, scan.library); } static void do_validate_library(unsigned int &lib_id) { std :: string path; - bool changed = false; + Database *db = &tagdb :: get_track_db(); + Database::iterator it; - if (track_db.size() == 0) - return; - - Database::iterator it; - for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) { - if ((*it)->library_id != lib_id) + for (it = db->begin(); it != db->end(); it = db->next(it)) { + Track *track = *it; + if (track->library->id != lib_id) continue; - path = (*it)->primary_key(); - if (g_file_test(path.c_str(), G_FILE_TEST_EXISTS) == false) { - dprint("Removing file: %s\n", path.c_str()); - track_db.remove(it - track_db.begin()); - library_db.at(lib_id)->size--; - changed = true; + if (g_file_test(track->path().c_str(), G_FILE_TEST_EXISTS) == false) { + dprint("Removing file: %s\n", track->path().c_str()); + tagdb :: remove_track(track->id); } } - if (changed == true) { - get_callbacks()->on_library_update(lib_id, &(*library_db.at(lib_id))); - save_all_dbs(); - } + get_callbacks()->on_library_update(lib_id, tagdb :: lookup_library(lib_id)); } static void do_update_library(unsigned int lib_id) { - struct scan_info scan = { lib_id, library_db.at(lib_id)->root_path }; + Library *library = tagdb :: lookup_library(lib_id); + struct scan_info scan = { library, library->root_path }; idle :: schedule(do_validate_library, lib_id); idle :: schedule(do_scan_path, scan); } -static void do_import_track(File &f, unsigned int lib_id) +static void do_import_track(File &f, Library *library) { struct ImportData data; - std::string artist, album, genre; - unsigned int artist_id, album_id, genre_id, track_id, year, banned, tmp; + unsigned int year, banned, tmp; - data.filepath = f.getline(); - data.title = f.getline(); + std::string filepath = f.getline(); + std::string title = f.getline(); + std::string artist = f.getline(); + std::string album = f.getline(); + std::string comment = f.getline(); + std::string genre = f.getline(); + std::string lenstr = f.getline(); - artist = f.getline(); - album = f.getline(); - f.getline(); /* comment */ - genre = f.getline(); - f.getline(); /* lenstr */ - f >> tmp /* id */ >> year >> data.track >> data.count; - f >> data.last_day >> data.last_month >> data.last_year >> data.length; + f >> tmp /* id */ >> year >> tmp >> data.play_count; + f >> data.last_day >> data.last_month >> data.last_year >> tmp; f >> tmp >> tmp >>tmp >> banned; /* bitrate, sample, channels, banned */ f.getline(); /* get rest of line */ - artist_id = artist_db.insert(library :: AGInfo(library :: DB_ARTIST, artist))->id; - album_id = album_db.insert(library :: Album(album, year, artist_id))->id; - genre_id = genre_db.insert(library :: AGInfo(library :: DB_GENRE, genre))->id; - track_id = track_db.insert(library :: Track(&data, lib_id, artist_id, - album_id, genre_id))->id; - library_db.at(lib_id)->size++; - - filter::add(artist_db.at(artist_id)->name, track_id); - filter::add(album_db.at(album_id)->name, track_id); - filter::add(track_db.at(track_id)->title, track_id); - get_callbacks()->on_library_track_add(track_id); + Track *track = tagdb :: import_track(filepath, library, data); + get_callbacks()->on_library_track_add(track->id); if (banned == true) - get_callbacks()->on_library_import_ban(track_id); + get_callbacks()->on_library_import_ban(track->id); } static void do_import_library(std::string &s) @@ -431,21 +131,19 @@ static void do_import_library(std::string &s) path = f.getline(); f >> id >> enabled >> next_id >> size; - /* Assign this path a new id */ - if (library_db.find(path) != NULL) { + Library *library = tagdb :: add_library(path); + if (library == NULL) { print("Library already contains path: %s, skipping\n", path.c_str()); return; } print("Adding path: %s\n", path.c_str()); - id = library_db.insert(library :: Library(path, enabled))->id; - get_callbacks()->on_library_add(id, &(*library_db.at(id))); - library_db.save(); + get_callbacks()->on_library_add(library->id, library); f.getline(); /* Get rest of line */ for (unsigned int i = 0; i < size; i++) - do_import_track(f, id); - save_all_dbs(); - get_callbacks()->on_library_update(id, &(*library_db.at(id))); + do_import_track(f, library); + tagdb :: commit(); + get_callbacks()->on_library_update(library->id, library); library :: update_path(id); } @@ -458,120 +156,86 @@ static void do_import_library(std::string &s) void library :: init() { - album_db.load(); - artist_db.load(); - genre_db.load(); - library_db.load(); - track_db.load(); + tagdb :: init(); + Database *db = &tagdb :: get_track_db(); Database::iterator it; - for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) { - filter::add(artist_db.at((*it)->artist_id)->name, (*it)->id); - filter::add(album_db.at((*it)->album_id)->name, (*it)->id); - filter::add((*it)->title, (*it)->id); - if (library_db.at((*it)->library_id)->enabled) + for (it = db->begin(); it != db->end(); it = db->next(it)) { + if ((*it)->library->enabled) get_callbacks()->on_library_track_add((*it)->id); } + Database *ldb = &tagdb :: get_library_db(); Database::iterator l_it; - for (l_it = library_db.begin(); l_it != library_db.end(); l_it = library_db.next(l_it)) - get_callbacks()->on_library_add((*l_it)->id, &(*library_db.at((*l_it)->id))); + + for (l_it = ldb->begin(); l_it != ldb->end(); l_it = ldb->next(l_it)) + get_callbacks()->on_library_add((*l_it)->id, *l_it); } void library :: add_path(const std::string &dir) { - unsigned int id; if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false) throw -E_INVAL; - if (library_db.find(dir) != NULL) + + Library *library = tagdb :: add_library(dir); + if (!library) return; - id = library_db.insert(library :: Library(dir, true))->id; - library_db.save(); - - get_callbacks()->on_library_add(id, &(*library_db.at(id))); - update_path(id); + get_callbacks()->on_library_add(library->id, library); + update_path(library->id); } void library :: del_path(unsigned int id) { + Database *db = &tagdb :: get_track_db(); Database::iterator it; - for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) { - if ((*it)->library_id == id) { + for (it = db->begin(); it != db->end(); it = db->next(it)) { + if ((*it)->library->id == id) get_callbacks()->on_library_track_del((*it)->id); - track_db.remove((*it)->id); - } } - library_db.remove(id); - - track_db.save(); - library_db.save(); + tagdb :: remove_library(id); + tagdb :: commit(); } void library :: update_path(unsigned int id) { - if (id > library_db.size()) - return; - if (library_db.at(id) == NULL) - return; - do_update_library(id); + Library *library = tagdb :: lookup_library(id); + if (library) + do_update_library(library->id); } void library :: update_all() { + Database *db = &tagdb :: get_library_db(); Database::iterator it; - for (it = library_db.begin(); it != library_db.end(); it = library_db.next(it)) - update_path(it - library_db.begin()); + for (it = db->begin(); it != db->end(); it = db->next(it)) + update_path((*it)->id); } void library :: set_enabled(unsigned int id, bool enabled) { - unsigned int t; + Library *library = tagdb :: lookup_library(id); + + library->enabled = enabled; + tagdb :: commit_library(); + + Database *db = &(tagdb :: get_track_db()); Database::iterator it; - library_db.at(id)->enabled = enabled; - library_db.save(); - - for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) { - if ((*it)->library_id == id) { - t = it - track_db.begin(); + for (it = db->begin(); it != db->end(); it = db->next(it)) { + if ((*it)->library->id == id) { if (enabled) - get_callbacks()->on_library_track_add(t); + get_callbacks()->on_library_track_add((*it)->id); else - get_callbacks()->on_library_track_del(t); + get_callbacks()->on_library_track_del((*it)->id); } } } -void library :: lookup(unsigned int id, library :: Song *song) -{ - if (id >= track_db.actual_size()) - throw -E_EXIST; - - song->track = &(*track_db.at(id)); - if (song->track == NULL) - throw -E_EXIST; - - song->track_id = id; - song->artist = &(*artist_db.at(song->track->artist_id)); - song->album = &(*album_db.at(song->track->album_id)); - song->genre = &(*genre_db.at(song->track->genre_id)); - song->library = &(*library_db.at(song->track->library_id)); -} - -library :: Library *library :: lookup_path(unsigned int id) -{ - if (id >= library_db.actual_size()) - throw -E_EXIST; - if (library_db.at(id) == NULL) - throw -E_EXIST; - return &(*library_db.at(id)); -} - void library :: import() { unsigned int i = 0; @@ -597,14 +261,18 @@ void library :: track_played(unsigned int id) { time_t the_time = time(NULL); struct tm *now = localtime(&the_time); + Track *track = tagdb :: lookup(id); - track_db.at(id)->play_count++; - track_db.at(id)->last_day = now->tm_mday; - track_db.at(id)->last_month = now->tm_mon + 1; - track_db.at(id)->last_year = now->tm_year + 1900; + if (!track) + return; - track_db.save(); - get_callbacks()->on_library_track_updated(id); + track->play_count++; + track->last_day = now->tm_mday; + track->last_month = now->tm_mon + 1; + track->last_year = now->tm_year + 1900; + + tagdb :: commit(); + get_callbacks()->on_library_track_updated(track->id); } #ifdef CONFIG_TEST diff --git a/lib/playqueue.cpp b/lib/playqueue.cpp index 03cce92d..15440487 100644 --- a/lib/playqueue.cpp +++ b/lib/playqueue.cpp @@ -97,72 +97,21 @@ std::string Playqueue :: get_length_str() return ss.str(); } -/* - * Returns: - * 0: lhs == rhs - * < 0: lhs < rhs - * > 0: lhs > rhs - */ -static inline int compare_uint(unsigned int a, unsigned int b) -{ - if (a == b) - return 0; - if (a < b) - return -1; - return 1; -} - -/* - * Returns: - * 0: lhs == rhs - * < 0: lhs < rhs, or rhs is empty - * > 0: lhs > rhs, or lhs is empty - */ -static inline int compare_string(const std::string &a, const std::string &b) -{ - if (a.size() == 0) - return 1; - else if (b.size() == 0) - return -1; - return a.compare(b); -} - /* * std::string.compare() returns * 0: Strings are equal * < 0: a < b * > 0: a > b */ -static inline int track_compare(library :: Song &lhs, library :: Song &rhs, - sort_t field) +static inline int track_compare(Track *lhs, Track *rhs, sort_t field) { - switch (field) { - case SORT_ARTIST: - return compare_string(lhs.artist->key_lower, rhs.artist->key_lower); - case SORT_ALBUM: - return compare_string(lhs.album->name_lower, rhs.album->name_lower); - case SORT_COUNT: - return compare_uint(lhs.track->play_count, rhs.track->play_count); - case SORT_GENRE: - return compare_string(lhs.genre->key_lower, rhs.genre->key_lower); - case SORT_LENGTH: - return compare_uint(lhs.track->length, rhs.track->length); - case SORT_PLAYED: - return compare_uint(lhs.track->play_count, rhs.track->play_count); - case SORT_TITLE: - return compare_string(lhs.track->title_lower, rhs.track->title_lower); - case SORT_TRACK: - return compare_uint(lhs.track->track, rhs.track->track); - default: //case SORT_YEAR - int ret = compare_uint(lhs.album->year, rhs.album->year); - if (ret != 0) - return ret; - return compare_string(lhs.album->name_lower, rhs.album->name_lower); - } + int ret = lhs->less_than(rhs, field); + if (field == SORT_YEAR && ret == 0) + ret = lhs->less_than(rhs, SORT_ALBUM); + return ret; } -static bool track_less_than(library :: Song &lhs, library :: Song &rhs, - std::list &order) +static bool track_less_than(Track *lhs, Track *rhs, std::list &order) { std::list::iterator it; int res; @@ -178,9 +127,9 @@ static bool track_less_than(library :: Song &lhs, library :: Song &rhs, return res; } -unsigned int Playqueue :: find_sorted_id(library :: Song &rhs) +unsigned int Playqueue :: find_sorted_id(Track *rhs) { - library :: Song lhs; + Track *lhs; unsigned int begin = 0, end = (tracks.size() - 1), mid; if (tracks.size() == 0) @@ -188,7 +137,7 @@ unsigned int Playqueue :: find_sorted_id(library :: Song &rhs) while (end > begin) { mid = begin + ((end - begin) / 2); - library :: lookup(tracks[mid], &lhs); + lhs = tagdb :: lookup(tracks[mid]); if (track_less_than(lhs, rhs, sort_order)) begin = mid + 1; else { @@ -199,7 +148,7 @@ unsigned int Playqueue :: find_sorted_id(library :: Song &rhs) } } - library :: lookup(tracks[begin], &lhs); + lhs = tagdb :: lookup(tracks[begin]); if (track_less_than(lhs, rhs, sort_order)) return begin + 1; return begin; @@ -208,14 +157,13 @@ unsigned int Playqueue :: find_sorted_id(library :: Song &rhs) unsigned int Playqueue :: add(unsigned int track_id) { unsigned int id = tracks.size(); - library :: Song song; - library :: lookup(track_id, &song); + Track *track = tagdb :: lookup(track_id); if (sort_order.size() > 0) - id = find_sorted_id(song); + id = find_sorted_id(track); tracks.insert(tracks.begin() + id, track_id); - length += song.track->length; + length += track->length; get_callbacks()->on_queue_track_add(this, id); if (!(flags & PQ_DISABLE_CHANGED_SIZE)) get_callbacks()->on_queue_changed(); @@ -224,11 +172,11 @@ unsigned int Playqueue :: add(unsigned int track_id) unsigned int Playqueue :: add_front(unsigned int track_id) { - library :: Song song; + Track *track; tracks.insert(tracks.begin(), track_id); - library :: lookup(track_id, &song); - length += song.track->length; + track = tagdb :: lookup(track_id); + length += track->length; get_callbacks()->on_queue_track_add(this, 0); if (!(flags & PQ_DISABLE_CHANGED_SIZE)) get_callbacks()->on_queue_changed(); @@ -237,12 +185,12 @@ unsigned int Playqueue :: add_front(unsigned int track_id) void Playqueue :: del(unsigned int plist_id) { - library :: Song song; + Track *track; unsigned int track_id = tracks[plist_id]; tracks.erase(tracks.begin() + plist_id); - library :: lookup(track_id, &song); - length -= song.track->length; + track = tagdb :: lookup(track_id); + length -= track->length; get_callbacks()->on_queue_track_del(this, plist_id); if (!(flags & PQ_DISABLE_CHANGED_SIZE)) get_callbacks()->on_queue_changed(); @@ -281,9 +229,8 @@ public: SortTracks(std::list f) : fields(f) {} bool operator()(unsigned int a, unsigned int b) { - library::Song lhs, rhs; - library :: lookup(a, &lhs); - library :: lookup(b, &rhs); + Track *lhs = tagdb :: lookup(a); + Track *rhs = tagdb :: lookup(b); return track_less_than(lhs, rhs, fields); } }; diff --git a/lib/tags.cpp b/lib/tags.cpp index 4c30c5c8..c3f8ec1f 100644 --- a/lib/tags.cpp +++ b/lib/tags.cpp @@ -324,6 +324,11 @@ void tagdb :: commit() track_db.save(); } +void tagdb :: commit_library() +{ + library_db.save(); +} + Track *tagdb :: add_track(const std::string &filepath, Library *library) { unsigned int size = track_db.size(); @@ -376,6 +381,11 @@ Track *tagdb :: lookup(unsigned int track_id) return track_db.at(track_id); } +Library *tagdb :: lookup_library(unsigned int library_id) +{ + return library_db.at(library_id); +} + Database &tagdb :: get_track_db() { return track_db;