2015-12-10 13:59:21 -05:00
|
|
|
/*
|
2013-12-22 17:24:09 -05:00
|
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
|
|
*/
|
2015-12-07 09:35:58 -05:00
|
|
|
#include <core/collection.h>
|
2016-04-22 13:56:42 -04:00
|
|
|
#include <core/idle.h>
|
2015-12-09 09:55:55 -05:00
|
|
|
#include <core/string.h>
|
2014-06-05 10:19:22 -04:00
|
|
|
#include <core/playlist.h>
|
2013-12-22 17:24:09 -05:00
|
|
|
|
2016-04-22 14:35:35 -04:00
|
|
|
static GHashTable *playlist_db = NULL;
|
2016-04-22 13:56:42 -04:00
|
|
|
static struct file playlist_f = FILE_INIT("playlist.db", 0, 0);
|
2015-12-10 10:55:53 -05:00
|
|
|
static struct queue playlist_q;
|
2015-12-10 13:26:22 -05:00
|
|
|
static enum playlist_t playlist_cur;
|
|
|
|
static const gchar *playlist_names[2] = { "Favorites", "Banned" };
|
2016-04-22 14:35:35 -04:00
|
|
|
static struct queue_ops *playlist_ops = NULL;
|
2014-02-02 14:20:56 -05:00
|
|
|
|
2015-12-10 10:55:53 -05:00
|
|
|
|
2016-04-22 14:17:17 -04:00
|
|
|
static inline struct queue *__playlist_lookup(const gchar *name)
|
2015-12-09 09:55:55 -05:00
|
|
|
{
|
2016-04-22 13:56:42 -04:00
|
|
|
return g_hash_table_lookup(playlist_db, name);
|
|
|
|
}
|
|
|
|
|
2016-04-22 14:17:17 -04:00
|
|
|
static inline struct queue *__playlist_alloc(const gchar *name)
|
2016-04-22 13:56:42 -04:00
|
|
|
{
|
2016-04-22 14:17:17 -04:00
|
|
|
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);
|
2016-04-22 13:56:42 -04:00
|
|
|
}
|
2016-04-22 14:17:17 -04:00
|
|
|
return queue;
|
2015-12-09 09:55:55 -05:00
|
|
|
}
|
|
|
|
|
2015-12-10 13:26:22 -05:00
|
|
|
static inline bool __playlist_is_static(enum playlist_t plist)
|
2015-12-09 09:55:55 -05:00
|
|
|
{
|
2016-02-26 15:37:27 -05:00
|
|
|
return (plist == PL_FAVORITED) || (plist == PL_HIDDEN);
|
2015-12-10 13:26:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool __playlist_is_dynamic(enum playlist_t plist)
|
|
|
|
{
|
|
|
|
return !__playlist_is_static(plist);
|
2015-12-09 09:55:55 -05:00
|
|
|
}
|
|
|
|
|
2015-12-10 13:26:22 -05:00
|
|
|
static void __playlist_fill_dynamic(enum playlist_t plist)
|
2015-12-10 10:55:53 -05:00
|
|
|
{
|
|
|
|
unsigned int count = 0, average = 0;
|
2015-12-10 13:26:22 -05:00
|
|
|
struct db_entry *track, *next;
|
2015-12-10 10:55:53 -05:00
|
|
|
|
2015-12-10 13:26:22 -05:00
|
|
|
if (plist == PL_MOST_PLAYED || plist == PL_LEAST_PLAYED)
|
2016-04-02 13:29:31 -04:00
|
|
|
average = track_db_average_plays();
|
2015-12-10 10:55:53 -05:00
|
|
|
|
|
|
|
db_for_each(track, next, track_db_get()) {
|
|
|
|
count = TRACK(track)->tr_count;
|
2015-12-10 13:26:22 -05:00
|
|
|
if (plist == PL_UNPLAYED && count == 0)
|
2015-12-10 13:38:30 -05:00
|
|
|
queue_add(&playlist_q, TRACK(track));
|
2015-12-10 13:26:22 -05:00
|
|
|
else if (plist == PL_MOST_PLAYED && count > average)
|
2015-12-10 13:38:30 -05:00
|
|
|
queue_add(&playlist_q, TRACK(track));
|
2016-04-02 13:29:31 -04:00
|
|
|
else if (plist == PL_LEAST_PLAYED && count <= average && count > 0)
|
2015-12-10 13:38:30 -05:00
|
|
|
queue_add(&playlist_q, TRACK(track));
|
2015-12-10 10:55:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-24 09:25:56 -04:00
|
|
|
static void __pl_system_load_queue()
|
2016-04-24 09:17:18 -04:00
|
|
|
{
|
2016-04-24 09:25:56 -04:00
|
|
|
struct queue *queue;
|
|
|
|
unsigned int valid;
|
|
|
|
gchar *name;
|
2016-04-24 09:17:18 -04:00
|
|
|
|
2016-04-24 09:25:56 -04:00
|
|
|
file_readf(&playlist_f, "%u ", &valid);
|
|
|
|
if (!valid)
|
2016-04-24 09:17:18 -04:00
|
|
|
return;
|
|
|
|
|
2016-04-24 09:25:56 -04:00
|
|
|
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);
|
2016-04-24 09:17:18 -04:00
|
|
|
queue_save_tracks(queue, &playlist_f);
|
|
|
|
file_writef(&playlist_f, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __pl_system_save()
|
2016-04-22 13:56:42 -04:00
|
|
|
{
|
|
|
|
if (!file_open(&playlist_f, OPEN_WRITE))
|
|
|
|
return;
|
|
|
|
|
|
|
|
file_writef(&playlist_f, "%u\n", g_hash_table_size(playlist_db));
|
2016-04-24 09:25:56 -04:00
|
|
|
g_hash_table_foreach(playlist_db, __pl_system_save_queue, NULL);
|
2016-04-22 13:56:42 -04:00
|
|
|
file_close(&playlist_f);
|
|
|
|
}
|
|
|
|
|
2016-04-24 09:25:56 -04:00
|
|
|
static bool __pl_system_init_idle()
|
2016-04-22 13:56:42 -04:00
|
|
|
{
|
2016-04-24 09:25:56 -04:00
|
|
|
unsigned int i, n;
|
2016-04-22 13:56:42 -04:00
|
|
|
|
|
|
|
if (!file_open(&playlist_f, OPEN_READ))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
file_readf(&playlist_f, "%u\n", &n);
|
2016-04-24 09:25:56 -04:00
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
__pl_system_load_queue();
|
2016-04-22 13:56:42 -04:00
|
|
|
|
|
|
|
file_close(&playlist_f);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-24 09:25:56 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-04-24 09:17:18 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-05-18 21:09:46 -04:00
|
|
|
|
2016-04-24 09:57:50 -04:00
|
|
|
struct playlist_type pl_system = {
|
|
|
|
.pl_get_queue = __pl_system_get_queue,
|
|
|
|
.pl_add_track = __pl_system_add,
|
|
|
|
.pl_remove_track = __pl_system_remove,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-12-09 08:11:21 -05:00
|
|
|
void playlist_init(struct queue_ops *ops)
|
2014-05-18 21:09:46 -04:00
|
|
|
{
|
2015-11-29 19:45:39 -05:00
|
|
|
queue_init(&playlist_q, Q_ENABLED | Q_REPEAT, ops);
|
2015-12-03 13:43:15 -05:00
|
|
|
queue_sort(&playlist_q, COMPARE_ARTIST, true);
|
|
|
|
queue_sort(&playlist_q, COMPARE_YEAR, false);
|
|
|
|
queue_sort(&playlist_q, COMPARE_TRACK, false);
|
2015-12-03 13:41:39 -05:00
|
|
|
queue_set_flag(&playlist_q, Q_NO_SORT);
|
2015-11-23 08:36:29 -05:00
|
|
|
|
2016-04-22 14:17:17 -04:00
|
|
|
playlist_ops = ops;
|
2016-04-24 09:25:56 -04:00
|
|
|
__pl_system_init();
|
2014-05-18 21:09:46 -04:00
|
|
|
}
|
2014-02-02 14:11:38 -05:00
|
|
|
|
2015-12-09 09:20:18 -05:00
|
|
|
void playlist_deinit()
|
|
|
|
{
|
2016-04-24 09:25:56 -04:00
|
|
|
__pl_system_deinit();
|
2015-12-09 09:20:18 -05:00
|
|
|
queue_deinit(&playlist_q);
|
|
|
|
}
|
|
|
|
|
2015-12-10 14:44:31 -05:00
|
|
|
bool playlist_add(enum playlist_t plist, struct track *track)
|
2013-12-22 17:53:58 -05:00
|
|
|
{
|
2016-04-22 13:56:42 -04:00
|
|
|
if (!track || __playlist_is_dynamic(plist))
|
|
|
|
return false;
|
2016-04-24 09:57:50 -04:00
|
|
|
return pl_system.pl_add_track(playlist_names[plist], track);
|
2013-12-22 17:53:58 -05:00
|
|
|
}
|
|
|
|
|
2015-12-11 08:21:21 -05:00
|
|
|
bool playlist_remove(enum playlist_t plist, struct track *track)
|
2013-12-22 17:53:58 -05:00
|
|
|
{
|
2016-04-22 13:56:42 -04:00
|
|
|
if (!track || __playlist_is_dynamic(plist))
|
|
|
|
return false;
|
2016-04-24 09:57:50 -04:00
|
|
|
return pl_system.pl_remove_track(playlist_names[plist], track);
|
2013-12-22 17:53:58 -05:00
|
|
|
}
|
2013-12-22 20:53:06 -05:00
|
|
|
|
2015-12-10 13:26:22 -05:00
|
|
|
bool playlist_has(enum playlist_t plist, struct track *track)
|
2015-12-09 09:31:12 -05:00
|
|
|
{
|
2016-04-24 09:57:50 -04:00
|
|
|
struct queue *queue = pl_system.pl_get_queue(playlist_names[plist]);
|
2016-04-24 09:17:18 -04:00
|
|
|
if (!track || !queue)
|
2015-12-09 09:31:12 -05:00
|
|
|
return false;
|
2016-04-22 14:17:17 -04:00
|
|
|
return queue_has(queue, track);
|
2015-12-09 09:31:12 -05:00
|
|
|
}
|
|
|
|
|
2015-12-10 13:26:22 -05:00
|
|
|
void playlist_select(enum playlist_t plist)
|
2014-02-02 14:05:56 -05:00
|
|
|
{
|
2016-04-22 14:42:25 -04:00
|
|
|
playlist_cur = plist;
|
|
|
|
|
|
|
|
if (__playlist_is_static(plist))
|
|
|
|
return;
|
|
|
|
|
2015-12-10 13:38:30 -05:00
|
|
|
queue_clear(&playlist_q);
|
|
|
|
queue_set_flag(&playlist_q, Q_ADD_FRONT);
|
2016-04-22 14:42:25 -04:00
|
|
|
__playlist_fill_dynamic(plist);
|
2015-12-10 13:38:30 -05:00
|
|
|
queue_unset_flag(&playlist_q, Q_ADD_FRONT);
|
|
|
|
queue_resort(&playlist_q);
|
2013-12-31 16:58:40 -05:00
|
|
|
}
|
|
|
|
|
2016-04-22 14:35:35 -04:00
|
|
|
struct queue *playlist_get_queue(enum playlist_t plist)
|
2013-12-31 16:58:40 -05:00
|
|
|
{
|
2016-04-22 14:35:35 -04:00
|
|
|
if (__playlist_is_static(plist))
|
2016-04-24 09:57:50 -04:00
|
|
|
return pl_system.pl_get_queue(playlist_names[plist]);
|
2014-05-18 21:09:46 -04:00
|
|
|
return &playlist_q;
|
2013-12-22 20:53:06 -05:00
|
|
|
}
|