first working kodi version

pull/135/head
Simon Stürz 2015-06-24 23:50:32 +02:00 committed by Michael Zanetti
parent 7836730b80
commit 5c05ac2bb6
16 changed files with 836 additions and 105 deletions

BIN
doc/images/kodi_remote.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

BIN
doc/images/kodi_upnp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

View File

@ -20,13 +20,34 @@
/*!
\page kodi.html
\title Kodi
\title Kodi - Media Center
\ingroup plugins
\ingroup network
TODO: description
This plugin allowes you to controll the media center \l{http://kodi.tv/}{Kodi}. If you want to discover
and control Kodi with guh, you need to activate the remote access and the UPnP service.
\chapter "Activate UPnP"
In order to discover Kodi in the network, you need to activate the UPnP serive in the Kodi settings:
\section2 Settings
\image kodi_settings.png
\section2 Settings \unicode{0x2192} Services
\image kodi_services.png
\section2 Settings \unicode{0x2192} Services \unicode{0x2192} UPnP
Activate all options.
\image kodi_upnp.png
\chapter Activate "Remote Control"
In order to control Kodi over the network with guh, you need to activate the remote control permissions:
\section2 Settings \unicode{0x2192} Services \unicode{0x2192} Remote Control
Activate all options.
\image kodi_remote.png
\chapter Plugin properties
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
@ -41,7 +62,7 @@
\note If a \l{StateType} has the parameter \tt{"writable": true}, an \l{ActionType} with the same uuid and \l{ParamType}{ParamTypes}
will be created automatically.
\quotefile plugins/deviceplugins/udpcommander/devicepluginudpcommander.json
\quotefile plugins/deviceplugins/kodi/devicepluginkodi.json
*/
#include "devicepluginkodi.h"
@ -61,32 +82,38 @@ DeviceManager::HardwareResources DevicePluginKodi::requiredHardware() const
DeviceManager::DeviceSetupStatus DevicePluginKodi::setupDevice(Device *device)
{
KodiConnection *kodiConnection = new KodiConnection(QHostAddress(device->paramValue("ip").toString()), 9090, this);
Kodi *kodi= new Kodi(QHostAddress(device->paramValue("ip").toString()), 9090, this);
connect(kodiConnection, &KodiConnection::connectionStateChanged, this, &DevicePluginKodi::onConnectionChanged);
connect(kodi, &Kodi::connectionStatusChanged, this, &DevicePluginKodi::onConnectionChanged);
connect(kodi, &Kodi::stateChanged, this, &DevicePluginKodi::onStateChanged);
connect(kodi, &Kodi::actionExecuted, this, &DevicePluginKodi::onActionExecuted);
connect(kodi, &Kodi::onPlayerPlay, this, &DevicePluginKodi::onPlayerPlay);
connect(kodi, &Kodi::onPlayerPause, this, &DevicePluginKodi::onPlayerPause);
connect(kodi, &Kodi::onPlayerStop, this, &DevicePluginKodi::onPlayerStop);
kodiConnection->connectToKodi();
kodi->connectKodi();
m_kodiConnections.insert(kodiConnection, device);
m_kodis.insert(kodi, device);
return DeviceManager::DeviceSetupStatusSuccess;
}
void DevicePluginKodi::deviceRemoved(Device *device)
{
KodiConnection *kodiConnection = m_kodiConnections.key(device);
m_kodiConnections.remove(kodiConnection);
qCDebug(dcKodi) << "delete Kodi" << device->paramValue("name");
kodiConnection->deleteLater();
Kodi *kodi = m_kodis.key(device);
m_kodis.remove(kodi);
qCDebug(dcKodi) << "delete " << device->paramValue("name");
kodi->deleteLater();
}
void DevicePluginKodi::guhTimer()
{
foreach (KodiConnection *kodi, m_kodiConnections.keys()) {
foreach (Kodi *kodi, m_kodis.keys()) {
if (!kodi->connected()) {
kodi->connectToKodi();
kodi->connectKodi();
continue;
} else {
// update.. ?
// no need for polling information, notifications do the job
//kodi->update();
}
}
}
@ -96,7 +123,7 @@ DeviceManager::DeviceError DevicePluginKodi::discoverDevices(const DeviceClassId
{
Q_UNUSED(params)
Q_UNUSED(deviceClassId)
qCDebug(dcKodi) << "start Kodi UPnP search";
qCDebug(dcKodi) << "start UPnP search";
upnpDiscover();
return DeviceManager::DeviceErrorAsync;
}
@ -134,31 +161,90 @@ void DevicePluginKodi::upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &
DeviceManager::DeviceError DevicePluginKodi::executeAction(Device *device, const Action &action)
{
if (device->deviceClassId() == kodiDeviceClassId) {
if (action.actionTypeId() == sendNotificationActionTypeId) {
Kodi *kodi = m_kodis.key(device);
// check connection state
if (!kodi->connected()) {
return DeviceManager::DeviceErrorHardwareNotAvailable;
}
return DeviceManager::DeviceErrorNoError;
if (action.actionTypeId() == showNotificationActionTypeId) {
kodi->showNotification(action.param("message").value().toString(), 8000, action.id());
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == volumeActionTypeId) {
return DeviceManager::DeviceErrorNoError;
kodi->setVolume(action.param("volume").value().toInt(), action.id());
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == muteActionTypeId) {
kodi->setMuted(action.param("mute").value().toBool(), action.id());
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == pressButtonActionTypeId) {
kodi->pressButton(action.param("button").value().toString(), action.id());
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == systemActionTypeId) {
kodi->systemCommand(action.param("command").value().toString(), action.id());
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == videoLibraryActionTypeId) {
kodi->videoLibrary(action.param("command").value().toString(), action.id());
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == audioLibraryActionTypeId) {
kodi->audioLibrary(action.param("command").value().toString(), action.id());
return DeviceManager::DeviceErrorAsync;
}
return DeviceManager::DeviceErrorActionTypeNotFound;
}
return DeviceManager::DeviceErrorDeviceClassNotFound;
}
void DevicePluginKodi::onConnectionChanged(const bool &connected)
void DevicePluginKodi::onConnectionChanged()
{
KodiConnection *kodiConnection = static_cast<KodiConnection *>(sender());
Device *device = m_kodiConnections.value(kodiConnection);
Kodi *kodi = static_cast<Kodi *>(sender());
Device *device = m_kodis.value(kodi);
device->setStateValue(connectedStateTypeId, connected);
if (kodi->connected()) {
kodi->showNotification("Connected", 2000, ActionId());
kodi->update();
}
device->setStateValue(connectedStateTypeId, kodi->connected());
}
void DevicePluginKodi::dataReceived(const QByteArray &data)
void DevicePluginKodi::onStateChanged()
{
KodiConnection *kodiConnection = static_cast<KodiConnection *>(sender());
emit dataReady(kodiConnection, data);
Kodi *kodi = static_cast<Kodi *>(sender());
Device *device = m_kodis.value(kodi);
// set device state values
device->setStateValue(volumeStateTypeId, kodi->volume());
device->setStateValue(muteStateTypeId, kodi->muted());
}
void DevicePluginKodi::onActionExecuted(const ActionId &actionId, const bool &success)
{
if (success) {
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
} else {
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorInvalidParameter);
}
}
void DevicePluginKodi::onPlayerPlay()
{
Kodi *kodi = static_cast<Kodi *>(sender());
Device *device = m_kodis.value(kodi);
emit emitEvent(Event(onPlayerPlayEventTypeId, device->id()));
}
void DevicePluginKodi::onPlayerPause()
{
Kodi *kodi = static_cast<Kodi *>(sender());
Device *device = m_kodis.value(kodi);
emit emitEvent(Event(onPlayerPauseEventTypeId, device->id()));
}
void DevicePluginKodi::onPlayerStop()
{
Kodi *kodi = static_cast<Kodi *>(sender());
Device *device = m_kodis.value(kodi);
emit emitEvent(Event(onPlayerStopEventTypeId, device->id()));
}

View File

@ -22,7 +22,7 @@
#define DEVICEPLUGINKODI_H
#include "plugin/deviceplugin.h"
#include "kodiconnection.h"
#include "kodi.h"
#include <QHash>
#include <QDebug>
@ -48,15 +48,16 @@ public:
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
private:
QHash<KodiConnection *, Device *> m_kodiConnections;
signals:
void dataReady(KodiConnection *kodiConnection, const QByteArray &data);
QHash<Kodi *, Device *> m_kodis;
private slots:
void onConnectionChanged(const bool &connected);
void dataReceived(const QByteArray &data);
void onConnectionChanged();
void onStateChanged();
void onActionExecuted(const ActionId &actionId, const bool &success);
void onPlayerPlay();
void onPlayerPause();
void onPlayerStop();
};
#endif // DEVICEPLUGINKODI_H

View File

@ -53,15 +53,123 @@
}
}
],
"eventTypes": [
{
"id": "2535a1eb-7643-4874-98f6-b027fdff6311",
"idName": "onPlayerPlay",
"name": "player play"
},
{
"id": "99498b1c-e9c0-480a-9e91-662ee79ba976",
"idName": "onPlayerPause",
"name": "player pause"
},
{
"id": "a02ce255-3abb-435d-a92e-7f99c952ecb2",
"idName": "onPlayerStop",
"name": "player stop"
}
],
"actionTypes": [
{
"id": "dc0aa3b5-4eae-4e58-a4ac-d4c124da53f1",
"idName": "sendNotification",
"name": "send notification",
"idName": "showNotification",
"name": "show notification",
"paramTypes": [
{
"name": "message",
"type": "QString"
"type": "QString",
"inputType": "TextLine"
}
]
},
{
"id": "28060803-aa85-44a4-9dec-ee669dfb629f",
"idName": "pressButton",
"name": "press button",
"paramTypes": [
{
"name": "button",
"type": "QString",
"allowedValues": [
"left",
"right",
"up",
"down",
"pageup",
"pagedown",
"select",
"back",
"info",
"pause",
"stop",
"skipnext",
"skipprevious",
"stepforward",
"stepback",
"osd",
"play",
"playpause",
"fastforward",
"rewind",
"togglefullscreen",
"mute",
"volumeup",
"volumedown",
"channelup",
"channeldown",
"red",
"green",
"yellow",
"blue"
]
}
]
},
{
"id": "8d51cd64-ecef-44f8-85b0-697bef252ce5",
"idName": "system",
"name": "system",
"paramTypes": [
{
"name": "command",
"type": "QString",
"allowedValues": [
"hibernate",
"reboot",
"shutdown",
"suspend"
]
}
]
},
{
"id": "59f7ad10-16eb-40b7-a88b-c8393ae8e413",
"idName": "videoLibrary",
"name": "video library",
"paramTypes": [
{
"name": "command",
"type": "QString",
"allowedValues": [
"scan",
"clean"
]
}
]
},
{
"id": "3d5120eb-1007-46c3-b76e-d9d4b105b9f2",
"idName": "audioLibrary",
"name": "audio library",
"paramTypes": [
{
"name": "command",
"type": "QString",
"allowedValues": [
"scan",
"clean"
]
}
]
}

View File

@ -1,42 +1,133 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "jsonhandler.h"
#include "loggingcategories.h"
#include <QPixmap>
#include <QBuffer>
#include <QJsonDocument>
JsonHandler::JsonHandler(QObject *parent) :
QObject(parent)
JsonHandler::JsonHandler(KodiConnection *connection, QObject *parent) :
QObject(parent),
m_connection(connection),
m_id(0)
{
connect(m_connection, &KodiConnection::dataReady, this, &JsonHandler::processResponse);
}
//QByteArray JsonHandler::createHelloMessage(QString title, QString message)
//{
// QByteArray payload;
void JsonHandler::sendData(const QString &method, const QVariantMap &params, const ActionId &actionId)
{
QVariantMap package;
package.insert("id", m_id);
package.insert("method", method);
package.insert("params", params);
package.insert("jsonrpc", "2.0");
// QByteArray iconData;
// QBuffer buffer(&iconData);
// buffer.open(QIODevice::WriteOnly);
// icon.save(&buffer, "PNG");
// // payload.clear();
m_replys.insert(m_id, KodiReply(method, params, actionId));
// // // titel
// // payload.push_back(QByteArray::fromStdString(title.toStdString()));
// // payload.push_back('\0');
QJsonDocument jsonDoc = QJsonDocument::fromVariant(package);
qCDebug(dcKodi) << "sending data" << jsonDoc.toJson();
m_connection->sendData(jsonDoc.toJson());
m_id++;
}
// // // message
// // payload.push_back(QByteArray::fromStdString(message.toStdString()));
// // payload.push_back('\0');
void JsonHandler::processNotification(const QString &method, const QVariantMap &params)
{
if (method == "Application.OnVolumeChanged") {
QVariantMap data = params.value("data").toMap();
qCDebug(dcKodi) << "got volume changed notification" << "volume:" << data.value("volume").toInt() << " muted:" << data.value("muted").toBool();
emit volumeChanged(data.value("volume").toInt(), data.value("muted").toBool());
} else if (method == "Player.onPlayerPlay") {
qCDebug(dcKodi) << "got player play notification";
emit onPlayerPlay();
} else if (method == "Player.onPlayerPause") {
qCDebug(dcKodi) << "got player pause notification";
emit onPlayerPause();
} else if (method == "Player.onPlayerStop") {
qCDebug(dcKodi) << "got player stop notification";
emit onPlayerPause();
}
// // // icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF )
// // payload.push_back(2);
}
// // payload.push_back("0000");
void JsonHandler::processActionResponse(const KodiReply &reply, const QVariantMap &response)
{
if (response.contains("error")) {
qCDebug(dcKodi) << QJsonDocument::fromVariant(response).toJson();
qCWarning(dcKodi) << "got action error response:" << response.value("error").toMap().value("message").toString();
emit actionExecuted(reply.actionId(), false);
} else {
emit actionExecuted(reply.actionId(), true);
}
}
// // // image data
// // payload.push_back(iconData);
// // payload.push_back('\0');
void JsonHandler::processRequestResponse(const KodiReply &reply, const QVariantMap &response)
{
if (response.contains("error")) {
qCDebug(dcKodi) << QJsonDocument::fromVariant(response).toJson();
qCWarning(dcKodi) << "got request error response:" << response.value("error").toMap().value("message").toString();
}
// // qCDebug(dcKodi) << payload;
if (reply.method() == "Application.GetProperties") {
qCDebug(dcKodi) << "got update response" << response;
emit updateDataReceived(response.value("result").toMap());
}
}
// return payload;
//}
void JsonHandler::processResponse(const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qCWarning(dcKodi) << "failed to parse JSON data:" << data << ":" << error.errorString();
return;
}
qCDebug(dcKodi) << "data received:" << jsonDoc.toJson();
QVariantMap message = jsonDoc.toVariant().toMap();
// check jsonrpc value
if (!message.contains("jsonrpc") || message.value("jsonrpc").toString() != "2.0") {
qCWarning(dcKodi) << "jsonrpc 2.0 value missing in message" << data;
}
// check id (if there is no id, it's an notification from kodi)
if (!message.contains("id")) {
// check method
if (!message.contains("method")) {
qCWarning(dcKodi) << "method missing in message" << data;
}
processNotification(message.value("method").toString(), message.value("params").toMap());
return;
}
int id = message.value("id").toInt();
KodiReply reply = m_replys.take(id);
// check if this message is a response to an action call
if (reply.actionId() != ActionId()) {
processActionResponse(reply, message);
return;
}
processRequestResponse(reply, message);
}

