Jellyfin binding

Hi openHAB community. I wrote a new binding for Jellyfin.
In case you want to give it a try those are the related links: PR, jar, README.
I hope it is useful for someone else. These are like my two favorite pieces of software, so I will be adding more interactions in the future.
Don’t hesitate to suggest any future additions/improvements here or contribute when it is ready.
Regards!

4 Likes

Great, thanks! Will test it

1 Like

Awesome, will be testing it as well.
Long time jellyfin user here.

Edit: btw @Miguel_M.A.D, can you attach the jar file here and also post functionality etc.? This will make it easier for a wider audience to test.

1 Like

This looks useful. I’m running Jellyfin Server 10.7.7 - I notice in the PR you’re working against the Jellyfin snapshot. If I was to use the binding would it work, and what would be missing?

Yes, it was tested agains a Jellyfin Server 10.7.7.

Seems like I can not upload jar files. I have updated the link to point to the file.

Thanks.

What does the binding expect for User ID (userId)? I’ve tried the main jellyfin user (jellyfin, for me), and the name of the service for which I’ve created an API key (openhab), but both times I get the following error:

12:29:19.813 [ERROR] [rnal.common.AbstractInvocationHandler] - An error occurred while calling method 'ThingHandler.initialize()' on 'org.openhab.binding.jellyfin.internal.handler.JellyfinServerHandler@23b4cf2e': Invalid UUID string: jellyfin
java.lang.IllegalArgumentException: Invalid UUID string: jellyfin
	at java.util.UUID.fromString(UUID.java:215) ~[?:?]
	at org.openhab.binding.jellyfin.internal.handler.JellyfinServerHandler.initialize(JellyfinServerHandler.java:96) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:154) [bundleFile:?]
	at org.openhab.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]
12:29:19.816 [ERROR] [.core.thing.internal.ThingManagerImpl] - Exception occurred while initializing handler of thing 'jellyfin:server:2d8a890a76': Invalid UUID string: jellyfin
java.lang.IllegalArgumentException: Invalid UUID string: jellyfin
	at java.util.UUID.fromString(UUID.java:215) ~[?:?]
	at org.openhab.binding.jellyfin.internal.handler.JellyfinServerHandler.initialize(JellyfinServerHandler.java:96) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:154) [bundleFile:?]
	at org.openhab.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]

Here’s my configuration:

UID: jellyfin:server:2d8a890a76
label: Jellyfin Server
thingTypeUID: jellyfin:server
configuration:
  clientActiveWithInSeconds: 0
  hostname: 192.168.1.177
  port: 8096
  refreshSeconds: 30
  userId: jellyfin
  ssl: false
  token: <redacted>

Other thank creating a new API token, anything else that needs to happen on the Jellyfin server itself?

EDIT: Scratch that, I left the userId blank and then saved, which gave me the following message:

I followed the instructions and now we’re online!

1 Like

Next query: how is a Client Thing configured? Presumably we need to create a Client Thing for each client that could be accessing Jellyfin? In the below do we need to put anything specific that points to a specific client?

Once the Client Thing is created it is OFFLINE, but doesn’t provide any configuration options:

The thing is related to the device by the id which should match the reported deviceId on his session.
But once your bridge is online you could use the discovery service to get those detected. The device should be online and support remote control. Take a look at the readme I have added the link at the top.
Regards!

Got the bridge and thing working (did not try the channels yet) but somehow it seems that my Android TV (Mibox) is not found whereas both my Chrome instance as well as my Android phone are recognized during discovery.
Jellyfin dashboard shows all 3 of them, with Android TV kind of the most important as Chrome (Laptop) and my phone are not really controlling Jellyfin.
Any ideas what could be wrong?

Actually I have a Xiaomi Tv and faced the same problem. After stoping the application from the apps list in settings and open it again the session is exposed to the server again. Maybe they have an issue with the system sleep. I didn’t investigate more or reported it. Hope this works for you. After discover it I automate this using the androiddebugbridge binding.
Another problem I found on the android tv app is the playback state when pause and play are triggered, I reported this one and I think will be fixed soon.

1 Like

Thanks, the force close and restart worked for me as well.
Did a quick test with force closing the app again and the thing went offline, after the defined refresh interval (60 sec for me) it came online again (I restarted Jellyfin on my Mibox).
Will report back once I got some items defined.

OK, that works well. I’m using the web clients and it looks like data is coming through correctly, and I’m able to control the media playback as expected!

Great work, thanks very much!

1 Like

For those luddites like me who like to configure everything in Things files, here’s my configuration:

jellyfin.bridge.things

Bridge jellyfin:server:proxmox "Jellyfin Server" [
	clientActiveWithInSeconds=0,
	hostname="192.168.1.177",
	port=8096,
	refreshSeconds=30,
	ssl="false"
]

Once this has saved you will have to go to

http://YOUROPENHABIP:PORT/jellyfin/proxmox

where proxmox is the ID of my bridge thing as shown in jellyfin:server:proxmox. Sign in with your jellyfin username and password.

