2013-05-13 23:13:54 -04:00
|
|
|
===============================================================================
|
|
|
|
= =
|
|
|
|
= Ocarina 6.0 =
|
|
|
|
= =
|
|
|
|
===============================================================================
|
|
|
|
|
2013-06-19 14:07:36 -04:00
|
|
|
My main goal for Ocarina 6.x is to plan out all of my actions before writing
|
|
|
|
code. In the past I was adding features as I thought of them before thinking
|
|
|
|
out how everything works together, and this made Ocarina difficult to maintain
|
|
|
|
because I had no overall plan. This document aims to fix that.
|
2013-05-13 23:13:54 -04:00
|
|
|
|
2013-05-26 11:08:41 -04:00
|
|
|
I will also create unit tests as I add features so bugs can be found faster.
|
|
|
|
|
|
|
|
|
2013-05-13 23:13:54 -04:00
|
|
|
Files:
|
2013-05-26 11:08:41 -04:00
|
|
|
ocarina/
|
|
|
|
design.txt
|
|
|
|
ocarina/gui/
|
|
|
|
ocarina/include/
|
2013-06-21 18:18:53 -04:00
|
|
|
group.h
|
2013-05-26 11:08:41 -04:00
|
|
|
library.h
|
|
|
|
playlist.h
|
|
|
|
ocarina/lib/
|
2013-06-21 18:18:53 -04:00
|
|
|
group.cpp
|
2013-05-26 11:08:41 -04:00
|
|
|
library.cpp
|
|
|
|
playlist.cpp
|
|
|
|
ocarina/tests/
|
|
|
|
|
2013-06-19 14:07:36 -04:00
|
|
|
$HOME/.ocarina{-debug}/
|
|
|
|
library/global.db
|
|
|
|
library/{0-X}
|
2013-05-13 23:13:54 -04:00
|
|
|
|
2013-05-26 11:08:41 -04:00
|
|
|
|
|
|
|
|
2013-05-13 23:13:54 -04:00
|
|
|
Database: (ocarina.db)
|
2013-05-26 11:08:41 -04:00
|
|
|
<Research FTS tables and inverted indexes for filtering>
|
2013-05-13 23:13:54 -04:00
|
|
|
|
2013-05-26 11:08:41 -04:00
|
|
|
Tags index -
|
|
|
|
<another FTS table>
|
|
|
|
Tag Name -> song ids
|
2013-05-13 23:13:54 -04:00
|
|
|
|
|
|
|
User settings -
|
|
|
|
create table if not exists config(
|
|
|
|
name PRIMARY KEY,
|
|
|
|
value INT,
|
|
|
|
);
|
|
|
|
|
2013-06-19 14:07:36 -04:00
|
|
|
Library: (lib/library.cpp)
|
2013-05-26 11:08:41 -04:00
|
|
|
|
2013-06-19 14:07:36 -04:00
|
|
|
This file will manage and control access to the library.
|
|
|
|
|
|
|
|
Album and artist information tables will be saved to a file in
|
|
|
|
library/global.db and can be shared across multiple library paths.
|
|
|
|
|
|
|
|
Internal:
|
|
|
|
|
|
|
|
struct Album {
|
|
|
|
unsigned int id;
|
|
|
|
string name;
|
|
|
|
short year;
|
|
|
|
};
|
|
|
|
vector<Album>;
|
|
|
|
|
|
|
|
struct Artist {
|
|
|
|
unsigned int id;
|
|
|
|
string name;
|
|
|
|
};
|
|
|
|
vector<Artist>
|
|
|
|
|
2013-06-21 18:18:53 -04:00
|
|
|
struct Genre {
|
|
|
|
unsigned int id;
|
|
|
|
string name;
|
|
|
|
};
|
|
|
|
vector<Genre>
|
|
|
|
|
2013-06-19 14:07:36 -04:00
|
|
|
struct Track {
|
|
|
|
unsigned int id;
|
|
|
|
unsigned int artist_id;
|
|
|
|
unsigned int album_id;
|
2013-06-21 18:18:53 -04:00
|
|
|
unsigned int genre_id;
|
2013-06-19 14:07:36 -04:00
|
|
|
bool valid;
|
|
|
|
|
|
|
|
string filepath;
|
|
|
|
string title;
|
|
|
|
string length_str;
|
|
|
|
short track;
|
|
|
|
short last_year;
|
|
|
|
short last_month;
|
|
|
|
short last_day;
|
|
|
|
unsigned int play_count;
|
|
|
|
unsigned int length;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Library {
|
|
|
|
string base_path;
|
|
|
|
bool enabled;
|
|
|
|
bool valid;
|
|
|
|
vector<struct Track>
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct trackid_t {
|
|
|
|
unsigned int library_id;
|
|
|
|
unsigned int track_id;
|
|
|
|
};
|
2013-05-26 11:08:41 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- API
|
|
|
|
/* Path management */
|
|
|
|
add_path_to_library(dir);
|
|
|
|
Add new row to paths table, update
|
|
|
|
rm_path_from_library(dir);
|
|
|
|
Remove row from paths table
|
|
|
|
update_path(dir);
|
|
|
|
Scan tracks table, remove paths that don't exist
|
|
|
|
Scan dir, add new files to database
|
|
|
|
Consider having SQLite create an index on tracks.filepath
|
|
|
|
update_all();
|
|
|
|
Call update_path() for each paths.dirpath
|
|
|
|
list_paths(list<>);
|
|
|
|
Tell the caller basic information about library paths
|
|
|
|
(dir, enabled, size,...)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
- 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)
|
|
|
|
|
|
|
|
- Flags
|
|
|
|
PL_ENABLED (1 << 0)
|
|
|
|
PL_RANDOM (1 << 1)
|
|
|
|
PL_DRAIN (1 << 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-06-21 18:18:53 -04:00
|
|
|
Groups: (lib/group.cpp)
|
|
|
|
Groups are going to be a new feature in Ocarina 6 and can compare
|
|
|
|
directly to Gmail-style labels. Ocarina 6 will create dynamic groups
|
|
|
|
that cannot be deleted by the user based on library status.
|
|
|
|
|
|
|
|
Default groups:
|
|
|
|
All music
|
|
|
|
All tracks are added to this group
|
|
|
|
Library
|
|
|
|
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
|
2013-05-26 11:08:41 -04:00
|
|
|
|
|
|
|
|
|
|
|
- API
|
2013-06-21 18:18:53 -04:00
|
|
|
list_groups();
|
|
|
|
Return a list of group names
|
|
|
|
group_get_tracks(name):
|
|
|
|
Return a list of tracks that are in group "name"
|
|
|
|
|
|
|
|
Track.add_to_group(name);
|
|
|
|
Add a track to a group
|
|
|
|
Track.rm_from_group(name);
|
|
|
|
Remove a track from a group
|
|
|
|
|
|
|
|
- Design TODO <<<<<
|
|
|
|
- I need a way to loop over each track in the library to create
|
|
|
|
dynamic groups. Whole library iterator?
|
|
|
|
- A "Track" class with functions for accessing tags and with access
|
|
|
|
to groups. Perhaps make "Track" its own file, outside of the
|
|
|
|
library and group code?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Future work:
|
|
|
|
I want to set reasonable expectations for Ocarina 6 so that I don't
|
|
|
|
have to spend a large amount of time coding before releasing something
|
|
|
|
to the wild. This section will be a list of features that I want, but
|
|
|
|
should be deferred to a future release so basic support can be coded.
|
|
|
|
|
|
|
|
Hint: If feature B depends on A, implement A in 6.x and B in 6.x+1
|
|
|
|
|
|
|
|
- Categories: (6.1)
|
|
|
|
Use these to make "groups of groups" for better organization.
|
|
|
|
Different categories can include Album, Artist and Genere
|
|
|
|
dynamic groups in addition to user created groups (see below)
|
|
|
|
|
|
|
|
The Artist, Album and Genre "tables" can be used to populate
|
|
|
|
these categories.
|
|
|
|
|
|
|
|
- User created song groups: (6.2)
|
|
|
|
Basic add and remove features can be implemented using the
|
|
|
|
Library and Banned Songs groups. This will give me a chance
|
|
|
|
to test saving groups on a small scale before letting users
|
|
|
|
create anything they want.
|
|
|
|
|
|
|
|
- Save a user's playlist as a group: (6.2)
|
|
|
|
|
|
|
|
- Library defragment: (6.1)
|
|
|
|
Ocarina 6.0 will leave holes in the library when tracks are
|
|
|
|
deleted, potentially leading to fragmentation and larger-than-
|
|
|
|
needed file sizes. A "defragment" utility can be created to
|
|
|
|
clean up unused slots.
|
|
|
|
|
|
|
|
To help with fixing groups, a mapping of (old values) ->
|
|
|
|
(new values) should be kept.
|