/* * 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 inline struct set *__playlist_lookup(const gchar *name) { return g_hash_table_lookup(playlist_db, name); } static inline struct set *__playlist_alloc(const gchar *name) { struct set *set = __playlist_lookup(name); if (!set) { set = g_malloc(sizeof(struct set)); set_init(set); g_hash_table_insert(playlist_db, (gpointer)name, set); } return set; } 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 set *set = __playlist_lookup(playlist_names[plist]); struct set_iter it; if (set) { set_for_each(set, &it) queue_add(&playlist_q, track_get(it.it_val)); } } 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 set *set; 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++) { set = __playlist_lookup(playlist_names[i]); if (!set) continue; file_writef(&playlist_f, "1 %s\n", playlist_names[i]); set_write(&playlist_f, set); file_writef(&playlist_f, "\n"); } file_close(&playlist_f); } static bool __playlist_init_idle() { unsigned int i, n, valid; struct set *set; 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); set = __playlist_alloc(name); set_read(&playlist_f, set); } 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); idle_schedule(IDLE_SYNC, __playlist_init_idle, NULL); } void playlist_deinit() { struct set *set; unsigned int i; for (i = 0; i < 2; i++) { set = __playlist_lookup(playlist_names[i]); if (set) set_deinit(set); } g_hash_table_destroy(playlist_db); queue_deinit(&playlist_q); } bool playlist_add(enum playlist_t plist, struct track *track) { struct set *set; if (!track || __playlist_is_dynamic(plist)) return false; set = __playlist_alloc(playlist_names[plist]); if (!set_insert(set, track->tr_dbe.dbe_index)) return false; __playlist_save(); if (playlist_cur == plist) queue_add(&playlist_q, track); return true; } bool playlist_remove(enum playlist_t plist, struct track *track) { struct set *set; if (!track || __playlist_is_dynamic(plist)) return false; set = __playlist_lookup(playlist_names[plist]); if (!set) return true; if (!set_remove(set, track->tr_dbe.dbe_index)) 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 set *set = __playlist_lookup(playlist_names[plist]); if (!set || !track) return false; return set_has(set, track->tr_dbe.dbe_index); } 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; }