### Set up tidalapi development environment with poetry
Source: https://tidalapi.netlify.app/
Set up the development environment for tidalapi. Installs pipx, then poetry, and installs project dependencies without the root package.
```bash
$ pip install pipx
$ pipx install poetry
$ poetry install --no-root
```
--------------------------------
### Install tidalapi with pip
Source: https://tidalapi.netlify.app/
Install the tidalapi package from PyPI using pip. Requires Python 3.9 or higher.
```bash
$ pip install tidalapi
```
--------------------------------
### Add tracks to a playlist with playlist.add
Source: https://tidalapi.netlify.app/_sources/playlist.rst.txt
Adds tracks to the playlist by their IDs and prints the names of all tracks in the playlist. The example adds two tracks and prints their names.
```python
playlist.add([133937137, 71823815])
[print(x.name) for x in playlist.tracks()]
```
--------------------------------
### Album.items
Source: https://tidalapi.netlify.app/api
Gets the first 'limit' tracks and videos in the album from TIDAL.
```APIDOC
## Album.items
### Description
Gets the first 'limit' tracks and videos in the album from TIDAL.
### Method
GET
### Endpoint
Not specified
### Parameters
- **limit** (int) - Optional - The number of items you want to retrieve.
- **offset** (int) - Optional - The index you want to start retrieving items from.
- **sparse_album** (bool) - Optional - Provide a sparse track.album, containing only essential attributes from track JSON. False: Populate the track.album attributes from the parent Album object (self).
### Returns
A list of `Tracks` and `Videos`.
```
--------------------------------
### Customizable OAuth login with desktop notification (tidalapi)
Source: https://tidalapi.netlify.app/_sources/login.rst.txt
Uses session.login_oauth() to get a verification URI and shows it in a desktop notification via plyer. After the user opens the URI and authorizes, future.result() waits for completion, then session.check_login() verifies login. Requires an initialized session from tests.conftest.login().
```python
from plyer import notification
login, future = session.login_oauth()
notification.notify("Open the URL to log in", login.verification_uri_complete)
future.result()
print(session.check_login())
```
--------------------------------
### Get album image URL with dimension validation
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Returns a URL to an album image cover. Valid dimensions are 80, 160, 320, 640, or 1280; otherwise raises ValueError.
```python
[docs] def image(self, dimensions: int = 320, default: str = DEFAULT_ALBUM_IMG) -> str:
"""A url to an album image cover.
:param dimensions: The width and height that you want from the image
:param default: An optional default image to serve if one is not available
:return: A url to the image.
Valid resolutions: 80x80, 160x160, 320x320, 640x640, 1280x1280
"""
if dimensions not in [80, 160, 320, 640, 1280]:
raise ValueError("Invalid resolution {0} x {0}".format(dimensions))
```
--------------------------------
### Remove tracks from a playlist by index and ID
Source: https://tidalapi.netlify.app/_sources/playlist.rst.txt
Removes tracks from the playlist by index and by ID, then prints the remaining tracks. The example removes the first track and the track with ID 71823815, resulting in an empty list.
```python
playlist.remove_by_index(0)
playlist.remove_by_id(71823815)
print(playlist.tracks())
```
--------------------------------
### Create a playlist with session.user.create_playlist
Source: https://tidalapi.netlify.app/_sources/playlist.rst.txt
Creates a new playlist for the logged-in user and prints its name. The playlist is created with the given title and description.
```python
playlist = session.user.create_playlist("Example playlist", "An example of a playlist")
print(playlist.name)
```
--------------------------------
### Configure tidalapi.Config with lossless quality
Source: https://tidalapi.netlify.app/_sources/config.rst.txt
Creates a tidalapi.Config instance with lossless track quality and low video quality, then passes it to tidalapi.Session. Historically, this configuration is done before initializing the session because some API keys did not support all qualities.
```python
import tidalapi
config = tidalapi.Config(quality=tidalapi.Quality.lossless, video_quality=tidalapi.VideoQuality.low)
session = tidalapi.Session(config)
```
--------------------------------
### Simple login with session.login_oauth_simple (tidalapi)
Source: https://tidalapi.netlify.app/_sources/login.rst.txt
Prints the login link using the provided print function (here printer writes to stderr to avoid being swallowed). Waits for login to complete, then prints session.check_login() result. Uses the default print if no fn_print is provided.
```python
# The function is print by default, but you can use anything, here we do it to avoid the print being swallowed
session.login_oauth_simple(fn_print=printer)
print(session.check_login())
```
--------------------------------
### Album.video
Source: https://tidalapi.netlify.app/api
Creates a url to an mp4 video cover for the album.
```APIDOC
## Album.video
### Description
Creates a url to an mp4 video cover for the album.
### Method
GET
### Endpoint
Not specified
### Parameters
- **dimensions** (int) - Required - The width and height of the video.
### Returns
A url to an mp4 of the video cover. Valid resolutions: 80x80, 160x160, 320x320, 640x640, 1280x1280.
```
--------------------------------
### video(dimensions: int) -> str
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Creates a URL to an mp4 video cover for the album. Valid resolutions are 80x80, 160x160, 320x320, 640x640, and 1280x1280. Raises AttributeError if no video cover exists and ValueError for invalid dimensions.
```APIDOC
## video(dimensions: int) -> str
### Description
Creates a URL to an mp4 video cover for the album. Valid resolutions: 80x80, 160x160, 320x320, 640x640, 1280x1280.
### Method
GET
### Endpoint
Not applicable (SDK method)
### Parameters
#### Parameters
- **dimensions** (int) - Required - The width and height of the video.
### Return Value
- **str** - A URL to an mp4 of the video cover.
### Errors
- **AttributeError** - If the album does not have a video cover.
- **ValueError** - If the dimensions is not one of [80, 160, 320, 640, 1280].
```
--------------------------------
### Simple login with print function
Source: https://tidalapi.netlify.app/login
Prints the login link using a custom print function to avoid swallowing. The login_oauth_simple() method waits for the login future to complete, then check_login() is called. Not very flexible.
```python
# The function is print by default, but you can use anything, here we do it to avoid the print being swallowed
session.login_oauth_simple(fn_print=printer)
print(session.check_login())
```
--------------------------------
### similar() -> List[Album]
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Retrieves albums similar to the current one. Raises MetadataNotAvailable when no similar albums exist, and TooManyRequests when rate limited.
```APIDOC
## similar() -> List[Album]
### Description
Retrieve albums similar to the current one. MetadataNotAvailable is raised when no similar albums exist.
### Method
GET
### Endpoint
Not applicable (SDK method)
### Parameters
None
### Return Value
- **List[Album]** - A list of similar albums.
### Errors
- **MetadataNotAvailable** - If no similar albums exist for this album.
- **TooManyRequests** - If similar artists are unavailable due to rate limiting.
```
--------------------------------
### review() -> str
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Retrieves the album review as a string. Raises requests.HTTPError if there isn't a review yet.
```APIDOC
## review() -> str
### Description
Retrieve the album review.
### Method
GET
### Endpoint
Not applicable (SDK method)
### Parameters
None
### Return Value
- **str** - The album review, with wimp links.
### Errors
- **requests.HTTPError** - If there isn't a review yet.
```
--------------------------------
### Album.similar
Source: https://tidalapi.netlify.app/api
Retrieve albums similar to the current one.
```APIDOC
## Album.similar
### Description
Retrieve albums similar to the current one. MetadataNotAvailable is raised when no similar albums exist.
### Method
GET
### Endpoint
Not specified
### Returns
A `list` of similar albums.
```
--------------------------------
### Fetch album items (tracks and videos) with sparse_album option
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Fetches the album's tracks and videos from the TIDAL API. When sparse_album is False, the media's album attribute is populated from the parent Album object via functools.partial.
```python
[docs] def items(
self, limit: int = 100, offset: int = 0, sparse_album: bool = False
) -> List[Union["Track", "Video"]]:
"""Gets the first 'limit' tracks and videos in the album from TIDAL.
:param limit: The number of items you want to retrieve
:param offset: The index you want to start retrieving items from
:param sparse_album: Provide a sparse track.album, containing only essential attributes from track JSON
False: Populate the track.album attributes from the parent Album object (self)
:return: A list of :class:`Tracks<.Track>` and :class:`Videos`<.Video>`
"""
params = {"offset": offset, "limit": limit}
if sparse_album:
parse_media_callable = self.session.parse_media
else:
# Parse tracks attributes but provide the Album object directly from self
parse_media_callable = functools.partial(
self.session.parse_media, album=self
)
items = self.request.map_request(
"albums/%s/items" % self.id, params=params, parse=parse_media_callable
)
assert isinstance(items, list)
return cast(List[Union["Track", "Video"]], items)
```
--------------------------------
### Album.review
Source: https://tidalapi.netlify.app/api
Retrieve the album review.
```APIDOC
## Album.review
### Description
Retrieve the album review.
### Method
GET
### Endpoint
Not specified
### Returns
A `str` containing the album review, with wimp links.
### Raises
`requests.HTTPError` if there isn't a review yet.
```
--------------------------------
### Loading login credentials
Source: https://tidalapi.netlify.app/login
Uses previously stored credentials to log in via load_oauth_session(). This allows logging in on one device and loading credentials elsewhere, e.g., in the cloud.
```python
print(session.load_oauth_session(token_type, access_token, refresh_token, expiry_time))
```
--------------------------------
### Album.image
Source: https://tidalapi.netlify.app/api
A url to an album image cover.
```APIDOC
## Album.image
### Description
A url to an album image cover.
### Method
GET
### Endpoint
Not specified
### Parameters
- **dimensions** (int) - Optional - The width and height that you want from the image.
- **default** (str) - Optional - An optional default image to serve if one is not available.
### Returns
A url to the image. Valid resolutions: 80x80, 160x160, 320x320, 640x640, 1280x1280.
```
--------------------------------
### Load stored OAuth credentials with session.load_oauth_session (tidalapi)
Source: https://tidalapi.netlify.app/_sources/login.rst.txt
Restores a session using previously stored credentials (token_type, access_token, refresh_token, expiry_time). Prints the result of session.check_login() to confirm the login state.
```python
print(session.load_oauth_session(token_type, access_token, refresh_token, expiry_time))
```
--------------------------------
### Iterate Home, Explore, and Videos pages with tidalapi.page
Source: https://tidalapi.netlify.app/pages
Iterates through the Home, Explore, and Videos pages, printing category titles and then each category's items with their relevant fields. Handles PageItem, PageLink, Mix, and other item types, with comments indicating when to call item.get() or session.album().
```python
from tidalapi.page import PageItem, PageLink
from tidalapi.mix import Mix
home = session.home()
home.categories.extend(session.explore().categories)
home.categories.extend(session.videos().categories)
for category in home.categories:
print(category.title)
for category in home.categories:
print(category.title)
items = []
for item in category.items:
if isinstance(item, PageItem):
items.append("\t" + item.short_header)
items.append("\t" + item.short_sub_header[0:50])
# Call item.get() on this one, for example on click
elif isinstance(item, PageLink):
items.append("\t" + item.title)
# Call item.get() on this one, for example on click
elif isinstance(item, Mix):
items.append("\t" + item.title)
# You can optionally call item.get() to request the items() first, but it does it for you if you don't
else:
items.append("\t" + item.name)
# An album could be handled by session.album(item.id) for example,
# to get full details. Usually the relevant info is there already however
print()
[print(x) for x in sorted(items)]
```
--------------------------------
### Delete a playlist with playlist.delete
Source: https://tidalapi.netlify.app/_sources/playlist.rst.txt
Deletes the playlist. This action is irreversible.
```python
playlist.delete()
```
--------------------------------
### Album.tracks
Source: https://tidalapi.netlify.app/api
Returns the tracks in the album.
```APIDOC
## Album.tracks
### Description
Returns the tracks in the album.
### Method
GET
### Endpoint
Not specified
### Parameters
- **limit** (int) - Optional - The amount of items you want returned.
- **offset** (int) - Optional - The position of the first item you want to include.
- **sparse_album** (bool) - Optional - Provide a sparse track.album, containing only essential attributes from track JSON. False: Populate the track.album attributes from the parent Album object (self).
### Returns
A list of the `Tracks` in the album.
```
--------------------------------
### Storing login credentials
Source: https://tidalapi.netlify.app/login
Shows which session attributes to store securely: token_type, access_token, refresh_token, and expiry_time. The refresh_token is optional if refreshing is not needed.
```python
token_type = session.token_type
access_token = session.access_token
refresh_token = session.refresh_token # Not needed if you don't care about refreshing
expiry_time = session.expiry_time
```
--------------------------------
### Parse album JSON fields and build URLs
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Parses album JSON fields, handling optional fields with .get() and parsing ISO dates with dateutil.parser.isoparse. Constructs listen and share URLs from session config and returns a shallow copy of the album object.
```python
# Certain fields may not be available
self.audio_quality = json_obj.get("audioQuality")
self.audio_modes = json_obj.get("audioModes")
if "mediaMetadata" in json_obj:
self.media_metadata_tags = json_obj.get("mediaMetadata")["tags"]
self.artist = artist
self.artists = artists
release_date = json_obj.get("releaseDate")
self.release_date = (
dateutil.parser.isoparse(release_date) if release_date else None
)
tidal_release_date = json_obj.get("streamStartDate")
self.tidal_release_date = (
dateutil.parser.isoparse(tidal_release_date) if tidal_release_date else None
)
user_date_added = json_obj.get("dateAdded")
self.user_date_added = (
dateutil.parser.isoparse(user_date_added) if user_date_added else None
)
self.listen_url = f"{self.session.config.listen_base_url}/album/{self.id}"
self.share_url = f"{self.session.config.share_base_url}/album/{self.id}"
return copy.copy(self)
```
--------------------------------
### Store login credentials from session fields (tidalapi)
Source: https://tidalapi.netlify.app/_sources/login.rst.txt
Captures token_type, access_token, refresh_token, and expiry_time from the session. These values must be stored in a secure place for later use. The refresh_token is optional if you don't need refreshing.
```python
token_type = session.token_type
access_token = session.access_token
refresh_token = session.refresh_token # Not needed if you don't care about refreshing
expiry_time = session.expiry_time
```
--------------------------------
### get_audio_resolution(individual_tracks: bool = False) -> [[int, int]]
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Retrieves the audio resolution (bit rate + sample rate) for the album track(s). Assumes all tracks use the same resolution unless individual_tracks is True, which may require many additional requests.
```APIDOC
## get_audio_resolution(individual_tracks: bool = False) -> [[int, int]]
### Description
Retrieve the audio resolution (bit rate + sample rate) for the album track(s). This function assumes that all album tracks use the same audio resolution. Some albums may consist of tracks with multiple audio resolution(s). The audio resolution can therefore be fetched for individual tracks by setting the `all_tracks` argument accordingly.
WARNING: For individual tracks, many additional requests are needed. Handle with care!
### Method
GET
### Endpoint
Not applicable (SDK method)
### Parameters
#### Parameters
- **individual_tracks** (bool) - Optional - Fetch individual track resolutions. Defaults to False.
### Return Value
- **[[int, int]]** - A list of tuples containing the (bit_rate, sample_rate) for one or more tracks.
```
--------------------------------
### Fetch album tracks with sparse_album option
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Fetches the album's tracks from the TIDAL API. When sparse_album is False, the track's album attribute is populated from the parent Album object via functools.partial.
```python
[docs] def tracks(
self,
limit: Optional[int] = None,
offset: int = 0,
sparse_album: bool = False,
) -> List["Track"]:
"""Returns the tracks in classes album.
:param limit: The amount of items you want returned.
:param offset: The position of the first item you want to include.
:param sparse_album: Provide a sparse track.album, containing only essential attributes from track JSON
False: Populate the track.album attributes from the parent Album object (self)
:return: A list of the :class:`Tracks <.Track>` in the album.
"""
params = {"limit": limit, "offset": offset}
if sparse_album:
parse_track_callable = self.session.parse_track
else:
# Parse tracks attributes but provide the Album object directly from self
parse_track_callable = functools.partial(
self.session.parse_track, album=self
)
tracks = self.request.map_request(
"albums/%s/tracks" % self.id, params, parse=parse_track_callable
)
assert isinstance(tracks, list)
return cast(List["Track"], tracks)
```
--------------------------------
### Album.page
Source: https://tidalapi.netlify.app/api
Retrieve the album page as seen on https://listen.tidal.com/album/$id.
```APIDOC
## Album.page
### Description
Retrieve the album page as seen on https://listen.tidal.com/album/$id.
### Method
GET
### Endpoint
Not specified
### Returns
A `Page` containing the different categories, e.g. similar artists and albums.
```
--------------------------------
### tidalapi.album module source code
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
The complete source code for the tidalapi.album module, defining the Album class. It includes imports, class attributes, the constructor that fetches album data, and the parse method that maps JSON fields to the object.
```python
# Copyright (C) 2023- The Tidalapi Developers
# Copyright (C) 2019-2022 morguldir
# Copyright (C) 2014 Thomas Amland
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
import copy
import functools
from datetime import datetime
from typing import TYPE_CHECKING, List, Optional, Union, cast
import dateutil.parser
from tidalapi.exceptions import MetadataNotAvailable, ObjectNotFound, TooManyRequests
from tidalapi.types import JsonObj
if TYPE_CHECKING:
from tidalapi.artist import Artist
from tidalapi.media import Track, Video
from tidalapi.page import Page
from tidalapi.session import Session
DEFAULT_ALBUM_IMG = "0dfd3368-3aa1-49a3-935f-10ffb39803c0"
[docs]class Album:
"""Contains information about a TIDAL album.
If the album is created from a media object, this object will only contain the id,
name, cover and video cover. TIDAL does this to reduce the network load.
"""
id: Optional[int] = -1
name: Optional[str] = None
cover = None
video_cover = None
type = None
duration: Optional[int] = -1
available: Optional[bool] = False
ad_supported_ready: Optional[bool] = False
dj_ready: Optional[bool] = False
allow_streaming: Optional[bool] = False
premium_streaming_only: Optional[bool] = False
num_tracks: Optional[int] = -1
num_videos: Optional[int] = -1
num_volumes: Optional[int] = -1
tidal_release_date: Optional[datetime] = None
release_date: Optional[datetime] = None
copyright = None
upc = None
version = None
explicit: Optional[bool] = True
universal_product_number: Optional[int] = -1
popularity: Optional[int] = -1
user_date_added: Optional[datetime] = None
audio_quality: Optional[str] = ""
audio_modes: Optional[List[str]] = [""]
media_metadata_tags: Optional[List[str]] = [""]
artist: Optional["Artist"] = None
artists: Optional[List["Artist"]] = None
# Direct URL to https://listen.tidal.com/album/
listen_url: str = ""
# Direct URL to https://tidal.com/browse/album/
share_url: str = ""
def __init__(self, session: "Session", album_id: Optional[str]):
self.session = session
self.request = session.request
self.artist = session.artist()
self.id = album_id
if self.id:
try:
request = self.request.request("GET", "albums/%s" % self.id)
except ObjectNotFound:
raise ObjectNotFound("Album not found")
except TooManyRequests:
raise TooManyRequests("Album unavailable")
else:
self.request.map_json(request.json(), parse=self.parse)
[docs] def parse(
self,
json_obj: JsonObj,
artist: Optional["Artist"] = None,
artists: Optional[List["Artist"]] = None,
) -> "Album":
if artists is None:
artists = self.session.parse_artists(json_obj["artists"])
# Sometimes the artist field is not filled, an example is 140196345
if "artist" not in json_obj:
artist = artists[0]
elif artist is None:
artist = self.session.parse_artist(json_obj["artist"])
self.id = json_obj["id"]
self.name = json_obj["title"]
self.cover = json_obj["cover"]
self.video_cover = json_obj["videoCover"]
self.duration = json_obj.get("duration")
self.available = json_obj.get("streamReady")
self.ad_supported_ready = json_obj.get("adSupportedStreamReady")
self.dj_ready = json_obj.get("djReady")
self.allow_streaming = json_obj.get("allowStreaming")
self.premium_streaming_only = json_obj.get("premiumStreamingOnly")
self.num_tracks = json_obj.get("numberOfTracks")
self.num_videos = json_obj.get("numberOfVideos")
self.num_volumes = json_obj.get("numberOfVolumes")
self.copyright = json_obj.get("copyright")
self.upc = json_obj.get("upc")
self.version = json_obj.get("version")
self.explicit = json_obj.get("explicit")
self.universal_product_number = json_obj.get("upc")
self.popularity = json_obj.get("popularity")
self.type = json_obj.get("type")
```
--------------------------------
### Album available_release_date property
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Property that returns the release date if available, otherwise the TIDAL release date, or None if neither is set.
```python
@property
def available_release_date(self) -> Optional[datetime]:
"""Get the release date if it's available, otherwise get the day it was released
on TIDAL.
:return: A :any:`python:datetime.datetime` object with the release date, or the
tidal release date, can be None
"""
if self.release_date:
return self.release_date
if self.tidal_release_date:
return self.tidal_release_date
return None
```
--------------------------------
### Album year property
Source: https://tidalapi.netlify.app/_modules/tidalapi/album
Property that returns the year of the album's release date, or None if no release date is available.
```python
@property
def year(self) -> Optional[int]:
"""Get the year using :class:`available_release_date`
:return: An :any:`python:int` containing the year the track was released
"""
return self.available_release_date.year if self.available_release_date else None
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.