Skip to content

Commit

Permalink
[ 1.0.36 ] * Added support for Spotify Connect LoginID specification …
Browse files Browse the repository at this point in the history
…in configuration options.

  * Updated underlying `spotifywebapiPython` package requirement to version 1.0.69.
  • Loading branch information
thlucas1 committed Jun 27, 2024
1 parent 720f4ac commit 625d012
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 20 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Change are listed in reverse chronological order (newest to oldest).

<span class="changelog">

###### [ 1.0.36 ] - 2024/06/26

* Added support for Spotify Connect LoginID specification in configuration options.
* Updated underlying `spotifywebapiPython` package requirement to version 1.0.69.

###### [ 1.0.35 ] - 2024/06/26

* Updated underlying `spotifywebapiPython` package requirement to version 1.0.68.
Expand Down
8 changes: 6 additions & 2 deletions custom_components/spotifyplus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from .appmessages import STAppMessages
from .const import (
CONF_OPTION_DEVICE_LOGINID,
CONF_OPTION_DEVICE_PASSWORD,
CONF_OPTION_DEVICE_USERNAME,
DOMAIN,
Expand Down Expand Up @@ -630,6 +631,7 @@
vol.Optional("use_ssl"): cv.boolean,
vol.Required("username"): cv.string,
vol.Required("password"): cv.string,
vol.Optional("loginid"): cv.string,
vol.Optional("pre_disconnect"): cv.boolean,
vol.Optional("verify_device_list_entry"): cv.boolean,
}
Expand Down Expand Up @@ -1291,10 +1293,11 @@ async def service_handle_spotify_serviceresponse(service: ServiceCall) -> Servic
use_ssl = service.data.get("use_ssl")
username = service.data.get("username")
password = service.data.get("password")
loginid = service.data.get("loginid")
pre_disconnect = service.data.get("pre_disconnect")
verify_device_list_entry = service.data.get("verify_device_list_entry")
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
response = await hass.async_add_executor_job(entity.service_spotify_zeroconf_device_connect, username, password, host_ipv4_address, host_ip_port, cpath, version, use_ssl, pre_disconnect, verify_device_list_entry)
response = await hass.async_add_executor_job(entity.service_spotify_zeroconf_device_connect, username, password, loginid, host_ipv4_address, host_ip_port, cpath, version, use_ssl, pre_disconnect, verify_device_list_entry)

elif service.service == SERVICE_SPOTIFY_ZEROCONF_DEVICE_DISCONNECT:

Expand Down Expand Up @@ -2105,7 +2108,8 @@ def _TokenUpdater() -> dict:
_TokenUpdater, # tokenUpdater:Callable=None,
zeroconf_instance, # zeroconfClient:Zeroconf=None,
entry.options.get(CONF_OPTION_DEVICE_USERNAME, None),
entry.options.get(CONF_OPTION_DEVICE_PASSWORD, None)
entry.options.get(CONF_OPTION_DEVICE_PASSWORD, None),
entry.options.get(CONF_OPTION_DEVICE_LOGINID, None),
)
_logsi.LogObject(SILevel.Verbose, "'%s': Component async_setup_entry spotifyClient object" % entry.title, spotifyClient)

Expand Down
10 changes: 10 additions & 0 deletions custom_components/spotifyplus/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