Note that even changing the label name on this Bridge Thing requires re-configuring through the URL above.

jellyfin.clients.things

// Clients
Thing jellyfin:client:proxmox:YOURCLIENTIDHERE "Jellyfin Z400 client" (jellyfin:server:proxmox)
Thing jellyfin:client:proxmox:YOURCLIENTIDHERE "Jellyfin Android client" (jellyfin:server:proxmox)

I found that working out how to get a client ID was tough. In the end here’s a silly method:
Go to your Logs section in the dashboard.

http://YOURJELLYFINIPADDRESS:PORT/web/index.html#!/log.html

Click on one of the logs. The URL of the log should include an api_key= part. Copy that key, and then go to the following URL substituting COPIEDAPIKEY for the key you just copied:

http://YOURJELLYFINIPADDRESS:PORT/Devices?api_key=COPIEDAPIKEY

You will now be presented with a bunch of JSON for each device. Find the device of interest, and copy the Id parameter into the YOURCLIENTIDHERE section of the Things file.

jellyfin.items

Example for the Jellyfin Android client:

String strJellyfinAndroidPlayStateCommand { channel="jellyfin:client:proxmox:28a2fb42432f1b35:play-state-command", stateDescription=""[options="STOP=Stop, PAUSE=Pause, UNPAUSE=Unpause, NEXT_TRACK=Next track, PREVIOUS_TRACK=Previous track, REWIND=Rewind, FAST_FORWARD=Fast forward, PLAY_PAUSE=Play Pause"]}
String strJellyfinAndroidSendNotification { channel="jellyfin:client:proxmox:28a2fb42432f1b35:send-notification " }
Player plJellyfinAndroidMediaControl { channel="jellyfin:client:proxmox:28a2fb42432f1b35:media-control" }
String strJellyfinAndroidPlayingItemName { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-name" }
String strJellyfinAndroidPlayingItemSeriesName { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-series-name" }
String strJellyfinAndroidPlayingItemSeasonName { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-season-name" }
Number nJellyfinAndroidPlayingItemSeason { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-season" }
Number nJellyfinAndroidPlpayingItemEpisode { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-episode" }
String strJellyfinAndroidPlayingItemGenders { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-genders" }
String strJellyfinAndroidPlayingItemType { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-type" }
Dimmer dJellyfinAndroidPlayingItemPercentage { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-percentage" }
Number nJellyfinAndroidPlayingItemSecond { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-second" }
Number nJellyfinAndroidPlayingItemTotalSeconds { channel="jellyfin:client:proxmox:28a2fb42432f1b35:playing-item-total-seconds" }
String strJellyfinAndroidPlayByTerms { channel="jellyfin:client:proxmox:28a2fb42432f1b35:play-by-terms" }
String strJellyfinAndroidPlayByNextTerms { channel="jellyfin:client:proxmox:28a2fb42432f1b35:play-next-by-terms" }
String strJellyfinAndroidPlayByLastTerms { channel="jellyfin:client:proxmox:28a2fb42432f1b35:play-last-by-terms" }
String strJellyfinAndroidBrowseByTerms { channel="jellyfin:client:proxmox:28a2fb42432f1b35:browse-by-terms" }

I really appreciate you have shared this. I will add it to the end of the readme if you don’t mind.
You don’t need to add the api token in the first step it is also filled in the next step as for the userId when you go to

http://YOUROPENHABIP:PORT/jellyfin/proxmox

and login.

Sure, no problem! I will also add the Items configuration at some point, once I’ve done it…!

Ah, very clever! I have removed that parameter from the example.

EDIT
@Miguel_M.A.D I’ve added an Items file example to the previous post.

An observation: playing-item-genders is quite strange English - gender is male, female etc. Looking at the Item whilst something is playing, should this actually be playing-item-category?

1 Like

Just to report back, the Mibox shows a similar behavior to your TV.
Once it restarts/wakes up from sleep the Thing is back to “offline”.
As you mentioned, workaround would be to use adb to force close the app on restart (my Mibox is though connected wit USB to ETH).

1 Like

Mine is connected through wifi.
I didn’t identify if it is a problem with how Xiaomi implements the device sleep or if it’s a general problem. I’ll try this afternoon to force sleep my Fire TV and see if the problem appears there.
Also I’m going to compile and install the app from the main branch to see if the problem with the pause state is solved and I’ll take the opportunity to test this one also. If the problem persists there I will open an issue now that I know is not only happening on my device.
Will keep you posted.
Thanks for sharing your case.

1 Like

The pause state reporting seems to be fixed on the main branch :smiley: .
The issue with the system sleep keeps happening. I have opened and issue there Device session is not exposed after system sleep. · Issue #1336 · jellyfin/jellyfin-androidtv · GitHub.

Oh wow! I hope that it works on a small htpc running kodi with the Jellyfin plugin that connects to my old Dell R720 running TrueNAS scale and Jellyfin server .

I can’t wait for the official GitHub merge!