Hi all,
as not all music in my library has cover arts I decided to try to dynamically get the cover image and some artist info for the playing album:
As usual, not an absolute step-by-step tutorial, but an “inspiration” … will be happy to add additional details if required.
Webview url="/static/Visualization/CoverArt.html" height=6
Utility .js to get data from OH via REST
// ***
// * Required definitions:
// * - var baseURL = "../";
// *
// ***
// * Required API
// * - Google jQuery: https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// * - jQuery CSV: https://github.com/evanplaice/jquery-csv
// * - date.js: http://www.datejs.com/
// ***
function GetGroupItemNames(groupItem) {
var groupUrl = baseURL.concat("rest/items/").concat(groupItem);
var groupData = GetData(groupUrl);
var items = [];
groupData.members.forEach(function (item) {
items.push(item.name);
});
return items;
}
function GetOpenHABHistory(item, days, serviceId) {
var csv = GetOpenItemHABHistoryCSV(item, days, serviceId);
var arrayData = $.csv.toArrays(csv, {
onParseValue: $.csv.hooks.castToScalar
});
return arrayData;
}
function GetData(itemUrl) {
var itemValue = null;
// http://api.jquery.com/jquery.getjson/
$.ajax({
// contentType: 'text/plain',
contentType : 'application/json; charset=utf-8',
// dataType : 'json',
url: itemUrl,
data: {},
async: false,
success: function (data) {
if (data != "NULL") {
itemValue = data;
}
}
});
return itemValue;
}
// JSON to CSV Converter
function ConvertToCSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
for (var i = 0; i < array.data.length; i++) {
var line = '';
for (var index in array.data[i]) {
if (line !== '') line += ',';
line += array.data[i][index];
}
str += line + '\r\n';
}
return str;
}
function GetOpenHABItemState(item) {
var itemUrl = baseURL.concat("rest/items/").concat(item).concat("/state/");
return GetData(itemUrl);
}
function GetOpenHABItem(item) {
var itemUrl = baseURL.concat("rest/items/").concat(item);
return GetData(itemUrl);
}
function GetOpenHABItemIntValue(item) {
return Math.round(GetOpenHabItemState(item));
}
function GetOpenHABItemHistoryJSON(item, days = 1, service = "rrd4j") {
var jsonData = null;
// var numberOfMilliseconds = 86400 * 1000 * days;
var startTimeObject = (new Date()).addDays(days * -1);
// var endTimeObject = new Date();
var _month = startTimeObject.getMonth() + 1;
var _starttime = startTimeObject.getFullYear() + "-" + _month + "-" + startTimeObject.getDate() + "T" + startTimeObject.getHours() + ":" + startTimeObject.getMinutes() + ":" + startTimeObject.getSeconds();
// var _endtime = endTimeObject.getFullYear() + "-" + endTimeObject.getMonth() + "-" + endTimeObject.getDate() + "T" + endTimeObject.getHours() + ":" + endTimeObject.getMinutes() + ":" + endTimeObject.getSeconds();
var itemUrl = baseURL.concat("rest/persistence/items/").concat(item);
itemUrl = itemUrl.concat("?serviceId=" + service);
if (days != 1) {
itemUrl = itemUrl.concat("&starttime=" + _starttime);
}
// itemUrl = itemUrl.concat("&endtime=" + _endtime);
jsonData = GetData(encodeURI(itemUrl));
return jsonData;
}
function GetOpenItemHABHistoryCSV(item, days = 1, service = "rrd4j") {
var jsonData = GetOpenHABItemHistoryJSON(item, days, service);
return ConvertToCSV(jsonData);
}
function GetParameter(parameterName) {
var result = null,
tmp = [];
location.search.substr(1).split("&")
.forEach(function (item) {
tmp = item.split("=");
if (tmp[0] === parameterName) {
result = decodeURIComponent(tmp[1]);
}
});
return result;
}
function DOMSetElementHeight(elementId, height) {
var pageElement = document.getElementById(elementId);
pageElement.style.height = height + "px";
}
function DOMSetElementWidth(elementId, width) {
var pageElement = document.getElementById(elementId);
pageElement.style.width = width + "px";
}
var WINDOWS_1252 = '\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ';
function Windows1252ToUTF8(binaryString) {
var text = '';
for (var i = 0; i < binaryString.length; i++) {
text += WINDOWS_1252.charAt(binaryString.charCodeAt(i));
}
return text;
}
The .html to display the image
<html>
<head>
<title>Cover art</title>
<link rel="stylesheet" type="text/css" href="../css/visualizationStyle.css">
<script type="text/javascript">
var baseURL = "../../../";
var pageWidth = window.innerWidth;
var pageHeight = window.innerHeight;
</script>
<script type="text/javascript" src="../javascript/openHAB.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script type="text/javascript">
function update() {
var url = GetOpenHABItemState("ItemCoverArtURL");
var artistInformation = GetOpenHABItemState("ItemArtistInformation");
var coverArtElement = document.getElementById("CoverArt");
var artistInfoElement = document.getElementById("ArtistInformation")
try {
var coverURL = unescape(JSON.parse(url));
if (coverURL == "") {
coverURL = "http://192.168.0.73:9000/music/current/cover.jpg";
}
coverArtElement.src = coverURL;
} catch (err) {
coverArtElement.src = unescape(url);
}
try {
artistInformation = unescape(JSON.parse(artistInformation));
artistInformation = artistInformation.replace(/(?:\r\n|\r|\n)/g, '<br />');
} catch (err) {}
// artistInformation = artistInformation.substr(0, artistInformation.indexOf("User-contributed text"));
artistInfoElement.innerHTML = artistInformation;
setTimeout(update, 10000);
}
$(document).ready(function() {
update();
});
</script>
<style>
img#CoverArt {
height: 190px;
width: 190px;
-moz-box-shadow: -10px 10px 40px -8px;
-webkit-box-shadow: -10px 10px 40px -8px;
box-shadow: -10px 10px 40px -8px;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
-khtml-border-radius: 20px;
border-radius: 20px;
float: right;
margin-right: 8px;
border: 4px solid black;
margin-left: 10px;
}
p#ArtistInformation {
color: gray;
text-indent: 38px;
font-style: italic;
margin-top: 10px;
}
</style>
</head>
<body>
<div>
<img id="CoverArt" />
</div>
<div>
<p id="ArtistInformation"></p>
</div>
</body>
</html>
The rules
Artist info
rule UpdateArtistSummary
when
Item ItemRadioAlbum changed
or Item ItemRadioArtist changed
or Item ItemRadioTitle changed
or Item ItemSqueezeSelectedRadioStation changed
then
val String _url = "http://ws.audioscrobbler.com/2.0/";
val String _commandAlbum = "?method=artist.getinfo";
val String _artist = ItemRadioArtist.state.toString
if (_artist != null && !_artist.isEmpty()) {
val String _artistEncoded = URLEncoder::encode(_artist, 'UTF-8')
val String _request = _url + _commandAlbum
+ "&api_key=" + lastFMAPIKey
+ "&artist=" + _artistEncoded
+ "&format=json"
val String _json = sendHttpGetRequest(_request);
var String _artistInfo = transform("JSONPATH", "$..bio.summary", _json)
//.content to get more details
ItemArtistInformation.postUpdate(_artistInfo)
} else {
ItemArtistInformation.postUpdate("")
}
end
Cover
rule UpdateRadioCover
when
Item ItemRadioAlbum changed
or Item ItemRadioArtist changed
or Item ItemRadioTitle changed
or Item ItemSqueezeSelectedRadioStation changed
then
val String _url = "http://ws.audioscrobbler.com/2.0/";
val String _commandAlbum = "?method=album.getinfo";
val String _commandTitle = "?method=track.getInfo";
val String _album = ItemRadioAlbum.state.toString
val String _title = ItemRadioTitle.state.toString
val String _artist = ItemRadioArtist.state.toString
var String _albumURL = "http://192.168.0.73:9000/music/current/cover.jpg";
if ((_artist != null && !_artist.isEmpty()) && (_title != null && !_title.isEmpty())) {
val String _artistEncoded = URLEncoder::encode(_artist, 'UTF-8')
val String _titleEncoded = URLEncoder::encode(_title, 'UTF-8')
val String _request = _url + _commandTitle
+ "&api_key=" + lastFMAPIKey
+ "&artist=" + _artistEncoded
+ "&track=" + _titleEncoded
+ "&format=json"
// println(_request)
val String _json = sendHttpGetRequest(_request);
var String _lastFMAlbumURL = transform("JSONPATH", "$..image[3].#text", _json)
_lastFMAlbumURL = _lastFMAlbumURL.replace("[","")
_lastFMAlbumURL = _lastFMAlbumURL.replace("]","")
if (_lastFMAlbumURL != null && !_lastFMAlbumURL.isEmpty()) {
println(_lastFMAlbumURL)
_albumURL = _lastFMAlbumURL;
}
} else if ((_artist != null && !_artist.isEmpty())
&& (_album != null && !_album.isEmpty())) {
val String _artistEncoded = URLEncoder::encode(_artist, 'UTF-8')
val String _albumEncoded = URLEncoder::encode(_album, 'UTF-8')
val String _request = _url + _commandAlbum
+ "&api_key=" + lastFMAPIKey
+ "&artist=" + _artistEncoded
+ "&album=" + _albumEncoded
+ "&format=json"
val String _json = sendHttpGetRequest(_request);
var String _lastFMAlbumURL = transform("JSONPATH", "$..image[3].#text", _json)
_lastFMAlbumURL = _lastFMAlbumURL.replace("[","")
_lastFMAlbumURL = _lastFMAlbumURL.replace("]","")
if (_lastFMAlbumURL != null && !_lastFMAlbumURL.isEmpty()) {
_albumURL = _lastFMAlbumURL;
}
} else if (ItemSqueezeSelectedRadioStation.state >= 0) {
_albumURL = "/static/img/radio/" + ItemSqueezeSelectedRadioStation.state + ".png"
} else if (ItemSqueezeSelectedPodcast.state >= 0) {
_albumURL = "/static/img/podcast/" + ItemSqueezeSelectedPodcast.state + ".png"
}
ItemCoverArtURL.postUpdate(_albumURL)
end
Moderators: Please feel free to wikify this article.
with kind regards,
Patrik