migrated to uri id base

This commit is contained in:
aj 2019-09-15 15:33:29 +01:00
parent 6076ecd610
commit 2bd26df92f
13 changed files with 250 additions and 97 deletions

View File

@ -2,6 +2,7 @@ from spotframework.net.user import NetworkUser
from spotframework.net.network import Network
import spotframework.net.const as const
import spotframework.io.json as json
import spotframework.util.monthstrings as month
import os
import datetime
@ -62,7 +63,8 @@ if __name__ == '__main__':
playlists = network.get_user_playlists()
if data['alarm']['use_month']:
playlisturi = next((i.uri for i in playlists if i.name == date.strftime("%B %-y").lower()), data['alarm']['uri'])
playlisturi = next((i.uri for i in playlists if i.name == month.get_this_month()),
data['alarm']['uri'])
else:
playlisturi = data['alarm']['uri']

View File

@ -35,7 +35,7 @@ if __name__ == '__main__':
playlists = network.get_user_playlists()
for playlist in playlists:
playlist.tracks = network.get_playlist_tracks(playlist.playlist_id)
playlist.tracks = network.get_playlist_tracks(playlist.uri)
path = sys.argv[1]

View File

@ -8,6 +8,7 @@ from spotframework.engine.processor.added import AddedSince
from typing import List, Optional
from spotframework.model.track import SpotifyTrack
from spotframework.model.playlist import SpotifyPlaylist
from spotframework.model.uri import Uri
from spotframework.net.network import Network
from spotframework.engine.processor.abstract import AbstractProcessor
from datetime import datetime
@ -44,7 +45,7 @@ class PlaylistEngine:
playlist: SpotifyPlaylist) -> None:
logger.info(f"pulling tracks for {playlist.name}")
tracks = self.net.get_playlist_tracks(playlist.playlist_id)
tracks = self.net.get_playlist_tracks(playlist.uri)
if tracks and len(tracks) > 0:
playlist.tracks = tracks
else:
@ -94,7 +95,7 @@ class PlaylistEngine:
tracks = processor.process(tracks)
if include_recommendations:
recommendations = self.net.get_recommendations(tracks=[i.spotify_id for i in tracks],
recommendations = self.net.get_recommendations(tracks=[i.uri.object_id for i in tracks],
response_limit=recommendation_limit)
if recommendations and len(recommendations) > 0:
tracks += recommendations
@ -137,16 +138,16 @@ class PlaylistEngine:
def reorder_playlist_by_added_date(self,
name: str = None,
playlistid: str = None,
uri: Uri = None,
reverse: bool = False):
if name is None and playlistid is None:
if name is None and uri is None:
logger.error('no playlist name or id provided')
raise ValueError('no playlist name or id provided')
if name:
playlist = next((i for i in self.playlists if i.name == name), None)
else:
playlist = next((i for i in self.playlists if i.spotify_id == playlistid), None)
playlist = next((i for i in self.playlists if i.uri == uri), None)
if playlist is None:
logger.error('playlist not found')
@ -171,9 +172,9 @@ class PlaylistEngine:
def execute_playlist(self,
tracks: List[SpotifyTrack],
playlist_id: str) -> Optional[Response]:
uri: Uri) -> Optional[Response]:
resp = self.net.replace_playlist_tracks(playlist_id, [i.uri for i in tracks])
resp = self.net.replace_playlist_tracks(uri, [i.uri for i in tracks])
if resp:
return resp
else:
@ -182,7 +183,7 @@ class PlaylistEngine:
def change_description(self,
playlistparts: List[str],
playlist_id: str,
uri: Uri,
overwrite: bool = None,
suffix: str = None) -> Optional[Response]:
@ -194,7 +195,7 @@ class PlaylistEngine:
if suffix:
string += f' - {str(suffix)}'
resp = self.net.change_playlist_details(playlist_id, description=string)
resp = self.net.change_playlist_details(uri, description=string)
if resp:
return resp
else:

View File

@ -1,7 +1,8 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import List
from typing import List, Union
from spotframework.util.console import Color
from spotframework.model.uri import Uri
if TYPE_CHECKING:
from spotframework.model.artist import Artist
@ -35,8 +36,7 @@ class SpotifyAlbum(Album):
artists: List[Artist],
href: str = None,
spotify_id: str = None,
uri: str = None,
uri: Union[str, Uri] = None,
genres: List[str] = None,
tracks: List = None,
@ -50,7 +50,9 @@ class SpotifyAlbum(Album):
super().__init__(name, artists)
self.href = href
self.spotify_id = spotify_id
if isinstance(uri, str):
self.uri = Uri(uri)
else:
self.uri = uri
self.genres = genres

