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
andmediatype
. In the rule below the items for these channels are namedKodi_Title
andKodi_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
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.