Skip to content

Commit

Permalink
[ 1.0.3 ] * Updated service get_show_episodes to include the `limit…
Browse files Browse the repository at this point in the history
…_total` argument.

  * Added service `get_player_queue_info` to retrieve the player queue information.
  * Added service `get_player_devices` to retrieve player device list.
  • Loading branch information
thlucas1 committed Mar 1, 2024
1 parent 6c17522 commit edecd89
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 40 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ Change are listed in reverse chronological order (newest to oldest).

<span class="changelog">

###### [ 1.0.3 ] - 2024/02/28

* Updated service `get_show_episodes` to include the `limit_total` argument.
* Added service `get_player_queue_info` to retrieve the player queue information.
* Added service `get_player_devices` to retrieve player device list.

###### [ 1.0.2 ] - 2024/02/28

* Updated underlying `spotifywebapiPython` package requirement to version 1.0.31.
Expand Down
50 changes: 49 additions & 1 deletion custom_components/spotifyplus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@
SERVICE_SPOTIFY_GET_BROWSE_CATEGORYS_LIST:str = 'get_browse_categorys_list'
SERVICE_SPOTIFY_GET_CATEGORY_PLAYLISTS:str = 'get_category_playlists'
SERVICE_SPOTIFY_GET_FEATURED_PLAYLISTS:str = 'get_featured_playlists'
SERVICE_SPOTIFY_GET_PLAYER_DEVICES:str = 'get_player_devices'
SERVICE_SPOTIFY_GET_PLAYER_QUEUE_INFO:str = 'get_player_queue_info'
SERVICE_SPOTIFY_GET_PLAYER_RECENT_TRACKS:str = 'get_player_recent_tracks'
SERVICE_SPOTIFY_GET_PLAYLIST:str = 'get_playlist'
SERVICE_SPOTIFY_GET_PLAYLIST_FAVORITES:str = 'get_playlist_favorites'
Expand Down Expand Up @@ -187,6 +189,19 @@
}
)

SERVICE_SPOTIFY_GET_PLAYER_DEVICES_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
vol.Optional("refresh"): cv.boolean,
}
)

SERVICE_SPOTIFY_GET_PLAYER_QUEUE_INFO_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
}
)

SERVICE_SPOTIFY_GET_PLAYER_RECENT_TRACKS_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
Expand Down Expand Up @@ -231,6 +246,7 @@
vol.Optional("limit", default=50): vol.All(vol.Range(min=1,max=50)),
vol.Optional("offset", default=0): vol.All(vol.Range(min=0,max=500)),
vol.Optional("market"): cv.string,
vol.Optional("limit_total", default=0): vol.All(vol.Range(min=0,max=9999)),
}
)

Expand Down Expand Up @@ -454,6 +470,19 @@ async def service_handle_spotify_serviceresponse(service: ServiceCall) -> Servic
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
response = await hass.async_add_executor_job(entity.service_spotify_get_featured_playlists, limit, offset, country, locale, timestamp, limit_total)

elif service.service == SERVICE_SPOTIFY_GET_PLAYER_DEVICES:

# get spotify connect device list.
refresh = service.data.get("refresh")
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
response = await hass.async_add_executor_job(entity.service_spotify_get_player_devices, refresh)

elif service.service == SERVICE_SPOTIFY_GET_PLAYER_QUEUE_INFO:

# get spotify queue info.
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
response = await hass.async_add_executor_job(entity.service_spotify_get_player_queue_info)

elif service.service == SERVICE_SPOTIFY_GET_PLAYER_RECENT_TRACKS:

# get spotify playlist favorites.
Expand Down Expand Up @@ -498,8 +527,9 @@ async def service_handle_spotify_serviceresponse(service: ServiceCall) -> Servic
limit = service.data.get("limit")
offset = service.data.get("offset")
market = service.data.get("market")
limit_total = service.data.get("limit_total")
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
response = await hass.async_add_executor_job(entity.service_spotify_get_show_episodes, show_id, limit, offset, market)
response = await hass.async_add_executor_job(entity.service_spotify_get_show_episodes, show_id, limit, offset, market, limit_total)

elif service.service == SERVICE_SPOTIFY_GET_SHOW_FAVORITES:

