Source code for spotify.models.track

"""Source implementation for spotify Tracks, and any other semantically relevent, implementation."""

import datetime
from itertools import starmap
from typing import Optional, TYPE_CHECKING

from ..oauth import set_required_scopes
from . import URIBase, Image, Artist

if TYPE_CHECKING:
    import spotify


class Track(URIBase):  # pylint: disable=too-many-instance-attributes
    """A Spotify Track object.

    Attribtues
    ----------
    id : :class:`str`
        The Spotify ID for the track.
    name : :class:`str`
        The name of the track.
    href : :class:`str`
        A link to the Web API endpoint providing full details of the track.
    uri : :class:`str`
        The Spotify URI for the track.
    duration : int
        The track length in milliseconds.
    explicit : bool
        Whether or not the track has explicit
        `True` if it does.
        `False` if it does not (or unknown)
    disc_number : int
        The disc number (usually 1 unless the album consists of more than one disc).
    track_number : int
        The number of the track.
        If an album has several discs, the track number is the number on the specified disc.
    url : :class:`str`
        The open.spotify URL for this Track
    is_local : bool
        Whether or not the track is from a local file.
    popularity : int
        POPULARITY
    preview_url : :class:`str`
        The preview URL for this Track.
    images : List[Image]
        The images of the Track.
    markets : List[:class:`str`]
        The available markets for the Track.
    """

    def __init__(self, client, data, *, album: Optional["spotify.Album"] = None):
        from .album import Album

        self.__client = client

        self.artists = artists = [
            Artist(client, artist) for artist in data.pop("artists", [])
        ]

        self.artist = artists[-1] if artists else None

        if album is not None:
            self.album = album
        else:
            album_ = data.pop("album", None)

            if album_ is not None:
                self.album = Album(client, album_)
            else:
                self.album = None


        self.id = data.pop("id", None)  # pylint: disable=invalid-name
        self.name = data.pop("name", None)
        self.href = data.pop("href", None)
        self.uri = data.pop("uri", None)
        self.duration = data.pop("duration_ms", None)
        self.explicit = data.pop("explicit", None)
        self.disc_number = data.pop("disc_number", None)
        self.track_number = data.pop("track_number", None)
        self.url = data.pop("external_urls").get("spotify", None)
        self.is_local = data.pop("is_local", None)
        self.popularity = data.pop("popularity", None)
        self.preview_url = data.pop("preview_url", None)
        self.markets = data.pop("available_markets", [])

        if "images" in data:
            self.images = list(starmap(Image, data.pop("images")))
        else:
            self.images = self.album.images.copy() if self.album is not None else []

    def __repr__(self):
        return f"<spotify.Track: {self.name!r}>"

    @set_required_scopes(None)
    def audio_analysis(self):
        """Get a detailed audio analysis for the track."""
        return self.__client.http.track_audio_analysis(self.id)

    @set_required_scopes(None)
    def audio_features(self):
        """Get audio feature information for the track."""
        return self.__client.http.track_audio_features(self.id)


[docs]class PlaylistTrack(Track, URIBase): """A Track on a Playlist. Like a regular :class:`Track` but has some additional attributes. Attributes ---------- added_by : :class:`str` The Spotify user who added the track. is_local : bool Whether this track is a local file or not. added_at : datetime.datetime The datetime of when the track was added to the playlist. """ __slots__ = ("added_at", "added_by", "is_local") def __init__(self, client, data): from .user import User super().__init__(client, data["track"]) self.added_by = User(client, data["added_by"]) self.added_at = datetime.datetime.strptime( data["added_at"], "%Y-%m-%dT%H:%M:%SZ" ) self.is_local = data["is_local"] def __repr__(self): return f"<spotify.PlaylistTrack: {self.name!r}>"