View File

@ -1,19 +1,63 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef JSONHANDLER_H
#define JSONHANDLER_H
#include <QObject>
#include <QVariant>
#include <QHash>
#include "kodiconnection.h"
#include "kodireply.h"
#include "typeutils.h"
class JsonHandler : public QObject
{
Q_OBJECT
public:
explicit JsonHandler(QObject *parent = 0);
explicit JsonHandler(KodiConnection *connection = 0, QObject *parent = 0);
//static QByteArray createHelloMessage(QString title, QString message);
void sendData(const QString &method, const QVariantMap &params, const ActionId &actionId);
private:
KodiConnection *m_connection;
int m_id;
QHash<int, KodiReply> m_replys;
void processNotification(const QString &method, const QVariantMap &params);
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);
public slots:
void onPlayerPlay();
void onPlayerPause();
void onPlayerStop();
private slots:
void processResponse(const QByteArray &data);
};

View File

@ -0,0 +1,182 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "kodi.h"
Kodi::Kodi(const QHostAddress &hostAddress, const int &port, QObject *parent) :
QObject(parent)
{
m_connection = new KodiConnection(hostAddress, port, this);
connect (m_connection, &KodiConnection::connectionStatusChanged, this, &Kodi::connectionStatusChanged);
m_jsonHandler = new JsonHandler(m_connection, this);
connect(m_jsonHandler, &JsonHandler::volumeChanged, this, &Kodi::onVolumeChanged);
connect(m_jsonHandler, &JsonHandler::actionExecuted, this, &Kodi::actionExecuted);
connect(m_jsonHandler, &JsonHandler::updateDataReceived, this, &Kodi::onUpdateFinished);
connect(m_jsonHandler, &JsonHandler::onPlayerPlay, this, &Kodi::onPlayerPlay);
connect(m_jsonHandler, &JsonHandler::onPlayerPause, this, &Kodi::onPlayerPause);
connect(m_jsonHandler, &JsonHandler::onPlayerStop, this, &Kodi::onPlayerStop);
}
QHostAddress Kodi::hostAddress() const
{
return m_connection->hostAddress();
}
int Kodi::port() const
{
return m_connection->port();
}
bool Kodi::connected() const
{
return m_connection->connected();
}
void Kodi::setMuted(const bool &muted, const ActionId &actionId)
{
QVariantMap params;
params.insert("mute", muted);
m_jsonHandler->sendData("Application.SetMute", params, actionId);
}
bool Kodi::muted() const
{
return m_muted;
}
void Kodi::setVolume(const int &volume, const ActionId &actionId)
{
QVariantMap params;
params.insert("volume", volume);
m_jsonHandler->sendData("Application.SetVolume", params, actionId);
}
int Kodi::volume() const
{
return m_volume;
}
void Kodi::showNotification(const QString &message, const int &displayTime, const ActionId &actionId)
{
QVariantMap params;
params.insert("title", "guh notification");
params.insert("message", message);
params.insert("displaytime", displayTime);
m_jsonHandler->sendData("GUI.ShowNotification", params, actionId);
}
void Kodi::pressButton(const QString &button, const ActionId &actionId)
{
QVariantMap params;
params.insert("action", button);
m_jsonHandler->sendData("Input.ExecuteAction", params, actionId);
}
void Kodi::systemCommand(const QString &command, const ActionId &actionId)
{
QString method;
if (command == "hibernate") {
method = "Hibernate";
} else if (command == "reboot") {
method = "Reboot";
} else if (command == "shutdown") {
method = "Shutdown";
} else if (command == "suspend") {
method = "Suspend";
} else {
// already checkt with allowed values
}
m_jsonHandler->sendData("System." + method, QVariantMap(), actionId);
}
void Kodi::videoLibrary(const QString &command, const ActionId &actionId)
{
QString method;
if (command == "scan") {
method = "Scan";
} else if (command == "clean") {
method = "Clean";
} else {
// already checkt with allowed values
}
m_jsonHandler->sendData("VideoLibrary." + method, QVariantMap(), actionId);
}
void Kodi::audioLibrary(const QString &command, const ActionId &actionId)
{
QString method;
if (command == "scan") {
method = "Scan";
} else if (command == "clean") {
method = "Clean";
} else {
// already checkt with allowed values
}
m_jsonHandler->sendData("AudioLibrary." + method, QVariantMap(), actionId);
}
void Kodi::update()
{
QVariantMap params;
QVariantList properties;
properties.append("volume");
properties.append("muted");
properties.append("name");
properties.append("version");
params.insert("properties", properties);
m_jsonHandler->sendData("Application.GetProperties", params, ActionId());
}
void Kodi::connectKodi()
{
m_connection->connectKodi();
}
void Kodi::disconnectKodi()
{
m_connection->disconnectKodi();
}
void Kodi::onVolumeChanged(const int &volume, const bool &muted)
{
if (m_volume != volume || m_muted != muted) {
m_volume = volume;
m_muted = muted;
emit stateChanged();
}
}
void Kodi::onUpdateFinished(const QVariantMap &data)
{
if (data.contains("volume")) {
m_volume = data.value("volume").toInt();
}
if (data.contains("muted")) {
m_volume = data.value("muted").toBool();
}
emit stateChanged();
}

