Skip to content

Commit

Permalink
[ 1.0.45 ] * Updated service player_transfer_playback to support So…
Browse files Browse the repository at this point in the history
…nos devices with some limitations; see the [Sonos Limitations](https://github.com/thlucas1/homeassistantcomponent_spotifyplus/wiki/Spotify-Connect-Brand-Notes#sonos) wiki documentation for further details.

  * Updated service `player_media_play_context` and `player_media_play_tracks` to support Sonos devices with some limitations; see the [Sonos Limitations](https://github.com/thlucas1/homeassistantcomponent_spotifyplus/wiki/Spotify-Connect-Brand-Notes#sonos) wiki documentation for further details.
  * Fixed a bug in the `player_transfer_playback` service that was not transferring control to offline Spotify Connect devices.
  • Loading branch information
thlucas1 committed Jul 31, 2024
1 parent 3658b86 commit edd9c4f
Show file tree
Hide file tree
Showing 8 changed files with 658 additions and 242 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.45 ] - 2024/07/30

* Updated service `player_transfer_playback` to support Sonos devices with some limitations; see the [Sonos Limitations](https://github.com/thlucas1/homeassistantcomponent_spotifyplus/wiki/Spotify-Connect-Brand-Notes#sonos) wiki documentation for further details.
* Updated service `player_media_play_context` and `player_media_play_tracks` to support Sonos devices with some limitations; see the [Sonos Limitations](https://github.com/thlucas1/homeassistantcomponent_spotifyplus/wiki/Spotify-Connect-Brand-Notes#sonos) wiki documentation for further details.
* Fixed a bug in the `player_transfer_playback` service that was not transferring control to offline Spotify Connect devices.

###### [ 1.0.44 ] - 2024/07/24

* Updated service `player_set_shuffle_mode` to correctly set shuffle mode for Sonos devices.
Expand Down
12 changes: 9 additions & 3 deletions custom_components/spotifyplus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@
vol.Optional("offset_position", default=-1): vol.All(vol.Range(min=-1,max=500)),
vol.Optional("position_ms", default=-1): vol.All(vol.Range(min=-1,max=999999999)),
vol.Optional("device_id"): cv.string,
vol.Optional("delay", default=0.50): vol.All(vol.Range(min=0,max=10.0)),
}
)

Expand All @@ -414,6 +415,7 @@
vol.Required("uris"): cv.string,
vol.Optional("position_ms", default=-1): vol.All(vol.Range(min=-1,max=999999999)),
vol.Optional("device_id"): cv.string,
vol.Optional("delay", default=0.50): vol.All(vol.Range(min=0,max=10.0)),
}
)

Expand Down Expand Up @@ -458,6 +460,7 @@
vol.Required("entity_id"): cv.entity_id,
vol.Optional("device_id"): cv.string,
vol.Optional("play"): cv.boolean,
vol.Optional("delay", default=0.50): vol.All(vol.Range(min=0,max=10.0)),
}
)

Expand Down Expand Up @@ -819,8 +822,9 @@ async def service_handle_spotify_command(service: ServiceCall) -> None:
offset_position = service.data.get("offset_position")
position_ms = service.data.get("position_ms")
device_id = service.data.get("device_id")
delay = service.data.get("delay")
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
await hass.async_add_executor_job(entity.service_spotify_player_media_play_context, context_uri, offset_uri, offset_position, position_ms, device_id)
await hass.async_add_executor_job(entity.service_spotify_player_media_play_context, context_uri, offset_uri, offset_position, position_ms, device_id, delay)

elif service.service == SERVICE_SPOTIFY_PLAYER_MEDIA_PLAY_TRACK_FAVORITES:

Expand All @@ -837,8 +841,9 @@ async def service_handle_spotify_command(service: ServiceCall) -> None:
uris = service.data.get("uris")
position_ms = service.data.get("position_ms")
device_id = service.data.get("device_id")
delay = service.data.get("delay")
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
await hass.async_add_executor_job(entity.service_spotify_player_media_play_tracks, uris, position_ms, device_id)
await hass.async_add_executor_job(entity.service_spotify_player_media_play_tracks, uris, position_ms, device_id, delay)

elif service.service == SERVICE_SPOTIFY_PLAYER_SET_REPEAT_MODE:

Expand Down Expand Up @@ -872,8 +877,9 @@ async def service_handle_spotify_command(service: ServiceCall) -> None:
# transfer playback to a new Spotify Connect device.
device_id = service.data.get("device_id")
play = service.data.get("play")
delay = service.data.get("delay")
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
await hass.async_add_executor_job(entity.service_spotify_player_transfer_playback, device_id, play)
await hass.async_add_executor_job(entity.service_spotify_player_transfer_playback, device_id, play, delay)

