ocarina/core/playlist.c

204 lines
4.6 KiB
C

/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/collection.h>
#include <core/idle.h>
#include <core/string.h>
#include <core/playlist.h>
static GHashTable *playlist_db;
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 inline struct set *__playlist_lookup(const gchar *name)
{
return g_hash_table_lookup(playlist_db, name);
}
static inline struct set *__playlist_alloc(const gchar *name)
{
struct set *set = __playlist_lookup(name);
if (!set) {
set = g_malloc(sizeof(struct set));
set_init(set);
g_hash_table_insert(playlist_db, (gpointer)name, set);
}
return set;
}
static inline bool __playlist_is_static(enum playlist_t plist)
{
return (plist == PL_FAVORITED) || (plist == PL_HIDDEN);
}
static inline bool __playlist_is_dynamic(enum playlist_t plist)
{
return !__playlist_is_static(plist);
}
static void __playlist_fill_static(enum playlist_t plist)
{
struct set *set = __playlist_lookup(playlist_names[plist]);
struct set_iter it;
if (set) {
set_for_each(set, &it)
queue_add(&playlist_q, track_get(it.it_val));
}
}
static void __playlist_fill_dynamic(enum playlist_t plist)
{
unsigned int count = 0, average = 0;
struct db_entry *track, *next;
if (plist == PL_MOST_PLAYED || plist == PL_LEAST_PLAYED)
average = track_db_average_plays();
db_for_each(track, next, track_db_get()) {
count = TRACK(track)->tr_count;
if (plist == PL_UNPLAYED && count == 0)
queue_add(&playlist_q, TRACK(track));
else if (plist == PL_MOST_PLAYED && count > average)
queue_add(&playlist_q, TRACK(track));
else if (plist == PL_LEAST_PLAYED && count <= average && count > 0)
queue_add(&playlist_q, TRACK(track));
}
}
static void __playlist_save()
{
struct set *set;
unsigned int i;
if (!file_open(&playlist_f, OPEN_WRITE))
return;
file_writef(&playlist_f, "%u\n", g_hash_table_size(playlist_db));
for (i = 0; i < 2; i++) {
set = __playlist_lookup(playlist_names[i]);
if (!set)
continue;
file_writef(&playlist_f, "1 %s\n", playlist_names[i]);
set_write(&playlist_f, set);
file_writef(&playlist_f, "\n");
}
file_close(&playlist_f);
}
static bool __playlist_init_idle()
{
unsigned int i, n, valid;
struct set *set;
gchar *name;
if (!file_open(&playlist_f, OPEN_READ))
return true;
file_readf(&playlist_f, "%u\n", &n);
for (i = 0; i < n; i++) {
file_readf(&playlist_f, "%u ", &valid);
if (!valid)
continue;
name = file_readl(&playlist_f);
set = __playlist_alloc(name);
set_read(&playlist_f, set);
}
file_close(&playlist_f);
return true;
}
void playlist_init(struct queue_ops *ops)
{
queue_init(&playlist_q, Q_ENABLED | Q_REPEAT, ops);
queue_sort(&playlist_q, COMPARE_ARTIST, true);
queue_sort(&playlist_q, COMPARE_YEAR, false);
queue_sort(&playlist_q, COMPARE_TRACK, false);
queue_set_flag(&playlist_q, Q_NO_SORT);
playlist_db = g_hash_table_new(g_str_hash, g_str_equal);
idle_schedule(IDLE_SYNC, __playlist_init_idle, NULL);
}
void playlist_deinit()
{
struct set *set;
unsigned int i;
for (i = 0; i < 2; i++) {
set = __playlist_lookup(playlist_names[i]);
if (set)
set_deinit(set);
}
g_hash_table_destroy(playlist_db);
queue_deinit(&playlist_q);
}
bool playlist_add(enum playlist_t plist, struct track *track)
{
struct set *set;
if (!track || __playlist_is_dynamic(plist))
return false;
set = __playlist_alloc(playlist_names[plist]);
if (!set_insert(set, track->tr_dbe.dbe_index))
return false;
__playlist_save();
if (playlist_cur == plist)
queue_add(&playlist_q, track);
return true;
}
bool playlist_remove(enum playlist_t plist, struct track *track)
{
struct set *set;
if (!track || __playlist_is_dynamic(plist))
return false;
set = __playlist_lookup(playlist_names[plist]);
if (!set)
return true;
if (!set_remove(set, track->tr_dbe.dbe_index))
return false;
__playlist_save();
if (playlist_cur == plist)
queue_remove_all(&playlist_q, track);
return true;
}
bool playlist_has(enum playlist_t plist, struct track *track)
{
struct set *set = __playlist_lookup(playlist_names[plist]);
if (!set || !track)
return false;
return set_has(set, track->tr_dbe.dbe_index);
}
void playlist_select(enum playlist_t plist)
{
queue_clear(&playlist_q);
queue_set_flag(&playlist_q, Q_ADD_FRONT);
if (__playlist_is_static(plist))
__playlist_fill_static(plist);
else
__playlist_fill_dynamic(plist);
queue_unset_flag(&playlist_q, Q_ADD_FRONT);
playlist_cur = plist;
queue_resort(&playlist_q);
}
struct queue *playlist_get_queue()
{
return &playlist_q;
}