implement new media interfaces in kodi
This commit is contained in:
parent
71314cafe3
commit
fc90d10636
@ -65,6 +65,12 @@
|
|||||||
#include "plugin/device.h"
|
#include "plugin/device.h"
|
||||||
#include "plugininfo.h"
|
#include "plugininfo.h"
|
||||||
#include "network/upnp/upnpdiscovery.h"
|
#include "network/upnp/upnpdiscovery.h"
|
||||||
|
#include "network/avahi/qtavahiservicebrowser.h"
|
||||||
|
#include "network/avahi/avahiserviceentry.h"
|
||||||
|
#include "network/networkaccessmanager.h"
|
||||||
|
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
DevicePluginKodi::DevicePluginKodi()
|
DevicePluginKodi::DevicePluginKodi()
|
||||||
{
|
{
|
||||||
@ -106,6 +112,56 @@ DeviceManager::DeviceSetupStatus DevicePluginKodi::setupDevice(Device *device)
|
|||||||
connect(kodi, &Kodi::updateDataReceived, this, &DevicePluginKodi::onSetupFinished);
|
connect(kodi, &Kodi::updateDataReceived, this, &DevicePluginKodi::onSetupFinished);
|
||||||
connect(kodi, &Kodi::playbackStatusChanged, this, &DevicePluginKodi::onPlaybackStatusChanged);
|
connect(kodi, &Kodi::playbackStatusChanged, this, &DevicePluginKodi::onPlaybackStatusChanged);
|
||||||
|
|
||||||
|
connect(kodi, &Kodi::activePlayerChanged, device, [device](const QString &playerType){
|
||||||
|
device->setStateValue(kodiPlayerTypeStateTypeId, playerType);
|
||||||
|
});
|
||||||
|
connect(kodi, &Kodi::mediaMetadataChanged, device, [this, device](const QString &title, const QString &artist, const QString &collection, const QString &artwork){
|
||||||
|
device->setStateValue(kodiTitleStateTypeId, title);
|
||||||
|
device->setStateValue(kodiArtistStateTypeId, artist);
|
||||||
|
device->setStateValue(kodiCollectionStateTypeId, collection);
|
||||||
|
|
||||||
|
|
||||||
|
QNetworkRequest request;
|
||||||
|
QHostAddress hostAddr(device->paramValue(kodiDeviceIpParamTypeId).toString());
|
||||||
|
QString addr;
|
||||||
|
if (hostAddr.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
|
addr = hostAddr.toString();
|
||||||
|
} else {
|
||||||
|
addr = "[" + hostAddr.toString() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
request.setUrl(QUrl("http://" + addr + ":8080/jsonrpc"));
|
||||||
|
qCDebug(dcKodi) << "Prepping file dl" << "http://" + addr + ":" + device->paramValue(kodiDevicePortParamTypeId).toString() + "/jsonrpc";
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
QVariantMap map;
|
||||||
|
map.insert("jsonrpc", "2.0");
|
||||||
|
map.insert("method", "Files.PrepareDownload");
|
||||||
|
map.insert("id", QString::number(123));
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("path", artwork);
|
||||||
|
map.insert("params", params);
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromVariant(map);
|
||||||
|
QNetworkReply *reply = hardwareManager()->networkManager()->post(request, jsonDoc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, device, [device, reply, addr](){
|
||||||
|
reply->deleteLater();
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
device->setStateValue(kodiArtworkStateTypeId, "http://" + addr + ":8080/" + jsonDoc.toVariant().toMap().value("result").toMap().value("details").toMap().value("path").toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(kodi, &Kodi::shuffleChanged, device, [device](bool shuffle){
|
||||||
|
device->setStateValue(kodiShuffleStateTypeId, shuffle);
|
||||||
|
});
|
||||||
|
connect(kodi, &Kodi::repeatChanged, device, [device](const QString &repeat){
|
||||||
|
if (repeat == "one") {
|
||||||
|
device->setStateValue(kodiRepeatStateTypeId, "One");
|
||||||
|
} else if (repeat == "all") {
|
||||||
|
device->setStateValue(kodiRepeatStateTypeId, "All");
|
||||||
|
} else {
|
||||||
|
device->setStateValue(kodiRepeatStateTypeId, "None");
|
||||||
|
}
|
||||||
|
});
|
||||||
m_kodis.insert(kodi, device);
|
m_kodis.insert(kodi, device);
|
||||||
m_asyncSetups.append(kodi);
|
m_asyncSetups.append(kodi);
|
||||||
|
|
||||||
@ -127,9 +183,21 @@ DeviceManager::DeviceError DevicePluginKodi::discoverDevices(const DeviceClassId
|
|||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
Q_UNUSED(deviceClassId)
|
Q_UNUSED(deviceClassId)
|
||||||
|
|
||||||
qCDebug(dcKodi) << "Start UPnP search";
|
QList<DeviceDescriptor> descriptors;
|
||||||
UpnpDiscoveryReply *reply = hardwareManager()->upnpDiscovery()->discoverDevices();
|
foreach (const AvahiServiceEntry &avahiEntry, hardwareManager()->avahiBrowser()->serviceEntries()) {
|
||||||
connect(reply, &UpnpDiscoveryReply::finished, this, &DevicePluginKodi::onUpnpDiscoveryFinished);
|
if (avahiEntry.serviceType() == "_xbmc-jsonrpc._tcp") {
|
||||||
|
qCDebug(dcKodi) << "Zeroconf entry:" << avahiEntry;
|
||||||
|
DeviceDescriptor descriptor(kodiDeviceClassId, avahiEntry.name(), avahiEntry.hostName() + " (" + avahiEntry.hostAddress().toString() + ")");
|
||||||
|
ParamList params;
|
||||||
|
params << Param(kodiDeviceIpParamTypeId, avahiEntry.hostAddress().toString());
|
||||||
|
params << Param(kodiDevicePortParamTypeId, avahiEntry.port());
|
||||||
|
descriptor.setParams(params);
|
||||||
|
descriptors << descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!descriptors.isEmpty()) {
|
||||||
|
emit devicesDiscovered(kodiDeviceClassId, descriptors);
|
||||||
|
}
|
||||||
|
|
||||||
return DeviceManager::DeviceErrorAsync;
|
return DeviceManager::DeviceErrorAsync;
|
||||||
}
|
}
|
||||||
@ -144,52 +212,52 @@ DeviceManager::DeviceError DevicePluginKodi::executeAction(Device *device, const
|
|||||||
return DeviceManager::DeviceErrorHardwareNotAvailable;
|
return DeviceManager::DeviceErrorHardwareNotAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int commandId = -1;
|
||||||
if (action.actionTypeId() == kodiShowNotificationActionTypeId) {
|
if (action.actionTypeId() == kodiShowNotificationActionTypeId) {
|
||||||
kodi->showNotification(action.param(kodiShowNotificationActionMessageParamTypeId).value().toString(), 8000, action.param(kodiShowNotificationActionTypeParamTypeId).value().toString(), action.id());
|
commandId = kodi->showNotification(action.param(kodiShowNotificationActionMessageParamTypeId).value().toString(), 8000, action.param(kodiShowNotificationActionTypeParamTypeId).value().toString());
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if (action.actionTypeId() == kodiVolumeActionTypeId) {
|
} else if (action.actionTypeId() == kodiVolumeActionTypeId) {
|
||||||
kodi->setVolume(action.param(kodiVolumeActionVolumeParamTypeId).value().toInt(), action.id());
|
commandId = kodi->setVolume(action.param(kodiVolumeActionVolumeParamTypeId).value().toInt());
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if (action.actionTypeId() == kodiMuteActionTypeId) {
|
} else if (action.actionTypeId() == kodiMuteActionTypeId) {
|
||||||
kodi->setMuted(action.param(kodiMuteActionMuteParamTypeId).value().toBool(), action.id());
|
commandId = kodi->setMuted(action.param(kodiMuteActionMuteParamTypeId).value().toBool());
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if (action.actionTypeId() == kodiPressButtonActionTypeId) {
|
} else if (action.actionTypeId() == kodiPressButtonActionTypeId) {
|
||||||
kodi->pressButton(action.param(kodiPressButtonActionButtonParamTypeId).value().toString(), action.id());
|
commandId = kodi->pressButton(action.param(kodiPressButtonActionButtonParamTypeId).value().toString());
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if (action.actionTypeId() == kodiSystemActionTypeId) {
|
} else if (action.actionTypeId() == kodiSystemActionTypeId) {
|
||||||
kodi->systemCommand(action.param(kodiSystemActionSystemCommandParamTypeId).value().toString(), action.id());
|
commandId = kodi->systemCommand(action.param(kodiSystemActionSystemCommandParamTypeId).value().toString());
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if (action.actionTypeId() == kodiVideoLibraryActionTypeId) {
|
} else if (action.actionTypeId() == kodiVideoLibraryActionTypeId) {
|
||||||
kodi->videoLibrary(action.param(kodiVideoLibraryActionVideoCommandParamTypeId).value().toString(), action.id());
|
commandId = kodi->videoLibrary(action.param(kodiVideoLibraryActionVideoCommandParamTypeId).value().toString());
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if (action.actionTypeId() == kodiAudioLibraryActionTypeId) {
|
} else if (action.actionTypeId() == kodiAudioLibraryActionTypeId) {
|
||||||
kodi->audioLibrary(action.param(kodiAudioLibraryActionAudioCommandParamTypeId).value().toString(), action.id());
|
commandId = kodi->audioLibrary(action.param(kodiAudioLibraryActionAudioCommandParamTypeId).value().toString());
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if(action.actionTypeId() == kodiSkipBackActionTypeId) {
|
} else if(action.actionTypeId() == kodiSkipBackActionTypeId) {
|
||||||
kodi->pressButton("skipprevious", action.id());
|
commandId = kodi->pressButton("skipprevious");
|
||||||
return DeviceManager::DeviceErrorAsync;
|
} else if(action.actionTypeId() == kodiFastRewindActionTypeId) {
|
||||||
} else if(action.actionTypeId() == kodiRewindActionTypeId) {
|
commandId = kodi->pressButton("rewind");
|
||||||
kodi->pressButton("rewind", action.id());
|
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if(action.actionTypeId() == kodiStopActionTypeId) {
|
} else if(action.actionTypeId() == kodiStopActionTypeId) {
|
||||||
kodi->pressButton("stop", action.id());
|
commandId = kodi->pressButton("stop");
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if(action.actionTypeId() == kodiPlayActionTypeId) {
|
} else if(action.actionTypeId() == kodiPlayActionTypeId) {
|
||||||
kodi->pressButton("play", action.id());
|
commandId = kodi->pressButton("play");
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if(action.actionTypeId() == kodiPauseActionTypeId) {
|
} else if(action.actionTypeId() == kodiPauseActionTypeId) {
|
||||||
kodi->pressButton("pause", action.id());
|
commandId = kodi->pressButton("pause");
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if(action.actionTypeId() == kodiFastForwardActionTypeId) {
|
} else if(action.actionTypeId() == kodiFastForwardActionTypeId) {
|
||||||
kodi->pressButton("fastforward", action.id());
|
commandId = kodi->pressButton("fastforward");
|
||||||
return DeviceManager::DeviceErrorAsync;
|
|
||||||
} else if(action.actionTypeId() == kodiSkipNextActionTypeId) {
|
} else if(action.actionTypeId() == kodiSkipNextActionTypeId) {
|
||||||
kodi->pressButton("skipnext", action.id());
|
commandId = kodi->pressButton("skipnext");
|
||||||
return DeviceManager::DeviceErrorAsync;
|
} else if (action.actionTypeId() == kodiShuffleActionTypeId) {
|
||||||
|
commandId = kodi->setShuffle(action.param(kodiShuffleActionShuffleParamTypeId).value().toBool());
|
||||||
|
} else if (action.actionTypeId() == kodiRepeatActionTypeId) {
|
||||||
|
QString repeat = action.param(kodiRepeatActionRepeatParamTypeId).value().toString();
|
||||||
|
if (repeat == "One") {
|
||||||
|
commandId = kodi->setRepeat("one");
|
||||||
|
} else if (repeat == "All") {
|
||||||
|
commandId = kodi->setRepeat("all");
|
||||||
|
} else {
|
||||||
|
commandId = kodi->setRepeat("off");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning(dcKodi()) << "Unhandled action type" << action.actionTypeId();
|
qWarning(dcKodi()) << "Unhandled action type" << action.actionTypeId();
|
||||||
|
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||||
}
|
}
|
||||||
return DeviceManager::DeviceErrorActionTypeNotFound;
|
m_pendingActions.insert(commandId, action.id());
|
||||||
|
return DeviceManager::DeviceErrorAsync;
|
||||||
}
|
}
|
||||||
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||||
}
|
}
|
||||||
@ -204,43 +272,6 @@ void DevicePluginKodi::onPluginTimer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::onUpnpDiscoveryFinished()
|
|
||||||
{
|
|
||||||
qCDebug(dcKodi()) << "Upnp discovery finished";
|
|
||||||
UpnpDiscoveryReply *reply = static_cast<UpnpDiscoveryReply *>(sender());
|
|
||||||
if (reply->error() != UpnpDiscoveryReply::UpnpDiscoveryReplyErrorNoError) {
|
|
||||||
qCWarning(dcKodi()) << "Upnp discovery error" << reply->error();
|
|
||||||
}
|
|
||||||
reply->deleteLater();
|
|
||||||
|
|
||||||
QList<DeviceDescriptor> deviceDescriptors;
|
|
||||||
foreach (const UpnpDeviceDescriptor &upnpDescriptor, reply->deviceDescriptors()) {
|
|
||||||
if (upnpDescriptor.modelName().contains("Kodi")) {
|
|
||||||
|
|
||||||
// check if we already found the kodi on this ip
|
|
||||||
bool alreadyAdded = false;
|
|
||||||
foreach (const DeviceDescriptor dDescriptor, deviceDescriptors) {
|
|
||||||
if (dDescriptor.params().paramValue(kodiDeviceIpParamTypeId).toString() == upnpDescriptor.hostAddress().toString()) {
|
|
||||||
alreadyAdded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alreadyAdded)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
qCDebug(dcKodi) << upnpDescriptor;
|
|
||||||
DeviceDescriptor deviceDescriptor(kodiDeviceClassId, "Kodi - Media Center", upnpDescriptor.hostAddress().toString());
|
|
||||||
ParamList params;
|
|
||||||
params.append(Param(kodiDeviceNameParamTypeId, upnpDescriptor.friendlyName()));
|
|
||||||
params.append(Param(kodiDeviceIpParamTypeId, upnpDescriptor.hostAddress().toString()));
|
|
||||||
params.append(Param(kodiDevicePortParamTypeId, 9090));
|
|
||||||
deviceDescriptor.setParams(params);
|
|
||||||
deviceDescriptors.append(deviceDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
emit devicesDiscovered(kodiDeviceClassId, deviceDescriptors);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevicePluginKodi::onConnectionChanged()
|
void DevicePluginKodi::onConnectionChanged()
|
||||||
{
|
{
|
||||||
Kodi *kodi = static_cast<Kodi *>(sender());
|
Kodi *kodi = static_cast<Kodi *>(sender());
|
||||||
@ -267,13 +298,12 @@ void DevicePluginKodi::onStateChanged()
|
|||||||
device->setStateValue(kodiMuteStateTypeId, kodi->muted());
|
device->setStateValue(kodiMuteStateTypeId, kodi->muted());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::onActionExecuted(const ActionId &actionId, const bool &success)
|
void DevicePluginKodi::onActionExecuted(int actionId, bool success)
|
||||||
{
|
{
|
||||||
if (success) {
|
if (!m_pendingActions.contains(actionId)) {
|
||||||
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
|
return;
|
||||||
} else {
|
|
||||||
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorInvalidParameter);
|
|
||||||
}
|
}
|
||||||
|
emit actionExecutionFinished(m_pendingActions.value(actionId), success ? DeviceManager::DeviceErrorNoError : DeviceManager::DeviceErrorInvalidParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::versionDataReceived(const QVariantMap &data)
|
void DevicePluginKodi::versionDataReceived(const QVariantMap &data)
|
||||||
@ -304,7 +334,7 @@ void DevicePluginKodi::onSetupFinished(const QVariantMap &data)
|
|||||||
|
|
||||||
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess);
|
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess);
|
||||||
|
|
||||||
kodi->showNotification("Connected", 2000, "info", ActionId());
|
kodi->showNotification("Connected", 2000, "info");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::onPlaybackStatusChanged(const QString &playbackStatus)
|
void DevicePluginKodi::onPlaybackStatusChanged(const QString &playbackStatus)
|
||||||
|
|||||||
@ -52,12 +52,13 @@ private:
|
|||||||
QHash<Kodi *, Device *> m_kodis;
|
QHash<Kodi *, Device *> m_kodis;
|
||||||
QList<Kodi *> m_asyncSetups;
|
QList<Kodi *> m_asyncSetups;
|
||||||
|
|
||||||
|
QHash<int, ActionId> m_pendingActions;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onPluginTimer();
|
void onPluginTimer();
|
||||||
void onUpnpDiscoveryFinished();
|
|
||||||
void onConnectionChanged();
|
void onConnectionChanged();
|
||||||
void onStateChanged();
|
void onStateChanged();
|
||||||
void onActionExecuted(const ActionId &actionId, const bool &success);
|
void onActionExecuted(int actionId, bool success);
|
||||||
void versionDataReceived(const QVariantMap &data);
|
void versionDataReceived(const QVariantMap &data);
|
||||||
void onSetupFinished(const QVariantMap &data);
|
void onSetupFinished(const QVariantMap &data);
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"name": "kodi",
|
"name": "kodi",
|
||||||
"displayName": "Kodi",
|
"displayName": "Kodi",
|
||||||
"deviceIcon": "Tv",
|
"deviceIcon": "Tv",
|
||||||
"interfaces": ["mediacontroller", "extendedvolumecontroller"],
|
"interfaces": ["mediaplayer", "extendedmediacontroller", "extendedvolumecontroller", "mediametadataprovider", "shufflerepeat"],
|
||||||
"basicTags": [
|
"basicTags": [
|
||||||
"Service",
|
"Service",
|
||||||
"Multimedia",
|
"Multimedia",
|
||||||
@ -22,13 +22,6 @@
|
|||||||
"createMethods": ["user", "discovery"],
|
"createMethods": ["user", "discovery"],
|
||||||
"criticalStateTypeId": "09dfbd40-c97c-4a20-9ecd-f80e389a4864",
|
"criticalStateTypeId": "09dfbd40-c97c-4a20-9ecd-f80e389a4864",
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
|
||||||
"id": "a704beb1-b0b0-46fc-91fc-3aac01e1a364",
|
|
||||||
"name": "name",
|
|
||||||
"displayName": "name",
|
|
||||||
"type": "QString",
|
|
||||||
"inputType": "TextLine"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "1a897065-57c6-49b3-bac9-1e5db27859e5",
|
"id": "1a897065-57c6-49b3-bac9-1e5db27859e5",
|
||||||
"name": "ip",
|
"name": "ip",
|
||||||
@ -89,8 +82,69 @@
|
|||||||
"displayNameEvent": "playback status changed",
|
"displayNameEvent": "playback status changed",
|
||||||
"displayNameAction": "set playback status",
|
"displayNameAction": "set playback status",
|
||||||
"writable": true
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "0af58b87-4e45-4f0a-9ef2-0ade74c7c22c",
|
||||||
|
"type": "QString",
|
||||||
|
"name": "playerType",
|
||||||
|
"displayName": "Active player type",
|
||||||
|
"possibleValues": ["audio", "video"],
|
||||||
|
"displayNameEvent": "Active player changed",
|
||||||
|
"defaultValue": "audio"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f2209fec-cceb-46ad-8189-4caf42166e6b",
|
||||||
|
"type": "QString",
|
||||||
|
"name": "title",
|
||||||
|
"displayName": "Title",
|
||||||
|
"displayNameEvent": "Title changed",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8cb920a3-3bf1-4231-92d4-8ac27e7b3d65",
|
||||||
|
"type": "QString",
|
||||||
|
"name": "artist",
|
||||||
|
"displayName": "Artist",
|
||||||
|
"displayNameEvent": "Artist changed",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ce399eec-9f6a-4903-9916-0e90e38b255e",
|
||||||
|
"type": "QString",
|
||||||
|
"name": "collection",
|
||||||
|
"displayName": "Collection",
|
||||||
|
"displayNameEvent": "Collection changed",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "44304c82-c2f6-433b-b62b-815382617d0b",
|
||||||
|
"type": "QString",
|
||||||
|
"name": "artwork",
|
||||||
|
"displayName": "Artwork",
|
||||||
|
"displayNameEvent": "Artwork changed",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5913aa2a-629d-4de5-bf44-a4a1f130c118",
|
||||||
|
"type": "bool",
|
||||||
|
"name": "shuffle",
|
||||||
|
"displayName": "Shuffle",
|
||||||
|
"displayNameEvent": "Shuffle changed",
|
||||||
|
"displayNameAction": "Set shuffle",
|
||||||
|
"defaultValue": false,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bc02c28e-3f5d-4de4-b9b5-c0b1576c6e7e",
|
||||||
|
"type": "QString",
|
||||||
|
"name": "repeat",
|
||||||
|
"displayName": "Repeat",
|
||||||
|
"displayNameEvent": "Repeat changed",
|
||||||
|
"displayNameAction": "Set repeat",
|
||||||
|
"possibleValues": ["None", "One", "All"],
|
||||||
|
"defaultValue": "None",
|
||||||
|
"writable": true
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
"eventTypes": [
|
"eventTypes": [
|
||||||
{
|
{
|
||||||
@ -117,7 +171,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "7e70b47b-7e79-4521-be34-04a3c427e5b1",
|
"id": "7e70b47b-7e79-4521-be34-04a3c427e5b1",
|
||||||
"name": "rewind",
|
"name": "fastRewind",
|
||||||
"displayName": "rewind"
|
"displayName": "rewind"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
216
kodi/kodi.cpp
216
kodi/kodi.cpp
@ -23,6 +23,7 @@
|
|||||||
#include "kodi.h"
|
#include "kodi.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
Kodi::Kodi(const QHostAddress &hostAddress, const int &port, QObject *parent) :
|
Kodi::Kodi(const QHostAddress &hostAddress, const int &port, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
@ -33,14 +34,8 @@ Kodi::Kodi(const QHostAddress &hostAddress, const int &port, QObject *parent) :
|
|||||||
connect (m_connection, &KodiConnection::connectionStatusChanged, this, &Kodi::connectionStatusChanged);
|
connect (m_connection, &KodiConnection::connectionStatusChanged, this, &Kodi::connectionStatusChanged);
|
||||||
|
|
||||||
m_jsonHandler = new KodiJsonHandler(m_connection, this);
|
m_jsonHandler = new KodiJsonHandler(m_connection, this);
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::volumeChanged, this, &Kodi::onVolumeChanged);
|
connect(m_jsonHandler, &KodiJsonHandler::notificationReceived, this, &Kodi::processNotification);
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::actionExecuted, this, &Kodi::actionExecuted);
|
connect(m_jsonHandler, &KodiJsonHandler::replyReceived, this, &Kodi::processResponse);
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::versionDataReceived, this, &Kodi::versionDataReceived);
|
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::updateDataReceived, this, &Kodi::updateDataReceived);
|
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::updateDataReceived, this, &Kodi::onUpdateFinished);
|
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::playbackStatusChanged, this, &Kodi::playbackStatusChanged);
|
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::activePlayersChanged, this, &Kodi::activePlayersChanged);
|
|
||||||
connect(m_jsonHandler, &KodiJsonHandler::playerPropertiesReveived, this, &Kodi::playerPropertiesReceived);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QHostAddress Kodi::hostAddress() const
|
QHostAddress Kodi::hostAddress() const
|
||||||
@ -58,12 +53,12 @@ bool Kodi::connected() const
|
|||||||
return m_connection->connected();
|
return m_connection->connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::setMuted(const bool &muted, const ActionId &actionId)
|
int Kodi::setMuted(const bool &muted)
|
||||||
{
|
{
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("mute", muted);
|
params.insert("mute", muted);
|
||||||
|
|
||||||
m_jsonHandler->sendData("Application.SetMute", params, actionId);
|
return m_jsonHandler->sendData("Application.SetMute", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Kodi::muted() const
|
bool Kodi::muted() const
|
||||||
@ -71,12 +66,12 @@ bool Kodi::muted() const
|
|||||||
return m_muted;
|
return m_muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::setVolume(const int &volume, const ActionId &actionId)
|
int Kodi::setVolume(const int &volume)
|
||||||
{
|
{
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("volume", volume);
|
params.insert("volume", volume);
|
||||||
|
|
||||||
m_jsonHandler->sendData("Application.SetVolume", params, actionId);
|
return m_jsonHandler->sendData("Application.SetVolume", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Kodi::volume() const
|
int Kodi::volume() const
|
||||||
@ -84,7 +79,23 @@ int Kodi::volume() const
|
|||||||
return m_volume;
|
return m_volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::showNotification(const QString &message, const int &displayTime, const QString ¬ificationType, const ActionId &actionId)
|
int Kodi::setShuffle(bool shuffle)
|
||||||
|
{
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("playerid", m_activePlayer);
|
||||||
|
params.insert("shuffle", shuffle);
|
||||||
|
return m_jsonHandler->sendData("Player.SetShuffle", params);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Kodi::setRepeat(const QString &repeat)
|
||||||
|
{
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("playerid", m_activePlayer);
|
||||||
|
params.insert("repeat", repeat);
|
||||||
|
return m_jsonHandler->sendData("Player.SetRepeat", params);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Kodi::showNotification(const QString &message, const int &displayTime, const QString ¬ificationType)
|
||||||
{
|
{
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("title", "nymea notification");
|
params.insert("title", "nymea notification");
|
||||||
@ -92,17 +103,17 @@ void Kodi::showNotification(const QString &message, const int &displayTime, cons
|
|||||||
params.insert("displaytime", displayTime);
|
params.insert("displaytime", displayTime);
|
||||||
params.insert("image", notificationType);
|
params.insert("image", notificationType);
|
||||||
|
|
||||||
m_jsonHandler->sendData("GUI.ShowNotification", params, actionId);
|
return m_jsonHandler->sendData("GUI.ShowNotification", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::pressButton(const QString &button, const ActionId &actionId)
|
int Kodi::pressButton(const QString &button)
|
||||||
{
|
{
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("action", button);
|
params.insert("action", button);
|
||||||
m_jsonHandler->sendData("Input.ExecuteAction", params, actionId);
|
return m_jsonHandler->sendData("Input.ExecuteAction", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::systemCommand(const QString &command, const ActionId &actionId)
|
int Kodi::systemCommand(const QString &command)
|
||||||
{
|
{
|
||||||
QString method;
|
QString method;
|
||||||
if (command == "hibernate") {
|
if (command == "hibernate") {
|
||||||
@ -117,10 +128,10 @@ void Kodi::systemCommand(const QString &command, const ActionId &actionId)
|
|||||||
// already checkt with allowed values
|
// already checkt with allowed values
|
||||||
}
|
}
|
||||||
|
|
||||||
m_jsonHandler->sendData("System." + method, QVariantMap(), actionId);
|
return m_jsonHandler->sendData("System." + method, QVariantMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::videoLibrary(const QString &command, const ActionId &actionId)
|
int Kodi::videoLibrary(const QString &command)
|
||||||
{
|
{
|
||||||
QString method;
|
QString method;
|
||||||
if (command == "scan") {
|
if (command == "scan") {
|
||||||
@ -131,10 +142,10 @@ void Kodi::videoLibrary(const QString &command, const ActionId &actionId)
|
|||||||
// already checkt with allowed values
|
// already checkt with allowed values
|
||||||
}
|
}
|
||||||
|
|
||||||
m_jsonHandler->sendData("VideoLibrary." + method, QVariantMap(), actionId);
|
return m_jsonHandler->sendData("VideoLibrary." + method, QVariantMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::audioLibrary(const QString &command, const ActionId &actionId)
|
int Kodi::audioLibrary(const QString &command)
|
||||||
{
|
{
|
||||||
QString method;
|
QString method;
|
||||||
if (command == "scan") {
|
if (command == "scan") {
|
||||||
@ -145,7 +156,7 @@ void Kodi::audioLibrary(const QString &command, const ActionId &actionId)
|
|||||||
// already checkt with allowed values
|
// already checkt with allowed values
|
||||||
}
|
}
|
||||||
|
|
||||||
m_jsonHandler->sendData("AudioLibrary." + method, QVariantMap(), actionId);
|
return m_jsonHandler->sendData("AudioLibrary." + method, QVariantMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::update()
|
void Kodi::update()
|
||||||
@ -158,15 +169,15 @@ void Kodi::update()
|
|||||||
properties.append("version");
|
properties.append("version");
|
||||||
params.insert("properties", properties);
|
params.insert("properties", properties);
|
||||||
|
|
||||||
m_jsonHandler->sendData("Application.GetProperties", params, ActionId());
|
m_jsonHandler->sendData("Application.GetProperties", params);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
m_jsonHandler->sendData("Player.GetActivePlayers", params, ActionId());
|
m_jsonHandler->sendData("Player.GetActivePlayers", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::checkVersion()
|
void Kodi::checkVersion()
|
||||||
{
|
{
|
||||||
m_jsonHandler->sendData("JSONRPC.Version", QVariantMap(), ActionId());
|
m_jsonHandler->sendData("JSONRPC.Version", QVariantMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::connectKodi()
|
void Kodi::connectKodi()
|
||||||
@ -202,29 +213,162 @@ void Kodi::onUpdateFinished(const QVariantMap &data)
|
|||||||
|
|
||||||
void Kodi::activePlayersChanged(const QVariantList &data)
|
void Kodi::activePlayersChanged(const QVariantList &data)
|
||||||
{
|
{
|
||||||
qCDebug(dcKodi()) << "active players changed" << data.count();
|
qCDebug(dcKodi()) << "active players changed" << data.count() << data;
|
||||||
m_activePlayerCount = data.count();
|
m_activePlayerCount = data.count();
|
||||||
if (m_activePlayerCount == 0) {
|
if (m_activePlayerCount == 0) {
|
||||||
emit playbackStatusChanged("Stopped");
|
onPlaybackStatusChanged("Stopped");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int activePlayer = data.first().toMap().value("playerid").toInt();
|
m_activePlayer = data.first().toMap().value("playerid").toInt();
|
||||||
QVariantMap params;
|
qCDebug(dcKodi) << "Active Player changed:" << m_activePlayer << data.first().toMap().value("type").toString();
|
||||||
params.insert("playerid", activePlayer);
|
emit activePlayerChanged(data.first().toMap().value("type").toString());
|
||||||
QVariantList properties;
|
|
||||||
properties.append("speed");
|
updatePlayerProperties();
|
||||||
params.insert("properties", properties);
|
|
||||||
m_jsonHandler->sendData("Player.GetProperties", params, ActionId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kodi::playerPropertiesReceived(const QVariantMap &properties)
|
void Kodi::playerPropertiesReceived(const QVariantMap &properties)
|
||||||
{
|
{
|
||||||
qCDebug(dcKodi()) << "player props received" << properties;
|
qCDebug(dcKodi()) << "player props received" << properties;
|
||||||
|
|
||||||
if (m_activePlayerCount > 0) {
|
if (m_activePlayerCount > 0) {
|
||||||
if (properties.value("speed").toDouble() > 0) {
|
if (properties.value("speed").toDouble() > 0) {
|
||||||
emit playbackStatusChanged("Playing");
|
onPlaybackStatusChanged("Playing");
|
||||||
} else {
|
} else {
|
||||||
emit playbackStatusChanged("Paused");
|
onPlaybackStatusChanged("Paused");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit shuffleChanged(properties.value("shuffled").toBool());
|
||||||
|
emit repeatChanged(properties.value("repeat").toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kodi::mediaMetaDataReceived(const QVariantMap &data)
|
||||||
|
{
|
||||||
|
QVariantMap item = data.value("item").toMap();
|
||||||
|
|
||||||
|
QString title = item.value("title").toString();
|
||||||
|
QString artist;
|
||||||
|
QString collection;
|
||||||
|
if (item.value("type").toString() == "song") {
|
||||||
|
artist = !item.value("artist").toList().isEmpty() ? item.value("artist").toList().first().toString() : "";
|
||||||
|
collection = item.value("album").toString();
|
||||||
|
} else if (item.value("type").toString() == "episode") {
|
||||||
|
collection = item.value("showtitle").toString();
|
||||||
|
} else if (item.value("type").toString() == "unknown") {
|
||||||
|
artist = item.value("channel").toString();
|
||||||
|
collection = item.value("showtitle").toString();
|
||||||
|
} else if (item.value("type").toString() == "channel") {
|
||||||
|
artist = item.value("channel").toString();
|
||||||
|
collection = item.value("showtitle").toString();
|
||||||
|
} else if (item.value("type").toString() == "movie") {
|
||||||
|
artist = item.value("director").toStringList().join(", ");
|
||||||
|
collection = item.value("year").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString artwork = item.value("thumbnail").toString();
|
||||||
|
if (artwork.isEmpty()) {
|
||||||
|
artwork = item.value("fanart").toString();
|
||||||
|
}
|
||||||
|
qCDebug(dcKodi) << "title:" << title << artwork;
|
||||||
|
emit mediaMetadataChanged(title, artist, collection, artwork);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kodi::onPlaybackStatusChanged(const QString &playbackState)
|
||||||
|
{
|
||||||
|
if (playbackState != "Stopped") {
|
||||||
|
updateMetadata();
|
||||||
|
} else {
|
||||||
|
emit mediaMetadataChanged(QString(), QString(), QString(), QString());
|
||||||
|
}
|
||||||
|
emit playbackStatusChanged(playbackState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kodi::processNotification(const QString &method, const QVariantMap ¶ms)
|
||||||
|
{
|
||||||
|
qCDebug(dcKodi) << "got notification" << method << params;
|
||||||
|
|
||||||
|
if (method == "Application.OnVolumeChanged") {
|
||||||
|
QVariantMap data = params.value("data").toMap();
|
||||||
|
onVolumeChanged(data.value("volume").toInt(), data.value("muted").toBool());
|
||||||
|
} else if (method == "Player.OnPlay" || method == "Player.OnResume") {
|
||||||
|
emit activePlayersChanged(QVariantList() << params.value("data").toMap().value("player"));
|
||||||
|
onPlaybackStatusChanged("Playing");
|
||||||
|
} else if (method == "Player.OnPause") {
|
||||||
|
emit playbackStatusChanged("Paused");
|
||||||
|
} else if (method == "Player.OnStop") {
|
||||||
|
emit playbackStatusChanged("Stopped");
|
||||||
|
emit activePlayersChanged(QVariantList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kodi::processResponse(int id, const QString &method, const QVariantMap &response)
|
||||||
|
{
|
||||||
|
|
||||||
|
qCDebug(dcKodi) << "response received:" << method << response;
|
||||||
|
|
||||||
|
if (response.contains("error")) {
|
||||||
|
//qCDebug(dcKodi) << QJsonDocument::fromVariant(response).toJson();
|
||||||
|
qCWarning(dcKodi) << "got error response for request " << method << ":" << response.value("error").toMap().value("message").toString();
|
||||||
|
emit actionExecuted(id, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == "Application.GetProperties") {
|
||||||
|
//qCDebug(dcKodi) << "got update response" << reply.method();
|
||||||
|
emit updateDataReceived(response.value("result").toMap());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == "JSONRPC.Version") {
|
||||||
|
qCDebug(dcKodi) << "got version response" << method;
|
||||||
|
emit versionDataReceived(response.value("result").toMap());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == "Player.GetActivePlayers") {
|
||||||
|
qCDebug(dcKodi) << "Active players changed" << response;
|
||||||
|
emit activePlayersChanged(response.value("result").toList());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == "Player.GetProperties") {
|
||||||
|
qCDebug(dcKodi) << "Player properties received" << response;
|
||||||
|
playerPropertiesReceived(response.value("result").toMap());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == "Player.GetItem") {
|
||||||
|
qCDebug(dcKodi) << "Played item received" << response;
|
||||||
|
emit mediaMetaDataReceived(response.value("result").toMap());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == "Player.SetShuffle" || method == "Player.SetRepeat") {
|
||||||
|
updatePlayerProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit actionExecuted(id, true);
|
||||||
|
|
||||||
|
qCDebug(dcKodi()) << "unhandled reply" << method << response;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kodi::updatePlayerProperties()
|
||||||
|
{
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("playerid", m_activePlayer);
|
||||||
|
QVariantList properties;
|
||||||
|
properties << "speed" << "shuffled" << "repeat";
|
||||||
|
params.insert("properties", properties);
|
||||||
|
m_jsonHandler->sendData("Player.GetProperties", params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kodi::updateMetadata()
|
||||||
|
{
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("playerid", m_activePlayer);
|
||||||
|
QVariantList fields;
|
||||||
|
fields << "title" << "artist" << "album" << "director" << "thumbnail" << "showtitle" << "fanart" << "channel" << "year";
|
||||||
|
params.insert("properties", fields);
|
||||||
|
m_jsonHandler->sendData("Player.GetItem", params);
|
||||||
}
|
}
|
||||||
|
|||||||
49
kodi/kodi.h
49
kodi/kodi.h
@ -34,7 +34,7 @@ class Kodi : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit Kodi(const QHostAddress &hostAddress, const int &port = 9090, QObject *parent = 0);
|
explicit Kodi(const QHostAddress &hostAddress, const int &port = 9090, QObject *parent = nullptr);
|
||||||
|
|
||||||
QHostAddress hostAddress() const;
|
QHostAddress hostAddress() const;
|
||||||
int port() const;
|
int port() const;
|
||||||
@ -42,18 +42,21 @@ public:
|
|||||||
bool connected() const;
|
bool connected() const;
|
||||||
|
|
||||||
// propertys
|
// propertys
|
||||||
void setMuted(const bool &muted, const ActionId &actionId);
|
int setMuted(const bool &muted);
|
||||||
bool muted() const;
|
bool muted() const;
|
||||||
|
|
||||||
void setVolume(const int &volume, const ActionId &actionId);
|
int setVolume(const int &volume);
|
||||||
int volume() const;
|
int volume() const;
|
||||||
|
|
||||||
|
int setShuffle(bool shuffle);
|
||||||
|
int setRepeat(const QString &repeat);
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
void showNotification(const QString &message, const int &displayTime, const QString ¬ificationType, const ActionId &actionId);
|
int showNotification(const QString &message, const int &displayTime, const QString ¬ificationType);
|
||||||
void pressButton(const QString &button, const ActionId &actionId);
|
int pressButton(const QString &button);
|
||||||
void systemCommand(const QString &command, const ActionId &actionId);
|
int systemCommand(const QString &command);
|
||||||
void videoLibrary(const QString &command, const ActionId &actionId);
|
int videoLibrary(const QString &command);
|
||||||
void audioLibrary(const QString &command, const ActionId &actionId);
|
int audioLibrary(const QString &command);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void checkVersion();
|
void checkVersion();
|
||||||
@ -61,26 +64,40 @@ public:
|
|||||||
void connectKodi();
|
void connectKodi();
|
||||||
void disconnectKodi();
|
void disconnectKodi();
|
||||||
|
|
||||||
private:
|
|
||||||
KodiConnection *m_connection;
|
|
||||||
KodiJsonHandler *m_jsonHandler;
|
|
||||||
bool m_muted;
|
|
||||||
int m_volume;
|
|
||||||
int m_activePlayerCount = 0; // if it's > 0, there is something playing (either music or video or slideshow)
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionStatusChanged();
|
void connectionStatusChanged();
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
void actionExecuted(const ActionId &actionId, const bool &success);
|
void activePlayerChanged(const QString &playerType);
|
||||||
|
void actionExecuted(int actionId, const bool &success);
|
||||||
void updateDataReceived(const QVariantMap &data);
|
void updateDataReceived(const QVariantMap &data);
|
||||||
void versionDataReceived(const QVariantMap &data);
|
void versionDataReceived(const QVariantMap &data);
|
||||||
void playbackStatusChanged(const QString &playbackState);
|
void playbackStatusChanged(const QString &playbackState);
|
||||||
|
void mediaMetadataChanged(const QString &title, const QString &artist, const QString &collection, const QString &artwork);
|
||||||
|
void shuffleChanged(bool shuffle);
|
||||||
|
void repeatChanged(const QString &repeat);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onVolumeChanged(const int &volume, const bool &muted);
|
void onVolumeChanged(const int &volume, const bool &muted);
|
||||||
void onUpdateFinished(const QVariantMap &data);
|
void onUpdateFinished(const QVariantMap &data);
|
||||||
void activePlayersChanged(const QVariantList &data);
|
void activePlayersChanged(const QVariantList &data);
|
||||||
void playerPropertiesReceived(const QVariantMap &properties);
|
void playerPropertiesReceived(const QVariantMap &properties);
|
||||||
|
void mediaMetaDataReceived(const QVariantMap &data);
|
||||||
|
void onPlaybackStatusChanged(const QString &plabackState);
|
||||||
|
|
||||||
|
void processNotification(const QString &method, const QVariantMap ¶ms);
|
||||||
|
void processResponse(int id, const QString &method, const QVariantMap &response);
|
||||||
|
|
||||||
|
void updatePlayerProperties();
|
||||||
|
void updateMetadata();
|
||||||
|
|
||||||
|
private:
|
||||||
|
KodiConnection *m_connection;
|
||||||
|
KodiJsonHandler *m_jsonHandler;
|
||||||
|
bool m_muted;
|
||||||
|
int m_volume;
|
||||||
|
int m_activePlayerCount = 0; // if it's > 0, there is something playing (either music or video or slideshow)
|
||||||
|
int m_activePlayer = -1;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KODI_H
|
#endif // KODI_H
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class KodiConnection : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit KodiConnection(const QHostAddress &hostAddress, const int &port = 9090, QObject *parent = 0);
|
explicit KodiConnection(const QHostAddress &hostAddress, const int &port = 9090, QObject *parent = nullptr);
|
||||||
|
|
||||||
void connectKodi();
|
void connectKodi();
|
||||||
void disconnectKodi();
|
void disconnectKodi();
|
||||||
@ -62,6 +62,8 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
void sendData(const QByteArray &message);
|
void sendData(const QByteArray &message);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KODICONNECTION_H
|
#endif // KODICONNECTION_H
|
||||||
|
|||||||
@ -33,82 +33,22 @@ KodiJsonHandler::KodiJsonHandler(KodiConnection *connection, QObject *parent) :
|
|||||||
connect(m_connection, &KodiConnection::dataReady, this, &KodiJsonHandler::processResponse);
|
connect(m_connection, &KodiConnection::dataReady, this, &KodiJsonHandler::processResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KodiJsonHandler::sendData(const QString &method, const QVariantMap ¶ms, const ActionId &actionId)
|
int KodiJsonHandler::sendData(const QString &method, const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
|
m_id++;
|
||||||
|
|
||||||
QVariantMap package;
|
QVariantMap package;
|
||||||
package.insert("id", m_id);
|
package.insert("id", m_id);
|
||||||
package.insert("method", method);
|
package.insert("method", method);
|
||||||
package.insert("params", params);
|
package.insert("params", params);
|
||||||
package.insert("jsonrpc", "2.0");
|
package.insert("jsonrpc", "2.0");
|
||||||
|
|
||||||
m_replys.insert(m_id, KodiReply(method, params, actionId));
|
m_replys.insert(m_id, KodiReply(method, params));
|
||||||
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(package);
|
QJsonDocument jsonDoc = QJsonDocument::fromVariant(package);
|
||||||
m_connection->sendData(jsonDoc.toJson());
|
m_connection->sendData(jsonDoc.toJson());
|
||||||
//qCDebug(dcKodi) << "sending data" << jsonDoc.toJson();
|
//qCDebug(dcKodi) << "sending data" << jsonDoc.toJson();
|
||||||
m_id++;
|
return m_id;
|
||||||
}
|
|
||||||
|
|
||||||
void KodiJsonHandler::processNotification(const QString &method, const QVariantMap ¶ms)
|
|
||||||
{
|
|
||||||
qCDebug(dcKodi) << "got notification" << method;
|
|
||||||
|
|
||||||
if (method == "Application.OnVolumeChanged") {
|
|
||||||
QVariantMap data = params.value("data").toMap();
|
|
||||||
emit volumeChanged(data.value("volume").toInt(), data.value("muted").toBool());
|
|
||||||
} else if (method == "Player.OnPlay" || method == "Player.OnResume") {
|
|
||||||
emit playbackStatusChanged("Playing");
|
|
||||||
} else if (method == "Player.OnPause") {
|
|
||||||
emit playbackStatusChanged("Paused");
|
|
||||||
} else if (method == "Player.OnStop") {
|
|
||||||
emit playbackStatusChanged("Stopped");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KodiJsonHandler::processActionResponse(const KodiReply &reply, const QVariantMap &response)
|
|
||||||
{
|
|
||||||
if (response.contains("error")) {
|
|
||||||
//qCDebug(dcKodi) << QJsonDocument::fromVariant(response).toJson();
|
|
||||||
qCWarning(dcKodi) << "got error response for action" << reply.method() << ":" << response.value("error").toMap().value("message").toString();
|
|
||||||
emit actionExecuted(reply.actionId(), false);
|
|
||||||
} else {
|
|
||||||
emit actionExecuted(reply.actionId(), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KodiJsonHandler::processRequestResponse(const KodiReply &reply, const QVariantMap &response)
|
|
||||||
{
|
|
||||||
if (response.contains("error")) {
|
|
||||||
//qCDebug(dcKodi) << QJsonDocument::fromVariant(response).toJson();
|
|
||||||
qCWarning(dcKodi) << "got error response for request " << reply.method() << ":" << response.value("error").toMap().value("message").toString();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply.method() == "Application.GetProperties") {
|
|
||||||
//qCDebug(dcKodi) << "got update response" << reply.method();
|
|
||||||
emit updateDataReceived(response.value("result").toMap());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply.method() == "JSONRPC.Version") {
|
|
||||||
qCDebug(dcKodi) << "got version response" << reply.method();
|
|
||||||
emit versionDataReceived(response.value("result").toMap());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply.method() == "Player.GetActivePlayers") {
|
|
||||||
qCDebug(dcKodi) << "Active players changed" << response;
|
|
||||||
emit activePlayersChanged(response.value("result").toList());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply.method() == "Player.GetProperties") {
|
|
||||||
qCDebug(dcKodi) << "Player properties received" << response;
|
|
||||||
emit playerPropertiesReveived(response.value("result").toMap());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(dcKodi()) << "unhandled reply" << reply.method() << response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KodiJsonHandler::processResponse(const QByteArray &data)
|
void KodiJsonHandler::processResponse(const QByteArray &data)
|
||||||
@ -138,18 +78,12 @@ void KodiJsonHandler::processResponse(const QByteArray &data)
|
|||||||
qCWarning(dcKodi) << "method missing in message" << data;
|
qCWarning(dcKodi) << "method missing in message" << data;
|
||||||
}
|
}
|
||||||
|
|
||||||
processNotification(message.value("method").toString(), message.value("params").toMap());
|
emit notificationReceived(message.value("method").toString(), message.value("params").toMap());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = message.value("id").toInt();
|
int id = message.value("id").toInt();
|
||||||
KodiReply reply = m_replys.take(id);
|
KodiReply reply = m_replys.take(id);
|
||||||
|
|
||||||
// check if this message is a response to an action call
|
emit replyReceived(id, reply.method(), message);
|
||||||
if (reply.actionId() != ActionId()) {
|
|
||||||
processActionResponse(reply, message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
processRequestResponse(reply, message);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,32 +35,22 @@ class KodiJsonHandler : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit KodiJsonHandler(KodiConnection *connection = 0, QObject *parent = 0);
|
explicit KodiJsonHandler(KodiConnection *connection, QObject *parent = nullptr);
|
||||||
|
|
||||||
void sendData(const QString &method, const QVariantMap ¶ms, const ActionId &actionId);
|
int sendData(const QString &method, const QVariantMap ¶ms);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void notificationReceived(const QString &method, const QVariantMap ¶ms);
|
||||||
|
void replyReceived(int id, const QString &method, const QVariantMap ¶ms);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void processResponse(const QByteArray &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KodiConnection *m_connection;
|
KodiConnection *m_connection;
|
||||||
int m_id;
|
int m_id;
|
||||||
QHash<int, KodiReply> m_replys;
|
QHash<int, KodiReply> m_replys;
|
||||||
|
|
||||||
void processNotification(const QString &method, const QVariantMap ¶ms);
|
|
||||||
void processActionResponse(const KodiReply &reply, const QVariantMap &response);
|
|
||||||
void processRequestResponse(const KodiReply &reply, const QVariantMap &response);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void volumeChanged(const int &volume, const bool &muted);
|
|
||||||
void actionExecuted(const ActionId &actionId, const bool &success);
|
|
||||||
void updateDataReceived(const QVariantMap &data);
|
|
||||||
void versionDataReceived(const QVariantMap &data);
|
|
||||||
void activePlayersChanged(const QVariantList &data);
|
|
||||||
void playerPropertiesReveived(const QVariantMap &properties);
|
|
||||||
|
|
||||||
void playbackStatusChanged(const QString &playbackStatus);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void processResponse(const QByteArray &data);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KODIJSONHANDLER_H
|
#endif // KODIJSONHANDLER_H
|
||||||
|
|||||||
@ -26,23 +26,12 @@ KodiReply::KodiReply()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
KodiReply::KodiReply(const QString &method, const QVariantMap ¶ms, const ActionId &actionId) :
|
KodiReply::KodiReply(const QString &method, const QVariantMap ¶ms) :
|
||||||
m_method(method),
|
m_method(method),
|
||||||
m_params(params),
|
m_params(params)
|
||||||
m_actionId(actionId)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void KodiReply::setActionId(const ActionId &actionId)
|
|
||||||
{
|
|
||||||
m_actionId = actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionId KodiReply::actionId() const
|
|
||||||
{
|
|
||||||
return m_actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KodiReply::setMethod(const QString &method)
|
void KodiReply::setMethod(const QString &method)
|
||||||
{
|
{
|
||||||
m_method = method;
|
m_method = method;
|
||||||
|
|||||||
@ -32,10 +32,7 @@ class KodiReply
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KodiReply();
|
KodiReply();
|
||||||
KodiReply(const QString &method, const QVariantMap ¶ms, const ActionId &actionId = ActionId());
|
KodiReply(const QString &method, const QVariantMap ¶ms);
|
||||||
|
|
||||||
void setActionId(const ActionId &actionId);
|
|
||||||
ActionId actionId() const;
|
|
||||||
|
|
||||||
void setMethod(const QString &method);
|
void setMethod(const QString &method);
|
||||||
QString method() const;
|
QString method() const;
|
||||||
@ -46,8 +43,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
QString m_method;
|
QString m_method;
|
||||||
QVariantMap m_params;
|
QVariantMap m_params;
|
||||||
ActionId m_actionId;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KODIREPLY_H
|
#endif // KODIREPLY_H
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user