View File

@ -0,0 +1,83 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef KODI_H
#define KODI_H
#include <QObject>
#include <QHostAddress>
#include "kodiconnection.h"
#include "jsonhandler.h"
class Kodi : public QObject
{
Q_OBJECT
public:
explicit Kodi(const QHostAddress &hostAddress, const int &port = 9090, QObject *parent = 0);
QHostAddress hostAddress() const;
int port() const;
bool connected() const;
// propertys
void setMuted(const bool &muted, const ActionId &actionId);
bool muted() const;
void setVolume(const int &volume, const ActionId &actionId);
int volume() const;
// actions
void showNotification(const QString &message, const int &displayTime, const ActionId &actionId);
void pressButton(const QString &button, const ActionId &actionId);
void systemCommand(const QString &command, const ActionId &actionId);
void videoLibrary(const QString &command, const ActionId &actionId);
void audioLibrary(const QString &command, const ActionId &actionId);
void update();
void connectKodi();
void disconnectKodi();
private:
KodiConnection *m_connection;
JsonHandler *m_jsonHandler;
bool m_muted;
int m_volume;
signals:
void connectionStatusChanged();
void stateChanged();
void actionExecuted(const ActionId &actionId, const bool &success);
void onPlayerPlay();
void onPlayerPause();
void onPlayerStop();
private slots:
void onVolumeChanged(const int &volume, const bool &muted);
void onUpdateFinished(const QVariantMap &data);
};
#endif // KODI_H

