Skip to content

Commit

Permalink
[ 1.0.46 ] * Updated service player_transfer_playback to transfer t…
Browse files Browse the repository at this point in the history
…he Spotify users queue (20 items max) to the Sonos device (instead of just the currently playing track). See the [Sonos Limitations](https://github.com/thlucas1/homeassistantcomponent_spotifyplus/wiki/Spotify-Connect-Brand-Notes#sonos) wiki documentation for further details about Sonos-related issues.
  • Loading branch information
thlucas1 committed Aug 4, 2024
1 parent edd9c4f commit f8ecf4e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 48 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Change are listed in reverse chronological order (newest to oldest).

<span class="changelog">

###### [ 1.0.46 ] - 2024/08/04

* Updated service `player_transfer_playback` to transfer the Spotify users queue (20 items max) to the Sonos device (instead of just the currently playing track). See the [Sonos Limitations](https://github.com/thlucas1/homeassistantcomponent_spotifyplus/wiki/Spotify-Connect-Brand-Notes#sonos) wiki documentation for further details about Sonos-related issues.

###### [ 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.
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.45",
"version": "1.0.46",
"zeroconf": [ "_spotify-connect._tcp.local." ]
}
78 changes: 31 additions & 47 deletions custom_components/spotifyplus/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,8 +796,6 @@ def play_media(self, media_type: MediaType | str, media_id: str, **kwargs: Any)
@spotify_exception_handler
def select_source(self, source: str) -> None:
""" Select playback device. """
saveSource:str = None

try:

# trace.
Expand All @@ -809,18 +807,13 @@ def select_source(self, source: str) -> None:
if (source is None) or (len(source) == 0):
raise HomeAssistantError("'%s': Source argument was not specified while trying to select a source.)" % (self.name))

# save current source in the event of an exception.
saveSource = self._attr_source

# are we currently powered off?
wasTurnedOn:bool = False
if self._attr_state == MediaPlayerState.OFF:

# power on the player.
# note that the `turn_on()` method will issue a transfer playback to the specified source.
self.turn_on()
self._isInCommandEvent = True # turn "in a command event" indicator back on.
wasTurnedOn = True

else:

Expand All @@ -831,30 +824,7 @@ def select_source(self, source: str) -> None:
self._attr_source = source
_logsi.LogVerbose("'%s': Selected source was changed to: '%s'" % (self.name, self._attr_source))

# # get current Spotify Connect player state.
# self._playerState, self._spotifyConnectDevice, self._sonosDevice = self._GetPlayerPlaybackState()

# # get the currently playing source (if any).
# if self._sonosDevice is not None:
# currentSource = self._sonosDevice.player_name
# elif self._spotifyConnectDevice is not None:
# currentSource = self._spotifyConnectDevice.DeviceInfo.RemoteName
# elif self._playerState.Device.Name is not None:
# currentSource = self._playerState.Device.Name

# # verify the source was switched.
# if (currentSource != source):
# raise HomeAssistantError("'%s': Source could not be selected: '%s'.)" % (self.name, source))

except HomeAssistantError: raise # pass handled exceptions on thru
# except Exception as ex:

# # assume source could not be selected if an exception occurred.
# self._attr_source = saveSource
# _logsi.LogVerbose("'%s': Exception while selecting source; resetting source to: '%s'" % (self.name, self._attr_source))

# _logsi.LogException(None, ex)
# raise HomeAssistantError(str(ex)) from ex

finally:

Expand Down Expand Up @@ -991,7 +961,8 @@ def turn_off(self) -> None:

else:

self.data.spotifyClient.PlayerMediaPause(self._spotifyConnectDevice.DeviceInfo.DeviceId)
if self._playerState.IsPlaying:
self.data.spotifyClient.PlayerMediaPause(self._spotifyConnectDevice.DeviceInfo.DeviceId)

# call script to power off device.
self._CallScriptPower(self.data.OptionScriptTurnOff, "turn_off")
Expand Down Expand Up @@ -4205,7 +4176,8 @@ def service_spotify_player_transfer_playback(
else:

# for everything else, just use the Spotify Web API.
self.data.spotifyClient.PlayerMediaPause(self._playerState.Device.Id)
if self._playerState.IsPlaying:
self.data.spotifyClient.PlayerMediaPause(self._playerState.Device.Id, delay)

# get target device reference from cached list of Spotify Connect devices.
scDevices:SpotifyConnectDevices = self.data.spotifyClient.GetSpotifyConnectDevices(refresh=False)
Expand Down Expand Up @@ -4269,24 +4241,39 @@ def service_spotify_player_transfer_playback(
# queue instead of the Spotify Connect queue.
_logsi.LogVerbose("'%s': Creating local queue from source playerstate for Sonos device '%s' ('%s')" % (self.name, sonosDevice.ip_address, sonosDevice.player_name))

# retrieve spotify web api player queue - this includes the currently playing item, as well
# as the first 20 items from the queue.
queue:PlayerQueueInfo = self.data.spotifyClient.GetPlayerQueueInfo()

# build a list of all queue item uri's, adding the currently playing item first.
arrUris:list[str] = []
arrUris.append(self._playerState.Item.Uri)
if queue.QueueCount > 0:
queueTrack:Track
for queueTrack in queue.Queue:
arrUris.append(queueTrack.Uri)

# build the Sonos local queue, adding all Spotify Web API player queue items.
sonosDevice = SoCo(scDevice.DiscoveryResult.HostIpAddress)
_logsi.LogVerbose("'%s': Issuing command to Sonos device '%s' ('%s'): CLEAR_QUEUE" % (self.name, sonosDevice.ip_address, sonosDevice.player_name))
sonosDevice.clear_queue()
sharelink = ShareLinkPlugin(sonosDevice)
uri:str = self._playerState.Item.Uri
_logsi.LogVerbose("'%s': Issuing command to Sonos device '%s' ('%s'): ADD_SHARE_LINK_TO_QUEUE (uri=%s)" % (self.name, sonosDevice.ip_address, sonosDevice.player_name, uri))
sharelink.add_share_link_to_queue(uri)
for uri in arrUris:
_logsi.LogVerbose("'%s': Issuing command to Sonos device '%s' ('%s'): ADD_SHARE_LINK_TO_QUEUE (uri=%s)" % (self.name, sonosDevice.ip_address, sonosDevice.player_name, uri))
sharelink.add_share_link_to_queue(uri)
_logsi.LogVerbose("'%s': Issuing command to Sonos device '%s' ('%s'): PLAY_FROM_QUEUE (index=%s)" % (self.name, sonosDevice.ip_address, sonosDevice.player_name, 0))
sonosDevice.play_from_queue(index=0, start=True)

sonosDevice.play_from_queue(index=0)
# give SoCo api time to process the change.
if delay > 0:
_logsi.LogVerbose(TRACE_MSG_DELAY_DEVICE_SONOS % delay)
time.sleep(delay)

# find position of currently playing track.
sonosPosition:str = positionHMS_fromMilliSeconds(self._playerState.ProgressMS) # convert from milliseconds to Sonos H:MM:SS format
_logsi.LogVerbose("'%s': Issuing command to Sonos device '%s' ('%s'): SEEK (position=%s)" % (self.name, sonosDevice.ip_address, sonosDevice.player_name, sonosPosition))
sonosDevice.seek(position=sonosPosition)

# give SoCo api time to process the change.
if delay > 0:
_logsi.LogVerbose(TRACE_MSG_DELAY_DEVICE_SONOS % delay)
Expand All @@ -4297,19 +4284,16 @@ def service_spotify_player_transfer_playback(
# for everything else, just use the Spotify Web API.
self.data.spotifyClient.PlayerTransferPlayback(deviceId, play, delay)

# set the selected source.
if scDevice is not None:
self._attr_source = scDevice.DeviceInfo.RemoteName
_logsi.LogVerbose("'%s': Selected source was changed to: '%s'" % (self.name, self._attr_source))

# get current Spotify Connect player state.
self._playerState, self._spotifyConnectDevice, self._sonosDevice = self._GetPlayerPlaybackState()

# reset internal SonosDevice to the SonosDevice that we just created (if transferring to Sonos).
self._sonosDevice = sonosDevice

# update ha state.
self.schedule_update_ha_state(force_refresh=False)
# set the selected source.
if scDevice is not None:
self._attr_source = scDevice.DeviceInfo.RemoteName
_logsi.LogVerbose("'%s': Selected source was changed to: '%s'" % (self.name, self._attr_source))

# media player command was processed, so force a scan window at the next interval.
_logsi.LogVerbose("'%s': Processed a transfer playback command - forcing a playerState scan window for the next %d updates" % (self.name, SPOTIFY_SCAN_INTERVAL_COMMAND - 1))
Expand All @@ -4332,8 +4316,8 @@ def service_spotify_player_transfer_playback(

finally:

# reset Sonos device instance.
sonosDevice = None
# update ha state.
self.schedule_update_ha_state(force_refresh=False)

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

0 comments on commit f8ecf4e

Please sign in to comment.