How-To: Display Kodi cover- and fanart in HABPanel

How-To: Display Kodi cover- and fanart in HABPanel.

This topic describes a way to enable the display of cover- and fanart in HABPanel. This how-to has been tried and tested on openHAB 2.2-SNAPSHOT and Kodi 17.3, but should work just as well with openHAB 2.0 and later.

Prerequisites:

  • A running Kodi instance, Allow control of Kodi via HTTP enabled. Optionally secured with a username and password.
  • OpenHAB and the Kodi Binding installed and configured. An item must be available for each of the following channels: title and mediatype. In the rule below the items for these channels are named Kodi_Title and Kodi_MediaType.
  • JSONPath Transformation installed.
  • Kodi logo from @ThomDietrich’s openhab-config Github repository: kodi.svg.

When all prerequisites are fulfilled we can start configuring openHAB.

Configuration:

Copy the kodi.svg image file to the <Site configuration>/html/static/ directory. This image will be shown when nothing is playing. Of course you’re free to choose any image you like.

Create a new items file: <Site configuration>/items/kodi.items

String Kodi_Fanart_Url        "Fanart URL [%s]"
String Kodi_Thumbnail_Url     "Thumbnail URL [%s]"

These two String items will contain the fanart and thumbnail URLs which will function as the images sources used by HABPanel (it also works with the Classic UI).

Next create a new rules file: <Site configuration>/rules/kodi.rules

// --- imports ------------------------------------------------------------------------------

// Required for Kodi thumbnail/fanart URL
import java.net.URLEncoder

// --- rules --------------------------------------------------------------------------------

rule "kodi.rules init"
when
	System started
then
	logInfo("kodi.rules","System started event triggered")
	// Use a default image to display when nothing is playing.
	Kodi_Fanart_Url.postUpdate("../static/images/kodi.svg")
	Kodi_Thumbnail_Url.postUpdate("../static/images/kodi.svg")
end

// ------------------------------------------------------------------------------------------

rule "Update Fanart and Thumbnail URLs"
when
	Item Kodi_Title changed or
	Item Kodi_MediaType changed
then
	logInfo("kodi.rules", "Update Fanart/Thumbnail URLs")

	// Initialize a sane defaults.
	var String fanartUrl = "../static/images/kodi.svg"
	var String thumnailUrl = "../static/images/kodi.svg"

	// When nothing is playing then mediatype will be empty
	val String mediatype = Kodi_MediaType.state.toString()
	if (!mediatype.isEmpty())
	{
		// If you set a username/password to protect the Kodi webserver then specify these here,
		// if not, then remove 'username:password@' from the baseUrl variable, i.e.
		// val String baseUrl = "http://192.168.0.7:8080"
		// Replace 192.168.0.7 with the IP address/hostname of your Kodi instance.
		val String baseUrl = "http://username:password@192.168.0.7:8080"
		val String requestUrl = baseUrl + "/jsonrpc"
		val String contentType = "application/json"

		// Get the active players
		var String content = '{"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}'
		var String playersJson = sendHttpPostRequest(requestUrl, contentType, content)

		val int nrOfPlayers = Integer.parseInt(transform("JSONPATH", "$.result.length()", playersJson))

		// Determine which player is playing audio or video
		for (var int i = 0; i < nrOfPlayers; i++)
		{
			var String playerType = transform("JSONPATH", "$.result[" + i + "].type", playersJson)
			if ((playerType == "audio") || (playerType == "video"))
			{
				var int playerId = Integer.parseInt(transform("JSONPATH", "$.result[" + i + "].playerid", playersJson))

				// Query Kodi for the fanart and thumbnail location
				content = '{"jsonrpc":"2.0","method":"Player.GetItem","params":{"properties":["fanart","thumbnail"],"playerid":' + playerId + '},"id":1}'
				var String jsonResponse = sendHttpPostRequest(requestUrl, contentType, content)

				var String jsonpath = "$.result.item.fanart"
				var String image = transform("JSONPATH", jsonpath, jsonResponse)
				if (!image.isEmpty())
				{
					// Create the complete URL. URLEncode the fanart location.
					fanartUrl = baseUrl + "/image/" + URLEncoder::encode(image, "UTF-8")
				}

				jsonpath = "$.result.item.thumbnail"
				image = transform("JSONPATH", jsonpath, jsonResponse)
				if (!image.isEmpty())
				{
					// Create the complete URL. URLEncode the thumbnail location.
					thumnailUrl = baseUrl + "/image/" + URLEncoder::encode(image, "UTF-8")
				}
			}
		}
	}
	// Update the String items with the final URLs
	Kodi_Fanart_Url.postUpdate(fanartUrl)
	Kodi_Thumbnail_Url.postUpdate(thumnailUrl)