from .const import (
CONF_OPTION_DEVICE_DEFAULT,
CONF_OPTION_DEVICE_LOGINID,
CONF_OPTION_DEVICE_PASSWORD,
CONF_OPTION_DEVICE_USERNAME,
CONF_OPTION_SCRIPT_TURN_OFF,
Expand Down Expand Up @@ -365,17 +366,21 @@ async def async_step_init(self, user_input:dict[str,Any]=None) -> FlowResult:

# update config entry options from user input values.
self._Options[CONF_OPTION_DEVICE_DEFAULT] = user_input.get(CONF_OPTION_DEVICE_DEFAULT, None)
self._Options[CONF_OPTION_DEVICE_LOGINID] = user_input.get(CONF_OPTION_DEVICE_LOGINID, None)
self._Options[CONF_OPTION_DEVICE_USERNAME] = user_input.get(CONF_OPTION_DEVICE_USERNAME, None)
self._Options[CONF_OPTION_DEVICE_PASSWORD] = user_input.get(CONF_OPTION_DEVICE_PASSWORD, None)
self._Options[CONF_OPTION_SCRIPT_TURN_OFF] = user_input.get(CONF_OPTION_SCRIPT_TURN_OFF, None)
self._Options[CONF_OPTION_SCRIPT_TURN_ON] = user_input.get(CONF_OPTION_SCRIPT_TURN_ON, None)

# validations.
# if device username was entered then device password is required.
deviceLoginid:str = user_input.get(CONF_OPTION_DEVICE_LOGINID, None)
deviceUsername:str = user_input.get(CONF_OPTION_DEVICE_USERNAME, None)
devicePassword:str = user_input.get(CONF_OPTION_DEVICE_PASSWORD, None)
if (deviceUsername is not None) and (devicePassword is None):
errors["base"] = "device_password_required"
if (deviceUsername is not None) and (deviceLoginid is None):
errors["base"] = "device_loginid_required"

# any validation errors? if not, then ...
if "base" not in errors:
Expand All @@ -395,6 +400,8 @@ async def async_step_init(self, user_input:dict[str,Any]=None) -> FlowResult:
# log device that is currently selected.
device_default:str = self._Options.get(CONF_OPTION_DEVICE_DEFAULT, None)
_logsi.LogVerbose("'%s': OptionsFlow option '%s' - SELECTED value: '%s'" % (self._name, CONF_OPTION_DEVICE_DEFAULT, device_default))
device_loginid:str = self._Options.get(CONF_OPTION_DEVICE_LOGINID, None)
_logsi.LogVerbose("'%s': OptionsFlow option '%s' - SELECTED value: '%s'" % (self._name, CONF_OPTION_DEVICE_USERNAME, device_loginid))
device_username:str = self._Options.get(CONF_OPTION_DEVICE_USERNAME, None)
_logsi.LogVerbose("'%s': OptionsFlow option '%s' - SELECTED value: '%s'" % (self._name, CONF_OPTION_DEVICE_USERNAME, device_username))

Expand All @@ -412,6 +419,9 @@ async def async_step_init(self, user_input:dict[str,Any]=None) -> FlowResult:
mode=SelectSelectorMode.DROPDOWN
)
),
vol.Optional(CONF_OPTION_DEVICE_LOGINID,
description={"suggested_value": self._Options.get(CONF_OPTION_DEVICE_LOGINID)},
): cv.string,
vol.Optional(CONF_OPTION_DEVICE_USERNAME,
description={"suggested_value": self._Options.get(CONF_OPTION_DEVICE_USERNAME)},
): cv.string,
Expand Down
1 change: 1 addition & 0 deletions custom_components/spotifyplus/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
LOGGER = logging.getLogger(__package__)

