Don't call syncPlaylistWithQueue() in nextSongInPlaylist() and
previousSongInPlaylist(). This is a relic from the time when there
was no event, and was a workaround to the timing problem.
Export the "g_playlist" variable, and pass it to all playlist
functions. This way, we can split playlist.c easier into separate
parts. The code which initializes the singleton variable is moved to
playlist_global.c.
Before every operation which modifies the playlist, remember a pointer
to the song struct. After the modification, determine the "next song"
again, and if it differs, dequeue and queue the new song.
This removes a lot of complexity from the playlist update code, and
makes it more robust.
When the playlist was loaded from the state file, the order numbers
were the same as the positions. In random mode, we need to shuffle
the queue order. To accomplish that, call setPlaylistRandomStatus()
at the end of readPlaylistState(), and do a fresh shuffle.
When MPD is not playing while in random mode, and the client issues
the "clear" command, MPD crashes in stopPlaylist(), or more exactly,
in queue_order_to_position(-1). Exit from stopPlaylist() if MPD isn't
playing.
PlaylistInfo() (notice the capital 'P') sends a stored playlist to the
client. Move it to a separate library, where all the code which glues
the playlist and the MPD protocol together will live.
The playlist.c source is currently quite hard to understand. I have
managed to wrap my head around it, and this patch attempts to explain
it to the next guy.
The function playPlaylistIfPlayerStopped() is only called when the
player thread is stopped. Converted that runtime check into an
assertion, and remove one indent level.
One of the previous patches removed the "random" mode check from
nextSongInPlaylist(), which caused a shuffle whenever MPD wrapped to
the first song in "repeat" mode. Re-add that "random" check.
In playPlaylist(), the second "song==-1 && playing" check can never be
reached, because at this point, the function has already returned
(after unpausing).
When a song is deleted, start playing the next song immediately,
within deleteFromPlaylist(). This allows us to remove the ugly
playlist_noGoToNext flag, and the currentSongInPlaylist() function.
By calling queue_next_order() before playlist.current is invalidated
(by the deletion of a song), we get more robust results, and the code
becomes a little bit easier. incrPlaylistCurrent() is unused now, and
can be removed.
The function shuffles the virtual order of songs, but does not move
them physically. This is used in random mode.
The new function replaces playlist.c's randomizeOrder() function,
which was aware of playlist.current and playlist.queued. The latter
is always -1 anyway, and the former as preserved by the caller, by
converting playlist.current to a position, and then back to an order
number.
Add a "changed" check to setPlaylistRepeatStatus(): when the new
repeat mode is the same as the old one, don't do anything at all. No
more checks, no "idle" event.
When the random mode is toggled, MPD did not clear the queue. Because
of this, MPD continued with the next (random or non-random) song
according to the previous mode. Clear the queued song to fix that.
The function moveSongInPlaylist() attempted to read the position of
the current song, even if it was -1. Check that first. The same bug
was in shufflePlaylist().
It is possible that playlist.current is reset before the TAG event
handler playlist_tag_event() is called. Convert the assertion into a
run-time check.
Don't attempt to restart the player if it was stopped, but there were
still songs left on the playlist. This looks like it has been a
workaround for a bug which has been fixed long time ago.