ocarina/core/playlists/user.c
Anna Schumaker b17585237a core/playlist: Add a playlist_played() function
This is used to notify when tracks have been played so dynamic playlists
can be updated, and so the model can display the correct playcount.

The old system playlist tests are mostly unnecessary at this point, so I
remove them as part of this patch.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00

176 lines
4.1 KiB
C

/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/playlists/user.h>
static struct queue_ops *user_pl_ops = NULL;
static struct database user_db;
static struct playlist_ops user_ops;
static struct user_playlist *__user_db_alloc(gchar *name, unsigned int index)
{
struct user_playlist *playlist = g_malloc(sizeof(struct user_playlist));
dbe_init(&playlist->pl_dbe, playlist);
playlist->pl_playlist.pl_name = name;
playlist->pl_playlist.pl_type = PL_USER;
playlist->pl_playlist.pl_id = index;
playlist->pl_playlist.pl_ops = &user_ops;
playlist_generic_init(&playlist->pl_playlist, Q_REPEAT, user_pl_ops);
return playlist;
}
static struct db_entry *user_db_alloc(const gchar *name, unsigned int index)
{
return &__user_db_alloc(g_strdup(name), index)->pl_dbe;
}
static void user_db_free(struct db_entry *dbe)
{
queue_deinit(&USER_PLAYLIST(dbe)->pl_playlist.pl_queue);
g_free(USER_PLAYLIST(dbe)->pl_playlist.pl_name);
g_free(USER_PLAYLIST(dbe));
}
static gchar *user_db_key(struct db_entry *dbe)
{
return g_strdup(USER_PLAYLIST(dbe)->pl_playlist.pl_name);
}
static struct db_entry *user_db_read(struct file *file, unsigned int index)
{
gchar *name = file_readl(file);
struct user_playlist *playlist = __user_db_alloc(name, index);
queue_load_flags(&playlist->pl_playlist.pl_queue, file, true);
queue_load_tracks(&playlist->pl_playlist.pl_queue, file);
queue_iter_set(&playlist->pl_playlist.pl_queue,
&playlist->pl_playlist.pl_queue.q_cur,
playlist->pl_playlist.pl_queue.q_cur.it_pos);
return &playlist->pl_dbe;
}
static void user_db_write(struct file *file, struct db_entry *dbe)
{
struct playlist *playlist = &USER_PLAYLIST(dbe)->pl_playlist;
file_writef(file, "%s\n", playlist->pl_name);
queue_save_flags(&playlist->pl_queue, file, true);
queue_save_tracks(&playlist->pl_queue, file);
}
static const struct db_ops user_db_ops = {
.dbe_alloc = user_db_alloc,
.dbe_free = user_db_free,
.dbe_key = user_db_key,
.dbe_read = user_db_read,
.dbe_write = user_db_write,
};
static bool pl_user_delete(struct playlist *playlist)
{
struct db_entry *dbe = db_get(&user_db, playlist->pl_name);
if (dbe) {
db_remove(&user_db, dbe);
db_defrag(&user_db);
}
return dbe != NULL;
}
static struct playlist_ops user_ops = {
.pl_add = playlist_generic_add_track,
.pl_can_select = playlist_generic_can_select,
.pl_delete = pl_user_delete,
.pl_next = playlist_generic_next,
.pl_remove = playlist_generic_remove_track,
.pl_set_flag = playlist_generic_set_flag,
.pl_sort = playlist_generic_sort,
};
static void pl_user_save(void)
{
db_save(&user_db);
}
static struct playlist *pl_user_lookup(const gchar *name)
{
struct db_entry *dbe = db_get(&user_db, name);
return dbe ? &USER_PLAYLIST(dbe)->pl_playlist : NULL;
}
static struct playlist *pl_user_get(unsigned int id)
{
struct db_entry *dbe = db_at(&user_db, id);
return dbe ? &USER_PLAYLIST(dbe)->pl_playlist : NULL;
}
static struct playlist *pl_user_new(const gchar *name)
{
struct db_entry *dbe;
if (db_get(&user_db, name))
return NULL;
dbe = db_insert(&user_db, name);
return dbe ? &USER_PLAYLIST(dbe)->pl_playlist : NULL;
}
static void pl_user_played(struct track *track)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
db_for_each(dbe, next, &user_db) {
playlist = &USER_PLAYLIST(dbe)->pl_playlist;
queue_updated(&playlist->pl_queue, track);
}
}
static void pl_user_update(const gchar *name)
{
}
struct playlist_type pl_user = {
.pl_save = pl_user_save,
.pl_lookup = pl_user_lookup,
.pl_get = pl_user_get,
.pl_new = pl_user_new,
.pl_played = pl_user_played,
.pl_update = pl_user_update,
};
void pl_user_init(struct queue_ops *ops)
{
user_pl_ops = ops;
db_init(&user_db, "playlist.user", true, &user_db_ops, 0);
db_load(&user_db);
}
void pl_user_deinit()
{
db_deinit(&user_db);
}
struct database *pl_user_db_get()
{
return &user_db;
}
void pl_user_delete_track(struct track *track)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
db_for_each(dbe, next, &user_db) {
playlist = &USER_PLAYLIST(dbe)->pl_playlist;
playlist_generic_remove_track(playlist, track);
}
}