#Media

1 messages · Page 1 of 1 (latest)

ashen birch
#

Chat about media in Home Assistant. Media sources, browsers and players.

#

@gilded tangle let's chat !

gilded tangle
prime socket
#

Media search would be awesome! HEOS would be able to implement that!

gilded tangle
#

@ashen birch what would you actually want to search for? A name: str | None and an allowed_content_types: set[MediaClass] as suggested?
Do you remember what Erik meant with searching for asterisks (image/*)? If we only filter down to MediaType that should seems unnecessary?

ashen birch
#

Let’s follow the search method that music assistant uses

#

Basically we should allow searching for artist named Beatles

#

So that would be media classes I think? Not file types

prime socket
#

I’d suggest making MediaType optional with the default None to mean all types supported by the platform. That’s how most UI implementations work as well.

#

(That’s also how music assistant works)

gilded tangle
ashen birch
#

@gilded tangle left a comment

#

I think the main thing is that we should add this to media players only first

#

and not media source

gilded tangle
#

I started adding it as media source because when checking browsing a lot of media players rely on media_source.async_browse

#

That’s why I thought about adding it to source first and player as follow up

#

But I guess we could do either

ashen birch
#

I think that we should only initially offer search for media players that have their own backing collection (ie spotify, music assistant, sonos)

#

let's avoid the whole "how are we going to merge search results from different sources"

gilded tangle
#

But also how would we handle a search for albums & artist and a title of „the beatles“

#

Which would give you both the album as well as the artist

#

Just throw them in the same result set?

ashen birch
#

that's up to the integration

#

I think for now we can just allow a single media type ?

#

and not multiple

#

so you either search for albums or artists

#

not both

gilded tangle
#

Because for service responses it shouldn’t matter as much

#

But changing it if integrations already implemented it that way is annoying

ashen birch
#

right

gilded tangle
#

so this should be pretty straightforward, the only thing I can't quite wrap my head around are the function parameters. I think we should have both query and allowed_media_class to allow for server side filtering. But should we also keep media_content_type and media_content_id to ensure we only get content relevant to that integration? New draft PR https://github.com/home-assistant/core/pull/140321/files

ashen birch
#

Content Id is to search in a specific folder

#

I wonder if we should add a new Boolean to folders if they are searchable.

#

And if so, we pass content type and ID of folder, query and type were looking for

#

So you can go into a playlist folder and search playlists

prime socket
#

I think adding "searchable" makes sense. I'd also suggest that Content Id be optional. For example, search in HEOS is global -- not constrained by a specific part of the browsable tree. It can be scoped to a specific music service (or multiple), which could be represented as a top-level folder, which then is "searchable=True". However, I think you'd want the UI to allow search at anytime, regardless of where you've navigated, thus an empty content id.

prime socket
gilded tangle
prime socket
#

In the method parameters what would media_content_type parameter be used for? Here's how I understand them now:

  • media_content_id container to search (or None for a global search). It would be a Media item that was marked searchable from the platform's browse.
  • query: The search string itself
  • target_media_classes an optional set of the types of items to return in the results. An empty set means all available items are included.

I'm wondering if we actually want target_media_classes to be target_content_types (with str as a valid option), as the platform may have unique items not currently represented in HA.

#

To be honest, I'm unclear on why we have both MediaType and MediaClass anyway. 😅

ashen birch
#

media_content_id is not enough, it always needs to be paired with a media_content_type. That's been a design mistake from Past Paulus

#

Same with media classes and media types…

#

I think that we should stick to media types, because if we don't, we cannot make a UI for it

#

every field in the UI would end up being a text box in the end if we were to do that 🙈

prime socket
#

Oh right, I forgot about the pairing of content_id and content_type.

prime socket
ashen birch
#

yes

prime socket
#

Seperate question (related to Media), what's the right way to represent paging in browse? I was thinking I could essentially create a virtual folder to represent the "Next Page" as the last item, but that feels clugy, especially if the service action is being used programatically.

ashen birch
#

we don't currently support pages

#

so yeah virtual ones is possible, also feels hacky

#

especially because the folder would be shown at the top I think ?

prime socket
#

I'll play around with it and see what happens

#

Another question related to browse, should I put all of the HEOS-specific sources at the root level alongside the media_source root items? (per screenshot) Or would it be better to put them all in a sub-item (i.e. "HEOS Music")?

#

(The first 7 items come from HEOS, the others are coming from media_source)

#

Sorry if this isn't the right place to ask, happy to take it elsewhere too

gilded tangle
#

As a user I'd definitely rather have them in an Integration specific folder

#

That’s what plex and sonos are doing at least maybe check those

prime socket
#

Sounds good and makes sense. Agree with consistency.

ashen birch
#

I believe we put all individual sources and then media source folders

#

No specific heos folder

#

Hm I only have a Sonos to test here

#

And it’s just one folder for favorites so hard to say which thing they follow

#

Anyway consistency is important

prime socket
#

I did an analysis of all 39 integrations that implement async_browse_media. Of these, only 9 combine media source and integration sources. Paulus was correct that that the standard is to put the individual sources first:

  • 7 integrations add local sources before media sources (music_assistant, forked_daapd, kodi, roku, sonos, sqeezebox, and yamaha_musiccast)
  • 1 integration adds local sources after media sources (cast)
  • 1 integration adds an integration folder before media sources (apple_tv)
#

Josef, note, Plex does not support media sources, it's only integration sources.

prime socket
#

Would this be valuable for me to submit an architectural item to memorialize the approach?

ashen birch
#

I would just open a dev docs PR and document it as such

prime socket
#

Will do!

gilded tangle
#

The only thing is that now all integrations need to care about overlaps with other integrations sonos/spotify&plex and so on

prime socket
#

True, however I don’t know if there are any actual products that support both a local source and the same one through a music source. Do you know of any that concretely do?

Maybe Sonos, but the integration doesn’t expose integration music services (ie Spotify). I don’t know if that’s a limitation of the API, or just not implemented though.

Plex doesn’t appear to expose browsing Tidal (their integrated music service) through their APIs.

gilded tangle
#

sonos does with both plex and spotify

prime socket
#

Right, but is there an overlap with sources Sonos provides via the integration itself?

gilded tangle
#

if I understood it correctly there is an overlap, but they just pass those to the integrations

#

like sonos would have a plex source, but they call plex.browse for those instead

prime socket
#

Yeah, it does that in the integration, I’m just not sure the Sonos library or APIs actually can browse directly though, meaning there was a potential overlap.

#

(And they chose to defer to the built in music source versions)

#

Seems like it should intuitively though. 🤔 HEOS does. However HEOS doesn’t offer a way to play something from the Sonos integration. At least, I haven’t been able to figure out how to translate that. 😂

gilded tangle
#

their app does yes

prime socket
#

Yeah

gilded tangle
#

like you can play something from plex in the sonos app

prime socket
#

Oh I know, but do their APIs and the SoCo lib allow that?

#

Just checked their source code, it does

#

Looks like it’s a different API with different auth in the cloud than when connecting to the local device. Interesting.

#

Fun it’s SOAP 😂

ashen birch
#

Sonos doesn't allow browsing spotify library natively

#

But Sonos can play Spotify links

#

so instead we have this cool thing where if you have Spotify integration set up, you can browse Spotify via Sonos media browser

gilded tangle
# ashen birch yes

I added pagination parameters. Mind checking if you’re fine with the spec then I'd continue with tests and try to give frontend a shot (although that is still very strange to me)

ashen birch
#

Got a link again

prime socket
#

ATTR_SEARCH_OFFSET_OR_NEXT feels stronge to me. Is that meant to mean page index offset or record offset?

#

And allow str? What would that be for?

#

Typically I’ve see record pagination using the combination page size and index or record start and end.

gilded tangle
prime socket
gilded tangle
#

Hm probably true

ashen birch
#

I would just start without pagination for now 🙂

prime socket
#

Yeah, I agree. I’d want to solve paging for Browse too. I’ll see if I have time to submit an arch proposal for that this weekend.

ashen birch
#

this looks great @gilded tangle

#

@lilac trail just want to keep you in the loop, we're working on media search for HA here

#

it's following the approved architecture issue

prime socket
#

How would we want to handle wildcards in the search query? I’m not sure all platforms will support it, but HEOS can accept “Beatles” to match that exactly in metadata or “Beatles*”. Would we want the implicit behavior to be “Beatles” or exact match? Or leave it up to tie platforms?

#

lol I can’t figure out how to escape an asterisk when on mobile

ashen birch
#

leave it up to platforms

#

I would say

#

in general, all searches are now considered to have a * I would expect

#

like, we're not using AND and NOT anymore either

#

beatles OR rolling stones AND submarine

lilac trail
#

Note that when we implemented the search for Music Assistant, we really quickly realized you need more context, hence we also have the optional artist and album fields to narrow down the search. This is especially important when the search is being used by an LLM to do automated lookups. Only do name lookups on a title is not enough if you want the results to be accurate.

#

We could also simplify that by accepting a splitter and let the integration deal with it

ashen birch
#

So in our current API we have the source where search originated

#

so if you have browsed to an artist folder, you can search within that

#

or would you expect to just have like 10 fields

#

query_artist, query_song etc

#

because voice can fill in those spots ?

#

while in the UI we would just do query. ?

#

and if an integration doesn't implemenet it, it can just concatenate all the fields to make a query

lilac trail
#

you always search on name/title

so MediaType.ARTIST + name "Queen"
or MediaType.PLAYLIST + name "Top40"

But in case of albums and songs, the chances of duplicates increase because the titles/names are not unique so you need/may provide ADDITIONAL context.

For example MediaType.ALBUM + name "Innuendo" + search_artist "Queen"
Which could also have been just the name field but typed as "Queen - Innuendo"

#

So, its optional context which also makes it easier to implement, an integration that supports it, listens for it

#

search on just innuendo gets me multiple results. Now in this case MA is smart enough to give back queen first as that is in the library but this could also have been something you dont listen often and then there is a potential of returning wrong items. Again, with automated searches. If you browse manually yourself you obvisously just pick the correct one by hand

#

So that is why we ended up with this now in the HA action...

#

the artist and album fields are optional but really recommended when an LLM is using the search

#

If we want to keep things simple for now, I'd opt for the seperator in the searchphrase

gilded tangle
lilac trail
#

Yeah, and then its up to the integration to actually support that

prime socket
#

I understand the problem, though I don’t think we want to push logic for splitting the query into each integration. Is there a way we can still have the parameters but abstracted? Like accept a dict[MediaType, str] called “constraints” or “context”?

ashen birch
#

let's start simple

#

it's good to think about these constraints, but they can also be added in step 2

gilded tangle
#

problem is changing that always will require integration changes

#

which we can't easily do from a core perspective

#

so I'd rather have the interface 95% correct even if we don't utilize certain parameters for now

ashen birch
#

Well just like having a response class, we could consider a request class

#

service call -> internal handler puts it in object -> calls the platform service handler

prime socket
#

I like that idea

primal gazelle
#

Its very simple, essentially "The page token will be an opaque string, and the format is specific to the integration."

prime socket
#

Yeah that would cover most use cases I can think off. Essentially the UI would show a “Next page” as long as the token isn’t None and pass that in to the browse function to get next result set.

#

It could easily support paging in reverse if it became “next_token” and “previous_token”

primal gazelle
#

the browser can also fetch as you scroll down the page in the UI without a need for a button press. (scroll up for reverse)

gilded tangle
#

Got sidetracked with breaking firmware update in one of my integrations will resume once that is solved

ashen birch
#

@gilded tangle are you still working on this? Would you be open for others to take over if you don't have time ?

#

We're quite close to the finish line of this landing and it would be awesome 🙂

gilded tangle
#

Or rather until next Thurday

ashen birch
#

nah no need for .4

#

because it's foundation, and it needs others to build on top

#

I was just going through my notes, hence the ping

prime socket
#

I’ll implement search for HEOS as soon as it’s ready. Also game to help out with the foundation too.

gilded tangle
ashen birch
#

We can ask Andy to pick up your PR if you want, it should be close to finish

gilded tangle
#

I've pushed the suggested changes, please have a look

ashen birch
#

this looks great

#

few tiny comments on the comments 😄

gilded tangle
#

hehe

#

I'll add tests later in the Hotel then

gilded tangle
#

small status update, other tests are fixed, just need my local media_player tests working and I'll add the test

terse frost
ashen birch
#

yeah that's fine

ashen birch
#

!!!

#

@gilded tangle merged 🎉

inland ember
#

Nice!

prime socket
#

Wohoo! Nice work @gilded tangle! Can’t wait to implement search in HEOS this weekend! 😃

dry token
#

Really exciting to see search and pagination 🙂 I'm just looking at adding it to Squeezebox now. One quick q - when you implement the action, will you consider supporting an optional extras dictionary? There's application specific parameters I'd like to add for Squeezebox when calling the action - e.g. to be able to override defaults tags which define what fields are returned - or perhaps a maximum number of returned items.

wary grove
#

So we have music assistant included in home assistant. I have also seen Kodi & Jellyfin Wouldn't it seem to be a way to merge the best parts into one system?

dry token
#

I may be being dumb, but there's no services.yaml, strings.json in the PR. I see the new action, but there's no UI for it currently.

#

Sorry if I'm missing something dumb

dry token
#

I see that SearchMedia takes list[BrowseMedia]. Is each BrowseMedia element parent with the search results as children to for example let you split a result across multiple media types, or is this just a list of the child elements - i.e. one BrowseMedia item for each search result with no hierarchy.

#

Sorry - not clear from the doc.

frank hazel
# dry token Sorry if I'm missing something dumb

I also just tried implementing for music_assistant and found that nothing seems to change when implementing the SEARCH_MEDIA feature and function.

I also thought I must be missing something obvious.

gilded tangle
frank hazel
gilded tangle
#

whoops 😅

frank hazel
#

Will there be a UI addition similar to the browse_media button in the near future also?

#

Well, I applied the service definition and strings locally and the service call now works well

dry token
#

it's always a relief when it's not me being dumb - that's been known to happen 😉

#

Is this supposed to also update the functionality of the media browser. I assume so if we set can_search, but nothing changes, so I guess the front end pr isn't done yet - is that right? Linked to my earlier question on the SearchMedia result - where should we set can_search?

#

BTW - thanks again - this is a much needed feature (and hence we're all asking loads of questions while you're still spinning the wheels)

gilded tangle
gilded tangle
#

someone needs to build it first 😉

dry token
#

I see that currently search_query is required, but media_content_id is optional. If I'm searching by media_content_id, then I likely won't want a search string as well - it's likely one or the other if the media_content_id identifies a specific item. I might want to seach using the content_id to get more details, but I can't do that if the search_query is required. Is there any reason for them to not all be optional and then to let us raise ServiceValidationErrors if the pattern doesn't work for us

rugged verge
#

Would it be mostly text search? Can it have filters for metadata?

dry token
# rugged verge Would certainly love a UI for that ☺️😉

You can filter the query for the action by content_media_type (e.g. albums, artists, playlists etc.) or by content_media_id and you can filter the response by the class of media, which is integration dependent, but might be "track", or for squeezebox, "audio" or "playlist"

ashen birch
#

once we get results we can see what types are in the results

dry token
#

We'll just have to document the supported media_types etc. in the integration docs. I proposed an adr to extend the standard list of media_types (e.g. include albums, artists etc.) but that didn't seem to be supported, so we can just add the allowed entries in the doc and raise errors for unsupported types

frank hazel
#

Would also like to see radio and audiobook in supported types 😉

#

But radio can be covered currently simply by the music type, so that isn't such a problem as audiobook

ashen birch
#

Let’s first get the basics out and usable before we look into expanding it

frank hazel
dry token
#

I've been working on the squeezebox integration with this and thinking about the return value from SearchMedia(), which currently takes list[BrowseMedia]. For now it doesn't matter, since it's just the response variable, but if we think about how this will integrate into the media browser at some point, I think this should be BrowseMedia, with the response being its children - i.e the same way we build a response for browse_media.

    return BrowseMedia(
        title=result.get("title"),
        media_class=media_class["item"],
        children_media_class=media_class["children"],
        media_content_id=search_id,
        media_content_type=search_type,
        can_play=any(child.can_play for child in children),
        children=children,
        can_expand=True,
    )

For the media browser, I imagine a situation where when we set can_search=True, we get the ability to enter a search string. Then the result from that search would be a BrowseMedia item for the media browser to display . If we're going to integrate the response to async_search_media into the media browser at some point, shouldn't the return type be the same as async_browse_media - i.e. BrowseMedia, rather than list[BrowseMedia]?

frank hazel
#

I think I follow, you're suggesting that a returned BrowseMedia object is in and of itself the more appropriate container of the results as children, rather than a list of BrowseMedia objects?

dry token
#

Yes - exactly that. That's already the mechanism we use to return a response from async_browse_media for the media browser, so if we want to integrate the search capability at some point, doesn't it make sense to use the same object for async_search_media

frank hazel
#

Sounds like a reasonable suggestion.

dry token
#

Just thinking that if we release this as it is, then integrating it into media browser in the future will be difficult, and perhaps a breaking change for anyone that's already used the action in its current form

dry token
#

it also makes writing the integration update easier as I've just basically just passed a new search string variable to the code I used to build the browse_media response

#

i.e. just thinking about search as something which produces the same output as browse

#

and just updating the browse code to take a search param

dry token
#

ok - squeezebox is done. I need to get a library update pushed. Extending the functions I already had for async_browse_media to take a search string and re-using those made it pretty straight forwards to implement.

frank hazel
dry token
dry token
#

once this is done, i'll be trying to use this to build some basic voice control blueprints for squeezebox. Combining search_media to find the content_id and then play_media to play it should be pretty straight forwards. "Play favorite classic fm in the den".... Tricky bit will be when the search finds more than one result ... hmmm... Full text seaching in the squeezebox api is pretty basic..

ashen birch
#

We should just make a real voice intent and solve it for all

#

The intent handler would just search and then play first result

#

Sentence matching helps to define filters

#

Play a song by ARTIST

dry token
#

a general voice intent would be v. nice

#

tricky to make it generic though - integrations define their own media_content_types

#

e..g. i have favorites, which has a mediaclass of favorite

#

the naming for albums isn't even standardised - i mean everyone will likely call it albums, but it's not defined as a standard

#

so, a general implementation might say "play ziggy stardust album", which would want to search the "albums" media content type, but that might not exist, or might be called releases for example. Until now, it didn't really matter what we called them internally, but now we're beginning to expose them in browse_media, search_media and play_media the naming matters more.

#

i proposed an adr recently to extend that list of standard types to try and improve this, but the feedback was that since it could never be an exhaustive list, we shouldn't make it longer, but i think it makes generalising any of these services or intents more unreliable for users.

dry token
# frank hazel Do you already have a PR in? I'd be interested in seeing your implementation.

PR is https://github.com/home-assistant/core/pull/143261. As you'll see, async_search_media is very short because I'm basically just re-using all the functionality already built for async_browse_media. There's more changes relating to tidying up the media_content_types etc., and making sure that if someone entered something different to what's used internally, that the search & browse still respond correctly.

nocturne phoenix
#

Is this supposed to be in the Media browser if you don't have NC subscription?
It appears to not work, if you try to "Say" I just get a spinning loading wheel forever. 😕

ashen birch
#

hm it used to not be loaded in the past

dry token
#

I don't know if it's related, but I now have 2 entries for Home Assistant Cloud - one with the NC icon and one without.

ashen birch
#

Fixed in latest beta

dry token
#

Hey @ashen birch I saw your comment in the LLM project #1346946515511279696 message re: your PR adding a general search and play intent to the media player https://github.com/home-assistant/core/pull/144269. Very exciting and I thought very interesting for this project as well. If I'm reading it right, if we've implemented MediaPlayerEntityFeature.SEARCH_MEDIA this should just work :-). It did re-raise my question on why async_search_media returns an array of BrowseMedia, whereas async_browse_media returns a BrowseMedia object with an array of children. Wouldn't it be easier for the hopeful future integration of search in the media browser UI to have async_search_media return the same as async_browse_media - and would be more consistent for future implementations. I just raise this now since your PR is likely the first thing using async_search_media. I've added it to the Squeezebox integration - just waiting for a library update to be pushed - so looking forward to having this intent available.

GitHub

GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.

ashen birch
#

So the return value can still be changed. For integrations the format already includes an object.

dry token
#

My thought was more that the return value from async_search_media is an array of BrowseMedia objects - i.e. children with no parent, so you're using result[0] for the first result, whereas async_browse_media returns a single BrowseMedia object with an array of children. So, wouldn't it be more consistent for async_search_media to return the same structure as async_browse_media - e.g. a parent which we could call something like "Search Results" and then the results are in the children, so the result for the intent would be different.

I guess I don't really understand why async_search_media and async_browse_media return different structures.

ashen birch
#

I’m missing what you’re saying. If I look at the entity method, it’s a SearchMedia object as return value

dry token
#

Right, and SearchMedia is defined as

class SearchMedia:
    """Represent search results."""

    version: int = field(default=1)
    result: list[BrowseMedia]

So, why

result: list[BrowseMedia]

rather than

result: BrowseMedia

why's it a list of BrowseMedia objects, rather than just a single BrowseMedia object and use the children to contain the search results. I may be missing something obvious (certainly won't be the first or last time), but we're using BrowseMedia here in a different way to the way we use it in async_browse_media, where there's a parent with children. I know it doesn't really matter, but there doesn't seem to be any reason to do it this way, rather than do it the same way as we use BrowseMedia elsewhere and consistency seems to make sense. Also, assuming at some point we want to use the search results as part of a UI for browse media, then we'll need the parent/child structure.

ashen birch
#

That whole class is the return value

gilded tangle
#

The reason I made it a list is that during browsing you always have a tree with a common root element. A search could return any branch or leaf of that tree. So to not have to include a common root that logically shouldn’t be part of the search result it’s a list

#

And in the UI you'll always want to see the results not the root, which would be the children list, hence we might already give it the list

dry token
# gilded tangle The reason I made it a list is that during browsing you always have a tree with ...

Thanks @gilded tangle I get that it doesn't matter when we're just thinking of the results being used in the action as they are currently. But, if you want to be able to use async_search_media to facilitate search UI for media browsing at some point in the future, then don't you need the parent of the children to provide the parental info - title, can_play etc.. I know it doesn't matter atm, but doesn't doing it with the list rather than parent/child store up potential problems for the future?

gilded tangle
#

In the UI you might wanna see a album next to a title in the search results, which doesn’t really make sense in the usual tree structure of BrowseMedia. Each BrowseMedia child would usually set their own properties so I don’t see why we'd need a root object just for the sake of it

dry token
#

I know this isn't currently in scope, but wouldn't integrating search into the media browser need a "normal" browse media tree with the parent info? I completely get that you don't need this for the action, but if we want to use this function to add search UI in the future, won't this cause problems?

#

Sorry if I'm fixating on this, but just trying to get something clear in my head.

gilded tangle
#

The UI isn't built yet, so it'll take whatever we give it. As I was trying to say earlier: In a search you would want to present a user only with the children of the BrowseMedia (which is a list) anyways (and not first click on the root element returned by the search). So we'll need to build the UI to handle a list[BrowseMedia] in any case, so I don't see a point in returning that first BrowseMedia root

dry token
#

Yes, I understand it's not built yet (and I'll definately put my hand up and admit I know nothing about front end coding), and I concur completely that you would just want the list, rather than clicking first on a parent. But, don't you also need data from the parent - specifically title and can_play? The overall browse media window needs a title, and you can set can_play at the list level so you can just click play once to play all the results. If you don't have the info from the parent, then you don't have a way to pass this overall info back.

gilded tangle
#

I don't think so. The title is basically just "search results" and if you wanna play the list, you can just queue up all list items that have can_play

dry token
#

but if you just passed a parent/child back, then you let the integration set the title, which I might want to set to something more specific - search result for zyz album - but other might not- and yes, you can click each item, but why would you effectively skip functionality which exists in the browser - if you search for something which returns 20 items, having to click each one would be frustrating when it's not necessary elsewhere. You could say the same for a list of tracks rather than a search result, but the can_play is there for a reason. I guess I just don't understand the downside of returning the parent/child when it allows us to pass information that might be used. In the integration, we'll likely be using the same code as we do to build the browse response, so we have it all anyway. In the action, you can just use the children, but if we don't pass back the parent info, we just don't have it for when we might want it.

ashen birch
#

I am very confused, at what level is a list being returned ?

dry token
#

As you say, async_search_media returns SearchMedia, which is

class SearchMedia:
    """Represent search results."""

    version: int = field(default=1)
    result: list[BrowseMedia]

I guess I think this should be

class SearchMedia:
    """Represent search results."""

    version: int = field(default=1)
    result: BrowseMedia

and we use the children in BrowseMedia to contain the list of results - i.e. the same way as we use the parent/child relationship in async_browse_media

children: Sequence[BrowseMedia] | None = None,

That would allow us to pass "parent" info back from async_search_media rather than just "child" info.

#

There's likely nothing useful in the parent info for the action, but it gives us the flexibility in the future.

ashen birch
#

If there is a specific need for providing search metadata, it should be added to the SearchMedia class

#

Each class has it's own concerns

#

the metadata of a search query are not the same as a playable folder/item

dry token
#

but don't they kinda need to be the same if we want to integrate the results of a search into the media browser window at some point? We're already using BrowseMedia objects for the search result items, but if we want to use the overall search results in the future in a media browser window, we'd need all the same data as a "normal" folder so that it can be displayed in the same way. As you say, we could do that by maybe adding another dictionary at that point to the SeachMedia class to allow us to pass back the necessary data, but then we're kinda just recreating everything that's alredy in BrowseMedia.

gilded tangle
ashen birch
#

One interesting discussion came up recently and that is that we have different media sources

#

Media players like Sonos or Cast will list media sources that are provided by other integrations

#

Should we explore how we can allow media sources to offer search ?

#

For example, the Radio Browser integration would allow to search for radio stations.

ashen birch
trim pike
#

@gilded tangle
Sorry that I'm late to the party, but I am just now getting around to implementing the search_media service in my SpotifyPlus (MediaPlayerEntity) integration.

Are there any plans to enhance the async_search_media method to include extra keyword arguments? Kind of like what the play_media method does for ENQUEUE support?

It would be nice to be able to pass some custom keyword arguments to the underlying interface, which is currently not possible with the static SearchMedia parameters. For example:

  • spotify_limit_total:int - contains the max # of items to return for each type.
  • spotify_market:str - contains an ISO 3166-1 alpha-2 country code. If a country code is specified, only content that is available in that market will be returned.
  • spotify_include_external:str - If "audio" is specified it signals that the client can play externally hosted audio content, and marks the content as playable in the response. By default externally hosted audio content is marked as unplayable in the response.

Example service call:

action: media_player.search_media
data:
  entity_id: media_player.spotifyplus_todd_l
  search_query: "Beatles"
  media_filter_classes:
    - album
    - artist
    - track
  spotify_limit_total: 25
  spotify_market: ES
  spotify_include_external: audio

I could then do something like this in the search_media method to access those parameters:

    # get keyword arguments (if any).
    spotify_limit_total:str = kwargs.get("spotify_limit_total", None)
    spotify_market:str = kwargs.get("spotify_market", None)
    spotify_include_external:str = kwargs.get("spotify_include_external", None)

Thoughts?

dry token
# trim pike <@1169191964646846487> Sorry that I'm late to the party, but I am just now gett...

Yes - I've also made the same request. Since it changes an entity model, I wrote it up as an architecture discussion, with the necessary changes at https://github.com/home-assistant/architecture/discussions/1241 but it hasn't got anywhere.

GitHub

Background The async_search_media action currently allows searching by a string, and querying by media_content_type, media_content_id and filterig the result set by media_filter_classes. There'...

trim pike
#

@dry token Thanks for the architecture discussion link; I added my use case example to it. Hopefully it gains some traction. Your proposed code really is a simple (and elegant) solution to the problem - nice work!

dry token
#

Thanks @trim pike . Yes, I could really do with extras support as well - there are searches you can't do currently which mean people can't migrate off using the native api, which was part of my goal with implement async_search.

#

I haven't submitted a PR since this is an entity model change so needs an approved architecture discussion, but I don't know anyway to push it forwards, so just been waiting basically.

dry token
#

I wonder if the right approach is to submit the PR and reference the arch discussion, but that seems a bit presumptuous.

dry token
nocturne phoenix
ashen birch
#

The challenge is that sometimes people do want to enter a normal URL

#

or they want to enter a deep link they manually crafted

#

which I guess, could be included in the media browser as a custom mode maybe

#

hidden behind an overflow menu

nocturne phoenix
#

I guess there's always yaml mode.

#

Guess I didn't realize normal urls were even possible there? Thought it had to be a media:// thing.

ashen birch
#

Depends 😬

nocturne phoenix
#

But the other day I was like trying to just do a basic thing, like play a song I had in my media folder and it's nearly impossible to figure out what the media_content_id is. The only reason I was even successful was I knew how to hack it out of browser developer-tools 😬 .

ashen birch
#

Basically, if media source / media browsing is supported, it also supports URLs

#

as media sources resolve to URLs (which can be local, but don't have to)

#

Yeah 100% agree

#

that's why the media selector was updated for media ID in assist_satellite.announce

#

definitely would be nice to bring this to play_media

#

so I am with you, but we might miss some

#

My vision for media source is that it will replace all use cases for local path in core

#

anytime we allow uploading something, it should be selectable in media browser

ashen birch
#

Did something recently change on the media browser? The vertical gap is too small

#

ah looks like the vertical gap changes as the width of the window changes

dusky gazelle
#

I think the whole view needs a design review

nocturne phoenix
#

When I pull up the media browser to select a specific content type (e.g. image), at the root level browse I get non-imagey sources like Radio Browser and TTS. Is there or should there be something to filter out these sources?

Inspecting the websocket response, I don't see anything in the information returned that could tell me about what kind of content I might find in those sources. Every root source child says:

media_class: "app",
media_content_type: "apps",
children_media_class: null

I'm not very clear on how these three keys are expected to be used.

Should something be set in one of these to indicate that this particular source has only a certain type, e.g. audio?

ashen birch
#

we don't have group content type

#

Would help here

nocturne phoenix
#

I think I'm confused between a media_class and a content_type. Are they explained on any of the dev docs?
children_media_class wouldn't be a way to represent that?

ashen birch
#

Yeah it's a hot mess

#

I don't know anyone knows what's what ...

#

I think media class was used for rendering frontend either square or rectangle