/* * Copyright 2013 (c) Anna Schumaker. */ #include #include #include #include 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 struct queue_ops *playlist_ops; static inline struct queue *__playlist_lookup(const gchar *name) { return g_hash_table_lookup(playlist_db, name); } static inline struct queue *__playlist_alloc(const gchar *name) { 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); } return queue; } 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 queue *queue = __playlist_lookup(playlist_names[plist]); struct queue_iter it; if (queue) { queue_for_each(queue, &it) queue_add(&playlist_q, queue_iter_val(&it)); } } 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 queue *queue; 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++) { queue = __playlist_lookup(playlist_names[i]); if (!queue) continue; file_writef(&playlist_f, "1 %s\n", playlist_names[i]); queue_save_tracks(queue, &playlist_f); file_writef(&playlist_f, "\n"); } file_close(&playlist_f); } static bool __playlist_init_idle() { unsigned int i, n, valid; struct queue *queue; 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); queue = __playlist_alloc(name); queue_load_tracks(queue, &playlist_f); } 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); playlist_ops = ops; idle_schedule(IDLE_SYNC, __playlist_init_idle, NULL); } void playlist_deinit() { struct queue *queue; unsigned int i; for (i = 0; i < 2; i++) { queue = __playlist_lookup(playlist_names[i]); if (queue) queue_deinit(queue); g_free(queue); } g_hash_table_destroy(playlist_db); queue_deinit(&playlist_q); } bool playlist_add(enum playlist_t plist, struct track *track) { struct queue *queue; if (!track || __playlist_is_dynamic(plist)) return false; queue = __playlist_alloc(playlist_names[plist]); if (queue_has(queue, track)) return false; queue_add(queue, track); __playlist_save(); if (playlist_cur == plist) queue_add(&playlist_q, track); return true; } bool playlist_remove(enum playlist_t plist, struct track *track) { struct queue *queue; if (!track || __playlist_is_dynamic(plist)) return false; queue = __playlist_lookup(playlist_names[plist]); if (!queue) return true; if (!queue_remove_all(queue, track)) 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 queue *queue = __playlist_lookup(playlist_names[plist]); if (!queue || !track) return false; return queue_has(queue, track); } 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; }