ocarina/core/playlists/generic.c
Anna Schumaker e1f13a7ef4 core/file: Create new functions for reading data from files
The readd(), readu(), and readhu() functions are all used to read
various forms of integers.  The readl() and readw() are for reading
either lines or individual whitespace-delimited words

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-21 16:01:15 -05:00

287 lines
6.6 KiB
C

/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlists/generic.h>
#include <stdlib.h>
static struct playlist_callbacks *callbacks = NULL;
static int __playlist_generic_find_sort(gconstpointer a, gconstpointer b)
{
return abs(GPOINTER_TO_INT(a)) - abs(GPOINTER_TO_INT(b));
}
static int __playlist_generic_less_than(gconstpointer a, gconstpointer b,
gpointer data)
{
struct track *lhs = (struct track *)a;
struct track *rhs = (struct track *)b;
GSList *cur = ((struct playlist *)data)->pl_sort;
int res, field;
while (cur) {
field = GPOINTER_TO_INT(cur->data);
res = track_compare(lhs, rhs, abs(field));
if (res != 0)
break;
cur = g_slist_next(cur);
};
return (field > 0) ? res : -res;
}
void playlist_generic_set_callbacks(struct playlist_callbacks *cb)
{
callbacks = cb;
}
void playlist_generic_init(struct playlist *playlist)
{
if (playlist) {
g_queue_init(&playlist->pl_tracks);
playlist->pl_length = 0;
playlist->pl_random = false;
playlist->pl_current = NULL;
playlist->pl_sort = NULL;
playlist->pl_search = NULL;
}
}
void playlist_generic_init_sorted(struct playlist *playlist)
{
if (playlist) {
playlist_generic_init(playlist);
playlist_generic_sort(playlist, COMPARE_ARTIST);
playlist_generic_sort(playlist, COMPARE_YEAR);
playlist_generic_sort(playlist, COMPARE_TRACK);
}
}
void playlist_generic_deinit(struct playlist *playlist)
{
if (playlist) {
playlist_generic_clear(playlist);
playlist_clear_sort(playlist);
g_strfreev(playlist->pl_search);
playlist->pl_search = NULL;
playlist->pl_length = 0;
}
}
struct playlist *playlist_generic_alloc(gchar *name, enum playlist_type_t type,
unsigned int id, struct playlist_ops *ops)
{
struct playlist *playlist = g_malloc(sizeof(struct playlist));
playlist->pl_name = name;
playlist->pl_type = type;
playlist->pl_id = id;
playlist->pl_ops = ops;
playlist_generic_init_sorted(playlist);
if (callbacks)
callbacks->pl_cb_alloc(playlist);
return playlist;
}
void playlist_generic_free(struct playlist *playlist)
{
if (playlist) {
playlist_generic_deinit(playlist);
g_free(playlist);
}
}
void playlist_generic_save(struct playlist *playlist, struct file *file,
unsigned int flags)
{
playlist_iter it;
GSList *sort;
int field;
if (!playlist)
return;
if (flags & PL_SAVE_ITER)
file_writef(file, "%u ", playlist_current_index(playlist));
if (flags & PL_SAVE_FLAGS) {
sort = playlist->pl_sort;
file_writef(file, "%u ", playlist->pl_random ? PL_RANDOM : 0);
file_writef(file, "%u", g_slist_length(sort));
while (sort) {
field = GPOINTER_TO_INT(sort->data);
file_writef(file, " %u %d", abs(field) - 1, field > 0);
sort = g_slist_next(sort);
}
file_writef(file, "\n");
}
if (flags & PL_SAVE_TRACKS) {
file_writef(file, "%u", playlist_size(playlist));
playlist_for_each(playlist, it)
file_writef(file, " %u",
track_index(playlist_iter_track(it)));
file_writef(file, "\n");
}
}
void playlist_generic_load(struct playlist *playlist, struct file *file,
unsigned int flags)
{
unsigned int f, n, i, t, it = 0;
int field, ascending;
if (!playlist)
return;
if (flags & PL_SAVE_ITER)
it = file_readu(file);
if (flags & PL_SAVE_FLAGS) {
f = file_readu(file);
n = file_readu(file);
playlist_clear_sort(playlist);
for (i = 0; i < n; i++) {
field = file_readu(file) + 1;
ascending = file_readd(file);
if (!ascending)
field = -field;
playlist->pl_sort = g_slist_append(playlist->pl_sort,
GINT_TO_POINTER(field));
}
playlist_generic_resort(playlist);
}
if (flags & PL_SAVE_TRACKS) {
n = file_readu(file);
for (i = 0; i < n; i++) {
t = file_readu(file);
playlist_generic_add(playlist, track_get(t));
}
}
playlist_generic_set_random(playlist, f == PL_RANDOM);
playlist_current_set(playlist, it);
}
bool playlist_generic_can_select(struct playlist *playlist)
{
return playlist_size(playlist) > 0;
}
void playlist_generic_clear(struct playlist *playlist)
{
unsigned int n;
if (!playlist)
return;
n = playlist_size(playlist);
g_queue_clear(&playlist->pl_tracks);
playlist->pl_length = 0;
playlist->pl_current = NULL;
if (callbacks)
callbacks->pl_cb_removed(playlist, NULL, n);
}
bool playlist_generic_add(struct playlist *playlist, struct track *track)
{
if (!playlist || !track || playlist_has(playlist, track))
return false;
playlist->pl_length += track->tr_length;
if (playlist->pl_sort) {
g_queue_insert_sorted(&playlist->pl_tracks, track,
__playlist_generic_less_than, playlist);
} else
g_queue_push_tail(&playlist->pl_tracks, track);
if (callbacks)
callbacks->pl_cb_added(playlist, track);
return true;
}
bool playlist_generic_add_front(struct playlist *playlist, struct track *track)
{
if (!playlist || !track)
return false;
playlist->pl_length += track->tr_length;
g_queue_push_head(&playlist->pl_tracks, track);
if (callbacks)
callbacks->pl_cb_added(playlist, track);
return true;
}
bool playlist_generic_remove(struct playlist *playlist, struct track *track)
{
unsigned int count;
if (!playlist || !track)
return false;
while (playlist_current_track(playlist) == track)
playlist_current_previous(playlist);
count = g_queue_remove_all(&playlist->pl_tracks, track);
playlist->pl_length -= (count * track->tr_length);
if (callbacks)
callbacks->pl_cb_removed(playlist, track, count);
return count > 0;
}
void playlist_generic_update(struct playlist *playlist, struct track *track)
{
if (playlist && callbacks)
callbacks->pl_cb_updated(playlist, track);
}
void playlist_generic_set_random(struct playlist *playlist, bool enabled)
{
playlist->pl_random = enabled;
}
void playlist_generic_sort(struct playlist *playlist, enum compare_t field)
{
gpointer sort = GINT_TO_POINTER(field);
GSList *found = g_slist_find_custom(playlist->pl_sort, sort,
__playlist_generic_find_sort);
if (found)
found->data = GINT_TO_POINTER(-field);
else
playlist->pl_sort = g_slist_append(playlist->pl_sort, sort);
playlist_generic_resort(playlist);
}
void playlist_generic_resort(struct playlist *playlist)
{
if (!playlist || !playlist->pl_sort)
return;
g_queue_sort(&playlist->pl_tracks, __playlist_generic_less_than, playlist);
playlist_generic_update(playlist, NULL);
}
struct track *playlist_generic_next(struct playlist *playlist)
{
unsigned int pos, size = playlist_size(playlist);
if (size == 0)
return NULL;
else if (playlist->pl_random) {
pos = playlist_current_index(playlist);
pos += g_random_int_range(1, size);
playlist_current_set(playlist, pos % size);
} else if (!playlist_current_next(playlist))
playlist_current_set(playlist, 0);
return playlist_current_track(playlist);
}