Skip to content

Library

The Library service manages a user’s saved content — albums and tracks.

Saved Tracks

Get saved tracks

import { Effect } from "effect";
import { Library, makeSpotifyLayer } from "@spotify-effect/core";
const program = Effect.gen(function* () {
const library = yield* Library;
const saved = yield* library.getSavedTracks({
limit: 50,
market: "US",
});
for (const item of saved.items) {
console.log(`${item.track.name}${item.added_at}`);
}
});

Check if tracks are saved

const program = Effect.gen(function* () {
const library = yield* Library;
const results = yield* library.areTracksSaved([
"4cOdK2wGLETKBW3PvgPWqT",
"5as3aKm2oGOikBg4arGMLi",
]);
results.forEach((isSaved, i) => {
console.log(`Track ${i}: ${isSaved ? "Saved" : "Not saved"}`);
});
});

Save tracks

yield * library.saveTracks(["4cOdK2wGLETKBW3PvgPWqT", "5as3aKm2oGOikBg4arGMLi"]);

Remove saved tracks

yield * library.removeSavedTracks(["4cOdK2wGLETKBW3PvgPWqT"]);

Saved Albums

Get saved albums

const program = Effect.gen(function* () {
const library = yield* Library;
const saved = yield* library.getSavedAlbums({
limit: 50,
});
for (const item of saved.items) {
console.log(`${item.album.name}${item.added_at}`);
}
});

Check if albums are saved

const results =
yield * library.areAlbumsSaved(["4aawyAB9vmqN3uQ7FjRGTy", "6rqhFgbbKwnb9MLmUQDhG6"]);

Save albums

yield * library.saveAlbums(["4aawyAB9vmqN3uQ7FjRGTy"]);

Remove saved albums

yield * library.removeSavedAlbums(["4aawyAB9vmqN3uQ7FjRGTy"]);

Practical Examples

Save search results to library

import { Effect } from "effect";
import { Library, Search } from "@spotify-effect/core";
const saveSearchToLibrary = (query: string) =>
Effect.gen(function* () {
const library = yield* Library;
const search = yield* Search;
const results = yield* search.search(query, ["track"], { limit: 50 });
const trackIds = results.tracks?.items.map((t) => t.id) ?? [];
const [saved, notSaved] = yield* Effect.all([
library.areTracksSaved(trackIds),
Effect.succeed(trackIds),
]);
const toSave = trackIds.filter((_, i) => !saved[i]);
if (toSave.length > 0) {
yield* library.saveTracks(toSave);
}
return { saved: toSave.length };
});

Sync playlist to library

const syncPlaylistToLibrary = (playlistId: string) =>
Effect.gen(function* () {
const library = yield* Library;
const playlists = yield* Playlists;
const albums = yield* Albums;
const tracks = yield* paginateAll(
(offset, limit) => playlists.getPlaylistItems(playlistId, { offset, limit }),
100,
);
const trackIds = tracks.items
.map((item) => (item.track?._tag === "Track" ? item.track.id : null))
.filter((id): id is string => id !== null);
const albumIds = [
...new Set(
tracks.items
.map((item) => (item.track?._tag === "Track" ? item.track.album.id : null))
.filter((id): id is string => id !== null),
),
];
const [savedTracks, savedAlbums] = yield* Effect.all([
library.areTracksSaved(trackIds),
library.areAlbumsSaved(albumIds),
]);
const tracksToSave = trackIds.filter((_, i) => !savedTracks[i]);
const albumsToSave = albumIds.filter((_, i) => !savedAlbums[i]);
if (tracksToSave.length > 0) {
yield* library.saveTracks(tracksToSave);
}
if (albumsToSave.length > 0) {
yield* library.saveAlbums(albumsToSave);
}
return {
tracksSaved: tracksToSave.length,
albumsSaved: albumsToSave.length,
};
});

Export library to playlist

const exportLibraryToPlaylist = (userId: string, name: string) =>
Effect.gen(function* () {
const library = yield* Library;
const playlists = yield* Playlists;
const savedTracks = yield* paginateAll(
(offset, limit) => library.getSavedTracks({ offset, limit }),
50,
);
const playlist = yield* playlists.createPlaylist(userId, name, {
description: "My saved tracks",
public: false,
});
const trackUris = savedTracks
.map((item) => item.track?.uri)
.filter((uri): uri is string => uri !== undefined);
for (let i = 0; i < trackUris.length; i += 100) {
yield* playlists.addItemsToPlaylist(playlist.id, trackUris.slice(i, i + 100));
}
return { playlist, trackCount: trackUris.length };
});

Pagination

Use paginateAll for large libraries:

import { paginateAll } from "@spotify-effect/core";
const getAllSavedTracks = () =>
Effect.gen(function* () {
const library = yield* Library;
return yield* paginateAll((offset, limit) => library.getSavedTracks({ offset, limit }), 50);
});
const getAllSavedAlbums = () =>
Effect.gen(function* () {
const library = yield* Library;
return yield* paginateAll((offset, limit) => library.getSavedAlbums({ offset, limit }), 50);
});

Scopes Required

OperationRequired Scope
getSavedTracks, getSavedAlbumsuser-library-read
saveTracks, saveAlbumsuser-library-modify
removeSavedTracks, removeSavedAlbumsuser-library-modify
areTracksSaved, areAlbumsSaveduser-library-read

Next steps