/* * Copyright 2016 (c) Anna Schumaker. */ #include #include #include static bool pl_system_add_track(const gchar *, struct track *); static bool pl_system_remove_track(const gchar *, struct track *); static inline struct queue *__sys_pl_queue(enum sys_playlist_t); static void __sys_pl_save(); static struct file sys_file = FILE_INIT("playlist.db", 0, 0); static struct file sys_collection_f = FILE_INIT("library.q", 0, 0); static struct sys_playlist *sys_playlists[SYS_PL_NUM_PLAYLISTS]; /* * Generic system playlist operations. */ static void sys_pl_generic_init(struct playlist *playlist, unsigned int flags, struct queue_ops *ops) { playlist_generic_init(playlist, Q_REPEAT | Q_ADD_FRONT, ops); } static bool sys_pl_generic_add(struct playlist *playlist, struct track *track) { if (queue_has(__sys_pl_queue(SYS_PL_HIDDEN), track)) return false; return playlist_generic_add_track(playlist, track); } /* * Favorite tracks playlist operations. */ static bool sys_pl_favorites_add(struct playlist *playlist, struct track *track) { bool ret = playlist_generic_add_track(playlist, track); __sys_pl_save(); return ret; } static bool sys_pl_favorites_remove(struct playlist *playlist, struct track *track) { bool ret = playlist_generic_remove_track(playlist, track); __sys_pl_save(); return ret; } static struct sys_playlist sys_favorites = { .spl_playlist = DEFINE_PLAYLIST(PL_SYSTEM, "Favorites"), .spl_init = playlist_generic_init, .spl_add = sys_pl_favorites_add, .spl_remove = sys_pl_favorites_remove, .spl_set_flag = playlist_generic_set_flag, .spl_sort = playlist_generic_sort, }; /* * Hidden tracks playlist operations. */ static bool sys_pl_hidden_add(struct playlist *playlist, struct track *track) { bool ret = playlist_generic_add_track(playlist, track); pl_system_remove_track("Collection", track); pl_system_remove_track("Unplayed", track); pl_system_remove_track("Most Played", track); pl_system_remove_track("Least Played", track); __sys_pl_save(); return ret; } static bool sys_pl_hidden_remove(struct playlist *playlist, struct track *track) { bool ret = playlist_generic_remove_track(playlist, track); pl_system_add_track("Collection", track); pl_system_add_track("Unplayed", track); pl_system_add_track("Most Played", track); pl_system_add_track("Least Played", track); __sys_pl_save(); return ret; } static struct sys_playlist sys_hidden = { .spl_playlist = DEFINE_PLAYLIST(PL_SYSTEM, "Hidden"), .spl_init = playlist_generic_init, .spl_add = sys_pl_hidden_add, .spl_remove = sys_pl_hidden_remove, .spl_set_flag = playlist_generic_set_flag, .spl_sort = playlist_generic_sort, }; /* * Collection playlist operations. */ static void sys_pl_collection_save(struct playlist *playlist) { if (file_open(&sys_collection_f, OPEN_WRITE)) { queue_save_flags(&playlist->pl_queue, &sys_collection_f); file_close(&sys_collection_f); } } static void sys_pl_collection_load(struct playlist *playlist) { if (file_open(&sys_collection_f, OPEN_READ)) { queue_load_flags(&playlist->pl_queue, &sys_collection_f); queue_unset_flag(&playlist->pl_queue, Q_SAVE_FLAGS); queue_unset_flag(&playlist->pl_queue, Q_SAVE_SORT); file_close(&sys_collection_f); } } static bool sys_pl_collection_add(struct playlist *playlist, struct track *track) { if (track->tr_library->li_enabled != true) return false; return sys_pl_generic_add(playlist, track); } static bool sys_pl_collection_update(struct playlist *playlist, struct track *track) { if (track->tr_library->li_enabled != true) return false; return sys_pl_generic_add(playlist, track) || true; } static void sys_pl_collection_set_flag(struct playlist *playlist, enum queue_flags flag, bool enabled) { playlist_generic_set_flag(playlist, flag, enabled); sys_pl_collection_save(playlist); } static void sys_pl_collection_sort(struct playlist *playlist, enum compare_t sort, bool reset) { playlist_generic_sort(playlist, sort, reset); sys_pl_collection_save(playlist); } static struct sys_playlist sys_collection = { .spl_playlist = DEFINE_PLAYLIST(PL_SYSTEM, "Collection"), .spl_init = sys_pl_generic_init, .spl_add = sys_pl_collection_add, .spl_remove = playlist_generic_remove_track, .spl_update = sys_pl_collection_update, .spl_set_flag = sys_pl_collection_set_flag, .spl_sort = sys_pl_collection_sort, }; /* * History playlist operations. */ static void sys_pl_history_init(struct playlist *playlist, unsigned int flags, struct queue_ops *ops) { queue_init(&playlist->pl_queue, Q_ENABLED | Q_REPEAT | Q_ADD_FRONT | Q_NO_SORT, ops, playlist); } static bool sys_pl_history_add(struct playlist *playlist, struct track *track) { queue_add(&playlist->pl_queue, track); queue_iter_set(&playlist->pl_queue, &playlist->pl_queue.q_cur, 0); return true; } static struct sys_playlist sys_history = { .spl_playlist = DEFINE_PLAYLIST(PL_SYSTEM, "History"), .spl_init = sys_pl_history_init, .spl_add = sys_pl_history_add, .spl_remove = playlist_generic_remove_track, .spl_set_flag = playlist_noop_set_flag, .spl_sort = playlist_noop_sort, }; /* * Unplayed tracks playlist operations. */ static bool sys_pl_unplayed_add(struct playlist *playlist, struct track *track) { if (track->tr_count > 0) return false; return sys_pl_generic_add(playlist, track); } static bool sys_pl_unplayed_update(struct playlist *playlist, struct track *track) { if (track->tr_count > 0) return false; return sys_pl_generic_add(playlist, track) || true; } static struct sys_playlist sys_unplayed = { .spl_playlist = DEFINE_PLAYLIST(PL_SYSTEM, "Unplayed"), .spl_init = sys_pl_generic_init, .spl_add = sys_pl_unplayed_add, .spl_remove = playlist_generic_remove_track, .spl_update = sys_pl_unplayed_update, .spl_set_flag = playlist_generic_set_flag, .spl_sort = playlist_generic_sort, }; /* * Most played tracks playlist operations. */ static bool sys_pl_most_played_add(struct playlist *playlist, struct track *track) { unsigned int average = track_db_average_plays(); if (track->tr_count <= average) return false; return sys_pl_generic_add(playlist, track); } static bool sys_pl_most_played_update(struct playlist *playlist, struct track *track) { unsigned int average = track_db_average_plays(); if (track->tr_count <= average) return false; return sys_pl_generic_add(playlist, track) || true; } static struct sys_playlist sys_most_played = { .spl_playlist = DEFINE_PLAYLIST(PL_SYSTEM, "Most Played"), .spl_init = sys_pl_generic_init, .spl_add = sys_pl_most_played_add, .spl_remove = playlist_generic_remove_track, .spl_update = sys_pl_most_played_update, .spl_set_flag = playlist_generic_set_flag, .spl_sort = playlist_generic_sort, }; /* * Least played tracks playlist operations. */ static bool sys_pl_least_played_add(struct playlist *playlist, struct track *track) { unsigned int average = track_db_average_plays(); if (!track->tr_count || track->tr_count > average) return false; return sys_pl_generic_add(playlist, track); } static bool sys_pl_least_played_update(struct playlist *playlist, struct track *track) { unsigned int average = track_db_average_plays(); if (!track->tr_count || track->tr_count > average) return false; return sys_pl_generic_add(playlist, track) || true; } static struct sys_playlist sys_least_played = { .spl_playlist = DEFINE_PLAYLIST(PL_SYSTEM, "Least Played"), .spl_init = sys_pl_generic_init, .spl_add = sys_pl_least_played_add, .spl_remove = playlist_generic_remove_track, .spl_update = sys_pl_least_played_update, .spl_set_flag = playlist_generic_set_flag, .spl_sort = playlist_generic_sort, }; static struct sys_playlist *sys_playlists[SYS_PL_NUM_PLAYLISTS] = { [SYS_PL_FAVORITES] = &sys_favorites, [SYS_PL_HIDDEN] = &sys_hidden, [SYS_PL_COLLECTION] = &sys_collection, [SYS_PL_HISTORY] = &sys_history, [SYS_PL_UNPLAYED] = &sys_unplayed, [SYS_PL_MOST_PLAYED] = &sys_most_played, [SYS_PL_LEAST_PLAYED] = &sys_least_played, }; static struct sys_playlist * __sys_pl_lookup(const gchar *name) { if (string_match(name, "Favorites")) return &sys_favorites; else if (string_match(name, "Hidden") || string_match(name, "Banned")) return &sys_hidden; else if (string_match(name, "Collection")) return &sys_collection; else if (string_match(name, "History")) return &sys_history; else if (string_match(name, "Unplayed")) return &sys_unplayed; else if (string_match(name, "Most Played")) return &sys_most_played; else if (string_match(name, "Least Played")) return &sys_least_played; return NULL; } static inline struct queue *__sys_pl_queue(enum sys_playlist_t plist) { return &sys_playlists[plist]->spl_playlist.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_load_playlists() { struct sys_playlist *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_lookup(name); if (plist) queue_load_tracks(&plist->spl_playlist.pl_queue, &sys_file); g_free(name); } file_close(&sys_file); return; } static bool __sys_pl_load() { __sys_pl_load_playlists(); sys_pl_collection_load(&__sys_pl_lookup("Collection")->spl_playlist); return true; } static struct queue *pl_system_get_queue(const gchar *name) { struct sys_playlist *sys_pl = __sys_pl_lookup(name); return sys_pl ? &sys_pl->spl_playlist.pl_queue : NULL; } static bool pl_system_new_delete(const gchar *name) { return false; } static bool pl_system_add_track(const gchar *name, struct track *track) { struct sys_playlist *sys_pl = __sys_pl_lookup(name); return sys_pl ? sys_pl->spl_add(&sys_pl->spl_playlist, track) : false; } static bool pl_system_remove_track(const gchar *name, struct track *track) { struct sys_playlist *sys_pl = __sys_pl_lookup(name); return sys_pl ? sys_pl->spl_remove(&sys_pl->spl_playlist, track) : false; } static void pl_system_update(const gchar *name) { struct sys_playlist *sys_pl = __sys_pl_lookup(name); if (sys_pl) playlist_generic_update(&sys_pl->spl_playlist, sys_pl->spl_update); } static void pl_system_set_flag(const gchar *name, enum queue_flags flag, bool enabled) { struct sys_playlist *sys_pl = __sys_pl_lookup(name); if (sys_pl) sys_pl->spl_set_flag(&sys_pl->spl_playlist, flag, enabled); } static void pl_system_sort(const gchar *name, enum compare_t sort, bool reset) { struct sys_playlist *sys_pl = __sys_pl_lookup(name); if (sys_pl) sys_pl->spl_sort(&sys_pl->spl_playlist, sort, reset); } struct playlist_type pl_system = { .pl_get_queue = pl_system_get_queue, .pl_new = pl_system_new_delete, .pl_delete = pl_system_new_delete, .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) { struct sys_playlist *sys_pl; unsigned int i; for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) { sys_pl = sys_playlists[i]; sys_pl->spl_init(&sys_pl->spl_playlist, 0, ops); } 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)); } void pl_system_new_track(struct track *track) { pl_system_add_track("Collection", track); pl_system_add_track("Unplayed", track); } void pl_system_delete_track(struct track *track) { struct sys_playlist *sys_pl; unsigned int i; for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) { sys_pl = sys_playlists[i]; sys_pl->spl_remove(&sys_pl->spl_playlist, track); } }