From 8824ee0131ace0550c5e141a0bb65da6745e6d48 Mon Sep 17 00:00:00 2001 From: Jon Kristian Nilsen Date: Thu, 27 Jul 2023 21:29:00 +0200 Subject: [PATCH] Handle cases where source is an external player which doesnt have artist meta and player control. Fix clear playlist. --- README.md | 35 ++++++++++-- custom_components/casatunes/manifest.json | 6 +-- custom_components/casatunes/media_player.py | 59 ++++++++++++++------- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index b2e0766..5e10528 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # CasaTunes -[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge)](https://github.com/custom-components/hacs) + +[![GitHub Release][releases-shield]][releases] +[![License][license-shield]](LICENSE) +[![hacs][hacsbadge]][hacs] +![Project Maintenance][maintenance-shield] +[![BuyMeCoffee][buymecoffeebadge]][buymecoffee] [CasaTunes](https://www.casatunes.com/) is a Multi-Room audio system. With CasaTunes, you can pick and choose from our flexible line of music servers and matrix amplifiers to create the perfect multiroom audio solution for your customers, whether looking for an entry, value, or high performance solution. @@ -18,8 +23,32 @@ Download or clone and copy the folder `custom/components/casatunes` into your `c Your casatunes unit should be discovered automatically, if this doesn't happen, please go to integrations and add it manually with the ip address of your unit. ## Attributions -@alphasixtyfive for the first casatunes component +- [alphasixtyfive] for the first casatunes component. +- This component uses the excellent [integration_blueprint] from [ludeeus]. + +## Contributions are welcome! + +If you want to contribute to this please read the [Contribution guidelines](CONTRIBUTING.md) + +*** ⭐️ this repository if you found it useful ❤️ -Buy Me A Coffee +[![BuyMeCoffee][buymecoffebadge2]][buymecoffee] + +[casatunes]: https://github.com/jonkristian/casatunes +[buymecoffee]: https://www.buymeacoffee.com/jonkristian +[buymecoffeebadge]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?style=for-the-badge +[buymecoffebadge2]: https://bmc-cdn.nyc3.digitaloceanspaces.com/BMC-button-images/custom_images/white_img.png +[hacs]: https://github.com/hacs/integration +[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge +[forum-shield]: https://img.shields.io/badge/community-forum-brightgreen.svg?style=for-the-badge +[forum]: https://community.home-assistant.io/ +[license-shield]: https://img.shields.io/github/license/jonkristian/casatunes.svg?style=for-the-badge +[maintenance-shield]: https://img.shields.io/badge/maintainer-Jon%20Kristian%20Nilsen%20%40jonkristian-blue.svg?style=for-the-badge +[releases-shield]: https://img.shields.io/github/release/jonkristian/casatunes.svg?style=for-the-badge +[releases]: https://github.com/jonkristian/casatunes/releases +[exampleimg]: example.png +[integration_blueprint]: https://github.com/ludeeus/integration_blueprint +[ludeeus]: https://github.com/ludeeus/ +[alphasixtyfive]: https://github.com/alphasixtyfive/ \ No newline at end of file diff --git a/custom_components/casatunes/manifest.json b/custom_components/casatunes/manifest.json index 574edbf..30beb3b 100644 --- a/custom_components/casatunes/manifest.json +++ b/custom_components/casatunes/manifest.json @@ -4,9 +4,9 @@ "config_flow": true, "documentation": "https://github.com/jonkristian/casatunes", "issue_tracker": "https://github.com/jonkristian/casatunes/issues", - "version": "0.1.5", + "version": "0.1.6", "requirements": [ - "pycasatunes==0.1.2" + "pycasatunes==0.1.3" ], "ssdp": [ { @@ -18,4 +18,4 @@ "@jonkristian" ], "iot_class": "local_polling" -} \ No newline at end of file +} diff --git a/custom_components/casatunes/media_player.py b/custom_components/casatunes/media_player.py index 646e129..44f01ee 100644 --- a/custom_components/casatunes/media_player.py +++ b/custom_components/casatunes/media_player.py @@ -134,14 +134,16 @@ async def async_will_remove_from_hass(self): def _media_playback_trackable(self) -> bool: """Detect if we have enough media data to track playback.""" if ( - self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Duration - is None + 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying) + and self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Duration + is not None ): - return False + return ( + self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Duration + > 0 + ) - return ( - self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Duration > 0 - ) + return False def _casatunes_entities(self) -> list[CasaTunesMediaPlayer]: """Return all media player entities of the casatunes system.""" @@ -180,16 +182,23 @@ def name(self) -> str | None: @property def state(self) -> str | None: """Return the state of the device.""" - if self.zone.Power is True: - state = self.coordinator.data.nowplaying[self.zone.SourceID].Status - return STATUS_TO_STATES.get(state, None) - else: - return STATE_OFF + if self.zone.Power: + if 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying): + curr_song = self.coordinator.data.nowplaying[ + self.zone.SourceID + ].CurrSong + if curr_song is not None: + state = self.coordinator.data.nowplaying[self.zone.SourceID].Status + return STATUS_TO_STATES.get(state, None) + return STATE_ON + return STATE_OFF @property def shuffle(self): """Boolean if shuffle is enabled.""" - return self.coordinator.data.nowplaying[self.zone.SourceID].ShuffleMode + if 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying): + return self.coordinator.data.nowplaying[self.zone.SourceID].ShuffleMode + return None @property def volume_level(self) -> str | None: @@ -219,22 +228,30 @@ def source_list(self): @property def media_track(self): """Return the track number of current media (Music track only).""" - return self.coordinator.data.nowplaying[self.zone.SourceID].QueueSongIndex + if 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying): + return self.coordinator.data.nowplaying[self.zone.SourceID].QueueSongIndex + return None @property def media_title(self): """Title of current playing media.""" - return self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Title + if 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying): + return self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Title + return None @property def media_artist(self): """Artist of current playing media, music track only.""" - return self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Artists + if 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying): + return self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Artists + return None @property def media_album_name(self): """Album name of current playing media, music track only.""" - return self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Album + if 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying): + return self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.Album + return None @property def media_duration(self) -> int | None: @@ -272,7 +289,11 @@ def media_content_type(self): @property def media_image_url(self): """Image url of current playing media.""" - return self.coordinator.data.nowplaying[self.zone.SourceID].CurrSong.ArtworkURI + if 0 <= self.zone.SourceID < len(self.coordinator.data.nowplaying): + return self.coordinator.data.nowplaying[ + self.zone.SourceID + ].CurrSong.ArtworkURI + return None @property def media_image_remotely_accessible(self): @@ -432,8 +453,8 @@ async def async_play_media(self, media_type, media_id, **kwargs): async def async_clear_playlist(self): """Send the media player the command for clear playlist.""" - await self._player.async_clear_playlist() + await self.coordinator.data.clear_playlist(self.zone.SourceID) async def search(self, keyword): """Emulate opening the search screen and entering the search keyword.""" - await self.coordinator.data.search_media(self.zone_id, keyword) \ No newline at end of file + await self.coordinator.data.search_media(self.zone_id, keyword)