end

Configure the correct baseUrl for your Kodi instance. If you set a username/password to protect the Kodi webserver then specify these here, if not, then remove ‘username:password@’ from the baseUrl variable.
Replace 192.168.0.7 with the IP address/hostname of your Kodi instance.

If your title and mediatype channel Items are not called Kodi_Title and Kodi_MediaType then update the rule with the correct item names.

If all went well then you should now see the Kodi_Fanart_Url and Kodi_Thumbnail_Url items change state in your <Log files>/events.log logfile when playing media.

HABPanel:

Both thumbnails and fanart come in different sizes. As a result, they sometimes overflow their designated space (mainly in vertical direction). To prevent this from happening I have written a small Angular directive.

There may be better ways to do this, but after much Googleing I could not find any. I then followed a couple of webbased trainings on AngularJS and CSS and here’s my first Angular code :slight_smile:

Create a new JavaScript file: <Site configuration>/html/js/ancestor-height.directive.js

(Note: by default, the js directory does not exist in the html directory. I just like keeping thing neatly organized instead of simply dumping everything into the html directory.)

(function () {
    "use strict";

    angular.module("app").directive("ancestorHeight", function() {
        return {
            restrict: "A",
            link: function(scope, element, attributes) {

                function setHeight(height) {
                    height = height.slice(0,-2);
                    var adjust = attributes['ancestorHeight'] * 1; // * 1 causes a result of 0 in case no value is provided
                    var pxHeight = (parseFloat(height) + parseFloat(adjust)) + "px";
                        element.css('height', pxHeight);
                }

                function onHeightChanged(newValue, oldValue) {
                    if (newValue != oldValue) {
                        setHeight(newValue);
                    }
                }

                // find the ancestor that has a css height
                var parent = element;
                while (parent) {
                    if (parent.css('height')) {
                        setHeight(parent.css('height'));

                        // watch for changes in height
                        scope.$watch(function () {
                            return parent.css('height');
                        }, onHeightChanged, true);

                        break;
                    }
                    parent = parent.parent();
                }
            }
        }
    });

})();

In HABPanel create a new template for the thumbnail picture, give it a name (e.g. Thumbnail), and paste in the following html:

<div oc-lazy-load="['/static/js/ancestor-height.directive.js']">
	<div ancestor-height="-20" style="display: flex; justify-content: center;">
  	<img ng-src="{{itemValue('Kodi_LivingRoom_Thumbnail_Url')}}" style="max-height: 100%; max-width: 100%; align-self: center;" />
	</div>
</div>

If you like to show the fanart as well, then create another template, give it a name (e.g. Fanart), and paste in the following html:

<div oc-lazy-load="['/static/js/ancestor-height.directive.js']">
	<div ancestor-height="-20" style="display: flex; justify-content: center;">
  	<img ng-src="{{itemValue('Kodi_LivingRoom_Fanart_Url')}}" style="max-height: 100%; max-width: 100%; align-self: center;" />
	</div>
</div>

In both template files adjust the item names in case you are using different names.

Update:

  • Added or Item Kodi_MediaType changed to the when clause.
  • Added AngularJS directive and HABPanel template examples for thumbnail and fanart.
9 Likes

any chance you have a video up on youtube or something showing this in action?

I hope to fix the image resizing issue after the weekend. Then I’ll create some screenshots and will add them to this topic.

Thanks for the Code Works as intended although one minor problem but I’m sure it can be fixed…

I’ll also try to look into the resizing issue

But Thank You
:smile:

