ocarina/core/playlists/artist.c
Anna Schumaker ef8a764780 core/playlists: Allocate artist and library playlists during startup
Rather than waiting for them to load with an idle task.  This speeds up
Ocarina startup dramatically, since playlists can be added to the UI
with the correct size instead of needing extra callbacks to update the
size each time a track is added.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:36 -04:00

227 lines
5.4 KiB
C

/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlists/artist.h>
#include <core/string.h>
static struct queue_ops *artist_ops = NULL;
static struct file artist_file = FILE_INIT("playlist.artist", 0);
static struct playlist *__artist_pl_alloc(gchar *name)
{
struct playlist *playlist = g_malloc(sizeof(struct playlist));
playlist->pl_name = name;
playlist->pl_type = PL_ARTIST;
playlist_generic_init(playlist, Q_REPEAT, artist_ops);
return playlist;
}
static void __artist_pl_free(struct playlist *playlist)
{
if (playlist) {
queue_deinit(&playlist->pl_queue);
g_free(playlist);
}
}
static bool __artist_pl_add(void *data)
{
struct playlist *playlist = (struct playlist *)data;
struct artist *artist = artist_lookup(playlist->pl_name);
struct db_entry *dbe, *next;
queue_set_flag(&playlist->pl_queue, Q_ADD_FRONT);
db_for_each(dbe, next, track_db_get()) {
if (TRACK(dbe)->tr_album->al_artist == artist)
queue_add(&playlist->pl_queue, TRACK(dbe));
}
queue_unset_flag(&playlist->pl_queue, Q_ADD_FRONT);
return true;
}
static struct playlist *__artist_pl_lookup(const gchar *name)
{
struct artist *artist = artist_lookup(name);
return artist ? artist->ar_playlist : NULL;
}
static bool __artist_pl_load(void *data)
{
struct playlist *playlist;
unsigned int i, n;
gchar *name;
if (!file_open(&artist_file, OPEN_READ))
return true;
file_readf(&artist_file, "%u\n", &n);
for (i = 0; i < n; i++) {
name = file_readl(&artist_file);
playlist = __artist_pl_lookup(name);
if (!playlist)
continue;
queue_load_flags(&playlist->pl_queue, &artist_file, true);
queue_iter_set(&playlist->pl_queue, &playlist->pl_queue.q_cur,
playlist->pl_queue.q_cur.it_pos);
g_free(name);
}
file_close(&artist_file);
return true;
}
static void pl_artist_save(void)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
if (!file_open(&artist_file, OPEN_WRITE))
return;
file_writef(&artist_file, "%u\n", artist_db_get()->db_size);
db_for_each(dbe, next, artist_db_get()) {
playlist = ARTIST(dbe)->ar_playlist;
file_writef(&artist_file, "%s\n", playlist->pl_name);
queue_save_flags(&playlist->pl_queue, &artist_file, true);
}
file_close(&artist_file);
}
static struct queue *pl_artist_get_queue(const gchar *name)
{
struct playlist *playlist = __artist_pl_lookup(name);
return playlist ? &playlist->pl_queue : NULL;
}
static unsigned int pl_artist_get_id(const gchar *name)
{
struct artist *artist = artist_lookup(name);
return artist ? artist->ar_dbe.dbe_index : -1;
}
static bool pl_artist_can_select(const gchar *name)
{
struct playlist *playlist = __artist_pl_lookup(name);
return playlist ? playlist_generic_can_select(playlist) : false;
}
static gchar *pl_artist_get_name(unsigned int id)
{
struct artist *artist = ARTIST(db_at(artist_db_get(), id));
return artist ? g_strdup(artist->ar_name) : NULL;
}
static bool pl_artist_new_delete(const gchar *name)
{
return false;
}
static bool pl_artist_add_rm(const gchar *name, struct track *track)
{
return false;
}
static void pl_artist_update(const gchar *name)
{
}
static void pl_artist_set_flag(const gchar *name, enum queue_flags flag,
bool enabled)
{
struct playlist *playlist = __artist_pl_lookup(name);
playlist_generic_set_flag(playlist, flag, enabled);
pl_artist_save();
}
static void pl_artist_sort(const gchar *name, enum compare_t sort, bool reset)
{
struct playlist *playlist = __artist_pl_lookup(name);
playlist_generic_sort(playlist, sort, reset);
pl_artist_save();
}
static struct track *pl_artist_next(const gchar *name)
{
struct playlist *playlist = __artist_pl_lookup(name);
struct track *track = playlist_generic_next(playlist);;
pl_artist_save();
return track;
}
struct playlist_type pl_artist = {
.pl_save = pl_artist_save,
.pl_get_queue = pl_artist_get_queue,
.pl_get_id = pl_artist_get_id,
.pl_get_name = pl_artist_get_name,
.pl_can_select = pl_artist_can_select,
.pl_new = pl_artist_new_delete,
.pl_delete = pl_artist_new_delete,
.pl_add_track = pl_artist_add_rm,
.pl_remove_track = pl_artist_add_rm,
.pl_update = pl_artist_update,
.pl_set_flag = pl_artist_set_flag,
.pl_sort = pl_artist_sort,
.pl_next = pl_artist_next,
};
void pl_artist_init(struct queue_ops *ops)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
artist_ops = ops;
db_for_each(dbe, next, artist_db_get()) {
playlist = __artist_pl_alloc(ARTIST(dbe)->ar_name);
ARTIST(dbe)->ar_playlist = playlist;
idle_schedule(IDLE_SYNC, __artist_pl_add, playlist);
}
idle_schedule(IDLE_SYNC, __artist_pl_load, NULL);
}
void pl_artist_deinit()
{
struct db_entry *dbe, *next;
struct playlist *playlist;
db_for_each(dbe, next, artist_db_get()) {
playlist = ARTIST(dbe)->ar_playlist;
ARTIST(dbe)->ar_playlist = NULL;
__artist_pl_free(playlist);
}
}
void pl_artist_new_track(struct track *track)
{
struct artist *artist = track->tr_album->al_artist;
struct playlist *playlist = (struct playlist *)artist->ar_playlist;
if (!playlist) {
playlist = __artist_pl_alloc(artist->ar_name);
artist->ar_playlist = playlist;
}
playlist_generic_add_track(playlist, track);
}
void pl_artist_delete_track(struct track *track)
{
struct artist *artist = track->tr_album->al_artist;
struct playlist *playlist = (struct playlist *)artist->ar_playlist;
if (playlist)
playlist_generic_remove_track(playlist, track);
}