[Jellyfin] Overhaul README.md (#16359)

* Overhaul README.md

- Fix some typos
- Add some code brackets
- Some formatting changes

* Minor spelling and grammar changes

Signed-off-by: Felix Schneider <fs@felix-schneider.org>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Felix Schneider 2024-03-22 14:37:00 +01:00 committed by Ciprian Pascu
parent fd5b27d50c
commit cd8b4faec8

View File

@ -1,52 +1,44 @@
# Jellyfin Binding # Jellyfin Binding
This is the binding for [Jellyfin](https://jellyfin.org) the volunteer-built media solution that puts you in control of your media. This is the binding for [Jellyfin](https://jellyfin.org), the volunteer built media solution that puts you in control of your media.
Stream to any device from your own server, with no strings attached. This binding allows you to connect to Jellyfin clients that supports remote control, it's built on top of the official Jellyfin Kotlin SDK.
Your media, your server, your way. It is compatible with Jellyfin servers from version `10.8.1`, recommended is `10.8.13`.
This binding allows connect to Jellyfin clients that supports remote control, it's build on top of the official Jellyfin kotlin sdk.
Compatible with Jellyfin servers from version 10.8.1, recommended 10.8.13.
## Supported Things
This binding was tested against the android tv, and web clients.
The only problem that I found is that the channels play-next-by-terms and play-last-by-terms don't work currently on the android tv client.
Before open an issue please test you are able to correctly control your device from the Jellyfin web ui to identify whetter is an issue on the client itself.
## Discovery ## Discovery
Before you are able to discover clients you should have a bridge to the server so until one is online the discovery will only look for servers on your local network. Once one is online the discovery will detect controllable clients connected to that server. To discover clients, you must first configure a server (bridge).
After that, device discovery will detect controllable clients.
## Thing Types ## Thing Types
| ThingTypeID | description | | ThingTypeID | Description |
|----------|------------------------------| |-----------------|---------------------------------------|
| server (bridge) | Jellyfin server instance | | server (bridge) | Jellyfin server instance |
| client | Jellyfin controllable client instance | | client | Jellyfin controllable client instance |
## Authentication ## Authentication
To allow the server thing to go online you should provide valid credentials for the user that the biding will use to interact with the server api (userId and token configuration properties). To allow the server thing to go online, you must provide valid credentials (`userId` and `token`) for the user that the biding will use to interact with the server.
Please note that the user should be allowed on the Jellyfin server to remote control devices. Please note that the user should be allowed on the Jellyfin server to remote control devices.
In order to assist you with this process the binding expose a simple login form you can access on \<local openHAB server url\>/jellyfin/\<server thing id\> for example `http://127.0.0.1:8080/jellyfin/2846b8fb60ad444f9ebd085335e3f6bf`. In order to assist you with this process the binding expose a simple login form you can access on `<local openHAB server url>/jellyfin/<server thing id>` (example `http://127.0.0.1:8080/jellyfin/2846b8fb60ad444f9ebd085335e3f6bf`).
## Server Thing Configuration ## Server Thing Configuration
| Config | Type | description | | Config | Type | Description |
|---------------------------|---------|----------------------------------------------------------------------------------------------| |---------------------------|---------|----------------------------------------------------------------------------------------------|
| hostname | text | Hostname or IP address of the server (required) | | hostname | Text | Hostname or IP address of the server (required) |
| port | integer | Port of the server (required) | | port | Integer | Port of the server (required) |
| ssl | boolean | Connect through https (required) | | ssl | Boolean | Connect through https (required) |
| path | text | Base path of the server | | path | Text | Base path of the server |
| refreshSeconds | integer | Interval to pull devices state from the server | | refreshSeconds | Integer | Interval to pull devices state from the server |
| clientActiveWithInSeconds | integer | Amount off seconds allowed since the last client activity to assert it's online (0 disabled) | | clientActiveWithInSeconds | Integer | Amount of seconds allowed since the last client activity to assert it's online (0 disabled) |
| userId | text | The user id | | userId | Text | The user id |
| token | text | The user access token | | token | Text | The user access token |
## Channels ## Channels
| channel | type | description | | channel | Type | Description |
|----------------------------|--------|-----------------------------------------------------------------------------------------------------------------| |----------------------------|--------|-----------------------------------------------------------------------------------------------------------------|
| send-notification | String | Display message in client | | send-notification | String | Display message in client |
| media-control | Player | Control media playback | | media-control | Player | Control media playback |
@ -56,7 +48,7 @@ In order to assist you with this process the binding expose a simple login form
| playing-item-season-name | String | Name of the item's season currently playing, only have value when item is an episode (readonly) | | playing-item-season-name | String | Name of the item's season currently playing, only have value when item is an episode (readonly) |
| playing-item-season | Number | Number of the item's season currently playing, only have value when item is an episode (readonly) | | playing-item-season | Number | Number of the item's season currently playing, only have value when item is an episode (readonly) |
| playing-item-episode | Number | Number of the episode item currently playing, only have value when item is an episode (readonly) | | playing-item-episode | Number | Number of the episode item currently playing, only have value when item is an episode (readonly) |
| playing-item-genders | String | Coma separate list genders of the item currently playing (readonly) | | playing-item-genders | String | Comma-separated list genders of the item currently playing (readonly) |
| playing-item-type | String | Type of the item currently playing (readonly) | | playing-item-type | String | Type of the item currently playing (readonly) |
| playing-item-percentage | Dimmer | Played percentage for the item currently playing, allow seek | | playing-item-percentage | Dimmer | Played percentage for the item currently playing, allow seek |
| playing-item-second | Number | Current second for the item currently playing, allow seek | | playing-item-second | Number | Current second for the item currently playing, allow seek |
@ -70,20 +62,30 @@ In order to assist you with this process the binding expose a simple login form
| play-last-by-id | String | Add to playback queue as last by id, works for series, episodes and movies | | play-last-by-id | String | Add to playback queue as last by id, works for series, episodes and movies |
| browse-by-id | String | Browse media by id, works for series, episodes and movies | | browse-by-id | String | Browse media by id, works for series, episodes and movies |
### Terms search: ### Terms Search
The terms search has a default behavior that can be modified sending some predefined prefixes. The terms search has a default behavior that can be modified by sending some predefined prefixes.
The default behavior will look for movies, series, or episodes whose name start with the provided text, if it found results the prevalence go as said before. The default behavior is to search for movies, series or episodes whose name starts with the given text.
If the result is a series the binding will try to resume some episode, if not it will look for the next episode to watch and finally will fall back to the first episode. If it finds results the bind will proceed as said before.
If the result is a series, the binding will try to resume some episode.
If not, it will look for the next episode to watch and finally will fall back to the first episode.
You can prefix your search with '\<type:movie\>', '\<type:episode\>', '\<type:series\>' to restrict your search to a given type. You can prefix your search with `<type:movie>`, `<type:episode>`, `<type:series>` to limit your search to a specific type.
Also, you can target a specific series episode by season and episode numbers prefixing your search with '\<season:1\>\<episode:1\>' with the desired values. So '\<season:3\>\<episode:10\>Something' will try to play the episode 10 for the season 3 of the series named 'Something'. You can also search for a specific series episode by season and episode number by prefixing your search with `<season:1><episode:1>` with the desired values.
So `<season:3><episode:10>Something` will try to play episode `10` of season `3` of the series called `Something`.
## Known Limitations
This binding has been tested with an Android TV and web client.
The only issue that was found is that the `play-next-by-terms` and `play-last-by-terms` channels currently don't work on the Android TV client.
Before opening an issue, please test that you are able to control your device correctly from the Jellyfin web UI to determine if it is a client-side issue.
## Full Example ## Full Example
### Example Server (Bridge) - jellyfin.bridge.things ### Example Server (Bridge) - jellyfin_bridge.things
```java ```java
Bridge jellyfin:server:exampleServerId "Jellyfin Server" [ Bridge jellyfin:server:exampleServerId "Jellyfin Server" [
@ -97,35 +99,36 @@ Bridge jellyfin:server:exampleServerId "Jellyfin Server" [
] ]
``` ```
- token and userId could be retrieved using the login form at `http://YOUROPENHABIP:PORT/jellyfin/exampleServerId` The `token` and `userId` can be obtained using the login form at `http://YOUROPENHABIP:PORT/jellyfin/exampleServerId`
### Example Client - jellyfin.clients.things ### Example Client - jellyfin_clients.things
```java ```java
Thing jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID> "Jellyfin Web client" (jellyfin:server:exampleServerId) Thing jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID> "Jellyfin Web client" (jellyfin:server:exampleServerId)
Thing jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID> "Jellyfin Android client" (jellyfin:server:exampleServerId) Thing jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID> "Jellyfin Android client" (jellyfin:server:exampleServerId)
``` ```
- I recommend creating the clients using the discovery. For getting the device ids manually I recommend to use the Jellyfin web interface with the web inspector and look for the request that is launched when you click the cast button (<jellyfin url>/Sessions?ControllableByUserId=XXXXXXXXXXXX). It is recommended to create the clients using the discovery.
To get the device ids manually, it is possible to use the Jellyfin web interface with the web inspector and look for the request that is launched when you click the cast button (`<jellyfin url>/Sessions?ControllableByUserId=XXXXXXXXXXXX`).
### Example Items - jellyfin.items ### Example Items - jellyfin.items
```java ```java
String strJellyfinAndroidSendNotification { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:send-notification " } String strJellyfinAndroidSendNotification { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:send-notification " }
Player plJellyfinAndroidMediaControl { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:media-control" } Player plJellyfinAndroidMediaControl { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:media-control" }
String strJellyfinAndroidPlayingItemId { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-id" } String strJellyfinAndroidPlayingItemId { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-id" }
String strJellyfinAndroidPlayingItemName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-name" } String strJellyfinAndroidPlayingItemName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-name" }
String strJellyfinAndroidPlayingItemSeriesName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-series-name" } String strJellyfinAndroidPlayingItemSeriesName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-series-name" }
String strJellyfinAndroidPlayingItemSeasonName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-season-name" } String strJellyfinAndroidPlayingItemSeasonName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-season-name" }
Number nJellyfinAndroidPlayingItemSeason { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-season" } Number nJellyfinAndroidPlayingItemSeason { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-season" }
Number nJellyfinAndroidPlpayingItemEpisode { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-episode" } Number nJellyfinAndroidPlpayingItemEpisode { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-episode" }
String strJellyfinAndroidPlayingItemGenders { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-genders" } String strJellyfinAndroidPlayingItemGenders { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-genders" }
String strJellyfinAndroidPlayingItemType { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-type" } String strJellyfinAndroidPlayingItemType { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-type" }
Dimmer dJellyfinAndroidPlayingItemPercentage { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-percentage" } Dimmer dJellyfinAndroidPlayingItemPercentage { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-percentage" }
Number nJellyfinAndroidPlayingItemSecond { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-second" } Number nJellyfinAndroidPlayingItemSecond { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-second" }
Number nJellyfinAndroidPlayingItemTotalSeconds { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-total-seconds" } Number nJellyfinAndroidPlayingItemTotalSeconds { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-total-seconds" }
String strJellyfinAndroidPlayByTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-by-terms" } String strJellyfinAndroidPlayByTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-by-terms" }
String strJellyfinAndroidPlayByNextTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-next-by-terms" } String strJellyfinAndroidPlayByNextTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-next-by-terms" }
String strJellyfinAndroidPlayByLastTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-last-by-terms" } String strJellyfinAndroidPlayByLastTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-last-by-terms" }
String strJellyfinAndroidBrowseByTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:browse-by-terms" } String strJellyfinAndroidBrowseByTerms { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:browse-by-terms" }
``` ```