268. Design Spotify Music Streaming
Asked in
Design Spotify Music Streaming
Design the catalogue and playback components of a simplified Spotify-like music streaming service. The system must allow songs to be added, updated, searched, and played while maintaining an independent playback session for every user.
All users already exist. Their user IDs are provided when the service is created. Input parameters passed to the constructor and methods are always valid.

Song Format

Each returned song is represented as:
"songId,title,artist,album,durationSeconds"

Playback State Format

Each playback state is represented as:
"status,songId,positionSeconds"
  • status is PLAYING, PAUSED, or STOPPED.
  • When no song is selected, return "STOPPED,NO_SONG,0".

Class

SpotifyMusicService

Constructor

SpotifyMusicService(List<String> userIds)
  • Creates an empty music catalogue.
  • Every value in userIds represents an existing user.
  • Each user initially has an empty playback session.

Method Signatures

Add or Update Song

void addOrUpdateSong(String songId, String title, String artist, String album, int durationSeconds)
  • Adds the song to the global music catalogue when songId does not already exist.
  • When songId already exists, replaces its title, artist, album, and duration with the supplied values.
  • The method does not return a value.
  • Updating a song does not reset or remove any user's current playback session.
  • A user currently playing the updated song observes its updated catalogue details.

Search Songs

List<String> searchSongs(String query)
  • Performs a case-insensitive substring search over song titles, artists, and albums.
  • Returns each matching song using the specified song format.
  • Returns matching songs in lexicographically increasing order of songId.
  • Returns an empty list when no song matches.

Play Song

String playSong(String userId, String songId)
  • Starts playing the given song for the user from position 0.
  • Replaces any song currently selected in the user's playback session.
  • Once a user starts playing a song, its duration for that playback session remains unchanged even if the song's catalogue details are later updated.
  • A user currently playing the updated song observes its updated title, artist, and album, but the duration stored in that playback session remains unchanged.
  • Starting or restarting a song creates a new playback session using the song's current catalogue duration.
  • Returns "PLAYING,songId,0".

Control Playback

String controlPlayback(String userId, String action, int positionSeconds)
  • action is "PAUSE", "RESUME", "SEEK", or "STOP".
  • "PAUSE" changes a playing song to PAUSED.
  • "RESUME" changes a paused song to PLAYING.
  • "SEEK" moves playback to positionSeconds without changing the current playback status.
  • "STOP" clears the user's current playback session.
  • For actions other than "SEEK", positionSeconds is 0.
  • For "SEEK", 0 ≤ positionSeconds < durationSeconds.
  • The playback session is always in a valid state for the supplied action.
  • Returns the resulting playback state.

Rules

  • Search is case-insensitive.
  • Search results are sorted by songId.
  • Every user has an independent playback session.
  • Starting another song replaces the user's current song.
  • Playback positions do not advance automatically between method calls.
  • Updating a song preserves its songId.
  • All user IDs and song IDs contain only lowercase English letters, digits, and hyphens.
  • The value NO_SONG is a special playback marker and is not a song ID.
  • All constructor and method parameters satisfy the stated constraints.

Design Expectations

  • Use separate components for the music catalogue and user playback sessions.
  • Updating catalogue metadata should not require recreating playback sessions.
  • Each user's playback state must be stored and modified independently.
  • Catalogue and playback operations should safely support calls from multiple users.

Constraints

  • 1 ≤ userIds.size() ≤ 100,000
  • 1 ≤ number of songs ≤ 100,000
  • 1 ≤ userId.length(), songId.length() ≤ 50
  • 1 ≤ title.length(), artist.length(), album.length() ≤ 100
  • 1 ≤ durationSeconds ≤ 86,400
  • 1 ≤ query.length() ≤ 100
  • userId and songId contain only a-z, 0-9, and -.
  • All user IDs passed to the constructor are unique.
  • All string parameters are non-empty.
  • Song titles, artist names, and album names do not contain commas.
  • All input parameters are valid.

Examples

Example 1: Add, Update, and Search Songs

SpotifyMusicService service = new SpotifyMusicService(userIds = ["user-1", "user-2"])
service.addOrUpdateSong(songId = "song-20", title = "Silent Road", artist = "Mira Sen", album = "Journeys", durationSeconds = 210)
Output: no value
service.addOrUpdateSong(songId = "song-05", title = "Road to Dawn", artist = "Kian Roy", album = "First Light", durationSeconds = 195)
Output: no value
service.addOrUpdateSong(songId = "song-20", title = "Silent Highway", artist = "Mira Sen", album = "New Journeys", durationSeconds = 225)
Output: no value
service.searchSongs(query = "road")
Output: ["song-05,Road to Dawn,Kian Roy,First Light,195"]
Updating song-20 replaces its old details, so its previous title no longer matches "road".

Example 2: Play and Pause a Song

service.playSong(userId = "user-1", songId = "song-20")
Output: "PLAYING,song-20,0"
service.controlPlayback(userId = "user-1", action = "SEEK", positionSeconds = 45)
Output: "PLAYING,song-20,45"
service.controlPlayback(userId = "user-1", action = "PAUSE", positionSeconds = 0)
Output: "PAUSED,song-20,45"
service.controlPlayback(userId = "user-1", action = "RESUME", positionSeconds = 0)
Output: "PLAYING,song-20,45"

Example 3: Independent Playback Sessions

service.playSong(userId = "user-2", songId = "song-05")
Output: "PLAYING,song-05,0"
service.controlPlayback(userId = "user-1", action = "STOP", positionSeconds = 0)
Output: "STOPPED,NO_SONG,0"
Stopping playback for user-1 does not affect the song being played by user-2.


Please use Laptop/Desktop or any other large screen to add/edit code.