core/playlists/system: Move system playlists into a new file

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2016-04-24 10:36:15 -04:00 committed by Anna Schumaker
parent e3d4143565
commit a465577c86
12 changed files with 282 additions and 145 deletions

View File

@ -4,6 +4,7 @@ Import("env")
res = Glob("*.c")
res += SConscript("tags/Sconscript")
res += SConscript("containers/Sconscript")
res += SConscript("playlists/Sconscript")
env.UsePackage("gstreamer-1.0")
env.UsePackage("libmusicbrainz5");

View File

@ -1,35 +1,14 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/collection.h>
#include <core/idle.h>
#include <core/string.h>
#include <core/playlist.h>
#include <core/playlists/system.h>
static GHashTable *playlist_db = NULL;
static struct file playlist_f = FILE_INIT("playlist.db", 0, 0);
static struct queue playlist_q;
static enum playlist_t playlist_cur;
static const gchar *playlist_names[2] = { "Favorites", "Banned" };
static struct queue_ops *playlist_ops = NULL;
static inline struct queue *__playlist_lookup(const gchar *name)
{
return g_hash_table_lookup(playlist_db, name);
}
static inline struct queue *__playlist_alloc(const gchar *name)
{
struct queue *queue = __playlist_lookup(name);
if (!queue) {
queue = g_malloc(sizeof(struct queue));
queue_init(queue, Q_ENABLED | Q_REPEAT, playlist_ops);
g_hash_table_insert(playlist_db, (gpointer)name, queue);
}
return queue;
}
static inline bool __playlist_is_static(enum playlist_t plist)
{
return (plist == PL_FAVORITED) || (plist == PL_HIDDEN);
@ -59,109 +38,6 @@ static void __playlist_fill_dynamic(enum playlist_t plist)
}
}
static void __pl_system_load_queue()
{
struct queue *queue;
unsigned int valid;
gchar *name;
file_readf(&playlist_f, "%u ", &valid);
if (!valid)
return;
name = file_readl(&playlist_f);
queue = __playlist_alloc(name);
queue_load_tracks(queue, &playlist_f);
}
static void __pl_system_save_queue(gpointer key, gpointer value,
gpointer data)
{
struct queue *queue = (struct queue *)value;
file_writef(&playlist_f, "1 %s\n", (gchar *)key);
queue_save_tracks(queue, &playlist_f);
file_writef(&playlist_f, "\n");
}
static void __pl_system_save()
{
if (!file_open(&playlist_f, OPEN_WRITE))
return;
file_writef(&playlist_f, "%u\n", g_hash_table_size(playlist_db));
g_hash_table_foreach(playlist_db, __pl_system_save_queue, NULL);
file_close(&playlist_f);
}
static bool __pl_system_init_idle()
{
unsigned int i, n;
if (!file_open(&playlist_f, OPEN_READ))
return true;
file_readf(&playlist_f, "%u\n", &n);
for (i = 0; i < n; i++)
__pl_system_load_queue();
file_close(&playlist_f);
return true;
}
static void __pl_system_init()
{
playlist_db = g_hash_table_new(g_str_hash, g_str_equal);
idle_schedule(IDLE_SYNC, __pl_system_init_idle, NULL);
}
static int __pl_system_deinit_queue(gpointer key, gpointer value, gpointer data)
{
struct queue *queue = (struct queue *)value;
queue_deinit(queue);
g_free(queue);
return true;
}
static void __pl_system_deinit()
{
g_hash_table_foreach_remove(playlist_db, __pl_system_deinit_queue, NULL);
g_hash_table_destroy(playlist_db);
}
static bool __pl_system_add(const gchar *name, struct track *track)
{
struct queue *queue = __playlist_alloc(name);
if (queue_has(queue, track))
return false;
queue_add(queue, track);
__pl_system_save();
return true;
}
static bool __pl_system_remove(const gchar *name, struct track *track)
{
struct queue *queue = __playlist_lookup(name);
if (!queue)
return false;
if (!queue_remove_all(queue, track))
return false;
__pl_system_save();
return true;
}
static struct queue *__pl_system_get_queue(const gchar *name)
{
return __playlist_lookup(name);
}
struct playlist_type pl_system = {
.pl_get_queue = __pl_system_get_queue,
.pl_add_track = __pl_system_add,
.pl_remove_track = __pl_system_remove,
};
void playlist_init(struct queue_ops *ops)
{
@ -171,14 +47,13 @@ void playlist_init(struct queue_ops *ops)
queue_sort(&playlist_q, COMPARE_TRACK, false);
queue_set_flag(&playlist_q, Q_NO_SORT);
playlist_ops = ops;
__pl_system_init();
pl_system_init(ops);
}
void playlist_deinit()
{
__pl_system_deinit();
queue_deinit(&playlist_q);
pl_system_deinit();
}
bool playlist_add(enum playlist_t plist, struct track *track)

View File

@ -0,0 +1,4 @@
#!/usr/bin/python
res = Glob("*.c")
Return("res")

110
core/playlists/system.c Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlists/system.h>
#include <core/string.h>
static struct file sys_file = FILE_INIT("playlist.db", 0, 0);
static struct queue sys_playlists[SYS_PL_NUM_PLAYLISTS];
static struct queue *pl_system_get_queue(const gchar *);
static void __sys_pl_save()
{
if (!file_open(&sys_file, OPEN_WRITE))
return;
file_writef(&sys_file, "%u\n 1 %s\n", 2, "Favorites");
queue_save_tracks(&sys_playlists[SYS_PL_FAVORITES], &sys_file);
file_writef(&sys_file, "\n1 %s\n", "Banned");
queue_save_tracks(&sys_playlists[SYS_PL_HIDDEN], &sys_file);
file_writef(&sys_file, "\n");
file_close(&sys_file);
}
static bool __sys_pl_load()
{
struct queue *queue;
unsigned int i, n;
gchar *name;
if (!file_open(&sys_file, OPEN_READ))
return true;
file_readf(&sys_file, "%u\n", &n);
for (i = 0; i < n; i++) {
file_readf(&sys_file, "%*u %m[^\n]\n", &name);
queue = pl_system_get_queue(name);
queue_load_tracks(queue, &sys_file);
g_free(name);
}
file_close(&sys_file);
return true;
}
static struct queue *pl_system_get_queue(const gchar *name)
{
if (string_match(name, "Favorites"))
return &sys_playlists[SYS_PL_FAVORITES];
else if (string_match(name, "Hidden") || string_match(name, "Banned"))
return &sys_playlists[SYS_PL_HIDDEN];
return NULL;
}
static bool pl_system_add_track(const gchar *name, struct track *track)
{
struct queue *queue = pl_system_get_queue(name);
if (!queue)
return false;
if (queue_has(queue, track))
return false;
queue_add(queue, track);
__sys_pl_save();
return true;
}
static bool pl_system_remove_track(const gchar *name, struct track *track)
{
struct queue *queue = pl_system_get_queue(name);
if (!queue)
return false;
if (!queue_remove_all(queue, track))
return false;
__sys_pl_save();
return true;
}
struct playlist_type pl_system = {
.pl_get_queue = pl_system_get_queue,
.pl_add_track = pl_system_add_track,
.pl_remove_track = pl_system_remove_track,
};
void pl_system_init(struct queue_ops *ops)
{
unsigned int i;
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) {
queue_init(&sys_playlists[i], Q_ENABLED | Q_REPEAT, ops);
queue_sort(&sys_playlists[i], COMPARE_ARTIST, true);
queue_sort(&sys_playlists[i], COMPARE_YEAR, false);
queue_sort(&sys_playlists[i], COMPARE_TRACK, false);
}
idle_schedule(IDLE_SYNC, __sys_pl_load, NULL);
}
void pl_system_deinit()
{
unsigned int i;
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++)
queue_deinit(&sys_playlists[i]);
}

View File

@ -20,18 +20,6 @@ enum playlist_t {
};
struct playlist_type {
/* Called to get the queue for the playlist. */
struct queue *(*pl_get_queue)(const gchar *);
/* Called to add a track to the playlist. */
bool (*pl_add_track)(const gchar *, struct track *);
/* Called to remove a track from the playlist. */
bool (*pl_remove_track)(const gchar *, struct track *);
};
/* Called to initialize the playlist manager. */
void playlist_init(struct queue_ops *);

View File

@ -0,0 +1,26 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_SYSTEM_H
#define OCARINA_CORE_PLAYLISTS_SYSTEM_H
#include <core/playlists/type.h>
enum sys_playlist_t {
SYS_PL_FAVORITES, /* Songs that the user likes. */
SYS_PL_HIDDEN, /* Songs that the user has hidden. */
SYS_PL_NUM_PLAYLISTS, /* Number of system playlists. */
};
/* System playlist type. */
extern struct playlist_type pl_system;
/* Called to initialize system playlists. */
void pl_system_init(struct queue_ops *);
/* Called to deinitialize system playlists. */
void pl_system_deinit();
#endif /* OCARINA_CORE_PLAYLISTS_SYSTEM_H */

View File

@ -0,0 +1,24 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_TYPE_H
#define OCARINA_CORE_PLAYLISTS_TYPE_H
#include <core/queue.h>
#include <core/tags/track.h>
#include <glib.h>
#include <stdbool.h>
struct playlist_type {
/* Called to get the queue for the playlist. */
struct queue *(*pl_get_queue)(const gchar *);
/* Called to add a track to the playlist. */
bool (*pl_add_track)(const gchar *, struct track *);
/* Called to remove a track from the playlist. */
bool (*pl_remove_track)(const gchar *, struct track *);
};
#endif /* OCARINA_CORE_PLAYLISTS_TYPE_H */

View File

@ -13,6 +13,7 @@ tags/genre
tags/library
tags/track
queue
playlists/system
playlist
collection
history

View File

@ -35,6 +35,8 @@ res += [ CoreTest("filter") ]
res += SConscript("tags/Sconscript")
res += [ CoreTest("queue") ]
res += SConscript("playlists/Sconscript")
res += [ CoreTest("playlist") ]
res += [ CoreTest("collection") ]
res += [ CoreTest("history") ]

View File

@ -18,8 +18,8 @@ static void test_init()
playlist_init(NULL);
while (idle_run_task()) {};
test_equal((void *)playlist_get_queue(PL_FAVORITED), NULL);
test_equal((void *)playlist_get_queue(PL_HIDDEN), NULL);
test_not_equal((void *)playlist_get_queue(PL_FAVORITED), NULL);
test_not_equal((void *)playlist_get_queue(PL_HIDDEN), NULL);
test_not_equal((void *)playlist_get_queue(PL_UNPLAYED), NULL);
test_not_equal((void *)playlist_get_queue(PL_MOST_PLAYED), NULL);
test_not_equal((void *)playlist_get_queue(PL_LEAST_PLAYED), NULL);
@ -68,7 +68,6 @@ static void test_add()
test_equal(playlist_add(PL_FAVORITED, track), (bool)true);
test_equal(playlist_has(PL_FAVORITED, track), (bool)true);
q = playlist_get_queue(PL_FAVORITED);
test_not_equal((void *)q, NULL);
test_equal(queue_size(q), 1);
test_equal(playlist_add(PL_FAVORITED, track), (bool)false);
test_equal(queue_size(q), 1);
@ -78,12 +77,10 @@ static void test_add()
track = track_get(2);
playlist_select(PL_HIDDEN);
q = playlist_get_queue(PL_HIDDEN);
test_equal((void *)q, NULL);
test_equal(playlist_has(PL_HIDDEN, track), (bool)false);
test_equal(playlist_add(PL_HIDDEN, track), (bool)true);
test_equal(playlist_has(PL_HIDDEN, track), (bool)true);
q = playlist_get_queue(PL_HIDDEN);
test_not_equal((void *)q, NULL);
test_equal(queue_size(q), 1);
}

