From a465577c86afd57b50bd2a13eb8bdd80d44cf752 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Sun, 24 Apr 2016 10:36:15 -0400 Subject: [PATCH] core/playlists/system: Move system playlists into a new file Signed-off-by: Anna Schumaker --- core/Sconscript | 1 + core/playlist.c | 131 +------------------------------- core/playlists/Sconscript | 4 + core/playlists/system.c | 110 +++++++++++++++++++++++++++ include/core/playlist.h | 12 --- include/core/playlists/system.h | 26 +++++++ include/core/playlists/type.h | 24 ++++++ tests/core/.gitignore | 1 + tests/core/Sconscript | 2 + tests/core/playlist.c | 7 +- tests/core/playlists/Sconscript | 15 ++++ tests/core/playlists/system.c | 94 +++++++++++++++++++++++ 12 files changed, 282 insertions(+), 145 deletions(-) create mode 100644 core/playlists/Sconscript create mode 100644 core/playlists/system.c create mode 100644 include/core/playlists/system.h create mode 100644 include/core/playlists/type.h create mode 100644 tests/core/playlists/Sconscript create mode 100644 tests/core/playlists/system.c diff --git a/core/Sconscript b/core/Sconscript index d322003b..69969138 100644 --- a/core/Sconscript +++ b/core/Sconscript @@ -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"); diff --git a/core/playlist.c b/core/playlist.c index f6e46fd2..583e183a 100644 --- a/core/playlist.c +++ b/core/playlist.c @@ -1,35 +1,14 @@ /* * Copyright 2013 (c) Anna Schumaker. */ -#include -#include -#include #include +#include -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) diff --git a/core/playlists/Sconscript b/core/playlists/Sconscript new file mode 100644 index 00000000..4812aaf3 --- /dev/null +++ b/core/playlists/Sconscript @@ -0,0 +1,4 @@ +#!/usr/bin/python + +res = Glob("*.c") +Return("res") diff --git a/core/playlists/system.c b/core/playlists/system.c new file mode 100644 index 00000000..c0393aae --- /dev/null +++ b/core/playlists/system.c @@ -0,0 +1,110 @@ +/* + * Copyright 2016 (c) Anna Schumaker. + */ +#include +#include +#include + +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]); +} diff --git a/include/core/playlist.h b/include/core/playlist.h index 54fbc795..53a0325a 100644 --- a/include/core/playlist.h +++ b/include/core/playlist.h @@ -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 *); diff --git a/include/core/playlists/system.h b/include/core/playlists/system.h new file mode 100644 index 00000000..844a79cf --- /dev/null +++ b/include/core/playlists/system.h @@ -0,0 +1,26 @@ +/* + * Copyright 2016 (c) Anna Schumaker. + */ +#ifndef OCARINA_CORE_PLAYLISTS_SYSTEM_H +#define OCARINA_CORE_PLAYLISTS_SYSTEM_H +#include + + +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 */ diff --git a/include/core/playlists/type.h b/include/core/playlists/type.h new file mode 100644 index 00000000..a47b74d7 --- /dev/null +++ b/include/core/playlists/type.h @@ -0,0 +1,24 @@ +/* + * Copyright 2016 (c) Anna Schumaker. + */ +#ifndef OCARINA_CORE_PLAYLISTS_TYPE_H +#define OCARINA_CORE_PLAYLISTS_TYPE_H +#include +#include +#include +#include + + +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 */ diff --git a/tests/core/.gitignore b/tests/core/.gitignore index a97ff3c2..41aa4cc7 100644 --- a/tests/core/.gitignore +++ b/tests/core/.gitignore @@ -13,6 +13,7 @@ tags/genre tags/library tags/track queue +playlists/system playlist collection history diff --git a/tests/core/Sconscript b/tests/core/Sconscript index 17ae4fbc..57c04c06 100644 --- a/tests/core/Sconscript +++ b/tests/core/Sconscript @@ -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") ] diff --git a/tests/core/playlist.c b/tests/core/playlist.c index 388b7c5a..ba87fb76 100644 --- a/tests/core/playlist.c +++ b/tests/core/playlist.c @@ -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); } diff --git a/tests/core/playlists/Sconscript b/tests/core/playlists/Sconscript new file mode 100644 index 00000000..573b16c3 --- /dev/null +++ b/tests/core/playlists/Sconscript @@ -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") diff --git a/tests/core/playlists/system.c b/tests/core/playlists/system.c new file mode 100644 index 00000000..186bfe72 --- /dev/null +++ b/tests/core/playlists/system.c @@ -0,0 +1,94 @@ +/* + * Copyright 2016 (c) Anna Schumaker. + */ +#include +#include +#include +#include +#include + +#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), +);