View File

@ -1,5 +1,6 @@
from typing import List
from typing import List, Union
from spotframework.util.console import Color
from spotframework.model.uri import Uri
class Artist:
@ -19,8 +20,7 @@ class SpotifyArtist(Artist):
name: str,
href: str = None,
spotify_id: str = None,
uri: str = None,
uri: Union[str, Uri] = None,
genres: List[str] = None,
@ -29,7 +29,9 @@ class SpotifyArtist(Artist):
super().__init__(name)
self.href = href
self.spotify_id = spotify_id
if isinstance(uri, str):
self.uri = Uri(uri)
else:
self.uri = uri
self.genres = genres

View File

@ -1,8 +1,9 @@
from spotframework.model.user import User
from spotframework.model.track import Track, SpotifyTrack, PlaylistTrack
from spotframework.model.uri import Uri
from spotframework.util.console import Color
from tabulate import tabulate
from typing import List
from typing import List, Union
import logging
logger = logging.getLogger(__name__)
@ -119,14 +120,13 @@ class Playlist:
class SpotifyPlaylist(Playlist):
def __init__(self,
playlistid: str,
uri: Union[str, Uri],
name: str = None,
owner: User = None,
description: str = None,
href: str = None,
uri: str = None,
collaborative: bool = None,
public: bool = None,
@ -134,10 +134,12 @@ class SpotifyPlaylist(Playlist):
super().__init__(name=name, description=description)
self.playlist_id = playlistid
self.owner = owner
self.href = href
if isinstance(uri, str):
self.uri = Uri(uri)
else:
self.uri = uri
self.collaborative = collaborative
@ -147,7 +149,6 @@ class SpotifyPlaylist(Playlist):
def __str__(self):
prefix = f'\n==={self.name}===\n\n' if self.name is not None else ''
prefix += f'id: {self.playlist_id}\n' if self.playlist_id is not None else ''
prefix += f'uri: {self.uri}\n' if self.uri is not None else ''
table = prefix + self.get_tracks_string() + '\n' + f'total: {len(self)}'

View File

@ -1,14 +1,19 @@
from datetime import datetime
from spotframework.model.track import Track
from spotframework.model.uri import Uri
from enum import Enum
from typing import Union
class Context:
def __init__(self,
uri: str,
uri: Union[str, Uri],
object_type: str = None,
href: str = None,
external_spot: str = None):
if isinstance(uri, str):
self.uri = Uri(uri)
else:
self.uri = uri
self.object_type = object_type
self.href = href

View File

@ -1,12 +1,14 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import List
from typing import List, Union
from datetime import datetime
from spotframework.model.uri import Uri
from spotframework.util.console import Color
if TYPE_CHECKING:
from spotframework.model.album import Album
from spotframework.model.artist import Artist
from spotframework.model.user import User
from spotframework.model.service import Context
class Track:
@ -57,8 +59,7 @@ class SpotifyTrack(Track):
artists: List[Artist],
href: str = None,
spotify_id: str = None,
uri: str = None,
uri: Union[str, Uri] = None,
disc_number: int = None,
duration_ms: int = None,
@ -73,7 +74,9 @@ class SpotifyTrack(Track):
excplicit=explicit)
self.href = href
self.spotify_id = spotify_id
if isinstance(uri, str):
self.uri = Uri(uri)
else:
self.uri = uri
self.is_playable = is_playable
@ -90,13 +93,12 @@ class PlaylistTrack(SpotifyTrack):
album: Album,
artists: List[Artist],
added_at: str,
added_at: datetime,
added_by: User,
is_local: bool,
href: str = None,
spotify_id: str = None,
uri: str = None,
uri: Union[str, Uri] = None,
disc_number: int = None,
duration_ms: int = None,
@ -107,7 +109,6 @@ class PlaylistTrack(SpotifyTrack):
):
super().__init__(name=name, album=album, artists=artists,
href=href,
spotify_id=spotify_id,
uri=uri,
disc_number=disc_number,
@ -116,10 +117,46 @@ class PlaylistTrack(SpotifyTrack):
is_playable=is_playable,
popularity=popularity)
self.added_at = datetime.fromisoformat(added_at.replace('T', ' ').replace('Z', ''))
self.added_at = added_at
self.added_by = added_by
self.is_local = is_local
def __repr__(self):
return Color.BOLD + Color.YELLOW + 'PlaylistTrack' + Color.END + \
f': {self.name}, ({self.album}), {self.artists}, {self.uri}, {self.added_at}'
class PlayedTrack(SpotifyTrack):
def __init__(self,
name: str,
album: Album,
artists: List[Artist],
href: str = None,
uri: Union[str, Uri] = None,
disc_number: int = None,
duration_ms: int = None,
explicit: bool = None,
is_playable: bool = None,
popularity: int = None,
played_at: datetime = None,
context: Context = None
):
super().__init__(name=name, album=album, artists=artists,
href=href,
uri=uri,
disc_number=disc_number,
duration_ms=duration_ms,
explicit=explicit,
is_playable=is_playable,
popularity=popularity)
self.played_at = played_at
self.context = context
def __repr__(self):
return Color.BOLD + Color.YELLOW + 'PlayedTrack' + Color.END + \
f': {self.name}, ({self.album}), {self.artists}, {self.uri}, {self.played_at}'