View File

@ -7,10 +7,14 @@ RESOURCES += images.qrc \
SOURCES += \
devicepluginkodi.cpp \
kodiconnection.cpp \
jsonhandler.cpp
jsonhandler.cpp \
kodi.cpp \
kodireply.cpp
HEADERS += \
devicepluginkodi.h \
kodiconnection.h \
jsonhandler.h
jsonhandler.h \
kodi.h \
kodireply.h

View File

@ -1,3 +1,23 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "kodiconnection.h"
#include "loggingcategories.h"
#include "jsonhandler.h"
@ -18,7 +38,7 @@ KodiConnection::KodiConnection(const QHostAddress &hostAddress, const int &port,
connect(m_socket, &QTcpSocket::readyRead, this, &KodiConnection::readData);
}
void KodiConnection::connectToKodi()
void KodiConnection::connectKodi()
{
if (m_socket->state() == QAbstractSocket::ConnectingState) {
return;
@ -26,7 +46,7 @@ void KodiConnection::connectToKodi()
m_socket->connectToHost(m_hostAddress, m_port);
}
void KodiConnection::disconnectFromKodi()
void KodiConnection::disconnectKodi()
{
m_socket->close();
}
@ -50,51 +70,31 @@ void KodiConnection::onConnected()
{
qCDebug(dcKodi) << "connected successfully to" << hostAddress().toString() << port();
m_connected = true;
// QPixmap logo = QPixmap(":/images/guh-logo.png");
// qCDebug(dcKodi) << "image size" << logo.size();
emit connectionStateChanged(true);
emit connectionStatusChanged();
}
void KodiConnection::onDisconnected()
{
qCDebug(dcKodi) << "disconnected from" << hostAddress().toString() << port();
m_connected = false;
emit connectionStateChanged(false);
emit connectionStatusChanged();
}
void KodiConnection::onError(QAbstractSocket::SocketError socketError)
{
qCWarning(dcKodi) << "socket error:" << socketError << m_socket->errorString();
if (connected()) {
qCWarning(dcKodi) << "socket error:" << socketError << m_socket->errorString();
}
}
void KodiConnection::readData()
{
QByteArray data = m_socket->readAll();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qCWarning(dcKodi) << "failed to parse JSON data:" << data << ":" << error.errorString();
return;
}
qCDebug(dcKodi) << "data received:" << jsonDoc.toJson();
emit dataReady(data);
}
void KodiConnection::sendData(const QString &method, const QVariantMap &params)
void KodiConnection::sendData(const QByteArray &message)
{
QVariantMap package;
package.insert("id", m_id);
package.insert("method", method);
package.insert("params", params);
package.insert("jsonrpc", "2.0");
m_id++;
QJsonDocument jsonDoc = QJsonDocument::fromVariant(package);
qCDebug(dcKodi) << "sending data" << jsonDoc.toJson();
m_socket->write(jsonDoc.toJson());
m_socket->write(message);
}