Nice, however it should eventually become obsolete because there is work in progress to add image channels for thumbnail and fanart to the Kodi binding:

Once it’s merged HABPanel’s image widget will support them natively:

Nice! That was the next thing I was planning to do after I figure out how to properly resize the image so that it does not overflow its reserved space. For me this is nothing more then a temporary workaround.

1 Like

One issue I’ve found is that sometimes the Kodi_Title is changed and the Kodi_MediaType change may take a period of time during which the Kodi_MediaType check is performed, and it can result in nothing happening. Not sure of a solution though :confused:

...
when
	Item Kodi_Title changed
then
	...
	// Kodi_MediaType may not have changed by this point
	// and could still be empty, but in the process of changing
	val String mediatype = Kodi_MediaType.state.toString()
	if (!mediatype.isEmpty())
	...

Hi Jim,

I have seen similar behaviour and have update the rule such that it also triggers when the media type changes:

rule "Update Fanart and Thumbnail URLs"
when
	Item Kodi_Title changed or
	Item Kodi_MediaType changed
then

Can you give that a try and see if it improves things for you?

That would probably work alright. The rule will get executed twice, but at least it you’d be sure that the change would happen. I’ll test it out later.

Thanks.

Updated the start topic with the information on how to limit the fanart and thumbnail pictures to their reserved space.

I see that there is progress on this in github.
Is this merged into nightly openhab addons?
Or could you make a test JAR and host it on github?
Cheers!

From what I can tell (I’m not involved in the Kodi binding) some changes still need to be merged which should fix some issues that were found during testing.

1 Like

Hi there,

the PR is ready to get merged.

You can download the latest .jar file here: https://openhab.jfrog.io/openhab/libs-pullrequest-local/org/openhab/binding/org.openhab.binding.kodi/2.2.0-SNAPSHOT/ . The changes should be included in it. We are happy to hear any feedback. Thanks.

2 Likes

@cweitkamp, I tried the binding.
There were no channels added via autodiscovery in PaperUI according to:
String myKodi_thumbnail { channel=“kodi:kodi:myKodi:thumbnail” }
String myKodi_fanart { channel=“kodi:kodi:myKodi:fanart” }

Is this normal?
I tried using “image” in HAPpanel and use home.items i manually created, but no such luck.

Which OH2 version do you use? Did you uninstall the old version before putting the jar file into your add-ons folder? The new channels are not added automatically to an existing thing. You have to remove the thing first and let it be discovered again.

If that doesn’t help the problem maybe located in the jar file itself. Maybe the generated file is not up-to-date. I can provide a new one for you, if you like?

I am on openhab 2.2 snapshot and used the downloadlink from the post before me.
I have never used any KODI binding before so did not have to uninstall :slight_smile:

My .things file is this standard one:

Thing kodi:kodi:8782962b-6a2c-d65f-adc7-12c6348f412c "Kodi" @ "Living Room" [ipAddress="192.168.1.9", port="9090"]

I could try another JAR if you have the time to provide me with one!

I uploaded a fresh build of my branch here.

I tried your “new” binding, but it’s still the same.
So I downloaded the latest OH snapshot 2.2.2 build 1069 and threw nothing but the .JAR in there. Still the same… I have up to “mediatype”, but fanart and thumbnail are not shown in paper UI.

The only thing I can think of is that my KODI is libreelec version. And/or it is version 17.5.

I have a “normal kodi” installation on my computer. But I can’t add it to paperUI, it says offline.
But even if it says offline, it still has the “normal” channels without fanart and thumbnail

Note: I can reach and control my KODIs via webinterface and commands from openhab.

Please be aware that the two new channels are advanced channels. Meaning that you have to push the Show more button in PaperUI to see them.

LibreELEC shouldn’t be the cause. I use it on my own devices.

1 Like

So… I had totally missed that “show more”.
Well, I redid my whole installation anyways (which only takes 20 minutes so no biggie) and the answer was so simple :slight_smile:
Cheers and thanks, it works great!

On another note, would be cool if one could see the movie library (and TV library) with images and information as well.
But perhaps that would be best suited for an iframe instead as kodi supports native webbrowsing.