playlist: Implement reachitecting of playlists

I changed the two playlists that are supported, added in exception
handling, and removed the list() function since I will always know the
names of playlists.  I also rename everything to "playlist" from
"group".

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
Anna Schumaker 2013-12-31 16:58:40 -05:00 committed by Anna Schumaker
parent 914473e10a
commit 114c22bb12
13 changed files with 224 additions and 183 deletions

20
config
View File

@ -34,16 +34,16 @@ class Config:
if self.TEST: env.Append( CCFLAGS = [ "-DCONFIG_TEST" ])
def reset(self, TEST = False):
self.AUDIO = False
self.DATABASE = False
self.DECK = False
self.FILE = False
self.FILTER = False
self.GROUP = False
self.IDLE = False
self.LIBRARY = False
self.PLAYLIST = False
self.TEST = TEST
self.AUDIO = False
self.DATABASE = False
self.DECK = False
self.FILE = False
self.FILTER = False
self.IDLE = False
self.LIBRARY = False
self.PLAYLIST = False
self.PLAYQUEUE = False
self.TEST = TEST
self.reconfigure()
CONFIG = Config()

View File

@ -496,9 +496,9 @@ Idle queue: (lib/idle.cpp)
Playlists: (lib/playlist.cpp)
Playlists are going to be a new feature in Ocarina 6 and can compare
directly to Gmail-style labels. Ocarina 6.0 will support two different
playlists that the user can add songs to: banned and favorites.
Playlists are a new feature in Ocarina 6 and are modeled after Gmail
labels. Ocarina 6.0 will support two different playlists that the
user can add tracks to: banned and favorites.
Future releases will add support for more playlists.
@ -508,24 +508,35 @@ Playlists: (lib/playlist.cpp)
- Default playlists:
Favorites:
The user will add music they really like to this playlist.
Banned:
The user should add music they do not like to this playlist.
Tracks should be removed from the Library playlist when they
are banned and added back to the playlist when they are
Tracks should be removed from the Library playqueue when they
are banned and added back to the playqueue when they are
un-banned.
- API
void playlist :: init():
Load the playlist database.
void playlist :: add(name, track_id);
playlist_idx.insert(name, track_id);
Add the track_id to the playlist named "name". Save the
database to disk.
Throw -EEXIST if "name" does not exist.
void playlist :: del(name, track_id);
playlist_idx.delete(name, track_id)
Remove the track_id from the playlist named "name". Save the
database to disk. Attempting to remove a track_id that does
not exist is not an error.
Throw -EEXIST if "name" does not exist.
void void playlist :: list(list<string> &);
return playlist_idx.keys();
const std::set<unsigned int> &playlist :: get_tracks(name);
Return the set of tracks representing the requested group.
Throw -EEXIST if "name" does not exist.
void playlist :: get_tracks(name);
return playlist_idx[name]
void playlist :: clear();
This function only exists if CONFIG_TEST is enabled. Clear
(reset) the playlist database.

View File

@ -10,9 +10,9 @@
database
Playlists: (lib/playlist.cpp)
Playlists are going to be a new feature in Ocarina 6 and can compare
directly to Gmail-style labels. Ocarina 6.0 will support two different
playlists that the user can add songs to: banned and favorites.
Playlists are a new feature in Ocarina 6 and are modeled after Gmail
labels. Ocarina 6.0 will support two different playlists that the
user can add tracks to: banned and favorites.
Future releases will add support for more playlists.
@ -22,21 +22,32 @@ Playlists: (lib/playlist.cpp)
- Default playlists:
Favorites:
The user will add music they really like to this playlist.
Banned:
The user should add music they do not like to this playlist.
Tracks should be removed from the Library playlist when they
are banned and added back to the playlist when they are
Tracks should be removed from the Library playqueue when they
are banned and added back to the playqueue when they are
un-banned.
- API
void playlist :: init():
Load the playlist database.
void playlist :: add(name, track_id);
playlist_idx.insert(name, track_id);
Add the track_id to the playlist named "name". Save the
database to disk.
Throw -EEXIST if "name" does not exist.
void playlist :: del(name, track_id);
playlist_idx.delete(name, track_id)
Remove the track_id from the playlist named "name". Save the
database to disk. Attempting to remove a track_id that does
not exist is not an error.
Throw -EEXIST if "name" does not exist.
void void playlist :: list(list<string> &);
return playlist_idx.keys();
const std::set<unsigned int> &playlist :: get_tracks(name);
Return the set of tracks representing the requested group.
Throw -EEXIST if "name" does not exist.
void playlist :: get_tracks(name);
return playlist_idx[name]
void playlist :: clear();
This function only exists if CONFIG_TEST is enabled. Clear
(reset) the playlist database.

