all actions are now functional
This commit is contained in:
parent
ac58d41ea6
commit
5ba83790c8
@ -38,15 +38,49 @@ DevicePluginSonos::DevicePluginSonos()
|
|||||||
|
|
||||||
DevicePluginSonos::~DevicePluginSonos()
|
DevicePluginSonos::~DevicePluginSonos()
|
||||||
{
|
{
|
||||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer5sec);
|
||||||
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer60sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
|
Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
|
||||||
{
|
{
|
||||||
if (!m_pluginTimer) {
|
if (!m_pluginTimer5sec) {
|
||||||
hardwareManager()->pluginTimerManager()->registerTimer(10);
|
m_pluginTimer5sec = hardwareManager()->pluginTimerManager()->registerTimer(5);
|
||||||
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginSonos::onPluginTimer);
|
connect(m_pluginTimer5sec, &PluginTimer::timeout, this, [this]() {
|
||||||
|
|
||||||
|
foreach (Device *connectionDevice, myDevices().filterByDeviceClassId(sonosConnectionDeviceClassId)) {
|
||||||
|
Sonos *sonos = m_sonosConnections.value(connectionDevice);
|
||||||
|
if (!sonos) {
|
||||||
|
qWarning(dcSonos()) << "No sonos connection found to device" << connectionDevice->name();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (Device *groupDevice, myDevices().filterByParentDeviceId(connectionDevice->id())) {
|
||||||
|
if (groupDevice->deviceClassId() == sonosGroupDeviceClassId) {
|
||||||
|
//get playback status of each group
|
||||||
|
QString groupId = groupDevice->paramValue(sonosGroupDeviceGroupIdParamTypeId).toString();
|
||||||
|
sonos->getGroupPlaybackStatus(groupId);
|
||||||
|
sonos->getGroupMetadataStatus(groupId);
|
||||||
|
sonos->getGroupVolume(groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_pluginTimer60sec) {
|
||||||
|
m_pluginTimer60sec = hardwareManager()->pluginTimerManager()->registerTimer(60);
|
||||||
|
connect(m_pluginTimer60sec, &PluginTimer::timeout, this, [this]() {
|
||||||
|
foreach (Device *device, myDevices().filterByDeviceClassId(sonosConnectionDeviceClassId)) {
|
||||||
|
Sonos *sonos = m_sonosConnections.value(device);
|
||||||
|
if (!sonos) {
|
||||||
|
qWarning(dcSonos()) << "No sonos connection found to device" << device->name();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//get groups for each household in order to add or remove groups
|
||||||
|
sonos->getHouseholds();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!m_tokenRefreshTimer) {
|
if(!m_tokenRefreshTimer) {
|
||||||
@ -74,8 +108,6 @@ Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return Device::DeviceSetupStatusSuccess;
|
return Device::DeviceSetupStatusSuccess;
|
||||||
}
|
}
|
||||||
@ -213,8 +245,10 @@ void DevicePluginSonos::deviceRemoved(Device *device)
|
|||||||
{
|
{
|
||||||
qCDebug(dcSonos) << "Delete " << device->name();
|
qCDebug(dcSonos) << "Delete " << device->name();
|
||||||
if (myDevices().empty()) {
|
if (myDevices().empty()) {
|
||||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer5sec);
|
||||||
m_pluginTimer = nullptr;
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer60sec);
|
||||||
|
m_pluginTimer5sec = nullptr;
|
||||||
|
m_pluginTimer60sec = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,31 +256,32 @@ void DevicePluginSonos::deviceRemoved(Device *device)
|
|||||||
Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Action &action)
|
Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Action &action)
|
||||||
{
|
{
|
||||||
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
||||||
Sonos *sonos = m_sonosConnections.value(device);
|
Sonos *sonos = m_sonosConnections.value(myDevices().findById(device->parentId()));
|
||||||
QByteArray groupId = device->paramValue(sonosGroupDeviceGroupIdParamTypeId).toByteArray();
|
QString groupId = device->paramValue(sonosGroupDeviceGroupIdParamTypeId).toString();
|
||||||
|
|
||||||
if (!sonos)
|
if (!sonos) {
|
||||||
|
qWarning(dcSonos()) << "Action cannot be executed: Sonos connection not available";
|
||||||
return Device::DeviceErrorInvalidParameter;
|
return Device::DeviceErrorInvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == sonosGroupPlayActionTypeId) {
|
if (action.actionTypeId() == sonosGroupPlayActionTypeId) {
|
||||||
sonos->groupPlay(groupId);
|
m_pendingActions.insert(sonos->groupPlay(groupId), action.id());
|
||||||
return Device::DeviceErrorAsync;
|
return Device::DeviceErrorAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == sonosGroupShuffleActionTypeId) {
|
if (action.actionTypeId() == sonosGroupShuffleActionTypeId) {
|
||||||
bool shuffle = action.param(sonosGroupShuffleActionShuffleParamTypeId).value().toBool();
|
bool shuffle = action.param(sonosGroupShuffleActionShuffleParamTypeId).value().toBool();
|
||||||
sonos->groupSetShuffle(groupId, shuffle);
|
m_pendingActions.insert(sonos->groupSetShuffle(groupId, shuffle), action.id());
|
||||||
return Device::DeviceErrorAsync;
|
return Device::DeviceErrorAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == sonosGroupRepeatActionTypeId) {
|
if (action.actionTypeId() == sonosGroupRepeatActionTypeId) {
|
||||||
|
|
||||||
if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "None") {
|
if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "None") {
|
||||||
sonos->groupSetRepeat(groupId, Sonos::RepeatModeNone);
|
m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeNone), action.id());
|
||||||
} else if (action.param(sonosGroupShuffleActionShuffleParamTypeId).value().toString() == "One") {
|
} else if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "One") {
|
||||||
sonos->groupSetRepeat(groupId, Sonos::RepeatModeOne);
|
m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeOne), action.id());
|
||||||
} else if (action.param(sonosGroupShuffleActionShuffleParamTypeId).value().toString() == "All") {
|
} else if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "All") {
|
||||||
sonos->groupSetRepeat(groupId, Sonos::RepeatModeAll);
|
m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeAll), action.id());
|
||||||
} else {
|
} else {
|
||||||
return Device::DeviceErrorHardwareFailure;
|
return Device::DeviceErrorHardwareFailure;
|
||||||
}
|
}
|
||||||
@ -269,6 +304,13 @@ Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Actio
|
|||||||
return Device::DeviceErrorAsync;
|
return Device::DeviceErrorAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (action.actionTypeId() == sonosGroupVolumeActionTypeId) {
|
||||||
|
int volume = action.param(sonosGroupVolumeActionVolumeParamTypeId).value().toInt();
|
||||||
|
m_pendingActions.insert(sonos->setGroupVolume(groupId, volume), action.id());
|
||||||
|
return Device::DeviceErrorAsync;
|
||||||
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == sonosGroupSkipNextActionTypeId) {
|
if (action.actionTypeId() == sonosGroupSkipNextActionTypeId) {
|
||||||
m_pendingActions.insert(sonos->groupSkipToNextTrack(groupId), action.id());
|
m_pendingActions.insert(sonos->groupSkipToNextTrack(groupId), action.id());
|
||||||
return Device::DeviceErrorAsync;
|
return Device::DeviceErrorAsync;
|
||||||
@ -282,11 +324,11 @@ Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Actio
|
|||||||
if (action.actionTypeId() == sonosGroupPlaybackStatusActionTypeId) {
|
if (action.actionTypeId() == sonosGroupPlaybackStatusActionTypeId) {
|
||||||
QString playbackStatus = action.param(sonosGroupPlaybackStatusActionPlaybackStatusParamTypeId).value().toString();
|
QString playbackStatus = action.param(sonosGroupPlaybackStatusActionPlaybackStatusParamTypeId).value().toString();
|
||||||
if (playbackStatus == "Playing") {
|
if (playbackStatus == "Playing") {
|
||||||
sonos->groupPlay(groupId);
|
m_pendingActions.insert(sonos->groupPlay(groupId), action.id());
|
||||||
} else if(playbackStatus == "Stopped") {
|
} else if(playbackStatus == "Stopped") {
|
||||||
sonos->groupPause(groupId);
|
m_pendingActions.insert(sonos->groupPause(groupId), action.id());
|
||||||
} else if(playbackStatus == "Paused") {
|
} else if(playbackStatus == "Paused") {
|
||||||
sonos->groupPause(groupId);
|
m_pendingActions.insert(sonos->groupPause(groupId), action.id());
|
||||||
}
|
}
|
||||||
return Device::DeviceErrorAsync;
|
return Device::DeviceErrorAsync;
|
||||||
}
|
}
|
||||||
@ -295,28 +337,6 @@ Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Actio
|
|||||||
return Device::DeviceErrorDeviceClassNotFound;
|
return Device::DeviceErrorDeviceClassNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginSonos::onPluginTimer()
|
|
||||||
{
|
|
||||||
foreach (Device *device, myDevices().filterByDeviceClassId(sonosConnectionDeviceClassId)) {
|
|
||||||
|
|
||||||
//get groups for each household in order to add or remove groups
|
|
||||||
Sonos *sonos = m_sonosConnections.value(device);
|
|
||||||
if (!sonos)
|
|
||||||
continue;
|
|
||||||
sonos->getHouseholds();
|
|
||||||
|
|
||||||
foreach (Device *groupDevice, myDevices().filterByParentDeviceId(device->id())) {
|
|
||||||
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
|
||||||
//get playback status of each group
|
|
||||||
QByteArray groupId = groupDevice->paramValue(sonosGroupDeviceGroupIdParamTypeId).toByteArray();
|
|
||||||
sonos->getGroupPlaybackStatus(groupId);
|
|
||||||
sonos->getGroupMetadataStatus(groupId);
|
|
||||||
sonos->getGroupVolume(groupId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevicePluginSonos::onConnectionChanged(bool connected)
|
void DevicePluginSonos::onConnectionChanged(bool connected)
|
||||||
{
|
{
|
||||||
Sonos *sonos = static_cast<Sonos *>(sender());
|
Sonos *sonos = static_cast<Sonos *>(sender());
|
||||||
@ -354,6 +374,10 @@ void DevicePluginSonos::onRefreshTimeout()
|
|||||||
if (jsonDoc.toVariant().toMap().contains("expires_in")) {
|
if (jsonDoc.toVariant().toMap().contains("expires_in")) {
|
||||||
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
|
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
|
||||||
qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
|
qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
|
||||||
|
if (!m_tokenRefreshTimer) {
|
||||||
|
qWarning(dcSonos()) << "Token refresh timer not initialized";
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_tokenRefreshTimer->start((expireTime - 20) * 1000);
|
m_tokenRefreshTimer->start((expireTime - 20) * 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -364,6 +388,34 @@ void DevicePluginSonos::onHouseholdIdsReceived(QList<QString> householdIds)
|
|||||||
Sonos *sonos = static_cast<Sonos *>(sender());
|
Sonos *sonos = static_cast<Sonos *>(sender());
|
||||||
foreach(QString householdId, householdIds) {
|
foreach(QString householdId, householdIds) {
|
||||||
sonos->getGroups(householdId);
|
sonos->getGroups(householdId);
|
||||||
|
sonos->getFavorites(householdId);
|
||||||
|
sonos->getPlaylists(householdId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginSonos::onFavouritesReceived(const QString &householdId, QList<Sonos::FavouriteObject> favourites)
|
||||||
|
{
|
||||||
|
Q_UNUSED(householdId);
|
||||||
|
foreach(Sonos::FavouriteObject favourite, favourites) {
|
||||||
|
qDebug(dcSonos()) << "Favourite: " << favourite.name << favourite.description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginSonos::onPlaylistsReceived(const QString &householdId, QList<Sonos::PlaylistObject> playlists)
|
||||||
|
{
|
||||||
|
Sonos *sonos = static_cast<Sonos *>(sender());
|
||||||
|
foreach(Sonos::PlaylistObject playlist, playlists) {
|
||||||
|
qDebug(dcSonos()) << "Playlist: " << playlist.name << playlist.type << playlist.trackCount;
|
||||||
|
sonos->getPlaylist(householdId, playlist.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginSonos::onPlaylistSummaryReceived(const QString &householdId, Sonos::PlaylistSummaryObject playlistSummary)
|
||||||
|
{
|
||||||
|
Q_UNUSED(householdId);
|
||||||
|
qDebug(dcSonos()) << "Playlist summary received: " << playlistSummary.name;
|
||||||
|
foreach(Sonos::PlaylistTrackObject track, playlistSummary.tracks) {
|
||||||
|
qDebug(dcSonos()) << "---- Track: " << track.name << track.album << track.artist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,27 +428,54 @@ void DevicePluginSonos::onGroupsReceived(QList<Sonos::GroupObject> groupObjects)
|
|||||||
|
|
||||||
QList<DeviceDescriptor> deviceDescriptors;
|
QList<DeviceDescriptor> deviceDescriptors;
|
||||||
foreach(Sonos::GroupObject groupObject, groupObjects) {
|
foreach(Sonos::GroupObject groupObject, groupObjects) {
|
||||||
if (!myDevices().filterByParam(sonosGroupDeviceGroupIdParamTypeId, groupObject.groupId).isEmpty()) {
|
Device *groupDevice = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupObject.groupId));
|
||||||
continue;
|
if (groupDevice) {
|
||||||
}
|
groupDevice->setName(groupObject.displayName);
|
||||||
|
} else {
|
||||||
|
//new device, add to the system
|
||||||
DeviceDescriptor deviceDescriptor(sonosGroupDeviceClassId, groupObject.displayName, "Sonos Group", parentDevice->id());
|
DeviceDescriptor deviceDescriptor(sonosGroupDeviceClassId, groupObject.displayName, "Sonos Group", parentDevice->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sonosGroupDeviceGroupIdParamTypeId, groupObject.groupId));
|
params.append(Param(sonosGroupDeviceGroupIdParamTypeId, groupObject.groupId));
|
||||||
deviceDescriptor.setParams(params);
|
deviceDescriptor.setParams(params);
|
||||||
deviceDescriptors.append(deviceDescriptor);
|
deviceDescriptors.append(deviceDescriptor);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!deviceDescriptors.isEmpty())
|
if (!deviceDescriptors.isEmpty())
|
||||||
emit autoDevicesAppeared(sonosGroupDeviceClassId, deviceDescriptors);
|
emit autoDevicesAppeared(sonosGroupDeviceClassId, deviceDescriptors);
|
||||||
|
|
||||||
|
//delete auto devices
|
||||||
|
foreach(Device *groupDevice, myDevices().filterByParentDeviceId(parentDevice->id())) {
|
||||||
|
QString groupId = groupDevice->paramValue(sonosGroupDeviceGroupIdParamTypeId).toString();
|
||||||
|
bool deviceRemoved = true;
|
||||||
|
foreach (Sonos::GroupObject groupObject, groupObjects) {
|
||||||
|
if(groupObject.groupId == groupId) {
|
||||||
|
deviceRemoved = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (deviceRemoved) {
|
||||||
|
emit autoDeviceDisappeared(groupDevice->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginSonos::onPlayBackStatusReceived(const QString &groupId, Sonos::PlayBackObject playBack)
|
void DevicePluginSonos::onPlayBackStatusReceived(const QString &groupId, Sonos::PlayBackObject playBack)
|
||||||
{
|
{
|
||||||
qDebug(dcSonos()) << "Playback status received" << playBack.playbackState;
|
|
||||||
Device *device = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupId));
|
Device *device = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupId));
|
||||||
if (!device)
|
if (!device)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
device->setStateValue(sonosGroupShuffleStateTypeId, playBack.playMode.shuffle);
|
||||||
|
|
||||||
|
if (playBack.playMode.repeatOne) {
|
||||||
|
device->setStateValue(sonosGroupRepeatStateTypeId, "One");
|
||||||
|
} else if (playBack.playMode.repeat) {
|
||||||
|
device->setStateValue(sonosGroupRepeatStateTypeId, "All");
|
||||||
|
} else {
|
||||||
|
device->setStateValue(sonosGroupRepeatStateTypeId, "None");
|
||||||
|
}
|
||||||
|
|
||||||
switch (playBack.playbackState) {
|
switch (playBack.playbackState) {
|
||||||
case Sonos::PlayBackStateIdle:
|
case Sonos::PlayBackStateIdle:
|
||||||
device->setStateValue(sonosGroupPlaybackStatusStateTypeId, "Stopped");
|
device->setStateValue(sonosGroupPlaybackStatusStateTypeId, "Stopped");
|
||||||
@ -424,7 +503,7 @@ void DevicePluginSonos::onMetadataStatusReceived(const QString &groupId, Sonos::
|
|||||||
device->setStateValue(sonosGroupArtworkStateTypeId, metaDataStatus.container.imageUrl);
|
device->setStateValue(sonosGroupArtworkStateTypeId, metaDataStatus.container.imageUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginSonos::onVolumeReceived(const QString &groupId, Sonos::GroupVolumeObject groupVolume)
|
void DevicePluginSonos::onVolumeReceived(const QString &groupId, Sonos::VolumeObject groupVolume)
|
||||||
{
|
{
|
||||||
Device *device = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupId));
|
Device *device = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupId));
|
||||||
if (!device)
|
if (!device)
|
||||||
|
|||||||
@ -52,7 +52,8 @@ public:
|
|||||||
Device::DeviceError executeAction(Device *device, const Action &action) override;
|
Device::DeviceError executeAction(Device *device, const Action &action) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PluginTimer *m_pluginTimer = nullptr;
|
PluginTimer *m_pluginTimer5sec = nullptr;
|
||||||
|
PluginTimer *m_pluginTimer60sec = nullptr;
|
||||||
QTimer *m_tokenRefreshTimer = nullptr;
|
QTimer *m_tokenRefreshTimer = nullptr;
|
||||||
|
|
||||||
QHash<Device *, Sonos *> m_sonosConnections;
|
QHash<Device *, Sonos *> m_sonosConnections;
|
||||||
@ -63,15 +64,18 @@ private:
|
|||||||
|
|
||||||
QHash<QUuid, ActionId> m_pendingActions;
|
QHash<QUuid, ActionId> m_pendingActions;
|
||||||
private slots:
|
private slots:
|
||||||
void onPluginTimer();
|
|
||||||
void onConnectionChanged(bool connected);
|
void onConnectionChanged(bool connected);
|
||||||
void onRefreshTimeout();
|
void onRefreshTimeout();
|
||||||
|
|
||||||
void onHouseholdIdsReceived(QList<QString> householdIds);
|
void onHouseholdIdsReceived(QList<QString> householdIds);
|
||||||
|
void onFavouritesReceived(const QString &householdId, QList<Sonos::FavouriteObject> favourites);
|
||||||
|
void onPlaylistsReceived(const QString &householdId, QList<Sonos::PlaylistObject> playlists);
|
||||||
|
void onPlaylistSummaryReceived(const QString &householdId, Sonos::PlaylistSummaryObject playlistSummary);
|
||||||
|
|
||||||
void onGroupsReceived(QList<Sonos::GroupObject> groupIds);
|
void onGroupsReceived(QList<Sonos::GroupObject> groupIds);
|
||||||
void onPlayBackStatusReceived(const QString &groupId, Sonos::PlayBackObject playBack);
|
void onPlayBackStatusReceived(const QString &groupId, Sonos::PlayBackObject playBack);
|
||||||
void onMetadataStatusReceived(const QString &groupId, Sonos::MetadataStatus metaDataStatus);
|
void onMetadataStatusReceived(const QString &groupId, Sonos::MetadataStatus metaDataStatus);
|
||||||
void onVolumeReceived(const QString &groupId, Sonos::GroupVolumeObject groupVolume);
|
void onVolumeReceived(const QString &groupId, Sonos::VolumeObject groupVolume);
|
||||||
void onActionExecuted(QUuid actionId, bool success);
|
void onActionExecuted(QUuid actionId, bool success);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
521
sonos/sonos.cpp
521
sonos/sonos.cpp
@ -76,28 +76,80 @@ void Sonos::getHouseholds()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::cancelAudioClip()
|
|
||||||
|
QUuid Sonos::loadFavorite(const QString &groupId, const QString &favouriteId)
|
||||||
{
|
{
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/favourites"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
QJsonObject object;
|
||||||
|
object.insert("favoriteId", QJsonValue::fromVariant(favouriteId));
|
||||||
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
emit actionExecuted(actionId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO parse response
|
||||||
|
emit actionExecuted(actionId, true);
|
||||||
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::loadAudioClip()
|
void Sonos::getFavorites(const QString &householdId)
|
||||||
{
|
{
|
||||||
QUuid actionId = QUuid::createUuid();
|
QNetworkRequest request;
|
||||||
return actionId;
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/households/" + householdId + "/favorites"));
|
||||||
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, householdId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
|
||||||
|
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
if (!data.isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!data["items"].isArray())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QJsonArray array = data["items"].toArray();
|
||||||
|
QList<FavouriteObject> favourites
|
||||||
|
;
|
||||||
|
foreach (const QJsonValue & value, array) {
|
||||||
|
QJsonObject itemObject = value.toObject();
|
||||||
|
qDebug(dcSonos()) << "Item ID received:" << itemObject["id"].toString();
|
||||||
|
FavouriteObject favourite;
|
||||||
|
favourite.id = itemObject["id"].toString();
|
||||||
|
favourite.name = itemObject["name"].toString();
|
||||||
|
favourite.description = itemObject["description"].toString();
|
||||||
|
favourites.append(favourite);
|
||||||
|
}
|
||||||
|
emit favouritesReceived(householdId, favourites);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sonos::getFavorites()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QUuid Sonos::loadFavorite()
|
|
||||||
{
|
|
||||||
QUuid actionId = QUuid::createUuid();
|
|
||||||
return actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sonos::getGroups(const QString &householdId)
|
void Sonos::getGroups(const QString &householdId)
|
||||||
{
|
{
|
||||||
@ -139,27 +191,6 @@ void Sonos::getGroups(const QString &householdId)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::createGroup(const QString &householdId, QList<QString> playerIds)
|
|
||||||
{
|
|
||||||
Q_UNUSED(householdId)
|
|
||||||
Q_UNUSED(playerIds)
|
|
||||||
QUuid actionId = QUuid::createUuid();
|
|
||||||
return actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUuid Sonos::modifyGroupMembers()
|
|
||||||
{
|
|
||||||
QUuid actionId = QUuid::createUuid();
|
|
||||||
return actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUuid Sonos::setGroupMembers(const QString &groupId)
|
|
||||||
{
|
|
||||||
Q_UNUSED(groupId)
|
|
||||||
QUuid actionId = QUuid::createUuid();
|
|
||||||
return actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sonos::getGroupVolume(const QString &groupId)
|
void Sonos::getGroupVolume(const QString &groupId)
|
||||||
{
|
{
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
@ -183,13 +214,13 @@ void Sonos::getGroupVolume(const QString &groupId)
|
|||||||
if (!data.isObject())
|
if (!data.isObject())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GroupVolumeObject groupVolume;
|
VolumeObject volume;
|
||||||
|
|
||||||
groupVolume.volume = data["volume"].toInt();
|
volume.volume = data["volume"].toInt();
|
||||||
groupVolume.muted = data["muted"].toBool();
|
volume.muted = data["muted"].toBool();
|
||||||
groupVolume.fixed = data["fixed"].toBool();
|
volume.fixed = data["fixed"].toBool();
|
||||||
|
|
||||||
emit volumeReceived(groupId, groupVolume);
|
emit volumeReceived(groupId, volume);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,11 +234,12 @@ QUuid Sonos::setGroupVolume(const QString &groupId, int volume)
|
|||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
QJsonObject object;
|
QJsonObject object;
|
||||||
object.insert("volume", QJsonValue::fromVariant(volume));
|
object.insert("volume", volume);
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
qDebug(dcSonos()) << "Set volume:" << groupId << doc.toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -217,6 +249,7 @@ QUuid Sonos::setGroupVolume(const QString &groupId, int volume)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupVolume(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -224,9 +257,6 @@ QUuid Sonos::setGroupVolume(const QString &groupId, int volume)
|
|||||||
|
|
||||||
QUuid Sonos::setGroupMute(const QString &groupId, bool mute)
|
QUuid Sonos::setGroupMute(const QString &groupId, bool mute)
|
||||||
{
|
{
|
||||||
Q_UNUSED(groupId)
|
|
||||||
Q_UNUSED(mute)
|
|
||||||
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
@ -235,11 +265,13 @@ QUuid Sonos::setGroupMute(const QString &groupId, bool mute)
|
|||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
QJsonObject object;
|
QJsonObject object;
|
||||||
object.insert("muted", QJsonValue::fromVariant(mute));
|
object.insert("muted", mute);
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
qDebug(dcSonos()) << "Set mute:" << groupId << doc.toJson(QJsonDocument::Compact);
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -249,6 +281,7 @@ QUuid Sonos::setGroupMute(const QString &groupId, bool mute)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupVolume(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -267,8 +300,10 @@ QUuid Sonos::setGroupRelativeVolume(const QString &groupId, int volumeDelta)
|
|||||||
object.insert("volumeDelta", QJsonValue::fromVariant(volumeDelta));
|
object.insert("volumeDelta", QJsonValue::fromVariant(volumeDelta));
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
qDebug(dcSonos()) << "Relative volume:" << groupId << volumeDelta;
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -278,6 +313,7 @@ QUuid Sonos::setGroupRelativeVolume(const QString &groupId, int volumeDelta)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupVolume(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -305,32 +341,61 @@ void Sonos::getGroupPlaybackStatus(const QString &groupId)
|
|||||||
if (!data.isObject())
|
if (!data.isObject())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PlayBackObject playBackObject;
|
PlayBackObject playBack;
|
||||||
QJsonObject object = data.object();
|
QJsonObject object = data.object();
|
||||||
playBackObject.itemId = object["itemId"].toString();
|
playBack.itemId = object["itemId"].toString();
|
||||||
playBackObject.positionMillis = object["positionMillis"].toInt();
|
playBack.positionMillis = object["positionMillis"].toInt();
|
||||||
playBackObject.previousItemId = object["previousItemId"].toInt();
|
playBack.previousItemId = object["previousItemId"].toInt();
|
||||||
playBackObject.previousPositionMillis = object["previousPositionMillis"].toInt();
|
playBack.previousPositionMillis = object["previousPositionMillis"].toInt();
|
||||||
QString playBackState = object["playbackState"].toString();
|
QString playBackState = object["playbackState"].toString();
|
||||||
if (playBackState.contains("BUFFERING")) {
|
if (playBackState.contains("BUFFERING")) {
|
||||||
playBackObject.playbackState = PlayBackStateBuffering;
|
playBack.playbackState = PlayBackStateBuffering;
|
||||||
} else if (playBackState.contains("IDLE")) {
|
} else if (playBackState.contains("IDLE")) {
|
||||||
playBackObject.playbackState = PlayBackStateIdle;
|
playBack.playbackState = PlayBackStateIdle;
|
||||||
} else if (playBackState.contains("PAUSE")) {
|
} else if (playBackState.contains("PAUSE")) {
|
||||||
playBackObject.playbackState = PlayBackStatePause;
|
playBack.playbackState = PlayBackStatePause;
|
||||||
} else if (playBackState.contains("PLAYING")) {
|
} else if (playBackState.contains("PLAYING")) {
|
||||||
playBackObject.playbackState = PlayBackStatePlaying;
|
playBack.playbackState = PlayBackStatePlaying;
|
||||||
}
|
}
|
||||||
playBackObject.isDucking = object["isDucking"].toBool();
|
playBack.isDucking = object["isDucking"].toBool();
|
||||||
playBackObject.queueVersion = object["queueVersion"].toString();
|
playBack.queueVersion = object["queueVersion"].toString();
|
||||||
emit playBackStatusReceived(groupId, playBackObject);
|
if (object.contains("playModes")) {
|
||||||
|
PlayMode playMode;
|
||||||
|
QJsonObject playModeObject = object["playModes"].toObject();
|
||||||
|
playMode.repeat = playModeObject["repeat"].toBool();
|
||||||
|
playMode.repeatOne = playModeObject["repeatOne"].toBool();
|
||||||
|
playMode.crossfade = playModeObject["crossfade"].toBool();
|
||||||
|
playMode.shuffle = playModeObject["shuffle"].toBool();
|
||||||
|
playBack.playMode = playMode;
|
||||||
|
}
|
||||||
|
emit playBackStatusReceived(groupId, playBack);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::groupLoadLineIn(const QString &groupId)
|
QUuid Sonos::groupLoadLineIn(const QString &groupId)
|
||||||
{
|
{
|
||||||
Q_UNUSED(groupId)
|
qDebug(dcSonos()) << "Load line in:" << groupId;
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/lineIn"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, "");
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
emit actionExecuted(actionId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getGroupVolume(groupId);
|
||||||
|
emit actionExecuted(actionId, true);
|
||||||
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,8 +408,10 @@ QUuid Sonos::groupPlay(const QString &groupId)
|
|||||||
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/play"));
|
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/play"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
qDebug(dcSonos()) << "Play:" << groupId;
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, "");
|
QNetworkReply *reply = m_networkManager->post(request, "");
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -354,6 +421,7 @@ QUuid Sonos::groupPlay(const QString &groupId)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupPlaybackStatus(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -368,8 +436,10 @@ QUuid Sonos::groupPause(const QString &groupId)
|
|||||||
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/pause"));
|
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/pause"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
qDebug(dcSonos()) << "Pause:" << groupId;
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, "");
|
QNetworkReply *reply = m_networkManager->post(request, "");
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -379,6 +449,7 @@ QUuid Sonos::groupPause(const QString &groupId)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupPlaybackStatus(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -398,7 +469,7 @@ QUuid Sonos::groupSeek(const QString &groupId, int possitionMillis)
|
|||||||
object.insert("positionMillis", QJsonValue::fromVariant(possitionMillis));
|
object.insert("positionMillis", QJsonValue::fromVariant(possitionMillis));
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
@ -416,7 +487,6 @@ QUuid Sonos::groupSeek(const QString &groupId, int possitionMillis)
|
|||||||
|
|
||||||
QUuid Sonos::groupSeekRelative(const QString &groupId, int deltaMillis)
|
QUuid Sonos::groupSeekRelative(const QString &groupId, int deltaMillis)
|
||||||
{
|
{
|
||||||
Q_UNUSED(groupId)
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
@ -428,7 +498,7 @@ QUuid Sonos::groupSeekRelative(const QString &groupId, int deltaMillis)
|
|||||||
object.insert("deltaMillis", QJsonValue::fromVariant(deltaMillis));
|
object.insert("deltaMillis", QJsonValue::fromVariant(deltaMillis));
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
@ -462,8 +532,8 @@ QUuid Sonos::groupSetPlayModes(const QString &groupId, PlayMode playMode)
|
|||||||
object.insert("playModes", playModesObject);
|
object.insert("playModes", playModesObject);
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -473,6 +543,7 @@ QUuid Sonos::groupSetPlayModes(const QString &groupId, PlayMode playMode)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupPlaybackStatus(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -493,8 +564,8 @@ QUuid Sonos::groupSetShuffle(const QString &groupId, bool shuffle)
|
|||||||
object.insert("playModes", playModesObject);
|
object.insert("playModes", playModesObject);
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -504,6 +575,7 @@ QUuid Sonos::groupSetShuffle(const QString &groupId, bool shuffle)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupPlaybackStatus(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -521,20 +593,23 @@ QUuid Sonos::groupSetRepeat(const QString &groupId, RepeatMode repeatMode)
|
|||||||
QJsonObject object;
|
QJsonObject object;
|
||||||
QJsonObject playModesObject;
|
QJsonObject playModesObject;
|
||||||
if (repeatMode == RepeatModeAll) {
|
if (repeatMode == RepeatModeAll) {
|
||||||
|
qDebug(dcSonos()) << "Setting repeat mode all";
|
||||||
playModesObject["repeat"] = true;
|
playModesObject["repeat"] = true;
|
||||||
playModesObject["repeatOne"] = false;
|
playModesObject["repeatOne"] = false;
|
||||||
} else if (repeatMode == RepeatModeOne) {
|
} else if (repeatMode == RepeatModeOne) {
|
||||||
|
qDebug(dcSonos()) << "Setting repeat mode one";
|
||||||
playModesObject["repeat"] = false;
|
playModesObject["repeat"] = false;
|
||||||
playModesObject["repeatOne"] = true;
|
playModesObject["repeatOne"] = true;
|
||||||
} else if (repeatMode == RepeatModeAll) {
|
} else if (repeatMode == RepeatModeNone) {
|
||||||
|
qDebug(dcSonos()) << "Setting repeat mode none";
|
||||||
playModesObject["repeat"] = false;
|
playModesObject["repeat"] = false;
|
||||||
playModesObject["repeatOne"] = false;
|
playModesObject["repeatOne"] = false;
|
||||||
}
|
}
|
||||||
object.insert("playModes", playModesObject);
|
object.insert("playModes", playModesObject);
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -544,6 +619,7 @@ QUuid Sonos::groupSetRepeat(const QString &groupId, RepeatMode repeatMode)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupPlaybackStatus(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -564,8 +640,8 @@ QUuid Sonos::groupSetCrossfade(const QString &groupId, bool crossfade)
|
|||||||
object.insert("playModes", playModesObject);
|
object.insert("playModes", playModesObject);
|
||||||
QJsonDocument doc(object);
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -575,6 +651,7 @@ QUuid Sonos::groupSetCrossfade(const QString &groupId, bool crossfade)
|
|||||||
emit actionExecuted(actionId, false);
|
emit actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupPlaybackStatus(groupId);
|
||||||
emit actionExecuted(actionId, true);
|
emit actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -590,7 +667,7 @@ QUuid Sonos::groupSkipToNextTrack(const QString &groupId)
|
|||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, "");
|
QNetworkReply *reply = m_networkManager->post(request, "");
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -600,6 +677,7 @@ QUuid Sonos::groupSkipToNextTrack(const QString &groupId)
|
|||||||
actionExecuted(actionId, false);
|
actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupMetadataStatus(groupId);
|
||||||
actionExecuted(actionId, true);
|
actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -615,7 +693,7 @@ QUuid Sonos::groupSkipToPreviousTrack(const QString &groupId)
|
|||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, "");
|
QNetworkReply *reply = m_networkManager->post(request, "");
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -625,6 +703,7 @@ QUuid Sonos::groupSkipToPreviousTrack(const QString &groupId)
|
|||||||
actionExecuted(actionId, false);
|
actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupMetadataStatus(groupId);
|
||||||
actionExecuted(actionId, true);
|
actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -640,7 +719,7 @@ QUuid Sonos::groupTogglePlayPause(const QString &groupId)
|
|||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, "");
|
QNetworkReply *reply = m_networkManager->post(request, "");
|
||||||
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, groupId, this] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
@ -650,6 +729,7 @@ QUuid Sonos::groupTogglePlayPause(const QString &groupId)
|
|||||||
actionExecuted(actionId, false);
|
actionExecuted(actionId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getGroupPlaybackStatus(groupId);
|
||||||
actionExecuted(actionId, true);
|
actionExecuted(actionId, true);
|
||||||
});
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
@ -693,7 +773,7 @@ void Sonos::getGroupMetadataStatus(const QString &groupId)
|
|||||||
container.service = service;
|
container.service = service;
|
||||||
}
|
}
|
||||||
if (containerObject.contains("id")) {
|
if (containerObject.contains("id")) {
|
||||||
qDebug(dcSonos()) << "Item ID" << containerObject.value("id").toString();
|
//TODO parse ID
|
||||||
}
|
}
|
||||||
metaDataStatus.container = container;
|
metaDataStatus.container = container;
|
||||||
}
|
}
|
||||||
@ -727,7 +807,7 @@ void Sonos::getGroupMetadataStatus(const QString &groupId)
|
|||||||
track.service = service;
|
track.service = service;
|
||||||
}
|
}
|
||||||
if (trackObject.contains("id")) {
|
if (trackObject.contains("id")) {
|
||||||
qDebug(dcSonos()) << "Item ID" << trackObject.value("id").toString();
|
//TODO parse id
|
||||||
}
|
}
|
||||||
|
|
||||||
track.type = trackObject["type"].toString();
|
track.type = trackObject["type"].toString();
|
||||||
@ -770,7 +850,7 @@ void Sonos::getGroupMetadataStatus(const QString &groupId)
|
|||||||
track.service = service;
|
track.service = service;
|
||||||
}
|
}
|
||||||
if (trackObject.contains("id")) {
|
if (trackObject.contains("id")) {
|
||||||
qDebug(dcSonos()) << "Item ID" << trackObject.value("id").toString();
|
//TODO parse id
|
||||||
}
|
}
|
||||||
track.type = trackObject["type"].toString();
|
track.type = trackObject["type"].toString();
|
||||||
track.name = trackObject["name"].toString();
|
track.name = trackObject["name"].toString();
|
||||||
@ -788,57 +868,304 @@ void Sonos::getGroupMetadataStatus(const QString &groupId)
|
|||||||
|
|
||||||
void Sonos::getPlayerVolume(const QByteArray &playerId)
|
void Sonos::getPlayerVolume(const QByteArray &playerId)
|
||||||
{
|
{
|
||||||
Q_UNUSED(playerId)
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume"));
|
||||||
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, playerId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
|
||||||
|
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
if (!data.isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
VolumeObject volume;
|
||||||
|
volume.volume = data["volume"].toInt();
|
||||||
|
volume.muted = data["muted"].toBool();
|
||||||
|
volume.fixed = data["fixed"].toBool();
|
||||||
|
emit playerVolumeReceived(playerId, volume);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::setPlayerVolume(const QByteArray &playerId, int volume)
|
QUuid Sonos::setPlayerVolume(const QByteArray &playerId, int volume)
|
||||||
{
|
{
|
||||||
Q_UNUSED(playerId)
|
QNetworkRequest request;
|
||||||
Q_UNUSED(volume)
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
qDebug(dcSonos()) << "Setting volume:" << playerId << volume;
|
||||||
|
|
||||||
|
QJsonObject object;
|
||||||
|
object.insert("volume", QJsonValue::fromVariant(volume));
|
||||||
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, playerId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
emit actionExecuted(actionId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getPlayerVolume(playerId);
|
||||||
|
emit actionExecuted(actionId, true);
|
||||||
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::setPlayerRelativeVolume(const QByteArray &playerId, int volumeDelta)
|
QUuid Sonos::setPlayerRelativeVolume(const QByteArray &playerId, int volumeDelta)
|
||||||
{
|
{
|
||||||
Q_UNUSED(playerId)
|
QNetworkRequest request;
|
||||||
Q_UNUSED(volumeDelta)
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume/relative"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
QJsonObject object;
|
||||||
|
object.insert("volumeDelta", QJsonValue::fromVariant(volumeDelta));
|
||||||
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, playerId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
emit actionExecuted(actionId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getPlayerVolume(playerId);
|
||||||
|
emit actionExecuted(actionId, true);
|
||||||
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::setPlayerMute(const QByteArray &playerId, bool mute)
|
QUuid Sonos::setPlayerMute(const QByteArray &playerId, bool mute)
|
||||||
{
|
{
|
||||||
Q_UNUSED(playerId)
|
QNetworkRequest request;
|
||||||
Q_UNUSED(mute)
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
QJsonObject object;
|
||||||
|
object.insert("muted", QJsonValue::fromVariant(mute));
|
||||||
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, playerId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
emit actionExecuted(actionId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getPlayerVolume(playerId);
|
||||||
|
emit actionExecuted(actionId, true);
|
||||||
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sonos::getPlaylist()
|
void Sonos::getPlaylist(const QString &householdId, const QString &playlistId)
|
||||||
{
|
{
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/households/" + householdId + "/playlists/getPlaylist"));
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject object;
|
||||||
|
object["playlistId"] = playlistId;
|
||||||
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, householdId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
|
||||||
|
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
if (!data.isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!data["tracks"].isArray())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlaylistSummaryObject playlist;
|
||||||
|
QJsonArray array = data["tracks"].toArray();
|
||||||
|
foreach (const QJsonValue & value, array) {
|
||||||
|
QJsonObject itemObject = value.toObject();
|
||||||
|
qDebug(dcSonos()) << "Item ID received:" << itemObject["id"].toString();
|
||||||
|
PlaylistTrackObject track;
|
||||||
|
track.name = itemObject["name"].toString();
|
||||||
|
track.album = itemObject["album"].toString();
|
||||||
|
track.artist= itemObject["artist"].toString();
|
||||||
|
playlist.tracks.append(track);
|
||||||
|
}
|
||||||
|
emit playlistSummaryReceived(householdId, playlist);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sonos::getPlaylists()
|
void Sonos::getPlaylists(const QString &householdId)
|
||||||
{
|
{
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/households/" + householdId + "/playlists"));
|
||||||
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, householdId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
|
||||||
|
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
if (!data.isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!data["items"].isArray())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QJsonArray array = data["playlists"].toArray();
|
||||||
|
QList<PlaylistObject> playlists;
|
||||||
|
foreach (const QJsonValue & value, array) {
|
||||||
|
QJsonObject itemObject = value.toObject();
|
||||||
|
qDebug(dcSonos()) << "Item ID received:" << itemObject["id"].toString();
|
||||||
|
PlaylistObject playlist;
|
||||||
|
playlist.id = itemObject["id"].toString();
|
||||||
|
playlist.name = itemObject["name"].toString();
|
||||||
|
playlist.type = itemObject["type"].toString();
|
||||||
|
playlist.trackCount = itemObject["trackCount"].toString();
|
||||||
|
playlists.append(playlist);
|
||||||
|
}
|
||||||
|
emit playlistsReceived(householdId, playlists);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::loadPlaylist()
|
QUuid Sonos::loadPlaylist(const QString &groupId, const QString &playlistId)
|
||||||
{
|
{
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playlists"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
QJsonObject object;
|
||||||
|
object["playlistId"] = playlistId;
|
||||||
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
emit actionExecuted(actionId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit actionExecuted(actionId, true);
|
||||||
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sonos::getPlayerSettings()
|
void Sonos::getPlayerSettings(const QString &playerId)
|
||||||
{
|
{
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/settings/player"));
|
||||||
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, playerId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
if (!data.isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlayerSettingsObject playerSettings;
|
||||||
|
playerSettings.monoMode = data["monoMode"].toBool();
|
||||||
|
playerSettings.volumeMode = data["volumeMode"].toString();
|
||||||
|
playerSettings.wifiDisabled = data["wifiDisable"].toBool();
|
||||||
|
playerSettings.volumeScalingFactor = data["wifiDisable"].toDouble();
|
||||||
|
emit playerSettingsRecieved(playerId, playerSettings);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Sonos::setPlayerSettings()
|
QUuid Sonos::setPlayerSettings(const QString &playerId, PlayerSettingsObject settings)
|
||||||
{
|
{
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
|
||||||
|
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
|
||||||
|
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/settings/player"));
|
||||||
QUuid actionId = QUuid::createUuid();
|
QUuid actionId = QUuid::createUuid();
|
||||||
|
|
||||||
|
QJsonObject object;
|
||||||
|
object["volumeMode"] = settings.volumeMode;
|
||||||
|
object["volumeScalingFactor"] = settings.volumeScalingFactor;
|
||||||
|
object["monoMode"] = settings.monoMode;
|
||||||
|
object["wifiDisable"] = settings.wifiDisabled;
|
||||||
|
QJsonDocument doc(object);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, actionId, playerId, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
|
||||||
|
emit actionExecuted(actionId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getPlayerSettings(playerId);
|
||||||
|
emit actionExecuted(actionId, true);
|
||||||
|
});
|
||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,10 +53,6 @@ public:
|
|||||||
bool crossfade;
|
bool crossfade;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayerObject {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Represents a Sonos household.*/
|
/* Represents a Sonos household.*/
|
||||||
struct GroupObject {
|
struct GroupObject {
|
||||||
QString CoordinatorId; //Player acting as the group coordinator for the group
|
QString CoordinatorId; //Player acting as the group coordinator for the group
|
||||||
@ -66,17 +62,11 @@ public:
|
|||||||
QString displayName; //The display name for the group, such as “Living Room” or “Kitchen + 2”.
|
QString displayName; //The display name for the group, such as “Living Room” or “Kitchen + 2”.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GroupVolumeObject {
|
struct VolumeObject {
|
||||||
int volume; //Group volume as an integer between 0 and 100, inclusive.
|
int volume; //Group volume as an integer between 0 and 100, inclusive.
|
||||||
bool muted; //A value indicating whether or not the group is muted
|
bool muted; //A value indicating whether or not the group is muted
|
||||||
bool fixed; //A value indicating whether or not the group volume is fixed or changeable.
|
bool fixed; //A value indicating whether or not the group volume is fixed or changeable.
|
||||||
};
|
};
|
||||||
/*
|
|
||||||
* Represents a Sonos household.*/
|
|
||||||
/*struct HouseholdObject {
|
|
||||||
QString id; //Identifies a Sonos household.
|
|
||||||
QString name; //A user-displayable name of the Sonos household
|
|
||||||
};*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The music service identifier or a pseudo-service identifier in the case of local library. */
|
* The music service identifier or a pseudo-service identifier in the case of local library. */
|
||||||
@ -95,6 +85,7 @@ public:
|
|||||||
QString name;
|
QString name;
|
||||||
QString description;
|
QString description;
|
||||||
QString imageUrl;
|
QString imageUrl;
|
||||||
|
ServiceObject service;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlaylistObject
|
struct PlaylistObject
|
||||||
@ -107,8 +98,8 @@ public:
|
|||||||
|
|
||||||
struct PlayerSettingsObject
|
struct PlayerSettingsObject
|
||||||
{
|
{
|
||||||
int volumeMode;
|
QString volumeMode;
|
||||||
float volumeScalingFactor;
|
double volumeScalingFactor;
|
||||||
bool monoMode;
|
bool monoMode;
|
||||||
bool wifiDisabled;
|
bool wifiDisabled;
|
||||||
};
|
};
|
||||||
@ -173,8 +164,7 @@ public:
|
|||||||
* A single music track or audio file. Tracks are identified by type,
|
* A single music track or audio file. Tracks are identified by type,
|
||||||
* which determines the key values for the object types included.
|
* which determines the key values for the object types included.
|
||||||
* The following fields are shared by all types of tracks. */
|
* The following fields are shared by all types of tracks. */
|
||||||
struct TrackObject
|
struct TrackObject {
|
||||||
{
|
|
||||||
QString type;
|
QString type;
|
||||||
QString name;
|
QString name;
|
||||||
QString imageUrl;
|
QString imageUrl;
|
||||||
@ -190,8 +180,7 @@ public:
|
|||||||
/* An item in a queue. Used for cloud queue tracks and radio stations that have track-like data
|
/* An item in a queue. Used for cloud queue tracks and radio stations that have track-like data
|
||||||
* for the currently playing content. For example, the currentItem and nextItem parameters in the
|
* for the currently playing content. For example, the currentItem and nextItem parameters in the
|
||||||
* metadataStatus event are item object types.*/
|
* metadataStatus event are item object types.*/
|
||||||
struct ItemObject
|
struct ItemObject {
|
||||||
{
|
|
||||||
QString itemId;
|
QString itemId;
|
||||||
TrackObject track;
|
TrackObject track;
|
||||||
bool deleted;
|
bool deleted;
|
||||||
@ -204,21 +193,28 @@ public:
|
|||||||
ItemObject nextItem;
|
ItemObject nextItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PlaylistTrackObject {
|
||||||
|
QString name;
|
||||||
|
QString artist;
|
||||||
|
QString album;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlaylistSummaryObject {
|
||||||
|
QString id;
|
||||||
|
QString name;
|
||||||
|
QString type;
|
||||||
|
QList<PlaylistTrackObject> tracks;
|
||||||
|
};
|
||||||
|
|
||||||
explicit Sonos(NetworkAccessManager *networkManager, const QByteArray &accessToken, QObject *parent = nullptr);
|
explicit Sonos(NetworkAccessManager *networkManager, const QByteArray &accessToken, QObject *parent = nullptr);
|
||||||
|
|
||||||
void setAccessToken(const QByteArray &accessToken);
|
void setAccessToken(const QByteArray &accessToken);
|
||||||
|
|
||||||
void getHouseholds();
|
void getHouseholds();
|
||||||
void getFavorites();
|
void getFavorites(const QString &householdId);
|
||||||
void getGroups(const QString &householdId);
|
void getGroups(const QString &householdId);
|
||||||
|
|
||||||
QUuid cancelAudioClip();
|
QUuid loadFavorite(const QString &groupId, const QString &favouriteId);
|
||||||
QUuid loadAudioClip();
|
|
||||||
QUuid loadFavorite();
|
|
||||||
|
|
||||||
QUuid createGroup(const QString &householdId, QList<QString> playerIds);
|
|
||||||
QUuid modifyGroupMembers();
|
|
||||||
QUuid setGroupMembers(const QString &groupId);
|
|
||||||
|
|
||||||
//Group volume
|
//Group volume
|
||||||
void getGroupVolume(const QString &groupId); //Get the volume and mute state of a group.
|
void getGroupVolume(const QString &groupId); //Get the volume and mute state of a group.
|
||||||
@ -254,13 +250,13 @@ public:
|
|||||||
QUuid setPlayerMute(const QByteArray &playerId, bool mute);
|
QUuid setPlayerMute(const QByteArray &playerId, bool mute);
|
||||||
|
|
||||||
//Playlists API namespace
|
//Playlists API namespace
|
||||||
void getPlaylist();
|
void getPlaylists(const QString &householdId);
|
||||||
void getPlaylists();
|
void getPlaylist(const QString &householdId, const QString &playlistId);
|
||||||
QUuid loadPlaylist();
|
QUuid loadPlaylist(const QString &groupId, const QString &playlistId);
|
||||||
|
|
||||||
//Settings
|
//Settings
|
||||||
void getPlayerSettings();
|
void getPlayerSettings(const QString &playerId);
|
||||||
QUuid setPlayerSettings();
|
QUuid setPlayerSettings(const QString &playerId, PlayerSettingsObject settings);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_baseAuthorizationUrl = "https://api.sonos.com/login/v3/oauth";
|
QByteArray m_baseAuthorizationUrl = "https://api.sonos.com/login/v3/oauth";
|
||||||
@ -275,12 +271,17 @@ private slots:
|
|||||||
signals:
|
signals:
|
||||||
void connectionChanged(bool connected);
|
void connectionChanged(bool connected);
|
||||||
void householdIdsReceived(QList<QString> householdIds);
|
void householdIdsReceived(QList<QString> householdIds);
|
||||||
|
void favouritesReceived(const QString &householdId, QList<FavouriteObject> favourites);
|
||||||
|
void playlistsReceived(const QString &householdId, QList<PlaylistObject> playlists);
|
||||||
void groupsReceived(QList<GroupObject> groups);
|
void groupsReceived(QList<GroupObject> groups);
|
||||||
|
void playlistSummaryReceived(const QString &householdId, PlaylistSummaryObject playlistSummary);
|
||||||
|
|
||||||
void playBackStatusReceived(const QString &groupId, PlayBackObject playBack);
|
void playBackStatusReceived(const QString &groupId, PlayBackObject playBack);
|
||||||
void metadataStatusReceived(const QString &groupId, MetadataStatus metaDataStatus);
|
void metadataStatusReceived(const QString &groupId, MetadataStatus metaDataStatus);
|
||||||
void volumeReceived(const QString &groupId, GroupVolumeObject groupVolume);
|
void volumeReceived(const QString &groupId, VolumeObject groupVolume);
|
||||||
|
|
||||||
|
void playerVolumeReceived(const QString &playerId, VolumeObject playerVolume);
|
||||||
|
void playerSettingsRecieved(const QString &playerId, PlayerSettingsObject playerSettings);
|
||||||
void actionExecuted(QUuid actionId,bool success);
|
void actionExecuted(QUuid actionId,bool success);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user