diff --git a/CHANGELOG.md b/CHANGELOG.md index 637bc8a..7974111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ Change are listed in reverse chronological order (newest to oldest). +###### [ 1.0.31 ] - 2024/06/24 + + * Updated underlying `spotifywebapiPython` package requirement to version 1.0.64. + * The underlying `spotifywebapiPython` update changes the way Spotify Connect Zeroconf API return codes are processed. It now processes the Spotify Zeroconf API status code from the JSON response instead of processing the HTTP request status code. It has been found that some Spotify Connect manufacturers return different HTTP status codes than other manufacturers; but the Spotify Connect `status`, `statusString` and `spotifyError` JSON properties seem to be consistent across the board. + * The underlying `spotifywebapiPython` update also filters out duplicate Spotify Connect Device entries for devices that have been grouped together. For example, the "Bose-ST10-1" and "Bose-ST10-2" are grouped as a stereo pair; there will be two Zeroconf discovery result entries with different instance names, but their Zeroconf getInfo endpoint url will be the same. This was causing two entries to appear in the device list, when there should have been only one. + ###### [ 1.0.30 ] - 2024/06/22 * Updated `config_flow` to utilize the HA shared Zeroconf instance. diff --git a/custom_components/spotifyplus/config_flow.py b/custom_components/spotifyplus/config_flow.py index 1e963f3..3fa268e 100644 --- a/custom_components/spotifyplus/config_flow.py +++ b/custom_components/spotifyplus/config_flow.py @@ -467,7 +467,8 @@ def _GetPlayerDevicesList(self) -> list: # get configuration instance data so we can reference the client instance. _logsi.LogVerbose("'%s': OptionsFlow is retrieving instance data" % self._name) data:InstanceDataSpotifyPlus = self.hass.data[DOMAIN].get(self._entry.entry_id, None) - _logsi.LogObject(SILevel.Verbose, "'%s': OptionsFlow instance data object" % self._name, data) + _logsi.LogObject(SILevel.Verbose, "'%s': OptionsFlow instance data.spotifyClient" % self._name, data.spotifyClient) + _logsi.LogObject(SILevel.Verbose, "'%s': OptionsFlow instance data.options" % self._name, data.options) # get spotify connect player device list. _logsi.LogVerbose("'%s': OptionsFlow is retrieving Spotify Connect player devices" % self._name) diff --git a/custom_components/spotifyplus/manifest.json b/custom_components/spotifyplus/manifest.json index b183445..ee0c8c7 100644 --- a/custom_components/spotifyplus/manifest.json +++ b/custom_components/spotifyplus/manifest.json @@ -17,10 +17,10 @@ "requests>=2.31.0", "requests_oauthlib>=1.3.1", "smartinspectPython>=3.0.33", - "spotifywebapiPython>=1.0.62", + "spotifywebapiPython>=1.0.64", "urllib3>=1.21.1,<1.27", "zeroconf>=0.132.2" ], - "version": "1.0.30", + "version": "1.0.31", "zeroconf": [ "_spotify-connect._tcp.local." ] } diff --git a/custom_components/spotifyplus/media_player.py b/custom_components/spotifyplus/media_player.py index f644beb..12e0f28 100644 --- a/custom_components/spotifyplus/media_player.py +++ b/custom_components/spotifyplus/media_player.py @@ -78,6 +78,7 @@ DOMAIN_SCRIPT, LOGGER, ) +from .utils import passwordMaskString # get smartinspect logger reference; create a new session for this module name. from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext, SIColors @@ -4720,7 +4721,7 @@ def service_spotify_zeroconf_device_connect( apiMethodParms.AppendKeyValue("version", version) apiMethodParms.AppendKeyValue("useSSL", useSSL) apiMethodParms.AppendKeyValue("username", username) - apiMethodParms.AppendKeyValue("password", password) + apiMethodParms.AppendKeyValue("password (with mask)", passwordMaskString(password)) apiMethodParms.AppendKeyValue("preDisconnect", preDisconnect) apiMethodParms.AppendKeyValue("verifyDeviceListEntry", verifyDeviceListEntry) _logsi.LogMethodParmList(SILevel.Verbose, "Spotify Connect ZeroConf Device Connect Service", apiMethodParms) diff --git a/custom_components/spotifyplus/utils.py b/custom_components/spotifyplus/utils.py new file mode 100644 index 0000000..6d2e7f8 --- /dev/null +++ b/custom_components/spotifyplus/utils.py @@ -0,0 +1,65 @@ +from copy import deepcopy + +# # get smartinspect logger reference; create a new session for this module name. +# from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIColors +# import logging +# _logsi:SISession = SIAuto.Si.GetSession(__name__) +# if (_logsi == None): +# _logsi = SIAuto.Si.AddSession(__name__, True) +# _logsi.SystemLogger = logging.getLogger(__name__) + +def passwordMaskDictionary(inputObj:dict) -> dict: + """ + Checks keys in a dictionary any keys that contain `password` and masks the + value so that the password is not displayed in a trace file. + + Args: + inputObj (dict): + Dictionary object to check. + + Returns: + A copy of the `inputObj` source dictionary with passwor(s) masked. + + Note that this method performs a simple copy of the dictionary. + """ + # if input is null then don't bother. + if (inputObj is None): + return inputObj + + # create a new dictionary. + result:dict = {} + + # process keys in the dictionary. + key:str + for key in inputObj.keys(): + keyLower:str = key.lower() + if (keyLower.find('password') == -1): + result[key] = inputObj[key] + else: + value:str = inputObj[key] + if (value is not None) and (isinstance(value, str)): + result[key] = ''.ljust(len(value), '*') + + return result + + +def passwordMaskString(inputObj:str) -> str: + """ + Checks a string for a password value and masks the value so that the password is not displayed + in a trace file. + + Args: + inputObj (str): + String object to check. + + Returns: + A copy of the `inputObj` value with password masked. + """ + # if input is null then don't bother. + if (inputObj is None): + return inputObj + + # create a new value. + result:str = ''.ljust(len(inputObj), '*') + + return result diff --git a/requirements.txt b/requirements.txt index c055d6a..85a3579 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,4 @@ colorlog==6.7.0 homeassistant==2024.5.0 ruff==0.1.3 smartinspectPython>=3.0.33 -spotifywebapiPython>=1.0.62 +spotifywebapiPython>=1.0.64 diff --git a/spotifyplus.pyproj b/spotifyplus.pyproj index a728fef..167d6a8 100644 --- a/spotifyplus.pyproj +++ b/spotifyplus.pyproj @@ -33,6 +33,7 @@ +