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; }
void playlist_set_single(struct playlist *playlist, bool status) { if (status == playlist->queue.single) return; playlist->queue.single = status; /* if the last song is currently being played, the "next song" might change when single mode is toggled */ playlist_update_queued_song(playlist, playlist_get_queued_song(playlist)); idle_add(IDLE_OPTIONS); }
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); }
enum playlist_result playlist_seek_song(struct playlist *playlist, struct player_control *pc, unsigned song, float seek_time) { const struct song *queued; unsigned i; bool success; if (!queue_valid_position(&playlist->queue, song)) return PLAYLIST_RESULT_BAD_RANGE; queued = playlist_get_queued_song(playlist); if (playlist->queue.random) i = queue_position_to_order(&playlist->queue, song); else i = song; pc_clear_error(pc); playlist->stop_on_error = true; playlist->error_count = 0; if (!playlist->playing || (unsigned)playlist->current != i) { /* seeking is not within the current song - prepare song change */ playlist->playing = true; playlist->current = i; queued = NULL; } success = pc_seek(pc, queue_get_order(&playlist->queue, i), seek_time); if (!success) { playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_NOT_PLAYING; } playlist->queued = -1; playlist_update_queued_song(playlist, pc, NULL); return PLAYLIST_RESULT_SUCCESS; }
void playlist_set_random(struct playlist *playlist, struct player_control *pc, bool status) { const struct song *queued; if (status == playlist->queue.random) return; queued = playlist_get_queued_song(playlist); playlist->queue.random = status; if (playlist->queue.random) { /* shuffle the queue order, but preserve playlist->current */ int current_position = playlist->playing && playlist->current >= 0 ? (int)queue_order_to_position(&playlist->queue, playlist->current) : -1; queue_shuffle_order(&playlist->queue); if (current_position >= 0) { /* make sure the current song is the first in the order list, so the whole rest of the playlist is played after that */ unsigned current_order = queue_position_to_order(&playlist->queue, current_position); queue_swap_order(&playlist->queue, 0, current_order); playlist->current = 0; } else playlist->current = -1; } else playlist_order(playlist); playlist_update_queued_song(playlist, pc, queued); idle_add(IDLE_OPTIONS); }
void playlist_set_single(struct playlist *playlist, struct player_control *pc, bool status) { if (status == playlist->queue.single) return; struct queue *queue = &playlist->queue; queue->single = status; pc_set_border_pause(pc, queue->single && !queue->repeat); /* if the last song is currently being played, the "next song" might change when single mode is toggled */ playlist_update_queued_song(playlist, pc, playlist_get_queued_song(playlist)); idle_add(IDLE_OPTIONS); }
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; }