== Files == ocarina/include/ library.h ocarina/lib/ library.cpp $HOME/.ocarina{-debug}/ album.db artist.db genre.db library.db track.db == Depends == idle database playlist filter Library: (lib/library.cpp) The library manages databases containing track information added by the user. Ocarina 6 splits the library into multiple database tables for storing content. The library will exist in a library namespace to to make functions and classes more unique. - Databases: enum DB_Type { DB_ALBUM, DB_ARTIST, DB_GENRE, DB_LIBRARY, DB_TRACK, }; - Album: class library :: Album : public DatabaseEntry { public: /* primary_key = "$name.$year.$artist_id" */ string name; string name_lower; unsigned int year; unsigned int artist_id; }; File << artist_id << year << name - Artist and Genre: class library :: AGInfo : public DatabaseEntry { public: string name; /* primary key */ string name_lower; }; File << name - Library: class library :: Library : public DatabaseEntry { public: string root_path; /* primary_key */ unsigned int count; bool enabled; }; File << enabled << root_path - Track: The primary key for a track is the full filepath (library.root_path + track.filepath) class library :: Track : public DatabaseEntry { public: /* primary_key = library.root_path + "/" + filepath */ 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; string length_str; string title; string title_lower; string filepath; }; File << library_id << artist_id << album_id << genre_id; File << track << last_year << last_month << last_day << play_count; File << length << length_str << endl File << title << endl; File << filepath << endl; - Song: struct Song { library :: Album *album; library :: AGInfo *artist; library :: AGInfo *genre; library :: Library *library; library :: Track *track; }; - Databases: Database album_db(album.db); Database artist_db(artist.db); Database genre_db(genre.db); Database library_db(library.db); Database track_db(track.db); - Updating algorithm: 1) Use a single IdleTask to loop over each track in the library, check if the track still exists in the filesystem and remove it from library_db if not. 2) For each directory in the scan directory, create an IdleTask to scan the next level of directories. 3) For each file in the scan directory, check if the file already exists in the track_db and add it to the database if not. Save each database after adding files. The taglib library should be used for finding artist, album, etc. tags for each track. - Importing Ocarina 5.11 stores library files in ~/.ocarina/library/. Importing involves reading each file and adding them to the database. If the file describes a path already in the database then DO NOT overwrite the current path and instead move on to the next file. If version != 2 then move on to the next file. File format: File << version << endl; /* version == 2 */ File << path << endl; File << id << enabled << next_track_id << size << endl; File << Track format: File << filepath << endl; File << title << endl; File << artist << endl; File << album << endl; File << comment << endl; File << genre << endl; File << lenstr << endl; File << id << year << track << count; File << last_day << last_month << last_year; File << length << bitrate << sample << channels << banned << endl; - Testing: The script tests/library/gen_library.sh will create a sample library in the /tmp/ directory for testing purposes. All the track files are complete silence, but the script will fake up tags for each file. To test importing, create several mock library files and copy them to ~/.ocarina-test/library/ and attempt to read them in. - API void library :: init(); Initialize databases and read files from disk. While reading the library: - Update the count of tracks in each library path - Find the lowercase text of artist, album, genre, track void library :: add_path(string dir); If dir is not a directory: throw -EINVAL Trigger the on_library_add() callback on success. void library :: del_path(unsigned int lib_id); Invalidate a library_db row and all tracks owned by that path if lib_id is not valid, throw -EEXIST. void library :: update_path(lib_id); Update the given library_db row. If lib_id is not valid, throw -EEXIST. Trigger the on_library_update() callback. void library :: update_all(); Update all library paths. Trigger the on_library_update() callback for each path. void library :: set_enabled(unsigned int id, bool enabled); Either enable or disable a library path. Trigger on_library_track_del() for each track disabled this way. struct Song library :: lookup(track_id); Fill out a Song structure for the provided track_id. Throw -EEXIST if there is no track mapping to track_id. struct library :: Library *library :: lookup_path(unsigned int id); Return the library path with index id. Throw -EEXIST if there is no such path. void library :: import(); Call this function to import an Ocarina 5.11 style library, following the "Importing" section above. #ifdef CONFIG_TEST 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_TEST */