View File

@ -0,0 +1,52 @@
from enum import Enum
class Uri:
class ObjectType(Enum):
track = 1
album = 2
artist = 3
user = 4
playlist = 5
def __init__(self, input_string: str):
self.object_type = None
self.object_id = None
self.username = None
parts = input_string.split(':')
if parts[0] != 'spotify':
raise ValueError('malformed uri')
if len(parts) == 3:
self.object_type = self.ObjectType[parts[1]]
self.object_id = parts[2]
elif len(parts) == 5:
if parts[1] != 'user':
raise ValueError('malformed uri')
self.object_type = self.ObjectType[parts[3]]
self.object_id = parts[4]
else:
raise ValueError(f'malformed uri: {len(parts)} parts')
def __str__(self):
if self.username:
return f'spotify:user:{self.username}:{self.object_type.name}:{self.object_id}'
else:
return f'spotify:{self.object_type.name}:{self.object_id}'
def __repr__(self):
if self.username:
return f'URI: {self.username} / {self.object_type.name} / {self.object_id}'
else:
return f'URI: {self.object_type.name} / {self.object_id}'
def __eq__(self, other):
if isinstance(other, Uri):
if other.object_type == self.object_type and other.object_id == self.object_id:
return True
return False

View File

@ -1,4 +1,6 @@
from spotframework.util.console import Color
from spotframework.model.uri import Uri
from typing import Union
class User:
@ -6,13 +8,16 @@ class User:
username: str,
href: str = None,
uri: str = None,
uri: Union[str, Uri] = None,
display_name: str = None,
ext_spotify: str = None):
self.username = username
self.href = href
if isinstance(uri, str):
self.uri = Uri(uri)
else:
self.uri = uri
self.display_name = display_name

View File