elif service.service == SERVICE_SPOTIFY_PLAYLIST_CHANGE:

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 @@ -21,6 +21,6 @@
"urllib3>=1.21.1,<1.27",
"zeroconf>=0.132.2"
],
"version": "1.0.44",
"version": "1.0.45",
"zeroconf": [ "_spotify-connect._tcp.local." ]
}
770 changes: 532 additions & 238 deletions custom_components/spotifyplus/media_player.py

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions custom_components/spotifyplus/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,16 @@ player_media_play_context:
required: false
selector:
text:
delay:
name: Delay
description: Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10.
example: "0.50"
required: false
selector:
number:
min: 0.0
max: 10.0
mode: box

player_media_play_track_favorites:
name: Player Media Play Track Favorites
Expand Down Expand Up @@ -1146,6 +1156,16 @@ player_media_play_tracks:
required: false
selector:
text:
delay:
name: Delay
description: Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10.
example: "0.50"
required: false
selector:
number:
min: 0.0
max: 10.0
mode: box

player_resolve_device_id:
name: Player Resolve Device ID
Expand Down Expand Up @@ -1334,6 +1354,16 @@ player_transfer_playback:
required: false
selector:
boolean:
delay:
name: Delay
description: Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10.
example: "0.50"
required: false
selector:
number:
min: 0.0
max: 10.0
mode: box

playlist_cover_image_add:
name: Playlist Cover Image Add
Expand Down
12 changes: 12 additions & 0 deletions custom_components/spotifyplus/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,10 @@
"device_id": {
"name": "Device ID",
"description": "The id or name of the Spotify Connect Player device this command is targeting. If not supplied, the user's currently active device is the target. If no device is active (or an '*' is specified), then the SpotifyPlus default device is activated."
},
"delay": {
"name": "Delay",
"description": "Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10."
}
}
},
Expand Down Expand Up @@ -711,6 +715,10 @@
"device_id": {
"name": "Device ID",
"description": "The id or name of the Spotify Connect Player device this command is targeting. If not supplied, the user's currently active device is the target. If no device is active (or an '*' is specified), then the SpotifyPlus default device is activated."
},
"delay": {
"name": "Delay",
"description": "Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10."
}
}
},
Expand Down Expand Up @@ -817,6 +825,10 @@
"play": {
"name": "Start Play?",
"description": "True (default) to start playback on the new device; otherise, False to keep the current playback state on the existing device."
},
"delay": {
"name": "Delay",
"description": "Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10."
}
}
},
Expand Down
12 changes: 12 additions & 0 deletions custom_components/spotifyplus/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,10 @@
"device_id": {
"name": "Device ID",
"description": "The id or name of the Spotify Connect Player device this command is targeting. If not supplied, the user's currently active device is the target. If no device is active (or an '*' is specified), then the SpotifyPlus default device is activated."
},
"delay": {
"name": "Delay",
"description": "Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10."
}
}
},
Expand Down Expand Up @@ -711,6 +715,10 @@
"device_id": {
"name": "Device ID",
"description": "The id or name of the Spotify Connect Player device this command is targeting. If not supplied, the user's currently active device is the target. If no device is active (or an '*' is specified), then the SpotifyPlus default device is activated."
},
"delay": {
"name": "Delay",
"description": "Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10."
}
}
},
Expand Down Expand Up @@ -817,6 +825,10 @@
"play": {
"name": "Start Play?",
"description": "True (default) to start playback on the new device; otherise, False to keep the current playback state on the existing device."
},
"delay": {
"name": "Delay",
"description": "Time delay (in seconds) to wait AFTER issuing the final Connect command (if necessary). This delay will give the spotify web api time to process the device list change before another command is issued. Default is 0.50; value range is 0 - 10."
}
}
},
Expand Down
56 changes: 56 additions & 0 deletions custom_components/spotifyplus/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,59 @@ def validateDelay(
result = delay

return result


def positionHMS_fromMilliSeconds(
position:int,
) -> float:
"""
Converts an integer position value from milliseconds to a string value in H:MM:SS format.
Args:
position (int):
The position value (as specified in milliseconds) to convert.
"""
result:str = '0:00:00'

# validations.
if (isinstance(position, float)):
position = int(position)
if (position is None) or (not isinstance(position, int)) or (position < 1):
return result

# convert milliseconds to H:MM:SS string format.
nSeconds = position / 1000
mm, ss = divmod(nSeconds, 60) # get minutes and seconds first
hh, mm= divmod(mm, 60) # get hours next
result = "%d:%02d:%02d" % (hh, mm, ss) # format to hh:mm:ss

# return result to caller.
return result


def positionHMS_fromSeconds(
position:int,
) -> float:
"""
Converts an integer position value from seconds to a string value in H:MM:SS format.
Args:
position (int):
The position value (as specified in seconds) to convert.
"""
result:str = '0:00:00'

# validations.
if (isinstance(position, float)):
position = int(position)
if (position is None) or (position < 1):
return result

# convert seconds to H:MM:SS string format.
nSeconds = int(position)
mm, ss = divmod(nSeconds, 60) # get minutes and seconds first
hh, mm= divmod(mm, 60) # get hours next
result = "%d:%02d:%02d" % (hh, mm, ss) # format to hh:mm:ss

# return result to caller.
return result

0 comments on commit edd9c4f

Please sign in to comment.