albums
backend.api.albums
Section titled “backend.api.albums”albums api endpoints.
Functions
Section titled “Functions”invalidate_album_cache source
Section titled “invalidate_album_cache source”invalidate_album_cache(handle: str, slug: str) -> Nonedelete cached album response. fails silently.
invalidate_album_cache_by_id source
Section titled “invalidate_album_cache_by_id source”invalidate_album_cache_by_id(db: AsyncSession, album_id: str) -> Nonelook up album handle+slug and invalidate cache. fails silently.
list_albums source
Section titled “list_albums source”list_albums(db: Annotated[AsyncSession, Depends(get_db)]) -> dict[str, list[AlbumListItem]]list all albums with basic metadata.
albums with zero tracks are hidden — they’re either unfinalized drafts from the multi-track upload flow or legacy albums awaiting sync. only albums that have at least one track appear in public listings.
list_artist_albums source
Section titled “list_artist_albums source”list_artist_albums(handle: str, db: Annotated[AsyncSession, Depends(get_db)]) -> dict[str, list[ArtistAlbumListItem]]list albums for a specific artist.
get_album source
Section titled “get_album source”get_album(handle: str, slug: str, db: Annotated[AsyncSession, Depends(get_db)], session: AuthSession | None = Depends(get_optional_session)) -> AlbumResponseget album details with tracks (ordered by ATProto list record or created_at).
create_album source
Section titled “create_album source”create_album(body: AlbumCreatePayload, db: Annotated[AsyncSession, Depends(get_db)], auth_session: Annotated[AuthSession, Depends(require_artist_profile)]) -> AlbumMetadatacreate an empty album shell for the multi-track upload flow.
the ATProto list record is NOT written here — it is deferred to
POST /albums/{id}/finalize, which runs after tracks have actually
been published so a total upload failure doesn’t leave a fake release
behind. for the same reason, the album_release CollectionEvent is
also deferred to finalize (first successful call only, deduped).
idempotent on (artist_did, slug): if an album with the same slug already exists, the existing row is returned instead of failing. this preserves the “type an existing album name to add tracks to it” UX — see finalize_album for the append semantics.
upload_album_cover source
Section titled “upload_album_cover source”upload_album_cover(album_id: str, db: Annotated[AsyncSession, Depends(get_db)], auth_session: Annotated[AuthSession, Depends(require_artist_profile)], image: UploadFile = File(...)) -> dict[str, str | None]upload cover art for an album (requires authentication).
finalize_album source
Section titled “finalize_album source”finalize_album(album_id: str, body: AlbumFinalizePayload, db: Annotated[AsyncSession, Depends(get_db)], auth_session: Annotated[AuthSession, Depends(require_artist_profile)]) -> AlbumMetadatawrite the album’s ATProto list record using an explicit track order.
called by the frontend after per-track uploads have settled. this is
the single place the list record is created/updated for albums built
via POST /albums/ + POST /tracks/?album_id=....
append semantics: track_ids carries only the tracks from the current
upload session. any tracks already on the album that are NOT in
track_ids are preserved in the list record at their current positions
(fetched from the existing list record if present, falling back to
created_at order). new tracks are appended at the end in the order
requested. this matches the “type an existing album name to add tracks
to it” UX without truncating prior track history.
also emits an album_release CollectionEvent on the first successful
finalize for the album — so total upload failures don’t leave a fake
release event in the activity feed.
update_album source
Section titled “update_album source”update_album(album_id: str, db: Annotated[AsyncSession, Depends(get_db)], auth_session: Annotated[AuthSession, Depends(require_artist_profile)], title: Annotated[str | None, Query(description='new album title')] = None, description: Annotated[str | None, Query(description='new album description')] = None) -> AlbumMetadataupdate album metadata (title, description). syncs ATProto records on title change.
remove_track_from_album source
Section titled “remove_track_from_album source”remove_track_from_album(album_id: str, track_id: int, db: Annotated[AsyncSession, Depends(get_db)], auth_session: Annotated[AuthSession, Depends(require_artist_profile)]) -> RemoveTrackFromAlbumResponseremove a track from an album (orphan it, don’t delete).
the track remains available as a standalone track.
delete_album source
Section titled “delete_album source”delete_album(album_id: str, db: Annotated[AsyncSession, Depends(get_db)], auth_session: Annotated[AuthSession, Depends(require_artist_profile)], cascade: Annotated[bool, Query(description='if true, also delete all tracks in the album')] = False) -> DeleteAlbumResponsedelete album. tracks are orphaned unless cascade=true. removes ATProto list record.
Classes
Section titled “Classes”AlbumMetadata source
Section titled “AlbumMetadata source”album metadata response.
AlbumResponse source
Section titled “AlbumResponse source”album detail response with tracks.
AlbumListItem source
Section titled “AlbumListItem source”minimal album info for listing.
RemoveTrackFromAlbumResponse source
Section titled “RemoveTrackFromAlbumResponse source”response for removing a track from an album.
DeleteAlbumResponse source
Section titled “DeleteAlbumResponse source”response for deleting an album.
ArtistAlbumListItem source
Section titled “ArtistAlbumListItem source”album info for a specific artist (used on artist pages).
AlbumCreatePayload source
Section titled “AlbumCreatePayload source”AlbumUpdatePayload source
Section titled “AlbumUpdatePayload source”AlbumFinalizePayload source
Section titled “AlbumFinalizePayload source”request body for POST /albums/{id}/finalize.
track_ids is the authoritative user-intended order for the album’s ATProto list record. every id must belong to this album and have a completed PDS write (atproto_record_uri + cid set).