From 355eccd17024eab535271a6a98fb31b775b612c5 Mon Sep 17 00:00:00 2001 From: Todd Lucas Date: Mon, 30 Oct 2023 16:41:39 -0500 Subject: [PATCH] [ 1.0.3 ] - 2023/10/30 * Added "play_url" service support that allows better support for playing URL media content. --- CHANGELOG.md | 4 + README.md | 1 + custom_components/soundtouchplus/__init__.py | 33 +++++++- custom_components/soundtouchplus/const.py | 1 + .../soundtouchplus/manifest.json | 2 +- .../soundtouchplus/media_player.py | 57 +++++++++++--- .../soundtouchplus/services.yaml | 68 +++++++++++++++++ custom_components/soundtouchplus/strings.json | 76 +++++++++++++++++++ .../soundtouchplus/translations/en.json | 76 +++++++++++++++++++ 9 files changed, 307 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a151be6..c06988b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Change are listed in reverse chronological order (newest to oldest). +###### [ 1.0.3 ] - 2023/10/30 + + * Added "play_url" service support that allows better support for playing URL media content. + ###### [ 1.0.2 ] - 2023/10/30 * Removed some HTML formatting from strings.json to be HASSFest validation compliant. diff --git a/README.md b/README.md index b3699d2..7f9691d 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ target: The following custom services are also supplied by this integration. - Play Handoff: Handoff playing source from one SoundTouch device to another. - Play TTS Message: Play Text-To-Speech notification on a SoundTouch device. Note that this is limited to ST10,20,30 devices, as Bose ST300 does not support notifications (AFAIK). +- Play URL: Play media content URL on a SoundTouch device. Note that this is limited to ST10,20,30 devices, as Bose ST300 does not support notifications (AFAIK). - Get Preset List: Retrieves the list of presets defined to the device. - Get Recent List: Retrieves the list of recently played items defined to the device. - Remote Keypress: Simulates the press and release of a key on the SoundTouch device remote control. diff --git a/custom_components/soundtouchplus/__init__.py b/custom_components/soundtouchplus/__init__.py index 99a1381..90d4a6c 100644 --- a/custom_components/soundtouchplus/__init__.py +++ b/custom_components/soundtouchplus/__init__.py @@ -23,6 +23,7 @@ DOMAIN, SERVICE_PLAY_HANDOFF, SERVICE_PLAY_TTS, + SERVICE_PLAY_URL, SERVICE_PRESETLIST, SERVICE_RECENTLIST, SERVICE_REMOTE_KEYPRESS, @@ -89,12 +90,24 @@ vol.Optional("album"): cv.string, vol.Optional("track"): cv.string, vol.Optional("tts_url"): cv.string, - vol.Optional("artist"): cv.string, vol.Optional("volume_level", default=0): vol.All(vol.Range(min=0,max=100)), vol.Optional("app_key"): cv.string } ) +SERVICE_PLAY_URL_SCHEMA = vol.Schema( + { + vol.Required("entity_id"): cv.entity_id, + vol.Required("url"): cv.string, + vol.Optional("artist"): cv.string, + vol.Optional("album"): cv.string, + vol.Optional("track"): cv.string, + vol.Optional("volume_level", default=0): vol.All(vol.Range(min=0,max=100)), + vol.Optional("app_key"): cv.string, + vol.Required("get_metadata_from_url_file", default=False): cv.boolean + } +) + SERVICE_PRESETLIST_SCHEMA = vol.Schema( { vol.Required("entity_id"): cv.entity_id, @@ -201,6 +214,16 @@ async def service_handle_entity(service:ServiceCall) -> None: app_key = service.data.get("app_key") await hass.async_add_executor_job(player.play_tts, message, artist, album, track, tts_url, volume_level, app_key) + elif service.service == SERVICE_PLAY_URL: + url = service.data.get("url") + artist = service.data.get("artist") + album = service.data.get("album") + track = service.data.get("track") + volume_level = service.data.get("volume_level") + app_key = service.data.get("app_key") + get_metadata_from_url_file = service.data.get("get_metadata_from_url_file") + await hass.async_add_executor_job(player.play_url, url, artist, album, track, volume_level, app_key, get_metadata_from_url_file) + else: _logsi.LogError(STAppMessages.MSG_SERVICE_REQUEST_UNKNOWN, service.service, "service_handle_entity") return @@ -368,6 +391,14 @@ def _GetEntityFromServiceData(hass:HomeAssistant, service:ServiceCall, field_id: schema=SERVICE_PLAY_TTS_SCHEMA, ) + _logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_PLAY_URL, SERVICE_PLAY_URL_SCHEMA) + hass.services.async_register( + DOMAIN, + SERVICE_PLAY_URL, + service_handle_entity, + schema=SERVICE_PLAY_URL_SCHEMA, + ) + _logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_PRESETLIST, SERVICE_PRESETLIST_SCHEMA) hass.services.async_register( DOMAIN, diff --git a/custom_components/soundtouchplus/const.py b/custom_components/soundtouchplus/const.py index b433f7b..4937dc0 100644 --- a/custom_components/soundtouchplus/const.py +++ b/custom_components/soundtouchplus/const.py @@ -15,6 +15,7 @@ # custom service names. SERVICE_PLAY_HANDOFF = "play_handoff" SERVICE_PLAY_TTS = "play_tts" +SERVICE_PLAY_URL = "play_url" SERVICE_PRESETLIST = "preset_list" SERVICE_RECENTLIST = "recent_list" SERVICE_REMOTE_KEYPRESS = "remote_keypress" diff --git a/custom_components/soundtouchplus/manifest.json b/custom_components/soundtouchplus/manifest.json index 46f017d..0a7a0a6 100644 --- a/custom_components/soundtouchplus/manifest.json +++ b/custom_components/soundtouchplus/manifest.json @@ -14,6 +14,6 @@ "smartinspectPython>=3.0.26", "bosesoundtouchapi>=1.0.3" ], - "version": "1.0.2", + "version": "1.0.3", "zeroconf": [ "_soundtouch._tcp.local." ] } diff --git a/custom_components/soundtouchplus/media_player.py b/custom_components/soundtouchplus/media_player.py index 809fe40..9b493b4 100644 --- a/custom_components/soundtouchplus/media_player.py +++ b/custom_components/soundtouchplus/media_player.py @@ -843,18 +843,57 @@ def play_tts(self, message:str, artist:str, album:str, track:str, ttsUrl:str, vo appKey (str): Bose Developer API application key. """ - parms:dict = {} - parms['message'] = message - parms['artist'] = artist - parms['album'] = album - parms['track'] = track - parms['ttsUrl'] = ttsUrl - parms['volumeLevel'] = volumeLevel - parms['appKey'] = appKey - _logsi.LogDictionary(SILevel.Verbose, STAppMessages.MSG_PLAYER_COMMAND % ("play_tts", self.name, self.entity_id), parms) + if _logsi.IsOn(SILevel.Verbose): + parms:dict = {} + parms['message'] = message + parms['artist'] = artist + parms['album'] = album + parms['track'] = track + parms['ttsUrl'] = ttsUrl + parms['volumeLevel'] = volumeLevel + parms['appKey'] = appKey + _logsi.LogDictionary(SILevel.Verbose, STAppMessages.MSG_PLAYER_COMMAND % ("play_tts", self.name, self.entity_id), parms) + self._client.PlayNotificationTTS(message, ttsUrl, artist, album, track, volumeLevel, appKey) + def play_url(self, url:str, artist:str, album:str, track:str, volumeLevel:int, appKey:str, getMetadataFromUrlFile:bool): + """ + Play media content from a URL on a SoundTouch device. + + Args: + url (str): + The URL media content to play on the device. + artist (str): + The text that will appear in the NowPlaying Artist node; if omitted, default is "Unknown Artist". + album (str): + The text that will appear in the NowPlaying Album node; if omitted, default is "Unknown Album". + track (str): + The text that will appear in the NowPlaying Track node; if omitted, default is "Unknown Track". + volumeLevel (int): + The temporary volume level that will be used when the media is played. + Specify a value of zero to play at the current volume. + Default is zero. + appKey (str): + Bose Developer API application key. + getMetadataFromUrlFile (bool): + The Text-To-Speech url used to translate the message. The value should contain a "{saytext}" format parameter, + that will be used to insert the encoded message text. + """ + if _logsi.IsOn(SILevel.Verbose): + parms:dict = {} + parms['url'] = url + parms['artist'] = artist + parms['album'] = album + parms['track'] = track + parms['volumeLevel'] = volumeLevel + parms['appKey'] = appKey + parms['getMetadataFromUrlFile'] = getMetadataFromUrlFile + _logsi.LogDictionary(SILevel.Verbose, STAppMessages.MSG_PLAYER_COMMAND % ("play_url", self.name, self.entity_id), parms) + + self._client.PlayUrl(url, artist, album, track, volumeLevel, appKey, getMetadataFromUrlFile) + + def preset_list(self) -> PresetList: """ Retrieves the list of presets defined for a device. diff --git a/custom_components/soundtouchplus/services.yaml b/custom_components/soundtouchplus/services.yaml index bef40d4..bbb6e61 100644 --- a/custom_components/soundtouchplus/services.yaml +++ b/custom_components/soundtouchplus/services.yaml @@ -103,6 +103,74 @@ play_tts: selector: text: +play_url: + name: Play URL Media + description: Play media content from a URL on a SoundTouch device. + fields: + entity_id: + name: Entity ID + description: Entity ID of the SoundTouch device to play the media. + example: "media_player.soundtouch_livingroom" + required: true + selector: + entity: + integration: soundtouchplus + domain: media_player + url: + name: URL + description: The url to play; value must start with http or https. + example: "https://freetestdata.com/wp-content/uploads/2021/09/Free_Test_Data_1MB_MP3.mp3" + required: true + selector: + text: + artist: + name: Artist Status Text + description: The message text that will appear in the NowPlaying Artist node; if omitted, default is "Unknown Artist". + example: "FreeTestData.com" + required: false + selector: + text: + album: + name: Album Status Text + description: The message text that will appear in the NowPlaying Album node; if omitted, default is "Unknown Album". + example: "MP3 Test Data" + required: false + selector: + text: + track: + name: Track Status Text + description: The message text that will appear in the NowPlaying Track node; if omitted, default is "Unknown Track". + example: "Free_Test_Data_1MB_MP3" + required: false + selector: + text: + volume_level: + name: Volume Level + description: The temporary volume level that will be used when the media is played. Specify a value of zero to play at the current volume. Default is zero. + example: 50 + required: false + selector: + number: + min: 0 + max: 100 + step: 5 + unit_of_measurement: "%" + mode: slider + app_key: + name: Bose App Key + description: Bose Developer API application key; if omitted, defaults to a pre-defined App Developer Key. + example: "abcdefghijklmnopqrstuvwxyz" + required: false + selector: + text: + get_metadata_from_url_file: + name: Get Metadata From URL? + description: If true, the artist, album, and song title metadata details will be retrieved from the ID3 header of the url content (if available); otherwise, False to use the artist, album, and song title arguments specified. + example: "false" + required: false + selector: + boolean: + preset_list: name: Get Preset List description: Retrieves the list of presets defined to the device. diff --git a/custom_components/soundtouchplus/strings.json b/custom_components/soundtouchplus/strings.json index cd5f8ce..2eed975 100644 --- a/custom_components/soundtouchplus/strings.json +++ b/custom_components/soundtouchplus/strings.json @@ -62,6 +62,82 @@ } } }, + "play_tts": { + "name": "Play TTS Message", + "description": "Play Text-To-Speech notification on a SoundTouch device. Note that this is limited to ST10,20,30 devices, as Bose ST300 does not support notifications (AFAIK).", + "fields": { + "entity_id": { + "name": "Entity ID", + "description": "Entity ID of the SoundTouch device to play the message." + }, + "message": { + "name": "Message Text", + "description": "The message that will be converted from text to speech and played on the device." + }, + "artist": { + "name": "Artist Status Text", + "description": "The text that will appear in the NowPlaying Artist node; if omitted, default is \"TTS Notification\"." + }, + "album": { + "name": "Album Status Text", + "description": "The text that will appear in the NowPlaying Album node; if omitted, default is \"Google TTS\"." + }, + "track": { + "name": "Track Status Text", + "description": "The text that will appear in the NowPlaying Track node; if omitted, default is the message value." + }, + "tts_url": { + "name": "TTS Service Url", + "description": "The Text-To-Speech url used to translate the message. The value should contain a \"{saytext}\" format parameter, that will be used to insert the encoded message text." + }, + "volume_level": { + "name": "Volume Level", + "description": "The temporary volume level that will be used when the media is played. Specify a value of zero to play at the current volume. Default is zero." + }, + "app_key": { + "name": "Bose App Key", + "description": "Bose Developer API application key; if omitted, defaults to a pre-defined App Developer Key." + } + } + }, + "play_url": { + "name": "Play URL Media", + "description": "Play media content from a URL on a SoundTouch device.", + "fields": { + "entity_id": { + "name": "Entity ID", + "description": "Entity ID of the SoundTouch device to play the media." + }, + "url": { + "name": "URL", + "description": "The url to play; value must start with http or https." + }, + "artist": { + "name": "Artist Status Text", + "description": "The text that will appear in the NowPlaying Artist node; if omitted, default is \"Unknown Artist\"." + }, + "album": { + "name": "Album Status Text", + "description": "The text that will appear in the NowPlaying Album node; if omitted, default is \"Unknown Album\"." + }, + "track": { + "name": "Track Status Text", + "description": "The text that will appear in the NowPlaying Track node; if omitted, default is \"Unknown Track\"." + }, + "volume_level": { + "name": "Volume Level", + "description": "The temporary volume level that will be used when the media is played. Specify a value of zero to play at the current volume. Default is zero." + }, + "app_key": { + "name": "Bose App Key", + "description": "Bose Developer API application key; if omitted, defaults to a pre-defined App Developer Key." + }, + "get_metadata_from_url_file": { + "name": "Get Metadata From URL?", + "description": "If true, the artist, album, and song title metadata details will be retrieved from the ID3 header of the url content (if available); otherwise, False to use the artist, album, and song title arguments specified." + } + } + }, "preset_list": { "name": "Get Preset List", "description": "Retrieves the list of presets defined to the device.", diff --git a/custom_components/soundtouchplus/translations/en.json b/custom_components/soundtouchplus/translations/en.json index cd5f8ce..2eed975 100644 --- a/custom_components/soundtouchplus/translations/en.json +++ b/custom_components/soundtouchplus/translations/en.json @@ -62,6 +62,82 @@ } } }, + "play_tts": { + "name": "Play TTS Message", + "description": "Play Text-To-Speech notification on a SoundTouch device. Note that this is limited to ST10,20,30 devices, as Bose ST300 does not support notifications (AFAIK).", + "fields": { + "entity_id": { + "name": "Entity ID", + "description": "Entity ID of the SoundTouch device to play the message." + }, + "message": { + "name": "Message Text", + "description": "The message that will be converted from text to speech and played on the device." + }, + "artist": { + "name": "Artist Status Text", + "description": "The text that will appear in the NowPlaying Artist node; if omitted, default is \"TTS Notification\"." + }, + "album": { + "name": "Album Status Text", + "description": "The text that will appear in the NowPlaying Album node; if omitted, default is \"Google TTS\"." + }, + "track": { + "name": "Track Status Text", + "description": "The text that will appear in the NowPlaying Track node; if omitted, default is the message value." + }, + "tts_url": { + "name": "TTS Service Url", + "description": "The Text-To-Speech url used to translate the message. The value should contain a \"{saytext}\" format parameter, that will be used to insert the encoded message text." + }, + "volume_level": { + "name": "Volume Level", + "description": "The temporary volume level that will be used when the media is played. Specify a value of zero to play at the current volume. Default is zero." + }, + "app_key": { + "name": "Bose App Key", + "description": "Bose Developer API application key; if omitted, defaults to a pre-defined App Developer Key." + } + } + }, + "play_url": { + "name": "Play URL Media", + "description": "Play media content from a URL on a SoundTouch device.", + "fields": { + "entity_id": { + "name": "Entity ID", + "description": "Entity ID of the SoundTouch device to play the media." + }, + "url": { + "name": "URL", + "description": "The url to play; value must start with http or https." + }, + "artist": { + "name": "Artist Status Text", + "description": "The text that will appear in the NowPlaying Artist node; if omitted, default is \"Unknown Artist\"." + }, + "album": { + "name": "Album Status Text", + "description": "The text that will appear in the NowPlaying Album node; if omitted, default is \"Unknown Album\"." + }, + "track": { + "name": "Track Status Text", + "description": "The text that will appear in the NowPlaying Track node; if omitted, default is \"Unknown Track\"." + }, + "volume_level": { + "name": "Volume Level", + "description": "The temporary volume level that will be used when the media is played. Specify a value of zero to play at the current volume. Default is zero." + }, + "app_key": { + "name": "Bose App Key", + "description": "Bose Developer API application key; if omitted, defaults to a pre-defined App Developer Key." + }, + "get_metadata_from_url_file": { + "name": "Get Metadata From URL?", + "description": "If true, the artist, album, and song title metadata details will be retrieved from the ID3 header of the url content (if available); otherwise, False to use the artist, album, and song title arguments specified." + } + } + }, "preset_list": { "name": "Get Preset List", "description": "Retrieves the list of presets defined to the device.",