/* * Copyright 2016 (c) Anna Schumaker. */ #include #include #include static bool __sys_pl_remove(enum sys_playlist_t, struct track *); static struct file sys_file = FILE_INIT("playlist.db", 0, 0); static struct file sys_collection = FILE_INIT("library.q", 0, 0); static struct playlist sys_playlists[SYS_PL_NUM_PLAYLISTS] = { [SYS_PL_FAVORITES] = DEFINE_PLAYLIST("Favorites"), [SYS_PL_HIDDEN] = DEFINE_PLAYLIST("Hidden"), [SYS_PL_COLLECTION] = DEFINE_PLAYLIST("Collection"), [SYS_PL_HISTORY] = DEFINE_PLAYLIST("History"), [SYS_PL_UNPLAYED] = DEFINE_PLAYLIST("Unplayed"), [SYS_PL_MOST_PLAYED] = DEFINE_PLAYLIST("Most Played"), [SYS_PL_LEAST_PLAYED] = DEFINE_PLAYLIST("Least Played"), }; static enum sys_playlist_t __sys_pl_convert(const gchar *name) { if (string_match(name, "Favorites")) return SYS_PL_FAVORITES; else if (string_match(name, "Hidden") || string_match(name, "Banned")) return SYS_PL_HIDDEN; else if (string_match(name, "Collection")) return SYS_PL_COLLECTION; else if (string_match(name, "History")) return SYS_PL_HISTORY; else if (string_match(name, "Unplayed")) return SYS_PL_UNPLAYED; else if (string_match(name, "Most Played")) return SYS_PL_MOST_PLAYED; else if (string_match(name, "Least Played")) return SYS_PL_LEAST_PLAYED; return SYS_PL_NUM_PLAYLISTS; } static inline struct queue *__sys_pl_queue(enum sys_playlist_t plist) { return &sys_playlists[plist].pl_queue; } static void __sys_pl_save() { if (!file_open(&sys_file, OPEN_WRITE)) return; file_writef(&sys_file, "%u\n 1 %s\n", 2, "Favorites"); queue_save_tracks(__sys_pl_queue(SYS_PL_FAVORITES), &sys_file); file_writef(&sys_file, "\n1 %s\n", "Banned"); queue_save_tracks(__sys_pl_queue(SYS_PL_HIDDEN), &sys_file); file_writef(&sys_file, "\n"); file_close(&sys_file); } static void __sys_pl_save_collection() { if (!file_open(&sys_collection, OPEN_WRITE)) return; queue_save_flags(__sys_pl_queue(SYS_PL_COLLECTION), &sys_collection); file_close(&sys_collection); } static void __sys_pl_load_playlists() { enum sys_playlist_t plist; unsigned int i, n; gchar *name; if (!file_open(&sys_file, OPEN_READ)) return; file_readf(&sys_file, "%u\n", &n); for (i = 0; i < n; i++) { file_readf(&sys_file, "%*u %m[^\n]\n", &name); plist = __sys_pl_convert(name); if (plist < SYS_PL_NUM_PLAYLISTS) queue_load_tracks(__sys_pl_queue(plist), &sys_file); g_free(name); } file_close(&sys_file); return; } static void __sys_pl_load_collection() { if (!file_open(&sys_collection, OPEN_READ)) return; queue_load_flags(__sys_pl_queue(SYS_PL_COLLECTION), &sys_collection); queue_unset_flag(__sys_pl_queue(SYS_PL_COLLECTION), Q_SAVE_FLAGS); queue_unset_flag(__sys_pl_queue(SYS_PL_COLLECTION), Q_SAVE_SORT); file_close(&sys_collection); } static bool __sys_pl_load() { __sys_pl_load_playlists(); __sys_pl_load_collection(); return true; } static bool __sys_pl_can_add(enum sys_playlist_t plist, struct track *track, unsigned int average) { if (plist == SYS_PL_COLLECTION) return track->tr_library->li_enabled; else if (track->tr_count == 0) return plist == SYS_PL_UNPLAYED; else if (track->tr_count <= average) return plist == SYS_PL_LEAST_PLAYED; /* track->tr_count > average */ return plist == SYS_PL_MOST_PLAYED; } static bool __sys_pl_add(enum sys_playlist_t plist, struct track *track, unsigned int average) { if (plist != SYS_PL_FAVORITES && plist != SYS_PL_HIDDEN && plist != SYS_PL_HISTORY) { if (!__sys_pl_can_add(plist, track, average)) return false; if (queue_has(__sys_pl_queue(SYS_PL_HIDDEN), track)) return false; } if (plist != SYS_PL_HISTORY && queue_has(__sys_pl_queue(plist), track)) return false; queue_add(__sys_pl_queue(plist), track); switch (plist) { case SYS_PL_HIDDEN: __sys_pl_remove(SYS_PL_COLLECTION, track); __sys_pl_remove(SYS_PL_UNPLAYED, track); __sys_pl_remove(SYS_PL_MOST_PLAYED, track); __sys_pl_remove(SYS_PL_LEAST_PLAYED, track); case SYS_PL_FAVORITES: __sys_pl_save(); break; case SYS_PL_MOST_PLAYED: __sys_pl_remove(SYS_PL_UNPLAYED, track); __sys_pl_remove(SYS_PL_LEAST_PLAYED, track); break; case SYS_PL_LEAST_PLAYED: __sys_pl_remove(SYS_PL_UNPLAYED, track); __sys_pl_remove(SYS_PL_MOST_PLAYED, track); break; case SYS_PL_HISTORY: queue_iter_set(__sys_pl_queue(plist), &__sys_pl_queue(plist)->q_cur, 0); default: break; } return true; } static bool __sys_pl_remove(enum sys_playlist_t plist, struct track *track) { if (!queue_remove_all(__sys_pl_queue(plist), track)) return false; switch (plist) { case SYS_PL_HIDDEN: __sys_pl_add(SYS_PL_COLLECTION, track, track_db_average_plays()); __sys_pl_add(SYS_PL_UNPLAYED, track, track_db_average_plays()); __sys_pl_add(SYS_PL_MOST_PLAYED, track, track_db_average_plays()); __sys_pl_add(SYS_PL_LEAST_PLAYED, track, track_db_average_plays()); case SYS_PL_FAVORITES: __sys_pl_save(); default: break; } return true; } static bool __sys_pl_update(enum sys_playlist_t plist) { unsigned int average = track_db_average_plays(); struct db_entry *dbe, *next; db_for_each(dbe, next, track_db_get()) { if (__sys_pl_can_add(plist, TRACK(dbe), average)) __sys_pl_add(plist, TRACK(dbe), average); else __sys_pl_remove(plist, TRACK(dbe)); } queue_unset_flag(__sys_pl_queue(plist), Q_ADD_FRONT); return true; } static struct queue *pl_system_get_queue(const gchar *name) { enum sys_playlist_t plist = __sys_pl_convert(name); if (plist == SYS_PL_NUM_PLAYLISTS) return NULL; return __sys_pl_queue(plist); } static bool pl_system_add_track(const gchar *name, struct track *track) { enum sys_playlist_t plist = __sys_pl_convert(name); if (plist == SYS_PL_NUM_PLAYLISTS) return false; return __sys_pl_add(plist, track, track_db_average_plays()); } static bool pl_system_remove_track(const gchar *name, struct track *track) { enum sys_playlist_t plist = __sys_pl_convert(name); if (plist == SYS_PL_NUM_PLAYLISTS) return false; return __sys_pl_remove(plist, track); } static void pl_system_update(const gchar *name) { enum sys_playlist_t plist = __sys_pl_convert(name); if (plist != SYS_PL_FAVORITES && plist != SYS_PL_HIDDEN && plist != SYS_PL_HISTORY) idle_schedule(IDLE_SYNC, IDLE_FUNC(__sys_pl_update), GUINT_TO_POINTER(plist)); } static void pl_system_set_flag(const gchar *name, enum queue_flags flag, bool enabled) { enum sys_playlist_t plist = __sys_pl_convert(name); if (plist == SYS_PL_HISTORY || plist == SYS_PL_NUM_PLAYLISTS) return; if (enabled) queue_set_flag(__sys_pl_queue(plist), flag); else queue_unset_flag(__sys_pl_queue(plist), flag); if (plist == SYS_PL_COLLECTION) __sys_pl_save_collection(); } static void pl_system_sort(const gchar *name, enum compare_t sort, bool reset) { enum sys_playlist_t plist = __sys_pl_convert(name); queue_sort(__sys_pl_queue(plist), sort, reset); if (plist == SYS_PL_COLLECTION) __sys_pl_save_collection(); } struct playlist_type pl_system = { .pl_get_queue = pl_system_get_queue, .pl_add_track = pl_system_add_track, .pl_remove_track = pl_system_remove_track, .pl_update = pl_system_update, .pl_set_flag = pl_system_set_flag, .pl_sort = pl_system_sort, }; void pl_system_init(struct queue_ops *ops) { unsigned int i; for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) { queue_init(__sys_pl_queue(i), Q_ENABLED | Q_REPEAT, ops, &sys_playlists[i]); if (i != SYS_PL_HISTORY) { queue_sort(__sys_pl_queue(i), COMPARE_ARTIST, true); queue_sort(__sys_pl_queue(i), COMPARE_YEAR, false); queue_sort(__sys_pl_queue(i), COMPARE_TRACK, false); } else queue_set_flag(__sys_pl_queue(i), Q_NO_SORT); if (i >= SYS_PL_COLLECTION) queue_set_flag(__sys_pl_queue(i), Q_ADD_FRONT); } idle_schedule(IDLE_SYNC, __sys_pl_load, NULL); pl_system_update("Collection"); pl_system_update("Unplayed"); pl_system_update("Most Played"); pl_system_update("Least Played"); } void pl_system_deinit() { unsigned int i; for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) queue_deinit(__sys_pl_queue(i)); }