Change Spotify to use the new MessageHandler, remove SpotifyMessageHandler
This commit is contained in:
parent
67c6dead5a
commit
bbf99fdd0b
|
@ -23,7 +23,6 @@
|
||||||
#include "mediapipeline.h"
|
#include "mediapipeline.h"
|
||||||
#include "spotifyclient.h"
|
#include "spotifyclient.h"
|
||||||
#include "spotifykey.h"
|
#include "spotifykey.h"
|
||||||
#include "spotifymessagehandler.h"
|
|
||||||
#include "spotifymessages.pb.h"
|
#include "spotifymessages.pb.h"
|
||||||
#include "spotify_utilities.h"
|
#include "spotify_utilities.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
@ -39,12 +38,13 @@ const int SpotifyClient::kWaveHeaderSize = 44;
|
||||||
|
|
||||||
|
|
||||||
SpotifyClient::SpotifyClient(QObject* parent)
|
SpotifyClient::SpotifyClient(QObject* parent)
|
||||||
: QObject(parent),
|
: AbstractMessageHandler<pb::spotify::Message>(NULL, parent),
|
||||||
api_key_(QByteArray::fromBase64(kSpotifyApiKey)),
|
api_key_(QByteArray::fromBase64(kSpotifyApiKey)),
|
||||||
protocol_socket_(new QTcpSocket(this)),
|
protocol_socket_(new QTcpSocket(this)),
|
||||||
handler_(new SpotifyMessageHandler(protocol_socket_, this)),
|
|
||||||
session_(NULL),
|
session_(NULL),
|
||||||
events_timer_(new QTimer(this)) {
|
events_timer_(new QTimer(this)) {
|
||||||
|
SetDevice(protocol_socket_);
|
||||||
|
|
||||||
memset(&spotify_callbacks_, 0, sizeof(spotify_callbacks_));
|
memset(&spotify_callbacks_, 0, sizeof(spotify_callbacks_));
|
||||||
memset(&spotify_config_, 0, sizeof(spotify_config_));
|
memset(&spotify_config_, 0, sizeof(spotify_config_));
|
||||||
memset(&playlistcontainer_callbacks_, 0, sizeof(playlistcontainer_callbacks_));
|
memset(&playlistcontainer_callbacks_, 0, sizeof(playlistcontainer_callbacks_));
|
||||||
|
@ -91,8 +91,6 @@ SpotifyClient::SpotifyClient(QObject* parent)
|
||||||
events_timer_->setSingleShot(true);
|
events_timer_->setSingleShot(true);
|
||||||
connect(events_timer_, SIGNAL(timeout()), SLOT(ProcessEvents()));
|
connect(events_timer_, SIGNAL(timeout()), SLOT(ProcessEvents()));
|
||||||
|
|
||||||
connect(handler_, SIGNAL(MessageArrived(pb::spotify::Message)),
|
|
||||||
SLOT(HandleMessage(pb::spotify::Message)));
|
|
||||||
connect(protocol_socket_, SIGNAL(disconnected()),
|
connect(protocol_socket_, SIGNAL(disconnected()),
|
||||||
QCoreApplication::instance(), SLOT(quit()));
|
QCoreApplication::instance(), SLOT(quit()));
|
||||||
}
|
}
|
||||||
|
@ -227,7 +225,7 @@ void SpotifyClient::SendSearchResponse(sp_search* result) {
|
||||||
if (error != SP_ERROR_OK) {
|
if (error != SP_ERROR_OK) {
|
||||||
response->set_error(sp_error_message(error));
|
response->set_error(sp_error_message(error));
|
||||||
|
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
sp_search_release(result);
|
sp_search_release(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -261,11 +259,11 @@ void SpotifyClient::SendSearchResponse(sp_search* result) {
|
||||||
response->set_total_tracks(sp_search_total_tracks(result));
|
response->set_total_tracks(sp_search_total_tracks(result));
|
||||||
response->set_did_you_mean(sp_search_did_you_mean(result));
|
response->set_did_you_mean(sp_search_did_you_mean(result));
|
||||||
|
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
sp_search_release(result);
|
sp_search_release(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyClient::HandleMessage(const pb::spotify::Message& message) {
|
void SpotifyClient::MessageArrived(const pb::spotify::Message& message) {
|
||||||
if (message.has_login_request()) {
|
if (message.has_login_request()) {
|
||||||
Login(message.login_request());
|
Login(message.login_request());
|
||||||
} else if (message.has_load_playlist_request()) {
|
} else if (message.has_load_playlist_request()) {
|
||||||
|
@ -340,7 +338,7 @@ void SpotifyClient::SendLoginCompleted(bool success, const QString& error,
|
||||||
response->set_error_code(error_code);
|
response->set_error_code(error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyClient::PlaylistContainerLoadedCallback(sp_playlistcontainer* pc, void* userdata) {
|
void SpotifyClient::PlaylistContainerLoadedCallback(sp_playlistcontainer* pc, void* userdata) {
|
||||||
|
@ -424,7 +422,7 @@ void SpotifyClient::SendPlaylistList() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_playlist* SpotifyClient::GetPlaylist(pb::spotify::PlaylistType type, int user_index) {
|
sp_playlist* SpotifyClient::GetPlaylist(pb::spotify::PlaylistType type, int user_index) {
|
||||||
|
@ -467,7 +465,7 @@ void SpotifyClient::LoadPlaylist(const pb::spotify::LoadPlaylistRequest& req) {
|
||||||
pb::spotify::Message message;
|
pb::spotify::Message message;
|
||||||
pb::spotify::LoadPlaylistResponse* response = message.mutable_load_playlist_response();
|
pb::spotify::LoadPlaylistResponse* response = message.mutable_load_playlist_response();
|
||||||
*response->mutable_request() = req;
|
*response->mutable_request() = req;
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +541,7 @@ void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* u
|
||||||
me->ConvertTrack(track, response->add_track());
|
me->ConvertTrack(track, response->add_track());
|
||||||
sp_track_release(track);
|
sp_track_release(track);
|
||||||
}
|
}
|
||||||
me->handler_->SendMessage(message);
|
me->SendMessage(message);
|
||||||
|
|
||||||
// Unref the playlist and remove our callbacks
|
// Unref the playlist and remove our callbacks
|
||||||
sp_playlist_remove_callbacks(pl, &me->load_playlist_callbacks_, me);
|
sp_playlist_remove_callbacks(pl, &me->load_playlist_callbacks_, me);
|
||||||
|
@ -752,7 +750,7 @@ void SpotifyClient::SendDownloadProgress(
|
||||||
progress->mutable_request()->set_user_playlist_index(index);
|
progress->mutable_request()->set_user_playlist_index(index);
|
||||||
}
|
}
|
||||||
progress->set_sync_progress(download_progress);
|
progress->set_sync_progress(download_progress);
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SpotifyClient::GetDownloadProgress(sp_playlist* playlist) {
|
int SpotifyClient::GetDownloadProgress(sp_playlist* playlist) {
|
||||||
|
@ -839,7 +837,7 @@ void SpotifyClient::SendPlaybackError(const QString& error) {
|
||||||
pb::spotify::PlaybackError* msg = message.mutable_playback_error();
|
pb::spotify::PlaybackError* msg = message.mutable_playback_error();
|
||||||
|
|
||||||
msg->set_error(DataCommaSizeFromQString(error));
|
msg->set_error(DataCommaSizeFromQString(error));
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyClient::LoadImage(const QString& id_b64) {
|
void SpotifyClient::LoadImage(const QString& id_b64) {
|
||||||
|
@ -852,7 +850,7 @@ void SpotifyClient::LoadImage(const QString& id_b64) {
|
||||||
pb::spotify::Message message;
|
pb::spotify::Message message;
|
||||||
pb::spotify::ImageResponse* msg = message.mutable_image_response();
|
pb::spotify::ImageResponse* msg = message.mutable_image_response();
|
||||||
msg->set_id(DataCommaSizeFromQString(id_b64));
|
msg->set_id(DataCommaSizeFromQString(id_b64));
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,7 +902,7 @@ void SpotifyClient::TryImageAgain(sp_image* image) {
|
||||||
if (data && size) {
|
if (data && size) {
|
||||||
msg->set_data(data, size);
|
msg->set_data(data, size);
|
||||||
}
|
}
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
|
|
||||||
// Free stuff
|
// Free stuff
|
||||||
image_callbacks_registered_[image] --;
|
image_callbacks_registered_[image] --;
|
||||||
|
@ -961,6 +959,6 @@ void SpotifyClient::AlbumBrowseComplete(sp_albumbrowse* result, void* userdata)
|
||||||
me->ConvertTrack(sp_albumbrowse_track(result, i), msg->add_track());
|
me->ConvertTrack(sp_albumbrowse_track(result, i), msg->add_track());
|
||||||
}
|
}
|
||||||
|
|
||||||
me->handler_->SendMessage(message);
|
me->SendMessage(message);
|
||||||
sp_albumbrowse_release(result);
|
sp_albumbrowse_release(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define SPOTIFYCLIENT_H
|
#define SPOTIFYCLIENT_H
|
||||||
|
|
||||||
#include "spotifymessages.pb.h"
|
#include "spotifymessages.pb.h"
|
||||||
|
#include "core/messagehandler.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
@ -34,9 +35,8 @@ class QTimer;
|
||||||
|
|
||||||
class MediaPipeline;
|
class MediaPipeline;
|
||||||
class ResponseMessage;
|
class ResponseMessage;
|
||||||
class SpotifyMessageHandler;
|
|
||||||
|
|
||||||
class SpotifyClient : public QObject {
|
class SpotifyClient : public AbstractMessageHandler<pb::spotify::Message> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -48,8 +48,10 @@ public:
|
||||||
|
|
||||||
void Init(quint16 port);
|
void Init(quint16 port);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void MessageArrived(const pb::spotify::Message& message);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void HandleMessage(const pb::spotify::Message& message);
|
|
||||||
void ProcessEvents();
|
void ProcessEvents();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -155,7 +157,6 @@ private:
|
||||||
QByteArray api_key_;
|
QByteArray api_key_;
|
||||||
|
|
||||||
QTcpSocket* protocol_socket_;
|
QTcpSocket* protocol_socket_;
|
||||||
SpotifyMessageHandler* handler_;
|
|
||||||
|
|
||||||
sp_session_config spotify_config_;
|
sp_session_config spotify_config_;
|
||||||
sp_session_callbacks spotify_callbacks_;
|
sp_session_callbacks spotify_callbacks_;
|
||||||
|
|
|
@ -27,11 +27,19 @@
|
||||||
|
|
||||||
_MessageHandlerBase::_MessageHandlerBase(QIODevice* device, QObject* parent)
|
_MessageHandlerBase::_MessageHandlerBase(QIODevice* device, QObject* parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
device_(device),
|
device_(NULL),
|
||||||
flush_abstract_socket_(NULL),
|
flush_abstract_socket_(NULL),
|
||||||
flush_local_socket_(NULL),
|
flush_local_socket_(NULL),
|
||||||
reading_protobuf_(false),
|
reading_protobuf_(false),
|
||||||
expected_length_(0) {
|
expected_length_(0) {
|
||||||
|
if (device) {
|
||||||
|
SetDevice(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _MessageHandlerBase::SetDevice(QIODevice* device) {
|
||||||
|
device_ = device;
|
||||||
|
|
||||||
buffer_.open(QIODevice::ReadWrite);
|
buffer_.open(QIODevice::ReadWrite);
|
||||||
|
|
||||||
connect(device, SIGNAL(readyRead()), SLOT(DeviceReadyRead()));
|
connect(device, SIGNAL(readyRead()), SLOT(DeviceReadyRead()));
|
||||||
|
@ -64,7 +72,7 @@ void _MessageHandlerBase::DeviceReadyRead() {
|
||||||
// Did we get everything?
|
// Did we get everything?
|
||||||
if (buffer_.size() == expected_length_) {
|
if (buffer_.size() == expected_length_) {
|
||||||
// Parse the message
|
// Parse the message
|
||||||
if (!MessageArrived(buffer_.data())) {
|
if (!RawMessageArrived(buffer_.data())) {
|
||||||
qLog(Error) << "Malformed protobuf message";
|
qLog(Error) << "Malformed protobuf message";
|
||||||
device_->close();
|
device_->close();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -95,15 +95,19 @@ class _MessageHandlerBase : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// device can be NULL, in which case you must call SetDevice before writing
|
||||||
|
// any messages.
|
||||||
_MessageHandlerBase(QIODevice* device, QObject* parent);
|
_MessageHandlerBase(QIODevice* device, QObject* parent);
|
||||||
|
|
||||||
|
void SetDevice(QIODevice* device);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void WriteMessage(const QByteArray& data);
|
void WriteMessage(const QByteArray& data);
|
||||||
void DeviceReadyRead();
|
void DeviceReadyRead();
|
||||||
virtual void SocketClosed() {}
|
virtual void SocketClosed() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool MessageArrived(const QByteArray& data) = 0;
|
virtual bool RawMessageArrived(const QByteArray& data) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef bool (QAbstractSocket::*FlushAbstractSocket)();
|
typedef bool (QAbstractSocket::*FlushAbstractSocket)();
|
||||||
|
@ -156,7 +160,7 @@ protected:
|
||||||
virtual void MessageArrived(const MessageType& message) {}
|
virtual void MessageArrived(const MessageType& message) {}
|
||||||
|
|
||||||
// _MessageHandlerBase
|
// _MessageHandlerBase
|
||||||
bool MessageArrived(const QByteArray& data);
|
bool RawMessageArrived(const QByteArray& data);
|
||||||
void SocketClosed();
|
void SocketClosed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -197,7 +201,7 @@ void AbstractMessageHandler<MessageType>::SendReply(const MessageType& request,
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename MessageType>
|
template<typename MessageType>
|
||||||
bool AbstractMessageHandler<MessageType>::MessageArrived(const QByteArray& data) {
|
bool AbstractMessageHandler<MessageType>::RawMessageArrived(const QByteArray& data) {
|
||||||
MessageType message;
|
MessageType message;
|
||||||
if (!message.ParseFromArray(data.constData(), data.size())) {
|
if (!message.ParseFromArray(data.constData(), data.size())) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,32 +1,18 @@
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/ext/libclementine-common)
|
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/blobversion.h.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/blobversion.h.in
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/blobversion.h)
|
${CMAKE_CURRENT_BINARY_DIR}/blobversion.h)
|
||||||
|
|
||||||
set(COMMON_SOURCES
|
set(MESSAGES
|
||||||
spotifymessagehandler.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(COMMON_HEADERS
|
|
||||||
spotifymessagehandler.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(COMMON_MESSAGES
|
|
||||||
spotifymessages.proto
|
spotifymessages.proto
|
||||||
)
|
)
|
||||||
|
|
||||||
qt4_wrap_cpp(COMMON_MOC ${COMMON_HEADERS})
|
protobuf_generate_cpp(PROTO_SOURCES PROTO_HEADERS ${MESSAGES})
|
||||||
protobuf_generate_cpp(PROTO_SOURCES PROTO_HEADERS ${COMMON_MESSAGES})
|
|
||||||
|
|
||||||
add_library(clementine-spotifyblob-messages STATIC
|
add_library(clementine-spotifyblob-messages STATIC
|
||||||
${COMMON_SOURCES}
|
|
||||||
${COMMON_MOC}
|
|
||||||
${PROTO_SOURCES}
|
${PROTO_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(clementine-spotifyblob-messages
|
target_link_libraries(clementine-spotifyblob-messages
|
||||||
libclementine-common
|
libclementine-common
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Note: this file is licensed under the Apache License instead of GPL because
|
|
||||||
// it is used by the Spotify blob which links against libspotify and is not GPL
|
|
||||||
// compatible.
|
|
||||||
|
|
||||||
|
|
||||||
#include "spotifymessages.pb.h"
|
|
||||||
#include "spotifymessagehandler.h"
|
|
||||||
#include "core/logging.h"
|
|
||||||
|
|
||||||
#include <QAbstractSocket>
|
|
||||||
#include <QBuffer>
|
|
||||||
|
|
||||||
SpotifyMessageHandler::SpotifyMessageHandler(QAbstractSocket* device, QObject* parent)
|
|
||||||
: QObject(parent),
|
|
||||||
device_(device),
|
|
||||||
reading_protobuf_(false),
|
|
||||||
expected_length_(0) {
|
|
||||||
buffer_.open(QIODevice::ReadWrite);
|
|
||||||
|
|
||||||
connect(device, SIGNAL(readyRead()), SLOT(DeviceReadyRead()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpotifyMessageHandler::DeviceReadyRead() {
|
|
||||||
while (device_->bytesAvailable()) {
|
|
||||||
if (!reading_protobuf_) {
|
|
||||||
// Read the length of the next message
|
|
||||||
QDataStream s(device_);
|
|
||||||
s >> expected_length_;
|
|
||||||
|
|
||||||
reading_protobuf_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read some of the message
|
|
||||||
buffer_.write(device_->read(expected_length_ - buffer_.size()));
|
|
||||||
|
|
||||||
// Did we get everything?
|
|
||||||
if (buffer_.size() == expected_length_) {
|
|
||||||
// Parse the message
|
|
||||||
pb::spotify::SpotifyMessage message;
|
|
||||||
if (!message.ParseFromArray(buffer_.data().constData(), buffer_.size())) {
|
|
||||||
qLog(Error) << "Malformed protobuf message";
|
|
||||||
device_->close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit MessageArrived(message);
|
|
||||||
|
|
||||||
// Clear the buffer
|
|
||||||
buffer_.close();
|
|
||||||
buffer_.setData(QByteArray());
|
|
||||||
buffer_.open(QIODevice::ReadWrite);
|
|
||||||
reading_protobuf_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpotifyMessageHandler::SendMessage(const pb::spotify::SpotifyMessage& message) {
|
|
||||||
std::string data = message.SerializeAsString();
|
|
||||||
WriteMessage(QByteArray(data.data(), data.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpotifyMessageHandler::SendMessageAsync(const pb::spotify::SpotifyMessage& message) {
|
|
||||||
std::string data = message.SerializeAsString();
|
|
||||||
metaObject()->invokeMethod(this, "WriteMessage", Qt::QueuedConnection,
|
|
||||||
Q_ARG(QByteArray, QByteArray(data.data(), data.size())));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpotifyMessageHandler::WriteMessage(const QByteArray& data) {
|
|
||||||
QDataStream s(device_);
|
|
||||||
s << quint32(data.length());
|
|
||||||
s.writeRawData(data.data(), data.length());
|
|
||||||
|
|
||||||
device_->flush();
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Note: this file is licensed under the Apache License instead of GPL because
|
|
||||||
// it is used by the Spotify blob which links against libspotify and is not GPL
|
|
||||||
// compatible.
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef SPOTIFYMESSAGEHANDLER_H
|
|
||||||
#define SPOTIFYMESSAGEHANDLER_H
|
|
||||||
|
|
||||||
#include <QBuffer>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class QAbstractSocket;
|
|
||||||
|
|
||||||
namespace pb {
|
|
||||||
namespace spotify {
|
|
||||||
class SpotifyMessage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define QStringFromStdString(x) \
|
|
||||||
QString::fromUtf8(x.data(), x.size())
|
|
||||||
#define DataCommaSizeFromQString(x) \
|
|
||||||
x.toUtf8().constData(), x.toUtf8().length()
|
|
||||||
|
|
||||||
|
|
||||||
class SpotifyMessageHandler : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
SpotifyMessageHandler(QAbstractSocket* device, QObject* parent);
|
|
||||||
|
|
||||||
void SendMessage(const pb::spotify::SpotifyMessage& message);
|
|
||||||
void SendMessageAsync(const pb::spotify::SpotifyMessage& message);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void MessageArrived(const pb::spotify::SpotifyMessage& message);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void WriteMessage(const QByteArray& data);
|
|
||||||
void DeviceReadyRead();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QAbstractSocket* device_;
|
|
||||||
|
|
||||||
bool reading_protobuf_;
|
|
||||||
quint32 expected_length_;
|
|
||||||
QBuffer buffer_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SPOTIFYMESSAGEHANDLER_H
|
|
|
@ -163,6 +163,9 @@ message PlaybackSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
message Message {
|
message Message {
|
||||||
|
// Not currently used
|
||||||
|
optional int32 id = 18;
|
||||||
|
|
||||||
optional LoginRequest login_request = 1;
|
optional LoginRequest login_request = 1;
|
||||||
optional LoginResponse login_response = 2;
|
optional LoginResponse login_response = 2;
|
||||||
optional Playlists playlists_updated = 3;
|
optional Playlists playlists_updated = 3;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
set(MESSAGES
|
set(MESSAGES
|
||||||
tagreadermessages.proto
|
tagreadermessages.proto
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "spotifymessagehandler.h"
|
|
||||||
#include "spotifysearchprovider.h"
|
#include "spotifysearchprovider.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "internet/internetmodel.h"
|
#include "internet/internetmodel.h"
|
||||||
|
|
|
@ -20,17 +20,14 @@
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
|
||||||
#include "spotifymessages.pb.h"
|
#include "spotifymessages.pb.h"
|
||||||
#include "spotifymessagehandler.h"
|
|
||||||
|
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
SpotifyServer::SpotifyServer(QObject* parent)
|
SpotifyServer::SpotifyServer(QObject* parent)
|
||||||
: QObject(parent),
|
: AbstractMessageHandler<pb::spotify::Message>(NULL, parent),
|
||||||
server_(new QTcpServer(this)),
|
server_(new QTcpServer(this)),
|
||||||
protocol_socket_(NULL),
|
|
||||||
handler_(NULL),
|
|
||||||
logged_in_(false)
|
logged_in_(false)
|
||||||
{
|
{
|
||||||
connect(server_, SIGNAL(newConnection()), SLOT(NewConnection()));
|
connect(server_, SIGNAL(newConnection()), SLOT(NewConnection()));
|
||||||
|
@ -47,33 +44,31 @@ int SpotifyServer::server_port() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::NewConnection() {
|
void SpotifyServer::NewConnection() {
|
||||||
delete protocol_socket_;
|
QTcpSocket* socket = server_->nextPendingConnection();
|
||||||
delete handler_;
|
SetDevice(socket);
|
||||||
|
|
||||||
protocol_socket_ = server_->nextPendingConnection();
|
qLog(Info) << "Connection from port" << socket->peerPort();
|
||||||
handler_ = new SpotifyMessageHandler(protocol_socket_, this);
|
|
||||||
connect(handler_, SIGNAL(MessageArrived(pb::spotify::Message)),
|
|
||||||
SLOT(HandleMessage(pb::spotify::Message)));
|
|
||||||
|
|
||||||
qLog(Info) << "Connection from port" << protocol_socket_->peerPort();
|
|
||||||
|
|
||||||
// Send any login messages that were queued before the client connected
|
// Send any login messages that were queued before the client connected
|
||||||
foreach (const pb::spotify::Message& message, queued_login_messages_) {
|
foreach (const pb::spotify::Message& message, queued_login_messages_) {
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
queued_login_messages_.clear();
|
queued_login_messages_.clear();
|
||||||
|
|
||||||
|
// Don't take any more connections from clients
|
||||||
|
disconnect(server_, SIGNAL(newConnection()), this, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::SendMessage(const pb::spotify::Message& message) {
|
void SpotifyServer::SendOrQueueMessage(const pb::spotify::Message& message) {
|
||||||
const bool is_login_message = message.has_login_request();
|
const bool is_login_message = message.has_login_request();
|
||||||
|
|
||||||
QList<pb::spotify::Message>* queue =
|
QList<pb::spotify::Message>* queue =
|
||||||
is_login_message ? &queued_login_messages_ : &queued_messages_;
|
is_login_message ? &queued_login_messages_ : &queued_messages_;
|
||||||
|
|
||||||
if (!protocol_socket_ || (!is_login_message && !logged_in_)) {
|
if (!device_ || (!is_login_message && !logged_in_)) {
|
||||||
queue->append(message);
|
queue->append(message);
|
||||||
} else {
|
} else {
|
||||||
handler_->SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +84,7 @@ void SpotifyServer::Login(const QString& username, const QString& password,
|
||||||
request->mutable_playback_settings()->set_bitrate(bitrate);
|
request->mutable_playback_settings()->set_bitrate(bitrate);
|
||||||
request->mutable_playback_settings()->set_volume_normalisation(volume_normalisation);
|
request->mutable_playback_settings()->set_volume_normalisation(volume_normalisation);
|
||||||
|
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::SetPlaybackSettings(pb::spotify::Bitrate bitrate, bool volume_normalisation) {
|
void SpotifyServer::SetPlaybackSettings(pb::spotify::Bitrate bitrate, bool volume_normalisation) {
|
||||||
|
@ -99,10 +94,10 @@ void SpotifyServer::SetPlaybackSettings(pb::spotify::Bitrate bitrate, bool volum
|
||||||
request->set_bitrate(bitrate);
|
request->set_bitrate(bitrate);
|
||||||
request->set_volume_normalisation(volume_normalisation);
|
request->set_volume_normalisation(volume_normalisation);
|
||||||
|
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::HandleMessage(const pb::spotify::Message& message) {
|
void SpotifyServer::MessageArrived(const pb::spotify::Message& message) {
|
||||||
if (message.has_login_response()) {
|
if (message.has_login_response()) {
|
||||||
const pb::spotify::LoginResponse& response = message.login_response();
|
const pb::spotify::LoginResponse& response = message.login_response();
|
||||||
logged_in_ = response.success();
|
logged_in_ = response.success();
|
||||||
|
@ -110,7 +105,7 @@ void SpotifyServer::HandleMessage(const pb::spotify::Message& message) {
|
||||||
if (response.success()) {
|
if (response.success()) {
|
||||||
// Send any messages that were queued before the client logged in
|
// Send any messages that were queued before the client logged in
|
||||||
foreach (const pb::spotify::Message& message, queued_messages_) {
|
foreach (const pb::spotify::Message& message, queued_messages_) {
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
queued_messages_.clear();
|
queued_messages_.clear();
|
||||||
}
|
}
|
||||||
|
@ -165,7 +160,7 @@ void SpotifyServer::LoadPlaylist(pb::spotify::PlaylistType type, int index) {
|
||||||
req->set_user_playlist_index(index);
|
req->set_user_playlist_index(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::SyncPlaylist(
|
void SpotifyServer::SyncPlaylist(
|
||||||
|
@ -178,7 +173,7 @@ void SpotifyServer::SyncPlaylist(
|
||||||
}
|
}
|
||||||
req->set_offline_sync(offline);
|
req->set_offline_sync(offline);
|
||||||
|
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::SyncInbox() {
|
void SpotifyServer::SyncInbox() {
|
||||||
|
@ -223,7 +218,7 @@ void SpotifyServer::StartPlayback(const QString& uri, quint16 port) {
|
||||||
|
|
||||||
req->set_track_uri(DataCommaSizeFromQString(uri));
|
req->set_track_uri(DataCommaSizeFromQString(uri));
|
||||||
req->set_media_port(port);
|
req->set_media_port(port);
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::Seek(qint64 offset_bytes) {
|
void SpotifyServer::Seek(qint64 offset_bytes) {
|
||||||
|
@ -231,7 +226,7 @@ void SpotifyServer::Seek(qint64 offset_bytes) {
|
||||||
pb::spotify::SeekRequest* req = message.mutable_seek_request();
|
pb::spotify::SeekRequest* req = message.mutable_seek_request();
|
||||||
|
|
||||||
req->set_offset_bytes(offset_bytes);
|
req->set_offset_bytes(offset_bytes);
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::Search(const QString& text, int limit, int limit_album) {
|
void SpotifyServer::Search(const QString& text, int limit, int limit_album) {
|
||||||
|
@ -241,7 +236,7 @@ void SpotifyServer::Search(const QString& text, int limit, int limit_album) {
|
||||||
req->set_query(DataCommaSizeFromQString(text));
|
req->set_query(DataCommaSizeFromQString(text));
|
||||||
req->set_limit(limit);
|
req->set_limit(limit);
|
||||||
req->set_limit_album(limit_album);
|
req->set_limit_album(limit_album);
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::LoadImage(const QString& id) {
|
void SpotifyServer::LoadImage(const QString& id) {
|
||||||
|
@ -249,7 +244,7 @@ void SpotifyServer::LoadImage(const QString& id) {
|
||||||
pb::spotify::ImageRequest* req = message.mutable_image_request();
|
pb::spotify::ImageRequest* req = message.mutable_image_request();
|
||||||
|
|
||||||
req->set_id(DataCommaSizeFromQString(id));
|
req->set_id(DataCommaSizeFromQString(id));
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyServer::AlbumBrowse(const QString& uri) {
|
void SpotifyServer::AlbumBrowse(const QString& uri) {
|
||||||
|
@ -257,5 +252,5 @@ void SpotifyServer::AlbumBrowse(const QString& uri) {
|
||||||
pb::spotify::BrowseAlbumRequest* req = message.mutable_browse_album_request();
|
pb::spotify::BrowseAlbumRequest* req = message.mutable_browse_album_request();
|
||||||
|
|
||||||
req->set_uri(DataCommaSizeFromQString(uri));
|
req->set_uri(DataCommaSizeFromQString(uri));
|
||||||
SendMessage(message);
|
SendOrQueueMessage(message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,16 +19,16 @@
|
||||||
#define SPOTIFYSERVER_H
|
#define SPOTIFYSERVER_H
|
||||||
|
|
||||||
#include "spotifymessages.pb.h"
|
#include "spotifymessages.pb.h"
|
||||||
|
#include "core/messagehandler.h"
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
class SpotifyMessageHandler;
|
|
||||||
|
|
||||||
class QTcpServer;
|
class QTcpServer;
|
||||||
class QTcpSocket;
|
class QTcpSocket;
|
||||||
|
|
||||||
class SpotifyServer : public QObject {
|
class SpotifyServer : public AbstractMessageHandler<pb::spotify::Message> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -70,18 +70,18 @@ signals:
|
||||||
void SyncPlaylistProgress(const pb::spotify::SyncPlaylistProgress& progress);
|
void SyncPlaylistProgress(const pb::spotify::SyncPlaylistProgress& progress);
|
||||||
void AlbumBrowseResults(const pb::spotify::BrowseAlbumResponse& response);
|
void AlbumBrowseResults(const pb::spotify::BrowseAlbumResponse& response);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void MessageArrived(const pb::spotify::Message& message);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void NewConnection();
|
void NewConnection();
|
||||||
void HandleMessage(const pb::spotify::Message& message);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadPlaylist(pb::spotify::PlaylistType type, int index = -1);
|
void LoadPlaylist(pb::spotify::PlaylistType type, int index = -1);
|
||||||
void SyncPlaylist(pb::spotify::PlaylistType type, int index, bool offline);
|
void SyncPlaylist(pb::spotify::PlaylistType type, int index, bool offline);
|
||||||
void SendMessage(const pb::spotify::Message& message);
|
void SendOrQueueMessage(const pb::spotify::Message& message);
|
||||||
|
|
||||||
QTcpServer* server_;
|
QTcpServer* server_;
|
||||||
QTcpSocket* protocol_socket_;
|
|
||||||
SpotifyMessageHandler* handler_;
|
|
||||||
bool logged_in_;
|
bool logged_in_;
|
||||||
|
|
||||||
QList<pb::spotify::Message> queued_login_messages_;
|
QList<pb::spotify::Message> queued_login_messages_;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "internetmodel.h"
|
#include "internetmodel.h"
|
||||||
#include "spotifyblobdownloader.h"
|
#include "spotifyblobdownloader.h"
|
||||||
#include "spotifymessagehandler.h"
|
|
||||||
#include "spotifyserver.h"
|
#include "spotifyserver.h"
|
||||||
#include "spotifyservice.h"
|
#include "spotifyservice.h"
|
||||||
#include "spotifysearchplaylisttype.h"
|
#include "spotifysearchplaylisttype.h"
|
||||||
|
|
Loading…
Reference in New Issue