design: Rework playlists, add filtering

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This commit is contained in:
Bryan Schumaker 2013-07-04 17:44:40 -04:00 committed by Anna Schumaker
parent b786b44a49
commit 0b2fc03f19
1 changed files with 114 additions and 23 deletions

View File

@ -21,6 +21,7 @@ Files:
database.h
database.hpp
file.h
filter.h
group.h
index.h
library.h
@ -43,6 +44,7 @@ Files:
genre.db
groups.idx
library.db
playlists.lst
track.db
@ -208,7 +210,8 @@ Database: (lib/database.cpp)
- API:
Database.Database(filename);
Initializes database to use ~/.ocarina{-debug}/filename
Initializes database to use ~/.ocarina{-debug}/filename. Pass
an empty string if you do not want this database to be saved.
Database.load();
Reads data from file. Call after static initialization of
Ocarina to ensure idle tasks are configured.
@ -249,7 +252,8 @@ Index: (lib/index.cpp)
- API:
Index.Index(filename);
Initializes an index using ~/.ocarina{-debug}/filename
Initializes an index using ~/.ocarina{-debug}K/filename. Pass
an empty string if you do not want this index to be saved.
Index.load();
Reads data from a file. Call after static initialization of
Ocarina to ensure idle tasks are configured
@ -361,8 +365,8 @@ Library: (lib/library.cpp)
2) For each file in the scan directory, check if (lib_id, track_path)
exists in the known_tracks map.
2a) If the file is in the map, do nothing.
2b) Else, add track to the library and to the "All Music" and
"Library" and "Unplayed Tracks" groups
2b) Else, add track to the library, to the groups "All Music" and
"Library", and then to the filter index.
3) Save all databases
The taglib library should be used for finding artist, album, etc. tags
@ -404,8 +408,6 @@ Groups: (lib/group.cpp)
Banned Songs
These groups are mutually exclusive. A track is either
in the Library or the Banned Songs group
Unplayed tracks
Tracks with a play count of 0
- API
group :: init();
@ -437,26 +439,97 @@ Preferences: (lib/prefs.cpp)
Playlist: (lib/playlist.cpp)
A playlist is a simple list of songs that can be played either randomly
or in a user-defined order. It would probably be best to use a linked
list or vector to represent playlists, rather than creating a SQLite
table. I will be able to easily rearrange tracks in the playlist this
way. This will also make it easier to deal with playlist renames and
reordering by the user.
Playlists are a list of songs that the user has configured to play. I
will create a pool of playlists that will be filled by user actions.
Playlists will be put on a "deck" that is used to give an order to the
next songs played. When deck :: next() is called, find the first
playlist with PL_ENABLED set and call that playlists next() function.
When a playlist is empty, remove it from the deck.
- Flags:
enum playlist_flags {
PL_ENABLED (1 << 0),
PL_RANDOM (1 << 1),
PL_DRAIN (1 << 2),
};
- Playlist:
class Playlist : public Database {
private:
database<track_id> tracks; /* Keyed on track id */
unsigned int cur;
unsigned int flags;
public:
Playlist();
void add(vector<track_id> &);
void del(vector<track_id> &);
void set_flag(playlist_flags);
const unsigned int get_flags();
unsigned int size()
File &operator<<(File &);
File &operator>>(File &);
void sort();
void next();
}
File << flags << cur << tracks[0] << tracks[1] << ... << tracks[N];
- Deck:
list<Playlist> deck;
File << deck[0] << endl;
File << deck[1] << endl;
File << deck[N] << endl;
- API
/* Playlist management */
new_playlist();
del_playlist(playlist);
add_to_playlist(playlist, songid);
rm_from_playlist(playlist, songid);
playlist_size(playlist)
set_flag(playlist, flag)
deck :: init();
Read in the playlist file
deck :: new();
Adds a new playlist to the deck
deck :: rm(N)
Removes playlist N from the deck
Playlist *deck :: get(N)
Return playlist N from the deck
- Flags
PL_ENABLED (1 << 0)
PL_RANDOM (1 << 1)
PL_DRAIN (1 << 2)
- TODO <<<<<
What if each playlist has its own playlist_id for tracks? This would
allow for simpler removals, since I won't need to search for a track id.
I can easily create a function for mapping a list of playlist_ids to
track_ids...
Filter: (lib/filter.cpp)
Filtering is used to generate a subset of songs for easier searching.
- Index:
map<string, string> lowercase_cache;
map<string, set<string>> substring_cache;
Index filter_index("");
- Parsing:
1) Convert the provided string into a list of words, using whitespace
and the following characters as delimiters: \/,;()_~+"
For each word:
2) Check the lowercase_cache to see if we have seen the word before,
a) If we have, return the stored string
b) Convert the string to lowercase and strip out remaining
special characters. Add the result to the lowercase_cache;
3) Check the substring_cache to see if we have seen the word before,
a) If we have, use the substring set returned
b) Break the word into substrings from the front only. For
example: "dalek" would contain the substrings
{d, da, dal, dale, dalek}. Add to the substring cache.
- API:
filter :: add(string, track_id);
Parses the string and adds the track_id to the index.
void filter :: search(string, set<track_id> &);
Parse the string and fill in the set with matching tracks.
@ -468,6 +541,12 @@ Future work:
Hint: If feature B depends on A, implement A in 6.x and B in 6.x+1
- Break design doc into pieces: (6.1)
Createa script to join everything together cleanly.
- New default groups: (6.1)
Unplayed tracks
- Categories: (6.1)
Use these to make "groups of groups" for better organization.
Different categories can include Album, Artist and Genere
@ -500,3 +579,15 @@ Future work:
- Track tag editor: (6.2)
Make a pop-up window for editing the tags of a track. Be sure
to update the library information and the on-disk file.
- Clean up Scons files / build system: (6.0) <<<<<
I just had to try looking up something for Josh. I have no idea
how my build system works anymore. This is bad.
- Album art: (6.1)
- Playlist custom sorting: (6.1)
Click column headers to choos sort order
Keep a list of fields that the user has selected and place new
fields in the front of this list. Use a recursive stable sort
to do the sorting.