View File

@ -0,0 +1,15 @@
#!/env/bin/python
Import("env", "CoreTest", "testing_group")
res = []
def PlaylistTest(name):
run = CoreTest("playlists/%s" % name)
Alias("tests/core/playlists", run)
if len(res) > 0 and testing_group([ "tests/core/playlists" ]):
Depends(run, res[1])
return run
res += [ PlaylistTest("system") ]
Return("res")

View File

@ -0,0 +1,94 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/filter.h>
#include <core/idle.h>
#include <core/playlists/system.h>
#include <core/tags/tags.h>
#include <tests/test.h>
#define __test_playlist_state(queue, ex_size, ex_track0, ex_track1) \
test_equal(queue_size(queue), ex_size); \
test_equal(queue_has(queue, track_get(0)), (bool)ex_track0); \
test_equal(queue_has(queue, track_get(1)), (bool)ex_track1)
#define __test_playlist_add(name, queue) \
__test_playlist_state(queue, 0, false, false); \
test_equal(pl_system.pl_add_track(name, track_get(0)), (bool)true); \
test_equal(pl_system.pl_add_track(name, track_get(0)), (bool)false); \
test_equal(pl_system.pl_add_track(name, track_get(1)), (bool)true); \
test_equal(pl_system.pl_add_track(name, track_get(1)), (bool)false); \
__test_playlist_state(queue, 2, true, true)
#define __test_playlist_remove(name, queue) \
test_equal(pl_system.pl_remove_track(name, track_get(0)), (bool)true); \
test_equal(pl_system.pl_remove_track(name, track_get(0)), (bool)false); \
test_equal(pl_system.pl_remove_track(name, track_get(1)), (bool)true); \
test_equal(pl_system.pl_remove_track(name, track_get(1)), (bool)false); \
__test_playlist_state(queue, 0, false, false)
#define __test_playlist_reinit(queue, ex_size, ex_track0, ex_track1) \
pl_system_deinit(); \
pl_system_init(NULL); \
__test_playlist_state(queue, 0, false, false); \
while (idle_run_task()) {}; \
__test_playlist_state(queue, ex_size, ex_track0, ex_track1)
static void test_init()
{
struct library *library;
idle_init();
filter_init();
tags_init();
pl_system_init(NULL);
while (idle_run_task()) {};
/* Add tracks to the collection. */
library = library_find("tests/Music");
track_add(library, "tests/Music/Hyrule Symphony/01 - Title Theme.ogg");
track_add(library, "tests/Music/Hyrule Symphony/02 - Kokiri Forest.ogg");
}
static void test_invalid()
{
test_init();
test_equal((void *)pl_system.pl_get_queue(NULL), NULL);
test_equal((void *)pl_system.pl_get_queue("Invalid"), NULL);
test_equal(pl_system.pl_add_track(NULL, track_get(0)), (bool)false);
test_equal(pl_system.pl_remove_track(NULL, track_get(0)), (bool)false);
}
static void test_favorites()
{
struct queue *queue = pl_system.pl_get_queue("Favorites");
test_not_equal((void *)queue, NULL);
__test_playlist_add("Favorites", queue);
__test_playlist_reinit(queue, 2, true, true);
__test_playlist_remove("Favorites", queue);
}
static void test_hidden()
{
struct queue *queue = pl_system.pl_get_queue("Hidden");
test_not_equal((void *)queue, NULL);
test_equal((void *)pl_system.pl_get_queue("Banned"), (void *)queue);
__test_playlist_add("Hidden", queue);
__test_playlist_reinit(queue, 2, true, true);
__test_playlist_remove("Hidden", queue);
pl_system_deinit();
}
DECLARE_UNIT_TESTS(
UNIT_TEST("Invalid Playlist", test_invalid),
UNIT_TEST("Favorites Playlist", test_favorites),
UNIT_TEST("Hidden Playlist", test_hidden),
);