206 lines
5.6 KiB
Plaintext
206 lines
5.6 KiB
Plaintext
== 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<library :: Album> album_db(album.db);
|
|
Database<library :: AGInfo> artist_db(artist.db);
|
|
Database<library :: AGInfo> genre_db(genre.db);
|
|
Database<library :: Library> library_db(library.db);
|
|
Database<library :: Track> 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 list>
|
|
|
|
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 */
|
|
|