Expand Down Expand Up @@ -702,6 +732,24 @@ def _GetEntityFromServiceData(hass:HomeAssistant, service:ServiceCall, field_id:
supports_response=SupportsResponse.ONLY,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_SPOTIFY_GET_PLAYER_DEVICES, SERVICE_SPOTIFY_GET_PLAYER_DEVICES_SCHEMA)
hass.services.async_register(
DOMAIN,
SERVICE_SPOTIFY_GET_PLAYER_DEVICES,
service_handle_spotify_serviceresponse,
schema=SERVICE_SPOTIFY_GET_PLAYER_DEVICES_SCHEMA,
supports_response=SupportsResponse.ONLY,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_SPOTIFY_GET_PLAYER_QUEUE_INFO, SERVICE_SPOTIFY_GET_PLAYER_QUEUE_INFO_SCHEMA)
hass.services.async_register(
DOMAIN,
SERVICE_SPOTIFY_GET_PLAYER_QUEUE_INFO,
service_handle_spotify_serviceresponse,
schema=SERVICE_SPOTIFY_GET_PLAYER_QUEUE_INFO_SCHEMA,
supports_response=SupportsResponse.ONLY,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_SPOTIFY_GET_PLAYER_RECENT_TRACKS, SERVICE_SPOTIFY_GET_PLAYER_RECENT_TRACKS_SCHEMA)
hass.services.async_register(
DOMAIN,
Expand Down
2 changes: 1 addition & 1 deletion custom_components/spotifyplus/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"spotifywebapiPython==1.0.31",
"urllib3>=1.21.1,<1.27"
],
"version": "1.0.1",
"version": "1.0.3",
"zeroconf": [ "_spotify-connect._tcp.local." ]
}
139 changes: 123 additions & 16 deletions custom_components/spotifyplus/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
Album,
AlbumPageSaved,
AlbumPageSimplified,
AlbumSaved,
AlbumSimplified,
Artist,
ArtistPage,
Category,
Expand All @@ -24,18 +22,15 @@
Episode,
EpisodePageSimplified,
PlayerPlayState,
PlayerQueueInfo,
PlayHistoryPage,
Playlist,
PlaylistPageSimplified,
PlaylistSimplified,
SearchResponse,
Show,
ShowPageSaved,
ShowSaved,
Track,
TrackPage,
TrackPageSaved,
TrackSaved,
UserProfile
)

Expand Down Expand Up @@ -270,6 +265,7 @@ def __init__(self, data:InstanceDataSpotifyPlus) -> None:
if self.data.spotifyClient.UserProfile.Product == "premium":
_logsi.LogVerbose("'%s': MediaPlayer is setting supported features for Spotify Premium user" % self.name)
self._attr_supported_features = MediaPlayerEntityFeature.BROWSE_MEDIA \
| MediaPlayerEntityFeature.MEDIA_ENQUEUE \
| MediaPlayerEntityFeature.NEXT_TRACK \
| MediaPlayerEntityFeature.PAUSE \
| MediaPlayerEntityFeature.PLAY \
Expand Down Expand Up @@ -524,9 +520,7 @@ def play_media(self, media_type: MediaType | str, media_id: str, **kwargs: Any)
#media_type = media_type.removeprefix(MEDIA_PLAYER_PREFIX)

# get enqueue keyword arguments (if any).
enqueue: MediaPlayerEnqueue = kwargs.get(
ATTR_MEDIA_ENQUEUE, MediaPlayerEnqueue.REPLACE
)
enqueue: MediaPlayerEnqueue = kwargs.get(ATTR_MEDIA_ENQUEUE, MediaPlayerEnqueue.REPLACE)

