22
33from __future__ import annotations
44
5- import re
65from typing import Any
76
87from xbox .webapi .api .provider .catalog .models import Image
98from xbox .webapi .api .provider .smartglass .models import (
109 PlaybackState ,
1110 PowerState ,
12- SmartglassConsole ,
1311 VolumeDirection ,
1412)
1513
1614from homeassistant .components .media_player import (
15+ BrowseMedia ,
1716 MediaPlayerEntity ,
1817 MediaPlayerEntityFeature ,
1918 MediaPlayerState ,
2019 MediaType ,
2120)
2221from homeassistant .core import HomeAssistant
23- from homeassistant .helpers .device_registry import DeviceInfo
2422from homeassistant .helpers .entity_platform import AddConfigEntryEntitiesCallback
25- from homeassistant .helpers .update_coordinator import CoordinatorEntity
2623
2724from .browse_media import build_item_response
28- from .const import DOMAIN
29- from .coordinator import ConsoleData , XboxConfigEntry , XboxUpdateCoordinator
25+ from .coordinator import XboxConfigEntry
26+ from .entity import XboxConsoleBaseEntity
3027
3128SUPPORT_XBOX = (
3229 MediaPlayerEntityFeature .TURN_ON
@@ -69,33 +66,10 @@ async def async_setup_entry(
6966 )
7067
7168
72- class XboxMediaPlayer (CoordinatorEntity [ XboxUpdateCoordinator ] , MediaPlayerEntity ):
69+ class XboxMediaPlayer (XboxConsoleBaseEntity , MediaPlayerEntity ):
7370 """Representation of an Xbox Media Player."""
7471
75- def __init__ (
76- self ,
77- console : SmartglassConsole ,
78- coordinator : XboxUpdateCoordinator ,
79- ) -> None :
80- """Initialize the Xbox Media Player."""
81- super ().__init__ (coordinator )
82- self .client = coordinator .client
83- self ._console = console
84-
85- @property
86- def name (self ):
87- """Return the device name."""
88- return self ._console .name
89-
90- @property
91- def unique_id (self ):
92- """Console device ID."""
93- return self ._console .id
94-
95- @property
96- def data (self ) -> ConsoleData :
97- """Return coordinator data for this console."""
98- return self .coordinator .data .consoles [self ._console .id ]
72+ _attr_media_image_remotely_accessible = True
9973
10074 @property
10175 def state (self ) -> MediaPlayerState | None :
@@ -117,15 +91,15 @@ def supported_features(self) -> MediaPlayerEntityFeature:
11791 return SUPPORT_XBOX
11892
11993 @property
120- def media_content_type (self ):
94+ def media_content_type (self ) -> MediaType :
12195 """Media content type."""
12296 app_details = self .data .app_details
12397 if app_details and app_details .product_family == "Games" :
12498 return MediaType .GAME
12599 return MediaType .APP
126100
127101 @property
128- def media_title (self ):
102+ def media_title (self ) -> str | None :
129103 """Title of current playing media."""
130104 if not (app_details := self .data .app_details ):
131105 return None
@@ -135,25 +109,18 @@ def media_title(self):
135109 )
136110
137111 @property
138- def media_image_url (self ):
112+ def media_image_url (self ) -> str | None :
139113 """Image url of current playing media."""
140- if not (app_details := self .data .app_details ):
141- return None
142- image = _find_media_image (app_details .localized_properties [0 ].images )
143-
144- if not image :
114+ if not (app_details := self .data .app_details ) or not (
115+ image := _find_media_image (app_details .localized_properties [0 ].images )
116+ ):
145117 return None
146118
147119 url = image .uri
148120 if url [0 ] == "/" :
149121 url = f"http:{ url } "
150122 return url
151123
152- @property
153- def media_image_remotely_accessible (self ) -> bool :
154- """If the image url is remotely accessible."""
155- return True
156-
157124 async def async_turn_on (self ) -> None :
158125 """Turn the media player on."""
159126 await self .client .smartglass .wake_up (self ._console .id )
@@ -193,15 +160,20 @@ async def async_media_next_track(self) -> None:
193160 """Send next track command."""
194161 await self .client .smartglass .next (self ._console .id )
195162
196- async def async_browse_media (self , media_content_type = None , media_content_id = None ):
163+ async def async_browse_media (
164+ self ,
165+ media_content_type : MediaType | str | None = None ,
166+ media_content_id : str | None = None ,
167+ ) -> BrowseMedia :
197168 """Implement the websocket media browsing helper."""
169+
198170 return await build_item_response (
199171 self .client ,
200172 self ._console .id ,
201173 self .data .status .is_tv_configured ,
202- media_content_type ,
203- media_content_id ,
204- )
174+ media_content_type or "" ,
175+ media_content_id or "" ,
176+ ) # type: ignore[return-value]
205177
206178 async def async_play_media (
207179 self , media_type : MediaType | str , media_id : str , ** kwargs : Any
@@ -214,22 +186,6 @@ async def async_play_media(
214186 else :
215187 await self .client .smartglass .launch_app (self ._console .id , media_id )
216188
217- @property
218- def device_info (self ) -> DeviceInfo :
219- """Return a device description for device registry."""
220- # Turns "XboxOneX" into "Xbox One X" for display
221- matches = re .finditer (
222- ".+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)" ,
223- self ._console .console_type ,
224- )
225-
226- return DeviceInfo (
227- identifiers = {(DOMAIN , self ._console .id )},
228- manufacturer = "Microsoft" ,
229- model = " " .join ([m .group (0 ) for m in matches ]),
230- name = self ._console .name ,
231- )
232-
233189
234190def _find_media_image (images : list [Image ]) -> Image | None :
235191 purpose_order = ["FeaturePromotionalSquareArt" , "Tile" , "Logo" , "BoxArt" ]
0 commit comments