enum playlist_result playlist_move_range(struct playlist *playlist, unsigned start, unsigned end, int to) { const struct song *queued; int currentSong; if (!queue_valid_position(&playlist->queue, start) || !queue_valid_position(&playlist->queue, end - 1)) return PLAYLIST_RESULT_BAD_RANGE; if ((to >= 0 && to + end - start - 1 >= queue_length(&playlist->queue)) || (to < 0 && abs(to) > (int)queue_length(&playlist->queue))) return PLAYLIST_RESULT_BAD_RANGE; if ((int)start == to) /* nothing happens */ return PLAYLIST_RESULT_SUCCESS; queued = playlist_get_queued_song(playlist); /* * (to < 0) => move to offset from current song * (-playlist.length == to) => move to position BEFORE current song */ currentSong = playlist->current >= 0 ? (int)queue_order_to_position(&playlist->queue, playlist->current) : -1; if (to < 0 && playlist->current >= 0) { if (start <= (unsigned)currentSong && (unsigned)currentSong <= end) /* no-op, can't be moved to offset of itself */ return PLAYLIST_RESULT_SUCCESS; to = (currentSong + abs(to)) % queue_length(&playlist->queue); if (start < (unsigned)to) to--; } queue_move_range(&playlist->queue, start, end, to); if (!playlist->queue.random) { /* update current/queued */ if ((int)start <= playlist->current && (unsigned)playlist->current < end) playlist->current += to - start; else if (playlist->current >= (int)end && playlist->current <= to) { playlist->current -= end - start; } else if (playlist->current >= to && playlist->current < (int)start) { playlist->current += end - start; } } playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); return PLAYLIST_RESULT_SUCCESS; }
enum playlist_result playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end) { const struct song *queued; if (start >= queue_length(&playlist->queue)) return PLAYLIST_RESULT_BAD_RANGE; if (end > queue_length(&playlist->queue)) end = queue_length(&playlist->queue); if (start >= end) return PLAYLIST_RESULT_SUCCESS; queued = playlist_get_queued_song(playlist); do { playlist_delete_internal(playlist, --end, &queued); } while (end != start); playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); return PLAYLIST_RESULT_SUCCESS; }
enum playlist_result playlist_delete(struct playlist *playlist, unsigned song) { const struct song *queued; if (song >= queue_length(&playlist->queue)) return PLAYLIST_RESULT_BAD_RANGE; queued = playlist_get_queued_song(playlist); playlist_delete_internal(playlist, song, &queued); playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); return PLAYLIST_RESULT_SUCCESS; }
void playlist_shuffle(struct playlist *playlist, struct player_control *pc, unsigned start, unsigned end) { const struct song *queued; if (end > queue_length(&playlist->queue)) /* correct the "end" offset */ end = queue_length(&playlist->queue); if ((start+1) >= end) /* needs at least two entries. */ return; queued = playlist_get_queued_song(playlist); if (playlist->playing && playlist->current >= 0) { unsigned current_position; current_position = queue_order_to_position(&playlist->queue, playlist->current); if (current_position >= start && current_position < end) { /* put current playing song first */ queue_swap(&playlist->queue, start, current_position); if (playlist->queue.random) { playlist->current = queue_position_to_order(&playlist->queue, start); } else playlist->current = start; /* start shuffle after the current song */ start++; } } else { /* no playback currently: reset playlist->current */ playlist->current = -1; } queue_shuffle_range(&playlist->queue, start, end); playlist_increment_version(playlist); playlist_update_queued_song(playlist, pc, queued); }
void playlist_clear(struct playlist *playlist) { playlist_stop(playlist); /* make sure there are no references to allocated songs anymore */ for (unsigned i = 0; i < queue_length(&playlist->queue); i++) { const struct song *song = queue_get(&playlist->queue, i); if (!song_in_database(song)) pc_song_deleted(song); } queue_clear(&playlist->queue); playlist->current = -1; playlist_increment_version(playlist); }
enum playlist_result playlist_set_priority(struct playlist *playlist, struct player_control *pc, unsigned start, unsigned end, uint8_t priority) { if (start >= queue_length(&playlist->queue)) return PLAYLIST_RESULT_BAD_RANGE; if (end > queue_length(&playlist->queue)) end = queue_length(&playlist->queue); if (start >= end) return PLAYLIST_RESULT_SUCCESS; /* remember "current" and "queued" */ int current_position = playlist->current >= 0 ? (int)queue_order_to_position(&playlist->queue, playlist->current) : -1; const struct song *queued = playlist_get_queued_song(playlist); /* apply the priority changes */ queue_set_priority_range(&playlist->queue, start, end, priority, playlist->current); playlist_increment_version(playlist); /* restore "current" and choose a new "queued" */ if (current_position >= 0) playlist->current = queue_position_to_order(&playlist->queue, current_position); playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_SUCCESS; }
enum playlist_result playlist_swap_songs(struct playlist *playlist, struct player_control *pc, unsigned song1, unsigned song2) { const struct song *queued; if (!queue_valid_position(&playlist->queue, song1) || !queue_valid_position(&playlist->queue, song2)) return PLAYLIST_RESULT_BAD_RANGE; queued = playlist_get_queued_song(playlist); queue_swap(&playlist->queue, song1, song2); if (playlist->queue.random) { /* update the queue order, so that playlist->current still points to the current song order */ queue_swap_order(&playlist->queue, queue_position_to_order(&playlist->queue, song1), queue_position_to_order(&playlist->queue, song2)); } else { /* correct the "current" song order */ if (playlist->current == (int)song1) playlist->current = song2; else if (playlist->current == (int)song2) playlist->current = song1; } playlist_increment_version(playlist); playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_SUCCESS; }
enum playlist_result playlist_append_song(struct playlist *playlist, struct song *song, unsigned *added_id) { const struct song *queued; unsigned id; if (queue_is_full(&playlist->queue)) return PLAYLIST_RESULT_TOO_LARGE; queued = playlist_get_queued_song(playlist); id = queue_append(&playlist->queue, song); if (playlist->queue.random) { /* shuffle the new song into the list of remaining songs to play */ unsigned start; if (playlist->queued >= 0) start = playlist->queued + 1; else start = playlist->current + 1; if (start < queue_length(&playlist->queue)) queue_shuffle_order_last(&playlist->queue, start, queue_length(&playlist->queue)); } playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); if (added_id) *added_id = id; return PLAYLIST_RESULT_SUCCESS; }