|
22 | 22 | import datetime as dt
|
23 | 23 | from functools import partial
|
24 | 24 | import logging
|
| 25 | +from os import path |
25 | 26 | import re
|
26 | 27 | from typing import Any
|
27 | 28 | import urllib.parse
|
| 29 | +from urllib.parse import unquote |
28 | 30 | from xml.etree import ElementTree
|
29 | 31 | from xml.etree.ElementTree import Element
|
30 | 32 |
|
@@ -909,9 +911,27 @@ def play_media(self, media_type:MediaType|str, media_id:str, **kwargs: Any) -> N
|
909 | 911 |
|
910 | 912 | # is the media an http or https url?
|
911 | 913 | elif re.match(r"http[s]?://", media_id):
|
912 |
| - |
913 |
| - _logsi.LogVerbose("'%s': MediaPlayer play_media detected URL media: Url='%s'", self.name, media_id) |
914 |
| - self._client.PlayUrl(media_id, artist=announceValue, album=announceValue, getMetaDataFromUrlFile=True, volumeLevel=0) |
| 914 | + |
| 915 | + # get the track name portion of the url. |
| 916 | + # example: media_id = "http://192.168.1.248:8123/media/local/01%20The%20First%20Noel.mp3?authSig=ey...nO4" |
| 917 | + # trackName = "01 The First Noel.mp3" |
| 918 | + trackName:str = self._GetUrlFilename(media_id) |
| 919 | + |
| 920 | + # always use the PlayUrl service, as it supports both HTTP and HTTPS url's. |
| 921 | + _logsi.LogVerbose("'%s': MediaPlayer play_media detected URL Notification media: Url='%s'", self.name, media_id) |
| 922 | + self._client.PlayUrl(media_id, artist=announceValue, album=announceValue, track=trackName, getMetaDataFromUrlFile=True, volumeLevel=0) |
| 923 | + |
| 924 | + # commented this code, as most Radio Stations are HTTPS format!!! |
| 925 | + # for announcements, we will use the `PlayUrl` service; otherwise, use the `PlayUrlDlna` service. |
| 926 | + # if announce: |
| 927 | + # _logsi.LogVerbose("'%s': MediaPlayer play_media detected URL Notification media: Url='%s'", self.name, media_id) |
| 928 | + # self._client.PlayUrl(media_id, artist=announceValue, album=announceValue, getMetaDataFromUrlFile=True, volumeLevel=0) |
| 929 | + # else: |
| 930 | + # _logsi.LogVerbose("'%s': MediaPlayer play_media detected URL DLNA media: Url='%s'", self.name, media_id) |
| 931 | + # self._client.PlayUrlDlna(media_id, artist="", album="", track=trackName, artUrl="", updateNowPlayingStatus=True) |
| 932 | + |
| 933 | + # inform Home Assistant of the status update. |
| 934 | + self.schedule_update_ha_state(force_refresh=False) |
915 | 935 |
|
916 | 936 | # is the media a spotify uri?
|
917 | 937 | elif re.match(r"spotify:", media_id):
|
@@ -1485,6 +1505,38 @@ def _FindEntityIdFromClientDeviceId(self, deviceId:str, serviceName:str) -> str:
|
1485 | 1505 | return entity_id
|
1486 | 1506 |
|
1487 | 1507 |
|
| 1508 | + def _GetUrlFilename(self, url:str): |
| 1509 | + """ |
| 1510 | + Returns the filename portion of a media_id url. |
| 1511 | + |
| 1512 | + Args: |
| 1513 | + url (str): |
| 1514 | + media_id url to parse for the file name. |
| 1515 | + |
| 1516 | + Returns: |
| 1517 | + The file name portion of the url if found; otherwise, an empty string. |
| 1518 | + """ |
| 1519 | + try: |
| 1520 | + |
| 1521 | + # get the filename portion of the media_id url. |
| 1522 | + # example: |
| 1523 | + # media_id = "http://192.168.1.248:8123/media/local/01%20The%20First%20Noel.mp3?authSig=ey...nO4" |
| 1524 | + # fileName = "01 The First Noel.mp3" |
| 1525 | + |
| 1526 | + fragment_removed = url.split("#")[0] # keep to left of first # |
| 1527 | + query_string_removed = fragment_removed.split("?")[0] |
| 1528 | + scheme_removed = query_string_removed.split("://")[-1].split(":")[-1] |
| 1529 | + if scheme_removed.find("/") == -1: |
| 1530 | + return "" |
| 1531 | + filename:str = path.basename(scheme_removed) |
| 1532 | + result = unquote(filename) |
| 1533 | + return result |
| 1534 | + |
| 1535 | + except Exception as ex: |
| 1536 | + # ignore exceptions. |
| 1537 | + return "" |
| 1538 | + |
| 1539 | + |
1488 | 1540 | def _GetSourceItemByTitle(self, title:str) -> SourceItem:
|
1489 | 1541 | """
|
1490 | 1542 | Returns a `SourceItem` instance for the given source title value
|
@@ -2275,7 +2327,9 @@ def service_play_url(
|
2275 | 2327 | getMetadataFromUrlFile:bool,
|
2276 | 2328 | ) -> None:
|
2277 | 2329 | """
|
2278 |
| - Play media content from a URL on a SoundTouch device. |
| 2330 | + Plays media from the given URL as a notification message, interrupting the currently playing |
| 2331 | + media to play the specified url. The currently playing will then resume playing once play of |
| 2332 | + the specified URL is complete. |
2279 | 2333 |
|
2280 | 2334 | Args:
|
2281 | 2335 | url (str):
|
@@ -2310,11 +2364,86 @@ def service_play_url(
|
2310 | 2364 | apiMethodParms.AppendKeyValue("volumeLevel", volumeLevel)
|
2311 | 2365 | apiMethodParms.AppendKeyValue("appKey", appKey)
|
2312 | 2366 | apiMethodParms.AppendKeyValue("getMetadataFromUrlFile", getMetadataFromUrlFile)
|
2313 |
| - _logsi.LogMethodParmList(SILevel.Verbose, "SoundTouch Play URL Service", apiMethodParms) |
| 2367 | + _logsi.LogMethodParmList(SILevel.Verbose, "SoundTouch Play URL Notification Service", apiMethodParms) |
2314 | 2368 |
|
2315 | 2369 | # play url.
|
2316 | 2370 | self.data.client.PlayUrl(url, artist, album, track, volumeLevel, appKey, getMetadataFromUrlFile)
|
2317 | 2371 |
|
| 2372 | + # inform Home Assistant of the status update. |
| 2373 | + self.schedule_update_ha_state(force_refresh=False) |
| 2374 | + |
| 2375 | + # the following exceptions have already been logged, so we just need to |
| 2376 | + # pass them back to HA for display in the log (or service UI). |
| 2377 | + except SoundTouchError as ex: |
| 2378 | + raise HomeAssistantError(ex.Message) |
| 2379 | + |
| 2380 | + finally: |
| 2381 | + |
| 2382 | + # trace. |
| 2383 | + _logsi.LeaveMethod(SILevel.Debug, apiMethodName) |
| 2384 | + |
| 2385 | + |
| 2386 | + def service_play_url_dlna( |
| 2387 | + self, |
| 2388 | + url:str, |
| 2389 | + artist:str, |
| 2390 | + album:str, |
| 2391 | + track:str, |
| 2392 | + artUrl:str, |
| 2393 | + updateNowPlayingStatus:bool, |
| 2394 | + delay:int, |
| 2395 | + ) -> None: |
| 2396 | + """ |
| 2397 | + Plays media from the given URL via the Bose DLNA API. |
| 2398 | + |
| 2399 | + Args: |
| 2400 | + url (str): |
| 2401 | + The url to play. |
| 2402 | + Note that HTTPS URL's are not supported by this service due to DLNA restrictions. |
| 2403 | + artist (str): |
| 2404 | + The message text that will appear in the NowPlaying Artist node for source-specific nowPlaying information. |
| 2405 | + Default is "Unknown Artist" |
| 2406 | + album (str): |
| 2407 | + The message text that will appear in the NowPlaying Album node, for source-specific nowPlaying information. |
| 2408 | + Default is "Unknown Album" |
| 2409 | + track (str): |
| 2410 | + The message text that will appear in the NowPlaying Track node, for source-specific nowPlaying information. |
| 2411 | + Default is "Unknown Track" |
| 2412 | + artUrl (str): |
| 2413 | + A url link to a cover art image that represents the URL, for source-specific nowPlaying information. |
| 2414 | + Default is None. |
| 2415 | + updateNowPlayingStatus (bool): |
| 2416 | + True (default) to update the source-specific nowPlaying information; |
| 2417 | + False to not update the source-specific nowPlaying information. |
| 2418 | + delay (int): |
| 2419 | + Time delay (in seconds) to wait AFTER sending the play next track request if |
| 2420 | + the currently playing media is a notification source. |
| 2421 | + This delay will give the device time to process the change before another |
| 2422 | + command is accepted. |
| 2423 | + Default is 1; value range is 0 - 10. |
| 2424 | + """ |
| 2425 | + apiMethodName:str = 'service_play_url' |
| 2426 | + apiMethodParms:SIMethodParmListContext = None |
| 2427 | + |
| 2428 | + try: |
| 2429 | + |
| 2430 | + # trace. |
| 2431 | + apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName) |
| 2432 | + apiMethodParms.AppendKeyValue("url", url) |
| 2433 | + apiMethodParms.AppendKeyValue("artist", artist) |
| 2434 | + apiMethodParms.AppendKeyValue("album", album) |
| 2435 | + apiMethodParms.AppendKeyValue("track", track) |
| 2436 | + apiMethodParms.AppendKeyValue("artUrl", artUrl) |
| 2437 | + apiMethodParms.AppendKeyValue("updateNowPlayingStatus", updateNowPlayingStatus) |
| 2438 | + apiMethodParms.AppendKeyValue("delay", delay) |
| 2439 | + _logsi.LogMethodParmList(SILevel.Verbose, "SoundTouch Play URL DLNA Service", apiMethodParms) |
| 2440 | + |
| 2441 | + # play url. |
| 2442 | + self.data.client.PlayUrlDlna(url, artist, album, track, artUrl, updateNowPlayingStatus, delay) |
| 2443 | + |
| 2444 | + # inform Home Assistant of the status update. |
| 2445 | + self.schedule_update_ha_state(force_refresh=False) |
| 2446 | + |
2318 | 2447 | # the following exceptions have already been logged, so we just need to
|
2319 | 2448 | # pass them back to HA for display in the log (or service UI).
|
2320 | 2449 | except SoundTouchError as ex:
|
|
0 commit comments