From 9d34e83f71af0e8f7466ca18fa316ca1281c9ba3 Mon Sep 17 00:00:00 2001 From: Manu Date: Sat, 27 Jun 2026 17:39:48 +0200 Subject: [PATCH] Remove Clementine Music Player (#174970) --- .../components/clementine/__init__.py | 1 - .../components/clementine/manifest.json | 10 -- .../components/clementine/media_player.py | 166 ------------------ homeassistant/generated/integrations.json | 6 - requirements_all.txt | 3 - script/hassfest/quality_scale.py | 2 - 6 files changed, 188 deletions(-) delete mode 100644 homeassistant/components/clementine/__init__.py delete mode 100644 homeassistant/components/clementine/manifest.json delete mode 100644 homeassistant/components/clementine/media_player.py diff --git a/homeassistant/components/clementine/__init__.py b/homeassistant/components/clementine/__init__.py deleted file mode 100644 index 668ba937345f..000000000000 --- a/homeassistant/components/clementine/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The clementine component.""" diff --git a/homeassistant/components/clementine/manifest.json b/homeassistant/components/clementine/manifest.json deleted file mode 100644 index 42fe81d0e9b9..000000000000 --- a/homeassistant/components/clementine/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "domain": "clementine", - "name": "Clementine Music Player", - "codeowners": [], - "documentation": "https://www.home-assistant.io/integrations/clementine", - "iot_class": "local_polling", - "loggers": ["clementineremote"], - "quality_scale": "legacy", - "requirements": ["python-clementine-remote==1.0.1"] -} diff --git a/homeassistant/components/clementine/media_player.py b/homeassistant/components/clementine/media_player.py deleted file mode 100644 index 216819a5730a..000000000000 --- a/homeassistant/components/clementine/media_player.py +++ /dev/null @@ -1,166 +0,0 @@ -"""Support for Clementine Music Player as media player.""" - -from datetime import timedelta -import time -from typing import override - -from clementineremote import ClementineRemote -import voluptuous as vol - -from homeassistant.components.media_player import ( - PLATFORM_SCHEMA as MEDIA_PLAYER_PLATFORM_SCHEMA, - MediaPlayerEntity, - MediaPlayerEntityFeature, - MediaPlayerState, - MediaType, -) -from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST, CONF_NAME, CONF_PORT -from homeassistant.core import HomeAssistant -from homeassistant.helpers import config_validation as cv -from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType - -DEFAULT_NAME = "Clementine Remote" -DEFAULT_PORT = 5500 - -SCAN_INTERVAL = timedelta(seconds=5) - -PLATFORM_SCHEMA = MEDIA_PLAYER_PLATFORM_SCHEMA.extend( - { - vol.Required(CONF_HOST): cv.string, - vol.Optional(CONF_ACCESS_TOKEN): cv.positive_int, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, - } -) - - -def setup_platform( - hass: HomeAssistant, - config: ConfigType, - add_entities: AddEntitiesCallback, - discovery_info: DiscoveryInfoType | None = None, -) -> None: - """Set up the Clementine platform.""" - - host = config[CONF_HOST] - port = config[CONF_PORT] - token = config.get(CONF_ACCESS_TOKEN) - - client = ClementineRemote(host, port, token, reconnect=True) - - add_entities([ClementineDevice(client, config[CONF_NAME])]) - - -class ClementineDevice(MediaPlayerEntity): - """Representation of Clementine Player.""" - - _attr_media_content_type = MediaType.MUSIC - _attr_supported_features = ( - MediaPlayerEntityFeature.PAUSE - | MediaPlayerEntityFeature.VOLUME_STEP - | MediaPlayerEntityFeature.PREVIOUS_TRACK - | MediaPlayerEntityFeature.VOLUME_SET - | MediaPlayerEntityFeature.NEXT_TRACK - | MediaPlayerEntityFeature.SELECT_SOURCE - | MediaPlayerEntityFeature.PLAY - ) - _attr_volume_step = 0.04 - - def __init__(self, client, name): - """Initialize the Clementine device.""" - self._client = client - self._attr_name = name - - def update(self) -> None: - """Retrieve the latest data from the Clementine Player.""" - try: - client = self._client - - if client.state == "Playing": - self._attr_state = MediaPlayerState.PLAYING - elif client.state == "Paused": - self._attr_state = MediaPlayerState.PAUSED - elif client.state == "Disconnected": - self._attr_state = MediaPlayerState.OFF - else: - self._attr_state = MediaPlayerState.PAUSED - - if client.last_update and (time.time() - client.last_update > 40): - self._attr_state = MediaPlayerState.OFF - - volume = float(client.volume) if client.volume else 0.0 - self._attr_volume_level = volume / 100.0 - if client.active_playlist_id in client.playlists: - self._attr_source = client.playlists[client.active_playlist_id]["name"] - else: - self._attr_source = "Unknown" - self._attr_source_list = [s["name"] for s in client.playlists.values()] - - if client.current_track: - self._attr_media_title = client.current_track["title"] - self._attr_media_artist = client.current_track["track_artist"] - self._attr_media_album_name = client.current_track["track_album"] - self._attr_media_image_hash = client.current_track["track_id"] - else: - self._attr_media_image_hash = None - - except Exception: - self._attr_state = MediaPlayerState.OFF - raise - - @override - def select_source(self, source: str) -> None: - """Select input source.""" - client = self._client - sources = [s for s in client.playlists.values() if s["name"] == source] - if len(sources) == 1: - client.change_song(sources[0]["id"], 0) - - @override - async def async_get_media_image(self) -> tuple[bytes | None, str | None]: - """Fetch media image of current playing image.""" - if self._client.current_track: - image = bytes(self._client.current_track["art"]) - return (image, "image/png") - - return None, None - - @override - def mute_volume(self, mute: bool) -> None: - """Send mute command.""" - self._client.set_volume(0) - - @override - def set_volume_level(self, volume: float) -> None: - """Set volume level.""" - self._client.set_volume(int(100 * volume)) - - def media_play_pause(self) -> None: - """Simulate play pause media player.""" - if self.state == MediaPlayerState.PLAYING: - self.media_pause() - else: - self.media_play() - - @override - def media_play(self) -> None: - """Send play command.""" - self._attr_state = MediaPlayerState.PLAYING - self._client.play() - - @override - def media_pause(self) -> None: - """Send media pause command to media player.""" - self._attr_state = MediaPlayerState.PAUSED - self._client.pause() - - @override - def media_next_track(self) -> None: - """Send next track command.""" - self._client.next() - - @override - def media_previous_track(self) -> None: - """Send the previous track command.""" - self._client.previous() diff --git a/homeassistant/generated/integrations.json b/homeassistant/generated/integrations.json index 32277115e0db..79279c961148 100644 --- a/homeassistant/generated/integrations.json +++ b/homeassistant/generated/integrations.json @@ -1047,12 +1047,6 @@ "config_flow": false, "iot_class": "cloud_polling" }, - "clementine": { - "name": "Clementine Music Player", - "integration_type": "hub", - "config_flow": false, - "iot_class": "local_polling" - }, "clickatell": { "name": "Clickatell", "integration_type": "hub", diff --git a/requirements_all.txt b/requirements_all.txt index a76aa0efbc6a..dc52f0c8260b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2620,9 +2620,6 @@ python-bsblan==6.1.4 # homeassistant.components.citybikes python-citybikes==0.3.3 -# homeassistant.components.clementine -python-clementine-remote==1.0.1 - # homeassistant.components.digital_ocean python-digitalocean==1.13.2 diff --git a/script/hassfest/quality_scale.py b/script/hassfest/quality_scale.py index 7f88c046e8eb..17ff2214ef87 100644 --- a/script/hassfest/quality_scale.py +++ b/script/hassfest/quality_scale.py @@ -220,7 +220,6 @@ INTEGRATIONS_WITHOUT_QUALITY_SCALE_FILE = [ "cisco_mobility_express", "cisco_webex_teams", "citybikes", - "clementine", "clickatell", "clicksend", "clicksend_tts", @@ -1160,7 +1159,6 @@ INTEGRATIONS_WITHOUT_SCALE = [ "cisco_mobility_express", "cisco_webex_teams", "citybikes", - "clementine", "clickatell", "clicksend", "clicksend_tts",