CONF_OPTION_DEVICE_DEFAULT = "device_default"
CONF_OPTION_DEVICE_LOGINID = "device_loginid"
CONF_OPTION_DEVICE_PASSWORD = "device_password"
CONF_OPTION_DEVICE_USERNAME = "device_username"
CONF_OPTION_SCRIPT_TURN_ON = "script_turn_on"
Expand Down
8 changes: 8 additions & 0 deletions custom_components/spotifyplus/instancedata_spotifyplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from .const import (
CONF_OPTION_DEVICE_DEFAULT,
CONF_OPTION_DEVICE_LOGINID,
CONF_OPTION_DEVICE_PASSWORD,
CONF_OPTION_DEVICE_USERNAME,
CONF_OPTION_SCRIPT_TURN_OFF,
Expand Down Expand Up @@ -63,6 +64,13 @@ def OptionDeviceDefault(self) -> str | None:
"""
return self.options.get(CONF_OPTION_DEVICE_DEFAULT, None)

@property
def OptionDeviceLoginId(self) -> str | None:
"""
The default Spotify Connect loginid to use when connecting to an inactive device.
"""
return self.options.get(CONF_OPTION_DEVICE_LOGINID, None)

@property
def OptionDevicePassword(self) -> str | None:
"""
Expand Down
4 changes: 2 additions & 2 deletions custom_components/spotifyplus/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
"requests>=2.31.0",
"requests_oauthlib>=1.3.1",
"smartinspectPython>=3.0.33",
"spotifywebapiPython>=1.0.68",
"spotifywebapiPython>=1.0.69",
"urllib3>=1.21.1,<1.27",
"zeroconf>=0.132.2"
],
"version": "1.0.35",
"version": "1.0.36",
"zeroconf": [ "_spotify-connect._tcp.local." ]
}
12 changes: 9 additions & 3 deletions custom_components/spotifyplus/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -4707,6 +4707,7 @@ def service_spotify_zeroconf_device_connect(
self,
username:str,
password:str,
loginid:str,
hostIpv4Address:str,
hostIpPort:str,
cpath:str,
Expand All @@ -4721,11 +4722,15 @@ def service_spotify_zeroconf_device_connect(
Args:
username (str):
Spotify Connect user name to login with.
Spotify Connect user name to login with (e.g. "yourspotifyusername").
This MUST match the account name (or one of them) that was used to configure Spotify Connect
on the manufacturer device.
on the manufacturer device.
password (str):
Spotify Connect user password to login with.
loginId (str):
Spotify Connect login id to login with (e.g. "31l77fd87g8h9j00k89f07jf87ge").
This is also known as the canonical user id value.
This MUST be the value that relates to the `username` argument.
hostIpv4Address (str):
IPV4 address (as a string) at which the Spotify Connect Zeroconf API can be reached
on the Spotify Connect device (e.g. "192.168.1.81").
Expand Down Expand Up @@ -4781,6 +4786,7 @@ def service_spotify_zeroconf_device_connect(
apiMethodParms.AppendKeyValue("useSSL", useSSL)
apiMethodParms.AppendKeyValue("username", username)
apiMethodParms.AppendKeyValue("password (with mask)", passwordMaskString(password))
apiMethodParms.AppendKeyValue("loginid", loginid)
apiMethodParms.AppendKeyValue("preDisconnect", preDisconnect)
apiMethodParms.AppendKeyValue("verifyDeviceListEntry", verifyDeviceListEntry)
_logsi.LogMethodParmList(SILevel.Verbose, "Spotify Connect ZeroConf Device Connect Service", apiMethodParms)
Expand Down Expand Up @@ -4817,7 +4823,7 @@ def service_spotify_zeroconf_device_connect(

# connect the device to Spotify Connect, which should make it known to any available
# Spotify Connect player clients.
result = zconn.Connect(username, password)
result = zconn.Connect(username, password, loginid)

# return the (partial) user profile that retrieved the result, as well as the result itself.
return {
Expand Down
11 changes: 9 additions & 2 deletions custom_components/spotifyplus/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2080,18 +2080,25 @@ zeroconf_device_connect:
boolean:
username:
name: Spotify User Name
description: Spotify user name to login with; this can be a standard username (e.g. '[email protected]') or a canonical userid (e.g. '31l77y75hfnhk79f7gk6jkk878mg'). This MUST match the account name (or one of them) that was used to configure Spotify Connect on the manufacturer device.
description: Spotify user name to login with (e.g. '[email protected]'). This MUST match the account name (or one of them) that was used to configure Spotify Connect on the manufacturer device.
example: "[email protected]"
required: true
selector:
text:
password:
name: Spotify User Password
description: Spotify user password to login with.
description: Spotify Connect user password to login with.
example: "yourpassword"
required: true
selector:
text:
loginid:
name: Spotify Login ID
description: Spotify Connect login id to login with (e.g. "31l77fd87g8h9j00k89f07jf87ge"). This is also known as the canonical user id value. This MUST be the value that relates to the `username` argument.
example: "31l77y75hfnhk79f7gk6jkk878mg"
required: false
selector:
text:
pre_disconnect:
name: Pre Disconnect?
description: True if a Disconnect should be made prior to the Connect call. This will ensure that the active user is logged out, which must be done if switching user accounts; otherwise, False to not issue a Disconnect call. Default is False.
Expand Down
16 changes: 11 additions & 5 deletions custom_components/spotifyplus/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
"description": "Configure SpotifyPlus integration options that control functionality.",
"data": {
"device_default": "Default Spotify Connect Player Device ID when none are active.",
"device_password": "Default Spotify Connect password to use when connecting to an inactive device.",
"device_username": "Default Spotify Connect username to use when connecting to an inactive device.",
"device_loginid": "Spotify Connect canonical loginid to use when connecting to an inactive device.",
"device_password": "Spotify Connect password to use when connecting to an inactive device.",
"device_username": "Spotify Connect username to use when connecting to an inactive device.",
"script_turn_on": "Script called to turn on device that plays media content.",
"script_turn_off": "Script called to turn off device that plays media content."
},
Expand All @@ -34,7 +35,8 @@
},
"error": {
"no_player_devices": "Per Spotify Web API, there are currently no Spotify Connect devices active. Please close the configuration options, play a track on any Spotify Connect player for a minute or two, and then open the configuration options again.",
"device_password_required": "Default Device Password is required if a Default Device Username was specified."
"device_password_required": "Spotify Connect Device Password is required if a Spotify Connect Device Username was specified.",
"device_loginid_required": "Spotify Connect Device LoginId is required if a Spotify Connect Device Username was specified."
}
},
"system_health": {
Expand Down Expand Up @@ -1201,11 +1203,15 @@
},
"username": {
"name": "Spotify User Name",
"description": "Spotify user name to login with; this can be a standard username (e.g. '[email protected]') or a canonical userid (e.g. '31l77y75hfnhk79f7gk6jkk878mg'). This MUST match the account name (or one of them) that was used to configure Spotify Connect on the manufacturer device."
"description": "Spotify user name to login with (e.g. '[email protected]'). This MUST match the account name (or one of them) that was used to configure Spotify Connect on the manufacturer device."
},
"password": {
"name": "Spotify Password",
"description": "Spotify user password to login with."
"description": "Spotify Connect user password to login with."
},
"loginid": {
"name": "Spotify Login ID",
"description": "Spotify Connect login id to login with (e.g. '31l77fd87g8h9j00k89f07jf87ge'). This is also known as the canonical user id value. This MUST be the value that relates to the `username` argument."
},
"pre_disconnect": {
"name": "Pre Disconnect?",
Expand Down
16 changes: 11 additions & 5 deletions custom_components/spotifyplus/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
"description": "Configure SpotifyPlus integration options that control functionality.",
"data": {
"device_default": "Default Spotify Connect Player Device ID when none are active.",
"device_password": "Default Spotify Connect password to use when connecting to an inactive device.",
"device_username": "Default Spotify Connect username to use when connecting to an inactive device.",
"device_loginid": "Spotify Connect canonical loginid to use when connecting to an inactive device.",
"device_password": "Spotify Connect password to use when connecting to an inactive device.",
"device_username": "Spotify Connect username to use when connecting to an inactive device.",
"script_turn_on": "Script called to turn on device that plays media content.",
"script_turn_off": "Script called to turn off device that plays media content."
},
Expand All @@ -34,7 +35,8 @@
},
"error": {
"no_player_devices": "Per Spotify Web API, there are currently no Spotify Connect devices active. Please close the configuration options, play a track on any Spotify Connect player for a minute or two, and then open the configuration options again.",
"device_password_required": "Default Device Password is required if a Default Device Username was specified."
"device_password_required": "Spotify Connect Device Password is required if a Spotify Connect Device Username was specified.",
"device_loginid_required": "Spotify Connect Device LoginId is required if a Spotify Connect Device Username was specified."
}
},
"system_health": {
Expand Down Expand Up @@ -1201,11 +1203,15 @@
},
"username": {
"name": "Spotify User Name",
"description": "Spotify user name to login with; this can be a standard username (e.g. '[email protected]') or a canonical userid (e.g. '31l77y75hfnhk79f7gk6jkk878mg'). This MUST match the account name (or one of them) that was used to configure Spotify Connect on the manufacturer device."
"description": "Spotify user name to login with (e.g. '[email protected]'). This MUST match the account name (or one of them) that was used to configure Spotify Connect on the manufacturer device."
},
"password": {
"name": "Spotify Password",
"description": "Spotify user password to login with."
"description": "Spotify Connect user password to login with."
},
"loginid": {
"name": "Spotify Login ID",
"description": "Spotify Connect login id to login with (e.g. '31l77fd87g8h9j00k89f07jf87ge'). This is also known as the canonical user id value. This MUST be the value that relates to the `username` argument."
},
"pre_disconnect": {
"name": "Pre Disconnect?",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ colorlog==6.7.0
homeassistant==2024.5.0
ruff==0.1.3
smartinspectPython>=3.0.33
spotifywebapiPython>=1.0.68
spotifywebapiPython>=1.0.69

0 comments on commit 625d012

Please sign in to comment.