View File

@ -1,3 +1,23 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef KODICONNECTION_H
#define KODICONNECTION_H
@ -12,8 +32,8 @@ class KodiConnection : public QObject
public:
explicit KodiConnection(const QHostAddress &hostAddress, const int &port = 9090, QObject *parent = 0);
void connectToKodi();
void disconnectFromKodi();
void connectKodi();
void disconnectKodi();
QHostAddress hostAddress() const;
int port() const;
@ -21,14 +41,13 @@ public:
bool connected();
private:
QTcpSocket *m_socket;
QHostAddress m_hostAddress;
int m_port;
int m_id;
bool m_connected;
QTcpSocket *m_socket;
private slots:
void onConnected();
void onDisconnected();
@ -36,11 +55,11 @@ private slots:
void readData();
signals:
void connectionStateChanged(const bool &connected);
void connectionStatusChanged();
void dataReady(const QByteArray &data);
public slots:
void sendData(const QString &method, const QVariantMap &params = QVariantMap());
void sendData(const QByteArray &message);
};

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "kodireply.h"
KodiReply::KodiReply()
{
}
KodiReply::KodiReply(const QString &method, const QVariantMap &params, const ActionId &actionId) :
m_method(method),
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)
{
m_method = method;
}
QString KodiReply::method() const
{
return m_method;
}
void KodiReply::setParams(const QVariantMap &params)
{
m_params = params;
}
QVariantMap KodiReply::params() const
{
return m_params;
}

View File

@ -0,0 +1,51 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef KODIREPLY_H
#define KODIREPLY_H
#include <QVariant>
#include <QString>
#include "typeutils.h"
class KodiReply
{
public:
KodiReply();
KodiReply(const QString &method, const QVariantMap &params, const ActionId &actionId = ActionId());
void setActionId(const ActionId &actionId);
ActionId actionId() const;
void setMethod(const QString &method);
QString method() const;
void setParams(const QVariantMap &params);
QVariantMap params() const;
private:
QString m_method;
QVariantMap m_params;
ActionId m_actionId;
};
#endif // KODIREPLY_H