state: pull playlist + media cache into state machine
Move playlist, playlist cursor, playlist-enabled flag, and the URL-keyed
media cache out of RoomActor and into PlaybackState. The actor now
dispatches every mutation through state.transition() and persists the
returned effects. Three new state-machine methods own the data:
- handle_playlist_entry_added/removed, handle_set_playlist_enabled
- next_playlist_entry (returns next entry, advances cursor)
- handle_download_resolved/failed (updates media cache + propagates)
Kills the duplicate ad-hoc fields (download_results, playlist,
playlist_index) and the next_playlist_track helper, leaving RoomActor
with download_tasks as its only ephemeral I/O state.
Frontend: RoomState gains playlist_enabled; Queue adds an Autoplay
toggle that round-trips over the existing WebSocket.
74 tests pass (was 56). 0 clippy warnings. 0 dead-code warnings.