diff --git a/design/library.txt b/design/library.txt index c16a7798..0c9248d5 100644 --- a/design/library.txt +++ b/design/library.txt @@ -35,10 +35,11 @@ Library: (lib/library.cpp) class library :: Album : public DatabaseEntry { public: string name; - short year; + unsigned int year; + unsigned int artist_id; }; - File << year << name + File << artist_id << year << name - Artist: class library :: Artist : public DatabaseEntry { @@ -68,15 +69,15 @@ Library: (lib/library.cpp) - Track: class library :: Track : public DatabaseEntry { public: + unsigned int library_id; unsigned int artist_id; unsigned int album_id; unsigned int genre_id; - unsigned int library_id; - short track; - short last_year; - short last_month; - short last_day; + unsigned int track; + unsigned int last_year; + unsigned int last_month; + unsigned int last_day; unsigned int play_count; unsigned int length; @@ -86,8 +87,8 @@ Library: (lib/library.cpp) string filepath; }; - File << artist_id << album_id << genre_id << library_id << track << last_year - File << last_year << last_month << last_day << play_count << length << banned << endl + File << library_id << artist_id << album_id << genre_id << track << last_year + File << last_month << last_day << play_count << length << banned << endl File << title << endl; File << filepath << endl; @@ -158,4 +159,7 @@ Library: (lib/library.cpp) #ifdef CONFIG_DEBUG void library :: print_db(DB_Type); Print the database corresponding to DB_Type + + void library :: reset(); + Clear all databases, returning the library to an empty state. endif /* CONFIG_DEBUG */ diff --git a/include/library.h b/include/library.h index bf9833cb..f236169b 100644 --- a/include/library.h +++ b/include/library.h @@ -8,6 +8,7 @@ #include #include +#include namespace library { @@ -84,6 +85,38 @@ namespace library }; + 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; + + bool banned; + std :: string title; + std :: string length_str; + std :: string filepath; + + Track(); + Track(TagLib :: Tag *, TagLib :: AudioProperties *, + unsigned int, unsigned int, unsigned int, + unsigned int, const std :: string &); + void read(File &); + void write(File &); +#ifdef CONFIG_DEBUG + void print(); +#endif /* CONFIG_DEBUG */ + bool operator==(const Track &); + }; + + void init(); bool add_path(const std::string &); void del_path(unsigned int); diff --git a/lib/library.cpp b/lib/library.cpp index 6030806c..07dfc702 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -4,12 +4,12 @@ #include #include -#include static Database artist_db("artist.db", DB_UNIQUE); static Database album_db("album.db", DB_UNIQUE); static Database genre_db("genre.db", DB_UNIQUE); static Database library_db("library.db", DB_NORMAL); +static Database track_db("track.db", DB_UNIQUE); @@ -174,6 +174,67 @@ bool library :: Library :: operator==(library :: Library &rhs) +/* + * 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()), banned(false), + title(tag->title().to8Bit(true)) +{ + filepath = path.substr(library_db[library_id].root_path.size() + 1); +} + +void library :: Track :: read(File &f) +{ + f >> library_id >> artist_id >> album_id >> genre_id; + f >> track >> last_year >> last_month >> last_day; + f >> play_count >> length >> banned; + title = f.getline(); + filepath = f.getline(); +} + +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 << " " << banned << std :: endl; + f << title << std :: endl; + f << filepath; +} + +#ifdef CONFIG_DEBUG +void library :: Track :: print() +{ + :: print("%u. %s by %s from %s (%u)\n", track, title.c_str(), + artist_db[artist_id].name.c_str(), + album_db[album_id].name.c_str(), album_db[album_id].year); + :: print(" Genre: %s, Length: %u (seconds)\n", + genre_db[genre_id].name.c_str(), length); + :: print(" Play count: %u, last played %u/%u/%u\n", play_count, + last_day, last_month, last_year); + :: print(" %s", filepath.c_str()); +} +#endif /* CONFIG_DEBUG */ + +bool library :: Track :: operator==(const library :: Track &rhs) +{ + if (library_id == rhs.library_id) + return filepath == rhs.filepath; + return false; +} + + + /* * Internal library functions */ @@ -182,8 +243,9 @@ static void do_update(unsigned int, const std :: string &); static void read_tags(unsigned int lib_id, const std :: string &path) { TagLib :: Tag *tag; - TagLib :: FileRef ref(path.c_str()); - unsigned int artist_id; + TagLib :: AudioProperties *audio; + TagLib :: FileRef ref(path.c_str(), true, TagLib :: AudioProperties :: Fast); + unsigned int artist_id, album_id, genre_id; if (ref.isNull()) { print("ERROR: Could not read tags for file %s", path.c_str()); @@ -191,9 +253,13 @@ static void read_tags(unsigned int lib_id, const std :: string &path) } tag = ref.tag(); + audio = ref.audioProperties(); + artist_id = artist_db.insert(tag); - album_db.insert(library :: Album(tag, artist_id)); - genre_db.insert(library :: Genre(tag)); + album_id = album_db.insert(library :: Album(tag, artist_id)); + genre_id = genre_db.insert(library :: Genre(tag)); + track_db.insert(library :: Track(tag, audio, lib_id, artist_id, + album_id, genre_id, path)); } static void process_path(unsigned int lib_id, const std :: string &dir, @@ -207,6 +273,14 @@ static void process_path(unsigned int lib_id, const std :: string &dir, read_tags(lib_id, path); } +static void save_all_dbs() +{ + artist_db.save(); + album_db.save(); + genre_db.save(); + track_db.save(); +} + static void do_update(unsigned int lib_id, const std :: string &path) { GDir *dir; @@ -219,6 +293,7 @@ static void do_update(unsigned int lib_id, const std :: string &path) name = g_dir_read_name(dir); while (name != NULL) { process_path(lib_id, path, name); + save_all_dbs(); name = g_dir_read_name(dir); } } @@ -277,8 +352,8 @@ void library :: print_db(DB_Type type) case DB_LIBRARY: library_db.print(); break; - default: - break; + case DB_TRACK: + track_db.print(); } } @@ -288,5 +363,6 @@ void library :: reset() artist_db.clear(); genre_db.clear(); library_db.clear(); + track_db.clear(); } #endif /* CONFIG_DEBUG */ diff --git a/tests/library/gen_library.sh b/tests/library/gen_library.sh index fe2f5774..dec34d4b 100755 --- a/tests/library/gen_library.sh +++ b/tests/library/gen_library.sh @@ -44,7 +44,7 @@ function gen_tracks() vorbiscomment -a -q -t "ARTIST=$artist" -t "ALBUM=$album" \ -t "GENRE=${genres[$album]}" -t "DATE=${dates[$album]}" \ - -t "TRACK=$i" -t "TITLE=$track" "tests/library/$OGG" \ + -t "TRACKNUMBER=$i" -t "TITLE=$track" "tests/library/$OGG" \ "/tmp/$library/$artist/$album/$i - $track.ogg" done } diff --git a/tests/library/library.cpp b/tests/library/library.cpp index 3b1cce78..a1624270 100644 --- a/tests/library/library.cpp +++ b/tests/library/library.cpp @@ -95,6 +95,8 @@ void test_4() library :: print_db(library :: DB_ALBUM); print("\n"); library :: print_db(library :: DB_GENRE); + print("\n"); + library :: print_db(library :: DB_TRACK); } int main(int argc, char **argv)