Add media_image to media_player component#5754
Conversation
|
I think that will kill the new cache layer on media_player and give a bad performance while it fetch this ever state change for "platform" fetch. I known that is only for platform they use this way. I think it will be better to have it as property and update with platform update process. So the platform can update if it needed with regular update interval. I think that will a lot of more perform as a function they will call ever state change. |
|
I agree and that is how I have implemented it in the Apple TV platform (but I have not pushed that yet). In this case, the async version of the get method is not really needed I guess (since we already have the image cached in the platform). But this still doesn't solve the problem of frontend not knowing that an image exist. Since all requests to the proxy are redirected if a cache image exist, any url from media_image_url will do. So I guess a hack would be to just return "something" in that method... |
|
I agree with @pvizeli However this has a downside of the platform fetching the image even if no one is looking at the UI. The platform can do something complicated, like each time the property is queried save a timestamp that will cause the it to update for some time in the future. As far as frontend is concerned it looks at the existence of |
|
I agree @andrey-git, it's not optimal that the image is fetched even when the frontend is not used. But I still think it's fine, changing the API in pyatv to return a URL would be more of a hack than this. I can probably re-work this in a better way later. |
There was a problem hiding this comment.
media image could be (None, None).
There was a problem hiding this comment.
Automatically fixed by my new commit.
There was a problem hiding this comment.
A constant url will lead to constant md5 and the browser caching this image.
The md5 should run on the image itself, or part of it or a separate property.
There was a problem hiding this comment.
Good point. I added so that media_image also returns a hash. This way the hash only needs to be calculated once instead of with every call.
|
@pvizeli You OK with merging this? |
There was a problem hiding this comment.
Need only (None, None) since it will evertime create a hash on https://github.com/postlund/home-assistant/blob/654ba940dc8d93e02445bf8fcc2255895a90472c/homeassistant/components/media_player/__init__.py#L826-L828 so we have no improve with that.
There was a problem hiding this comment.
Problem is that the hash generated by entity_picture depends on url - all the other factors are always the same (entity_id and access token). So in reality, the hash is just a transformation of the url from an entity point-of-view, so it must be different for every image otherwise we will always generate the same url for the client. This is basically what @andrey-git commented on earlier, so I still feel certain that we need to do this to avoid caching problems. Agree?
There was a problem hiding this comment.
You have if url is None twice in code. make only else: return
balloob
left a comment
There was a problem hiding this comment.
I think that we should alter the code slightly. Properties are not allowed to do I/O so it means that whenever we call update, platforms implementing media_image will have to download the album cover. That is not optimal.
Another tricky part is the hashing part of images. We can't know if the image has changed until we get the image. I think because of that we should add a hash property media_image_hash. This will solve the entity_picture problem.
Can I suggest a slightly different approach:
- Add a
media_image_hashproperty that returns a hash string, defaults to None - Test if media player supports media image by checking if
player.media_image_hash is not None - Add
async_get_media_imagemethod (with sync versionget_media_image) that will return bytes and content type.
|
Good point. I will try to update according to this tonight. |
|
Hi, according to gitter chat, I'd like to suggest to use a more global solution. URLs might allow for file:// schemas. This would be extensible later to other schemas (ftp, memory-mapped...). Caching might be included here too. I have implemented file:// support in media_player (jjmontesl@9e28138) which might be of interest, but is still limited to media_player. I suggest a more global solution to reduce code. |
|
@balloob I've tried to get my head around this but I don't think I fully understand how it's supposed to work. How does |
|
Something like this: (note: didn't run this code) # Overwrite this in ATV case
@property
def media_image_hash(self):
url = self.media_image_url
if url is not None:
return hashlib.md5(url.encode('utf-8')).hexdigest()[:5]
return None
# Overwrite this in ATV case
@asyncio.coroutine
def async_get_media_image(self):
url = self.media_image_url
if url is None:
return None, None
return (yield from _async_fetch_image(self.hass, url))
@property
def entity_picture(self):
"""Return image of the media playing."""
if self.state == STATE_OFF:
return None
image_hash = self.media_image_hash
if image_hash is None:
return None
return ENTITY_IMAGE_URL.format(
self.entity_id, self.access_token, image_hash)And for the web view: @asyncio.coroutine
def get(self, request, entity_id):
"""Start a get request."""
player = self.entities.get(entity_id)
if player is None:
status = 404 if request[KEY_AUTHENTICATED] else 401
return web.Response(status=status)
authenticated = (request[KEY_AUTHENTICATED] or
request.GET.get('token') == player.access_token)
if not authenticated:
return web.Response(status=401)
data, content_type = yield from player.async_get_media_image()
if data is None:
return web.Response(status=500)
return web.Response(body=data, content_type=content_type) |
|
Ok, looks good. I guess I have to check if |
654ba94 to
0bca1ef
Compare
|
You don't have to generate the hash based on the image content. You can base it on the content ID, current artist + album + song title or whatever information you have available to uniquely identify the content. |
0bca1ef to
e574651
Compare
|
You are so wise, @balloob! 😄 I made your proposed changes and they work. Will update my other PR with the Apple TV changes. Then we should be able to leave this behind. |
|
Please update this when you are done, as #5877 is waiting for this :-) |
|
Great code! 😉 🐬 |
|
Unittests? |
Description:
Purpose of this PR is to add a media_image concept to media_player that can serve binary images (when a platform provides that instead of a URL) through media_player_proxy. This is based on comments from @balloob in PR #5698.
It is currently not complete as the frontend must somehow know if there is an image available. This is determined by media_entity_picture and that doesn't really fit with this implementation. Ideas to solve this is welcome as that would help me complete the Apple TV platform.
Checklist:
If the code does not interact with devices:
toxrun successfully. Your PR cannot be merged unless tests pass