# resolve the device id.
# if now playing media does not have a device id set, then use the first device
Expand Down Expand Up @@ -817,7 +811,7 @@ def service_spotify_get_album_favorites(self,
Returns:
A dictionary that contains the following keys:
- user_profile: A (partial) user profile that retrieved the result.
- result: A `AlbumPageSaved` object that contains playlist information.
- result: A `AlbumPageSaved` object that contains album information.
"""
apiMethodName:str = 'service_spotify_get_album_favorites'
apiMethodParms:SIMethodParmListContext = None
Expand Down Expand Up @@ -888,7 +882,7 @@ def service_spotify_get_album_new_releases(self,
Returns:
A dictionary that contains the following keys:
- user_profile: A (partial) user profile that retrieved the result.
- result: A `AlbumPageSimplified` object that contains playlist information.
- result: A `AlbumPageSimplified` object that contains album information.
"""
apiMethodName:str = 'service_spotify_get_album_new_releases'
apiMethodParms:SIMethodParmListContext = None
Expand Down Expand Up @@ -940,7 +934,7 @@ def service_spotify_get_artist(self,
Returns:
A dictionary that contains the following keys:
- user_profile: A (partial) user profile that retrieved the result.
- result: An `Album` object that contains the artist details.
- result: An `Artist` object that contains the artist details.
"""
apiMethodName:str = 'service_spotify_get_artist'
apiMethodParms:SIMethodParmListContext = None
Expand Down Expand Up @@ -1378,6 +1372,109 @@ def service_spotify_get_featured_playlists(self,
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)


def service_spotify_get_player_devices(self,
refresh:bool=True
) -> dict:
"""
Get information about a user's available Spotify Connect player devices.
Some device models are not supported and will not be listed in the API response.
This method requires the `user-read-playback-state` scope.
Args:
refresh (bool):
True (default) to return real-time information from the spotify web api and
update the cache; otherwise, False to just return the cached value.
Returns:
A dictionary that contains the following keys:
- user_profile: A (partial) user profile that retrieved the result.
- result: A list of `Device` objects that contain the device details, sorted by name.
"""
apiMethodName:str = 'service_spotify_get_player_devices'
apiMethodParms:SIMethodParmListContext = None
result:PlayerQueueInfo = None

try:

# trace.
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
_logsi.LogMethodParmList(SILevel.Verbose, "Spotify Get Player Queue Info", apiMethodParms)

# request information from Spotify Web API.
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_QUERY_WEB_API)
result = self.data.spotifyClient.GetPlayerDevices(refresh)

# build dictionary result from array.
resultArray:list = []
item:Device
for item in result:
resultArray.append(item.ToDictionary())

# return the (partial) user profile that retrieved the result, as well as the result itself.
return {
"user_profile": self._GetUserProfilePartialDictionary(self.data.spotifyClient.UserProfile),
"result": resultArray
}

# the following exceptions have already been logged, so we just need to
# pass them back to HA for display in the log (or service UI).
except SpotifyApiError as ex:
raise HomeAssistantError(ex.Message)
except SpotifyWebApiError as ex:
raise HomeAssistantError(ex.Message)

finally:

# trace.
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)


def service_spotify_get_player_queue_info(self) -> dict:
"""
Get the list of objects that make up the user's playback queue.
This method requires the `user-read-currently-playing` and `user-read-playback-state` scope.
Returns:
A dictionary that contains the following keys:
- user_profile: A (partial) user profile that retrieved the result.
- result: A `PlayerQueueInfo` object that contains the player queue information.
"""
apiMethodName:str = 'service_spotify_get_player_queue_info'
apiMethodParms:SIMethodParmListContext = None
result:PlayerQueueInfo = None

try:

# trace.
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
_logsi.LogMethodParmList(SILevel.Verbose, "Spotify Get Player Queue Info", apiMethodParms)

# request information from Spotify Web API.
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_QUERY_WEB_API)
result = self.data.spotifyClient.GetPlayerQueueInfo()

# return the (partial) user profile that retrieved the result, as well as the result itself.
return {
"user_profile": self._GetUserProfilePartialDictionary(self.data.spotifyClient.UserProfile),
"result": result.ToDictionary()
}

# the following exceptions have already been logged, so we just need to
# pass them back to HA for display in the log (or service UI).
except SpotifyApiError as ex:
raise HomeAssistantError(ex.Message)
except SpotifyWebApiError as ex:
raise HomeAssistantError(ex.Message)

finally:

# trace.
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)


def service_spotify_get_player_recent_tracks(self,
limit:int,
after:int,
Expand Down Expand Up @@ -1652,14 +1749,15 @@ def service_spotify_get_show_episodes(self,
limit:int,
offset:int,
market:str=None,
limitTotal:int=None
) -> dict:
"""
Get Spotify catalog information about a show's episodes.
Args:
showId (str):
The Spotify ID for the show.
Example: `38bS44xjbVVZ3No3ByF1dJ`
Example: `6kAsbP8pxwaU2kPibKTuHE`
limit (int):
The maximum number of items to return in a page of items.
Default: 20, Range: 1 to 50.
Expand All @@ -1674,6 +1772,12 @@ def service_spotify_get_show_episodes(self,
Note: If neither market or user country are provided, the content is considered unavailable for the client.
Users can view the country that is associated with their account in the account settings.
Example: `ES`
limitTotal (int):
The maximum number of items to return for the request.
If specified, this argument overrides the limit and offset argument values
and paging is automatically used to retrieve all available items up to the
maximum count specified.
Default: None (disabled)
Returns:
A dictionary that contains the following keys:
Expand All @@ -1692,11 +1796,12 @@ def service_spotify_get_show_episodes(self,
apiMethodParms.AppendKeyValue("limit", limit)
apiMethodParms.AppendKeyValue("additionaoffsetlTypes", offset)
apiMethodParms.AppendKeyValue("market", market)
apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
_logsi.LogMethodParmList(SILevel.Verbose, "Spotify Get Show Episodes Service", apiMethodParms)

# request information from Spotify Web API.
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_QUERY_WEB_API)
result = self.data.spotifyClient.GetShowEpisodes(showId, limit, offset, market)
result = self.data.spotifyClient.GetShowEpisodes(showId, limit, offset, market, limitTotal)

# return the (partial) user profile that retrieved the result, as well as the result itself.
return {
Expand Down Expand Up @@ -1960,7 +2065,7 @@ def service_spotify_get_users_top_tracks(self,
Returns:
A dictionary that contains the following keys:
- user_profile: A (partial) user profile that retrieved the result.
- result: An `TrackPage` object of matching results.
- result: A `TrackPage` object of matching results.
"""
apiMethodName:str = 'service_spotify_get_users_top_tracks'
apiMethodParms:SIMethodParmListContext = None
Expand Down Expand Up @@ -2058,7 +2163,9 @@ def service_spotify_search_playlists(self,
Default is False.
Returns:
A dictionary representation of a `SearchResponse` object that contain the results.
A dictionary that contains the following keys:
- user_profile: A (partial) user profile that retrieved the result.
- result: A `PlaylistPageSimplified` object of matching results.
"""
apiMethodName:str = 'service_spotify_search_playlists'
apiMethodParms:SIMethodParmListContext = None
Expand Down
Loading

0 comments on commit edecd89

Please sign in to comment.