View File

@ -82,7 +82,7 @@ static inline void index_insert(Database<IndexEntry> &db,
{
try {
db.find(key).insert(val);
} catch (...) {
} catch (int error) {
db.insert(IndexEntry(key, val));
}
}

View File

@ -1,21 +1,24 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#ifndef OCARINA_GROUP_H
#define OCARINA_GROUP_H
#ifndef OCARINA_PLAYLIST_H
#define OCARINA_PLAYLIST_H
#include <list>
#include <set>
#include <string>
namespace group
namespace playlist
{
void init();
void add(const std::string &, unsigned int);
void del(const std::string &, unsigned int);
void list(std::list<std::string> &);
const std::set<unsigned int> &get_tracks(const std::string &);
#ifdef CONFIG_TEST
void clear();
#endif /* CONFIG_TEST */
};
#endif /* OCARINA_GROUP_H */
#endif /* OCARINA_PLAYLIST_H */

View File

@ -20,9 +20,9 @@ modules = {
"DECK" : Module("deck.cpp", depends = [ "PLAYQUEUE" ]),
"FILE" : Module("file.cpp", package = "glib-2.0"),
"FILTER" : Module("filter.cpp", depends = [ "DATABASE" ]),
"PLAYLIST" : Module("playlist.cpp", depends = [ "DATABASE" ]),
"IDLE" : Module("idle.cpp"),
"LIBRARY" : Module("library.cpp", package = "taglib", depends = [ "DATABASE", "IDLE" ]),
"PLAYLIST" : Module("playlist.cpp", depends = [ "DATABASE" ]),
"PLAYQUEUE" : Module("playlist.cpp", depends = [ "FILE" ]),
###########################

View File

@ -2,45 +2,50 @@
* Copyright 2013 (c) Anna Schumaker.
*/
#include <database.h>
#include <group.h>
#include <error.h>
#include <playlist.h>
static std::set<unsigned int> empty_set;
Database<IndexEntry, const std::string> group_index("");
static Database<IndexEntry> playlist_db("playlist.db");
void group :: add(const std::string &name, unsigned int track_id)
void playlist :: init()
{
if ((name == "All Music") || (name == "Library") || (name == "Banned")) {
playlist_db.load();
}
void playlist :: add(const std::string &name, unsigned int track_id)
{
if ((name == "Banned") || (name == "Favorites")) {
index_insert(playlist_db, name, track_id);
playlist_db.save();
} else
throw -EEXIST;
}
void playlist :: del(const std::string &name, unsigned int track_id)
{
if ((name == "Banned") || (name == "Favorites")) {
index_remove(playlist_db, name, track_id);
playlist_db.save();
} else
throw -EEXIST;
}
const std::set<unsigned int> &playlist :: get_tracks(const std::string &name)
{
if ((name == "Banned") || (name == "Favorites")) {
try {
index_insert(group_index, name, track_id);
} catch (...) {
return;
return playlist_db.find(name).values;
} catch (int error) {
return empty_set;
}
}
throw -EEXIST;
}
void group :: del(const std::string &name, unsigned int track_id)
#ifdef CONFIG_TEST
void playlist :: clear()
{
if ((name == "All Music") || (name == "Library") || (name == "Banned")) {
try {
index_remove(group_index, name, track_id);
} catch (...) {
return;
}
}
}
void group :: list(std::list<std::string> &res)
{
res.push_back("All Music");
res.push_back("Library");
res.push_back("Banned");
}
const std::set<unsigned int> &group :: get_tracks(const std::string &name)
{
try {
return group_index.find(name).values;
} catch (...) {
return empty_set;
}
playlist_db.clear();
}
#endif /* CONFIG_TEST */

View File

@ -57,8 +57,9 @@ rm_test_dir(xdg.BaseDirectory.xdg_data_home);
#
# Read SConscript files
#
scripts = [ "audio", "database", "deck", "file", "filter", "group", "idle",
"index", "library", "playlist", "print" ]
#scripts = [ "audio", "database", "deck", "file", "filter", "group", "idle",
# "index", "library", "playlist", "print" ]
scripts = [ "print", "file", "database", "index", "filter", "idle", "playlist" ]
for s in scripts:
CONFIG.reset(TEST = True)
SConscript("%s/Sconscript" % s)

View File

@ -1,6 +1,6 @@
#!/usr/bin/python
Import("Test", "CONFIG")
CONFIG.GROUP = True
CONFIG.PLAYLIST = True
Test("group", "group.cpp")
Test("playlist", "playlist.cpp")

View File

@ -1,97 +0,0 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <group.h>
#include <print.h>
void list_tracks(const std::string &name)
{
std::set<unsigned int> tracks = group :: get_tracks(name);
std::set<unsigned int>::iterator it;
print("Group \"%s\": ", name.c_str());
for (it = tracks.begin(); it != tracks.end(); it++) {
if (it != tracks.begin())
print(", ");
print("%u", *it);
}
print("\n");
}
/*
* Add songs to different groups
*/
void test_0()
{
for (unsigned int i = 0; i < 128; i++) {
group :: add("All Music", i);
if (i % 3 == 0)
group :: add("Banned", i);
else
group :: add("Library", i);
}
}
/*
* Find group names
*/
void test_1()
{
std::list<std::string> groups;
std::list<std::string>::iterator it;
group :: list(groups);
for (it = groups.begin(); it != groups.end(); it++)
print("Found group: %s\n", it->c_str());
print("\n");
}
/*
* Find tracks in a group
*/
void test_2()
{
list_tracks("All Music");
list_tracks("Library");
list_tracks("Banned");
}
/*
* Delete tracks from a group
*/
void test_3()
{
print("\n");
for (unsigned int i = 0; i < 30; i+=3)
group :: del("Banned", i);
list_tracks("Banned");
}
/*
* Do stuff with groups that don't exist
*/
void test_4()
{
print("\n");
for (unsigned int i = 0; i < 10; i++)
group :: add("No Group", i);
list_tracks("No Group");
for (unsigned int i = 0; i < 10; i+=2)
group :: del("No Group", i);
list_tracks("No Group");
}
int main(int argc, char **argv)
{
test_0();
test_1();
test_2();
test_3();
test_4();
return 0;
}

View File

@ -1,12 +0,0 @@
Found group: All Music
Found group: Library
Found group: Banned
Group "All Music": 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127
Group "Library": 1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 100, 101, 103, 104, 106, 107, 109, 110, 112, 113, 115, 116, 118, 119, 121, 122, 124, 125, 127
Group "Banned": 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126
Group "Banned": 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126
Group "No Group":
Group "No Group":

112
tests/playlist/playlist.cpp Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <error.h>
#include <playlist.h>
#include <print.h>
void list_tracks(const std::string &name)
{
std::set<unsigned int> tracks = playlist :: get_tracks(name);
std::set<unsigned int>::iterator it;
print("Playlist \"%s\": ", name.c_str());
for (it = tracks.begin(); it != tracks.end(); it++) {
if (it != tracks.begin())
print(", ");
print("%u", *it);
}
print("\n");
}
void check_error(int expected, int error)
{
if (expected != error)
print("Exception error: expected %d actual %d", expected, error);
}
/*
* Add songs to different playlists
*/
void test_0()
{
for (unsigned int i = 0; i < 128; i++) {
switch (i % 3) {
case 0:
playlist :: add("Banned", i);
break;
case 1:
playlist :: add("Favorites", i);
break;
default:
try {
playlist :: add("No Such Playlist", i);
} catch (int error) {
check_error(-EEXIST, error);
}
}
}
}
/*
* Find tracks in a playlist
*/
void test_1()
{
list_tracks("Banned");
list_tracks("Favorites");
try {
list_tracks("No Such Playlist");
} catch (int error) {
check_error(-EEXIST, error);
}
}
/*
* Delete tracks from a playlist
*/
void test_2()
{
print("\n");
for (unsigned int i = 0; i < 30; i+=3)
playlist :: del("Banned", i);
list_tracks("Banned");
try {
playlist :: del("No Such Playlist", 2);
} catch (int error) {
check_error(-EEXIST, error);
}
}
/*
* Check persistence of playlists
*/
void test_3()
{
print("\n");
playlist :: clear();
playlist :: init();
list_tracks("Banned");
list_tracks("Favorites");
try {
list_tracks("No Schu Playlist");
} catch (int error) {
check_error(-EEXIST, error);
}
}
int main(int argc, char **argv)
{
test_0();
test_1();
test_2();
test_3();
return 0;
}

View File

@ -0,0 +1,7 @@
Playlist "Banned": 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126
Playlist "Favorites": 1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127
Playlist "Banned": 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126
Playlist "Banned": 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126
Playlist "Favorites": 1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127