Collections

The Spotify service implements the standard collection interfaces that are common across all services.

Library Collection

The SpotifyLibraryCollection represents the full spotify catalog from the perspective of an authenticated user.

from plistsync.services.spotify import SpotifyLibraryCollection

library = SpotifyLibraryCollection()

Track Lookup

The Spotify library collection supports lookup by global IDs, specifically by spotify_id and isrc. This allows for efficient retrieval of tracks using these identifiers.

# By spotify id
if track1 := library.find_by_global_ids({"spotify_id": "6fzwardfFs6sVfNA5R1ypt"}):
    print(track1)

# By isrc
if track2 := library.find_by_global_ids({"isrc": "GBBZH9601601"}):
    print(track2)

assert track1 == track2
Track[Origin Unknown > Valley of the Shadows, hash: -406311439666707691]
Track[Origin Unknown > Valley of the Shadows, hash: -406311439666707691]

If you need/want to lookup many tracks at once, consider using SpotifyLibraryCollection.find_many_by_global_ids for better performance.

Playlist Collection

The SpotifyPlaylistCollection represents a playlist of an authenticated user.

Retrieving playlists

You can retrieve all playlists of a user using the library’s SpotifyLibraryCollection.playlists property.

playlists = library.playlists
for playlist in playlists:
    print(f"Playlist: {playlist.name} ({len(playlist)} tracks)")
Playlist: plistsync (3 tracks)

If you just want a specific playlist, you can use the library’s SpotifyLibraryCollection.get_playlist method to retrieve a playlist.

# By name
pl = library.get_playlist(
    name="plistsync"
    # id = "6tPAXg3zqkOgUPZPyD5Pph"
    # uri = "spotify:playlist:6tPAXg3zqkOgUPZPyD5Pph"
    # url = "https://open.spotify.com/playlist/6tPAXg3zqkOgUPZPyD5Pph"
)
if pl is not None:
    print(f"Found playlist: {pl.name} ({len(pl.tracks)} tracks)")
else:
    print("Playlist not found.")
Found playlist: plistsync (3 tracks)

Note

This method supports lookup by various identifiers, including name=, id=, url=, or uri=. Lookup by name will return None if no matching playlist is found, while lookups by other identifiers will raise a ValueError if the playlist cannot be resolved.

Creating playlists

Use {py.class}SpotifyPlaylistCollection <plistsync.services.spotify.SpotifyPlaylistCollection> to model a playlist locally, then (optionally) create/associate it on Spotify.

from plistsync.services.spotify import SpotifyPlaylistCollection

pl = SpotifyPlaylistCollection(
    library,
    name="My New Playlist",
    description="Created via plistsync",
)
assert pl.remote_associated == False

To remotly create the same playlist use the SpotifyPlaylistCollection.remote_create method.

pl.remote_create()
assert pl.remote_associated == True

Updating a playlist

For updating a playlist, you should use the playlist’s SpotifyPlaylistCollection.edit context manager. This ensures that all changes are properly saved back to Spotify when you exit the context. This also minifies changes and therefore reduces API calls.

# Updating a playlist description/name
with pl.remote_edit():
    pl.description = "Updated Description"

pl.description
'Updated Description'

You can add tracks to a playlist using the same context manager, again this will add the tracks when you exit the context.

from plistsync.services.spotify import SpotifyPlaylistTrack

new_track_1 = library.find_by_global_ids({"isrc": "GBBZH9601601"})
new_track_2 = library.find_by_global_ids({"isrc": "GBXJH1000082"})
assert new_track_1 is not None
assert new_track_2 is not None

with pl.remote_edit():
    # TODO: We should reevaluate the type hierarchy here.
    # for now, we have to manually cast SpotifyTrack to SpotifyPlaylistTrack.
    # this will become more convenient, eventually.
    pl.tracks.append(SpotifyPlaylistTrack(new_track_1))
    pl.tracks.append(SpotifyPlaylistTrack(new_track_2))

pl.tracks
[Track[Origin Unknown > Valley of the Shadows, hash: -406311439666707691],
 Track[Break > If I Could, hash: 1472772941810935056]]

To reorder tracks in a playlist, you can change the order of the SpotifyPlaylistCollection.tracks list within the context manager.

with pl.remote_edit():
    pl.tracks.insert(0, pl.tracks.pop())

Delete a playlist

You can also delete the playlist again.

pl.remote_delete()

Even tho the playlist is deleted from your users library it still does exist on spotify. This is a design choice with spotify itself as it is impossible to truly delete a playlist. See here for more information.

We opted to have the playlist still registered as remote_associated in this case.

assert pl.remote_associated

You can also still get the playlist via its id but lookup by name does not work anymore.

assert pl.id
assert library.get_playlist(id=pl.id)
assert not library.get_playlist(name=pl.name)