@ -3,12 +3,14 @@ import random
import logging
import time
from typing import List, Optional
from datetime import datetime
from . import const
from spotframework.net.parse import parse
from spotframework.net.user import NetworkUser
from spotframework.model.playlist import SpotifyPlaylist
from spotframework.model.track import Track, PlaylistTrack
from spotframework.model.track import Track, PlaylistTrack, PlayedTrack
from spotframework.model.service import CurrentlyPlaying, Device
from spotframework.model.uri import Uri
from requests.models import Response
limit = 50
@ -121,20 +123,20 @@ class Network:
return None
def get_playlist(self, playlistid: str) -> Optional[SpotifyPlaylist]:
def get_playlist(self, uri: Uri) -> Optional[SpotifyPlaylist]:
logger.info(f"{playlistid}")
logger.info(f"{uri}")
tracks = self.get_playlist_tracks(playlistid)
tracks = self.get_playlist_tracks(uri)
if tracks is not None:
playlist = SpotifyPlaylist(playlistid)
playlist = SpotifyPlaylist(uri.object_id)
playlist.tracks += tracks
return playlist
else:
logger.error(f"{playlistid} - no tracks returned")
logger.error(f"{uri} - no tracks returned")
return None
def create_playlist(self,
@ -142,7 +144,7 @@ class Network:
name='New Playlist',
public=True,
collaborative=False,
description=None) -> Optional[dict]:
description=None) -> Optional[SpotifyPlaylist]:
json = {"name": name, "public": public, "collaborative": collaborative}
@ -152,7 +154,7 @@ class Network:
req = self._make_post_request('createPlaylist', f'users/{username}/playlists', json=json)
if 200 <= req.status_code < 300:
return req.json()
return parse.parse_playlist(req.json())
else:
logger.error('error creating playlist')
return None
@ -195,28 +197,28 @@ class Network:
logger.error('no playlists returned to filter')
return None
def get_playlist_tracks(self, playlistid, offset=0) -> List[PlaylistTrack]:
def get_playlist_tracks(self, uri: Uri, offset=0) -> List[PlaylistTrack]:
logger.info(f"{playlistid}{' ' + str(offset) if offset is not 0 else ''}")
logger.info(f"{uri}{' ' + str(offset) if offset is not 0 else ''}")
tracks = []
params = {'offset': offset, 'limit': limit}
resp = self._make_get_request('getPlaylistTracks', f'playlists/{playlistid}/tracks', params=params)
resp = self._make_get_request('getPlaylistTracks', f'playlists/{uri.object_id}/tracks', params=params)
if resp:
if resp.get('items', None):
tracks += [parse.parse_track(i) for i in resp.get('items', None)]
else:
logger.warning(f'{playlistid} no items returned')
logger.warning(f'{uri} no items returned')
if resp.get('next', None):
more_tracks = self.get_playlist_tracks(playlistid, offset + limit)
more_tracks = self.get_playlist_tracks(uri, offset + limit)
if more_tracks:
tracks += more_tracks
else:
logger.warning(f'{playlistid} error on response')
logger.warning(f'{uri} error on response')
return tracks
@ -231,6 +233,32 @@ class Network:
logger.error('no devices returned')
return None
def get_recently_played_tracks(self,
response_limit: int = None,
after: datetime = None,
before: datetime = None) -> Optional[List[PlayedTrack]]:
logger.info("retrieving")
params = dict()
if response_limit:
params['limit'] = response_limit
if after and before:
raise ValueError('cant have before and after')
if after:
params['after'] = int(after.timestamp() * 1000)
if before:
params['before'] = int(before.timestamp() * 1000)
resp = self._make_get_request('getRecentlyPlayedTracks', 'me/player/recently-played', params=params)
if resp:
return [parse.parse_track(i) for i in resp['items']]
else:
logger.error('no tracks returned')
return None
def get_player(self) -> Optional[CurrentlyPlaying]:
logger.info("retrieved")
@ -271,7 +299,7 @@ class Network:
else:
return None
def play(self, uri=None, uris=None, deviceid=None) -> Optional[Response]:
def play(self, uri: Uri = None, uris: List[Uri] = None, deviceid=None) -> Optional[Response]:
logger.info(f"{uri}{' ' + deviceid if deviceid is not None else ''}")
@ -286,9 +314,9 @@ class Network:
payload = dict()
if uri:
payload['context_uri'] = uri
payload['context_uri'] = str(uri)
if uris:
payload['uris'] = uris[:200]
payload['uris'] = [str(i) for i in uris[:200]]
req = self._make_put_request('play', 'me/player/play', params=params, json=payload)
if req:
@ -378,33 +406,34 @@ class Network:
logger.error(f"{volume} not accepted value")
return None
def replace_playlist_tracks(self, playlistid, uris):
def replace_playlist_tracks(self, uri: Uri, uris: List[Uri]):
logger.info(f"{playlistid}")
logger.info(f"{uri}")
headers = {"Content-Type": "application/json"}
json = {"uris": uris[:100]}
json = {"uris": [str(i) for i in uris[:100]]}
req = self._make_put_request('replacePlaylistTracks', f'playlists/{playlistid}/tracks', json=json, headers=headers)
req = self._make_put_request('replacePlaylistTracks', f'playlists/{uri.object_id}/tracks',
json=json, headers=headers)
if req is not None:
if len(uris) > 100:
return self.add_playlist_tracks(playlistid, uris[100:])
return self.add_playlist_tracks(uri, uris[100:])
return req
else:
logger.error(f'error replacing playlist tracks, total: {len(uris)}')
def change_playlist_details(self,
playlistid,
uri: Uri,
name=None,
public=None,
collaborative=None,
description=None) -> Optional[Response]:
logger.info(f"{playlistid}")
logger.info(f"{uri}")
headers = {"Content-Type": "application/json"}
@ -426,22 +455,24 @@ class Network:
logger.warning('update dictionairy length 0')
return None
else:
req = self._make_put_request('changePlaylistDetails', f'playlists/{playlistid}', json=json, headers=headers)
req = self._make_put_request('changePlaylistDetails', f'playlists/{uri.object_id}',
json=json, headers=headers)
if req:
return req
else:
logger.error('error updating details')
return None
def add_playlist_tracks(self, playlistid: str, uris: List[str]) -> List[dict]:
def add_playlist_tracks(self, uri: Uri, uris: List[Uri]) -> List[dict]:
logger.info(f"{playlistid}")
logger.info(f"{uri}")
headers = {"Content-Type": "application/json"}
json = {"uris": uris[:100]}
json = {"uris": [str(i) for i in uris[:100]]}
req = self._make_post_request('addPlaylistTracks', f'playlists/{playlistid}/tracks', json=json, headers=headers)
req = self._make_post_request('addPlaylistTracks', f'playlists/{uri.object_id}/tracks',
json=json, headers=headers)
if req is not None:
resp = req.json()
@ -450,12 +481,12 @@ class Network:
if len(uris) > 100:
snapshots += self.add_playlist_tracks(playlistid, uris[100:])
snapshots += self.add_playlist_tracks(uri, uris[100:])
return snapshots
else:
logger.error(f'error retrieving tracks {playlistid}, total: {len(uris)}')
logger.error(f'error retrieving tracks {uri}, total: {len(uris)}')
return []
def get_recommendations(self, tracks=None, artists=None, response_limit=10) -> Optional[List[Track]]:
@ -490,17 +521,17 @@ class Network:
playlist: SpotifyPlaylist,
append_tracks: bool = False):
if playlist.playlist_id:
if playlist.uri:
if playlist.tracks == -1:
self.replace_playlist_tracks(playlist.playlist_id, [])
self.replace_playlist_tracks(playlist.uri, [])
elif playlist.tracks:
if append_tracks:
self.add_playlist_tracks(playlist.playlist_id, [i.uri for i in playlist.tracks])
self.add_playlist_tracks(playlist.uri, [i.uri for i in playlist.tracks])
else:
self.replace_playlist_tracks(playlist.playlist_id, [i.uri for i in playlist.tracks])
self.replace_playlist_tracks(playlist.uri, [i.uri for i in playlist.tracks])
if playlist.name or playlist.collaborative or playlist.public or playlist.description:
self.change_playlist_details(playlist.playlist_id,
self.change_playlist_details(playlist.uri,
playlist.name,
playlist.public,
playlist.collaborative,
@ -510,12 +541,12 @@ class Network:
logger.error('playlist has no id')
def reorder_playlist_tracks(self,
playlistid: str,
uri: Uri,
range_start: int,
range_length: int,
insert_before: int) -> Optional[Response]:
logger.info(f'id: {playlistid}')
logger.info(f'id: {uri}')
if range_start < 0:
logger.error('range_start must be positive')
@ -531,7 +562,7 @@ class Network:
'range_length': range_length,
'insert_before': insert_before}
resp = self._make_put_request('reorderPlaylistTracks', f'playlists/{playlistid}/tracks', json=json)
resp = self._make_put_request('reorderPlaylistTracks', f'playlists/{uri.object_id}/tracks', json=json)
if resp:
return resp

View File

@ -1,10 +1,11 @@
from spotframework.model.artist import SpotifyArtist
from spotframework.model.album import SpotifyAlbum
from spotframework.model.track import Track, SpotifyTrack, PlaylistTrack
from spotframework.model.track import Track, SpotifyTrack, PlaylistTrack, PlayedTrack
from spotframework.model.playlist import SpotifyPlaylist
from spotframework.model.user import User
from spotframework.model.service import Context, CurrentlyPlaying, Device
import datetime
from typing import Union
def parse_artist(artist_dict) -> SpotifyArtist:
@ -12,7 +13,6 @@ def parse_artist(artist_dict) -> SpotifyArtist:
name = artist_dict.get('name', None)
href = artist_dict.get('href', None)
spotify_id = artist_dict.get('id', None)
uri = artist_dict.get('uri', None)
genres = artist_dict.get('genres', None)
@ -23,7 +23,6 @@ def parse_artist(artist_dict) -> SpotifyArtist:
return SpotifyArtist(name,
href=href,
spotify_id=spotify_id,
uri=uri,
genres=genres,
@ -39,7 +38,6 @@ def parse_album(album_dict) -> SpotifyAlbum:
artists = [parse_artist(i) for i in album_dict.get('artists', [])]
href = album_dict.get('href', None)
spotify_id = album_dict.get('id', None)
uri = album_dict.get('uri', None)
genres = album_dict.get('genres', None)
@ -55,7 +53,6 @@ def parse_album(album_dict) -> SpotifyAlbum:
artists=artists,
href=href,
spotify_id=spotify_id,
uri=uri,
genres=genres,
@ -68,7 +65,7 @@ def parse_album(album_dict) -> SpotifyAlbum:
popularity=popularity)
def parse_track(track_dict) -> Track:
def parse_track(track_dict) -> Union[Track, SpotifyTrack, PlayedTrack]:
if 'track' in track_dict:
track = track_dict.get('track', None)
@ -84,12 +81,9 @@ def parse_track(track_dict) -> Track:
else:
album = None
# print(album.name)
artists = [parse_artist(i) for i in track.get('artists', [])]
href = track.get('href', None)
spotify_id = track.get('id', None)
uri = track.get('uri', None)
disc_number = track.get('disc_number', None)
@ -101,9 +95,16 @@ def parse_track(track_dict) -> Track:
added_by = parse_user(track_dict.get('added_by')) if track_dict.get('added_by', None) else None
added_at = track_dict.get('added_at', None)
if added_at:
added_at = datetime.datetime.strptime(added_at, '%Y-%m-%dT%H:%M:%S%z')
is_local = track_dict.get('is_local', None)
# print(album.name)
played_at = track_dict.get('played_at', None)
if played_at:
played_at = datetime.datetime.strptime(played_at, '%Y-%m-%dT%H:%M:%S.%f%z')
context = track_dict.get('context', None)
if context:
context = parse_context(context)
if added_at or added_by or is_local:
return PlaylistTrack(name=name,
@ -115,7 +116,6 @@ def parse_track(track_dict) -> Track:
is_local=is_local,
href=href,
spotify_id=spotify_id,
uri=uri,
disc_number=disc_number,
@ -124,13 +124,28 @@ def parse_track(track_dict) -> Track:
is_playable=is_playable,
popularity=popularity)
elif played_at or context:
return PlayedTrack(name=name,
album=album,
artists=artists,
href=href,
uri=uri,
disc_number=disc_number,
duration_ms=duration_ms,
explicit=explicit,
is_playable=is_playable,
popularity=popularity,
played_at=played_at,
context=context)
else:
return SpotifyTrack(name=name,
album=album,
artists=artists,
href=href,
spotify_id=spotify_id,
uri=uri,
disc_number=disc_number,
@ -164,7 +179,6 @@ def parse_playlist(playlist_dict) -> SpotifyPlaylist:
ext_spotify = playlist_dict['external_urls']['spotify']
href = playlist_dict.get('href', None)
playlist_id = playlist_dict.get('id', None)
description = playlist_dict.get('description', None)
name = playlist_dict.get('name', None)
@ -177,12 +191,11 @@ def parse_playlist(playlist_dict) -> SpotifyPlaylist:
public = playlist_dict.get('public', None)
uri = playlist_dict.get('uri', None)
return SpotifyPlaylist(playlistid=playlist_id,
return SpotifyPlaylist(uri=uri,
name=name,
owner=owner,
description=description,
href=href,
uri=uri,
collaborative=collaborative,
public=public,
ext_spotify=ext_spotify)

View File

@ -1,7 +1,9 @@
from spotframework.net.network import Network
from spotframework.model.track import SpotifyTrack
from spotframework.model.album import SpotifyAlbum
from spotframework.model.playlist import SpotifyPlaylist
from spotframework.model.service import Context, Device
from typing import List
from typing import List, Union
import logging
logger = logging.getLogger(__name__)
@ -32,7 +34,7 @@ class Player:
return self.last_status
def play(self,
context: Context = None,
context: Union[Context, SpotifyAlbum, SpotifyPlaylist] = None,
tracks: List[SpotifyTrack] = None,
device: Device = None):
if context and tracks: