Skip to content

Added media browsing request#50

Merged
zehnm merged 26 commits intounfoldedcircle:mainfrom
albaintor:media_browsing
Mar 27, 2026
Merged

Added media browsing request#50
zehnm merged 26 commits intounfoldedcircle:mainfrom
albaintor:media_browsing

Conversation

@albaintor
Copy link
Copy Markdown
Contributor

Hi Markus @zehnm ,

To begin with the new media browsing in Kodi integration, I modified the Python integration library with new request/messages.

For now I simulate requests and it seems to work correctly.

Only browse_media request is handled at this time. I will add support for play_media and then :

  • clear_playlist
  • browse_media
  • search_media
  • search_media_classes

@albaintor albaintor marked this pull request as draft March 4, 2026 11:47
@zehnm
Copy link
Copy Markdown
Contributor

zehnm commented Mar 4, 2026

Please wait with enhancing the integration library: the Integration-API specification for media browsing and searching is not yet finalized in the core-api repository and might still change!
Also the reference implementation to verify the API is not yet finished.

@albaintor
Copy link
Copy Markdown
Contributor Author

Ok sorry, I was anticipating a little bit too much : I just want to have a working solution, then it won't be a problem to bring some changes. I can keep going with my simulator and raise questions on discord channel.

Copy link
Copy Markdown
Contributor

@zehnm zehnm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python integration library should be similar as the Node.js library.

Instead of a generic params: dict[str, Any] browse parameter, it is much more convenient for integration developers to know what they are getting, and what to send back.
Please check https://github.com/unfoldedcircle/integration-node-library/blob/main/lib/entities/media_player.ts for all definitions.
They can easily be converted into Python classes with your AI agent of choice, including Python docs :-)

Comment thread ucapi/entity.py Outdated
@zehnm
Copy link
Copy Markdown
Contributor

zehnm commented Mar 18, 2026

I can offer to do the refactoring after the next release is out.

@albaintor
Copy link
Copy Markdown
Contributor Author

I am on it

@albaintor
Copy link
Copy Markdown
Contributor Author

All done, I have integrated it locally in Kodi integration and it works fine. Just the pagination "count" field to check vs NodeJS implementation

@albaintor albaintor marked this pull request as ready for review March 19, 2026 11:27
@albaintor albaintor requested a review from zehnm March 19, 2026 11:28
Comment thread ucapi/media_player.py
Comment thread ucapi/api_definitions.py Outdated
data: AssistantEventData | None = None


class MediaContentType(str, Enum):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strEnum is the preferred approach for defining enums. It also aligns with the behavior found when calling asdict() as it returns the value of the enum rather than the enum.

The one question would be if it is better to align with the previous declarations using (str, Enum) or if it is agreed that this is the better approach, using it going forward.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I changed it StrEnum

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do want @zehnm to weigh in on this change. It does break with the other enum definitions. I think it's better, and is a natural break point, but since it isn't like the others we should see what he thinks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm traveling today but should get a chance to look at it on the train

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strEnum definitely makes sense with the minimal Python version 3.11.
I can change all other str, Enum definitions before the next library release.

Comment thread ucapi/api_definitions.py Outdated
Comment thread ucapi/api.py Outdated
Comment thread ucapi/api.py Outdated
Comment thread ucapi/api.py Outdated
Comment thread ucapi/api_definitions.py Outdated
Comment thread ucapi/media_player.py Outdated
Comment thread ucapi/media_player.py
Comment thread ucapi/media_player.py
Comment thread ucapi/api.py Outdated
@albaintor
Copy link
Copy Markdown
Contributor Author

OK I have made the fixes reported by @JackJPowell

Comment thread ucapi/api_definitions.py Outdated
Comment thread ucapi/api_definitions.py Outdated
Comment thread ucapi/media_player.py Outdated
Comment thread ucapi/media_player.py
@albaintor
Copy link
Copy Markdown
Contributor Author

Ok this is done, you can review, thanks

@albaintor albaintor requested review from JackJPowell and zehnm March 20, 2026 14:55
@albaintor albaintor requested a review from zehnm March 24, 2026 18:29
- move media-player related classes to media_player.py
- create msg_definitions.py for internal WS msg data definitions
- Replace MediaType with MediaContentType
- Use StrEnum for all media-player enums
@zehnm
Copy link
Copy Markdown
Contributor

zehnm commented Mar 24, 2026

Since I don't call myself a Python developer, I've asked Junie Pro for some feedback about the enums.
Maybe @JackJPowell can chime in too?


Using MediaClass | str | None is indeed the correct and modern Pythonic way to handle extensible enums. It provides excellent developer experience with IDE autocompletion for known values while remaining flexible.

Why this works well:

  • Static Analysis: Tools like Mypy and Pyright understand that the value can be one of the enum members OR any string.
  • IDE Support: Developers get suggestions for MediaClass.ALBUM, but can also pass "custom_type".
  • Runtime: Since StrEnum values are strings, they serialize to JSON naturally without extra conversion.

I'll prepare the changes and also improve the Paging / Pagination classes. An integration driver should always receive a Paging class for consistent handling.

zehnm added 3 commits March 24, 2026 20:01
- Rename `PagingOptions` to `Paging`
- Replace `PagingOptions` with `Paging` for better consistency.
- Add validation, default values, and utility methods to `Paging`.
- Make Paging mandatory in `BrowseOptions` and `SearchOptions`
- Update references across `media_player.py` and `api.py` to use the new
  `Paging` class.
@zehnm
Copy link
Copy Markdown
Contributor

zehnm commented Mar 24, 2026

Refactoring should be done now. I'll test it tomorrow.

@JackJPowell
Copy link
Copy Markdown
Contributor

I wonder if we could add MediaClass / MediaContentType as optional types instead of str but I think I had issues manipulating enum types instead of strings. I could test this on my side

I suspect the trouble was before the change to strEnum. Glad your testing worked since the change above looks good and looks like it should work 😅

Copy link
Copy Markdown
Contributor

@zehnm zehnm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will fix the media_classes definition in SearchMediaFilter

Comment thread ucapi/media_player.py Outdated
zehnm added 2 commits March 25, 2026 10:15
Updated `media_classes` attribute in `SearchMediaFilter` to accept
both `MediaClass` and custom string values.
Added unit tests.
Copy link
Copy Markdown
Contributor

@zehnm zehnm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed all issues from the last review, added documentation and made the browse and search error handling more robust.

@JackJPowell @albaintor please double check if I didn't introduce new issues :-)

@zehnm zehnm requested a review from JackJPowell March 25, 2026 10:06
zehnm added a commit that referenced this pull request Mar 25, 2026
The media-player module is refactored in PR #50
Comment thread ucapi/api_definitions.py
Comment thread ucapi/api_definitions.py
Comment thread ucapi/media_player.py
if self.album is not None:
validate_str("album", self.album)
if isinstance(self.media_class, str):
validate_str("media_class", self.media_class, 0)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to confirm this was intentional that it's valid to have an empty string for media_class and media_type since None is valid for these too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's a special quirk for Home Assistant. None and empty are different things. And some HA media-player integrations hand out empty media_class and media_type values and expect them again for continue browsing or start playing media.
If you omit it, HA rejects it.
It's also documented in the media-player entity documentation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pytest is the testing framework preference now, but these tests will still run under pytest if we wanted to move in that direction and can be easily converted later. AI can do it in a heartbeat as well.

Comment thread ucapi/api_definitions.py Outdated
Comment thread ucapi/media_player.py
@@ -1,193 +1,659 @@
"""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entity specific classes are not exported in init.py so I assume we don't want to start by adding the new MediaPlayer classes either... but wanted to point it out

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess they should be exported :-) Completely forgot about it!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the unique media-player classes in init.
Python modules and exports will always feel weird to me...
Let me know if you see missing things or other improvements

Copy link
Copy Markdown
Contributor

@JackJPowell JackJPowell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just very minor things. Mostly questions with a couple of additions to init

@JackJPowell
Copy link
Copy Markdown
Contributor

Those last changes look great! I think everything is being exported now.

@zehnm zehnm merged commit e5ed5f9 into unfoldedcircle:main Mar 27, 2026
6 checks passed
@zehnm
Copy link
Copy Markdown
Contributor

zehnm commented Mar 27, 2026

Thanks everyone!

zehnm added a commit that referenced this pull request Apr 10, 2026
Breaking Changes
- Renamed `MediaType` to `MediaContentType` and changed enums to lowercase.
  See media-player entity documentation for more information (#50).
- Changed `str, Enum` to new Python 3.11 `StrEnum` class (#54).
- All entity constructors require named parameters for the optional fields (#49, #54).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants