Added message to retrive the library (table songs).
This commit is contained in:
parent
662b635d96
commit
3a309e9b25
@ -21,6 +21,7 @@ enum MsgType {
|
||||
LOVE = 12;
|
||||
BAN = 13;
|
||||
STOP_AFTER = 17;
|
||||
GET_LIBRARY = 18;
|
||||
|
||||
// Messages send by both
|
||||
DISCONNECT = 2;
|
||||
@ -49,6 +50,7 @@ enum MsgType {
|
||||
LYRICS = 49;
|
||||
SONG_FILE_CHUNK = 50;
|
||||
DOWNLOAD_QUEUE_EMPTY = 51;
|
||||
LIBRARY_CHUNK = 52;
|
||||
}
|
||||
|
||||
// Valid Engine states
|
||||
@ -255,6 +257,13 @@ message ResponseSongFileChunk {
|
||||
optional int32 size = 8;
|
||||
}
|
||||
|
||||
message ResponseLibraryChunk {
|
||||
optional int32 chunk_number = 1;
|
||||
optional int32 chunk_count = 2;
|
||||
optional bytes data = 3;
|
||||
optional int32 size = 4;
|
||||
}
|
||||
|
||||
message ResponseSongOffer {
|
||||
optional bool accepted = 1; // true = client wants to download item
|
||||
}
|
||||
@ -290,4 +299,5 @@ message Message {
|
||||
optional ResponseLyrics response_lyrics = 30;
|
||||
optional ResponseSongFileChunk response_song_file_chunk = 32;
|
||||
optional ResponseSongOffer response_song_offer = 33;
|
||||
optional ResponseLibraryChunk response_library_chunk = 34;
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ Database::Database(Application* app, QObject* parent, const QString& database_na
|
||||
Utilities::GetConfigPath(Utilities::Path_Root));
|
||||
|
||||
attached_databases_["jamendo"] = AttachedDatabase(
|
||||
directory_ + "/jamendo.db", ":/schema/jamendo.sql");
|
||||
directory_ + "/jamendo.db", ":/schema/jamendo.sql", false);
|
||||
|
||||
QMutexLocker l(&mutex_);
|
||||
Connect();
|
||||
@ -410,6 +410,9 @@ QSqlDatabase Database::Connect() {
|
||||
// We might have to initialise the schema in some attached databases now, if
|
||||
// they were deleted and don't match up with the main schema version.
|
||||
foreach (const QString& key, attached_databases_.keys()) {
|
||||
if (attached_databases_[key].is_temporary_ &&
|
||||
attached_databases_[key].schema_.isEmpty())
|
||||
continue;
|
||||
// Find out if there are any tables in this database
|
||||
QSqlQuery q(QString("SELECT ROWID FROM %1.sqlite_master"
|
||||
" WHERE type='table'").arg(key), db);
|
||||
@ -479,6 +482,27 @@ void Database::RecreateAttachedDb(const QString& database_name) {
|
||||
}
|
||||
}
|
||||
|
||||
void Database::AttachDatabase(const QString& database_name,
|
||||
const AttachedDatabase& database) {
|
||||
attached_databases_[database_name] = database;
|
||||
}
|
||||
|
||||
void Database::DetachDatabase(const QString& database_name) {
|
||||
QMutexLocker l(&mutex_);
|
||||
{
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
QSqlQuery q("DETACH DATABASE :alias", db);
|
||||
q.bindValue(":alias", database_name);
|
||||
if (!q.exec()) {
|
||||
qLog(Warning) << "Failed to detach database" << database_name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
attached_databases_.remove(database_name);
|
||||
}
|
||||
|
||||
void Database::UpdateDatabaseSchema(int version, QSqlDatabase &db) {
|
||||
QString filename;
|
||||
if (version == 0)
|
||||
|
@ -46,6 +46,16 @@ class Database : public QObject {
|
||||
Database(Application* app, QObject* parent = 0,
|
||||
const QString& database_name = QString());
|
||||
|
||||
struct AttachedDatabase {
|
||||
AttachedDatabase() {}
|
||||
AttachedDatabase(const QString& filename, const QString& schema, bool is_temporary)
|
||||
: filename_(filename), schema_(schema), is_temporary_(is_temporary) {}
|
||||
|
||||
QString filename_;
|
||||
QString schema_;
|
||||
bool is_temporary_;
|
||||
};
|
||||
|
||||
static const int kSchemaVersion;
|
||||
static const char* kDatabaseFilename;
|
||||
static const char* kMagicAllSongsTables;
|
||||
@ -63,6 +73,9 @@ class Database : public QObject {
|
||||
int startup_schema_version() const { return startup_schema_version_; }
|
||||
int current_schema_version() const { return kSchemaVersion; }
|
||||
|
||||
void AttachDatabase(const QString& database_name, const AttachedDatabase& database);
|
||||
void DetachDatabase(const QString& database_name);
|
||||
|
||||
signals:
|
||||
void Error(const QString& message);
|
||||
|
||||
@ -87,15 +100,6 @@ class Database : public QObject {
|
||||
void BackupFile(const QString& filename);
|
||||
bool OpenDatabase(const QString& filename, sqlite3** connection) const;
|
||||
|
||||
struct AttachedDatabase {
|
||||
AttachedDatabase() {}
|
||||
AttachedDatabase(const QString& filename, const QString& schema)
|
||||
: filename_(filename), schema_(schema) {}
|
||||
|
||||
QString filename_;
|
||||
QString schema_;
|
||||
};
|
||||
|
||||
Application* app_;
|
||||
|
||||
// Alias -> filename
|
||||
|
@ -212,6 +212,17 @@ QString MakeTempDir(const QString template_name) {
|
||||
return path;
|
||||
}
|
||||
|
||||
QString GetTempFileName() {
|
||||
QString file;
|
||||
{
|
||||
QTemporaryFile tempfile;
|
||||
tempfile.open();
|
||||
file = tempfile.fileName();
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void RemoveRecursive(const QString& path) {
|
||||
QDir dir(path);
|
||||
foreach (const QString& child, dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Hidden))
|
||||
|
@ -49,6 +49,7 @@ namespace Utilities {
|
||||
quint64 FileSystemFreeSpace(const QString& path);
|
||||
|
||||
QString MakeTempDir(const QString template_name = QString());
|
||||
QString GetTempFileName();
|
||||
void RemoveRecursive(const QString& path);
|
||||
bool CopyRecursive(const QString& source, const QString& destination);
|
||||
bool Copy(QIODevice* source, QIODevice* destination);
|
||||
|
@ -99,64 +99,87 @@ void IncomingDataParser::Parse(const pb::remote::Message& msg) {
|
||||
|
||||
// Now check what's to do
|
||||
switch (msg.type()) {
|
||||
case pb::remote::CONNECT: ClientConnect(msg);
|
||||
break;
|
||||
case pb::remote::DISCONNECT: close_connection_ = true;
|
||||
break;
|
||||
case pb::remote::REQUEST_PLAYLISTS: SendPlaylists(msg);
|
||||
break;
|
||||
case pb::remote::REQUEST_PLAYLIST_SONGS: GetPlaylistSongs(msg);
|
||||
break;
|
||||
case pb::remote::SET_VOLUME: emit SetVolume(msg.request_set_volume().volume());
|
||||
break;
|
||||
case pb::remote::PLAY: emit Play();
|
||||
break;
|
||||
case pb::remote::PLAYPAUSE: emit PlayPause();
|
||||
break;
|
||||
case pb::remote::PAUSE: emit Pause();
|
||||
break;
|
||||
case pb::remote::STOP: emit Stop();
|
||||
break;
|
||||
case pb::remote::STOP_AFTER: emit StopAfterCurrent();
|
||||
break;
|
||||
case pb::remote::NEXT: emit Next();
|
||||
break;
|
||||
case pb::remote::PREVIOUS: emit Previous();
|
||||
break;
|
||||
case pb::remote::CHANGE_SONG: ChangeSong(msg);
|
||||
break;
|
||||
case pb::remote::SHUFFLE_PLAYLIST: emit ShuffleCurrent();
|
||||
break;
|
||||
case pb::remote::REPEAT: SetRepeatMode(msg.repeat());
|
||||
break;
|
||||
case pb::remote::SHUFFLE: SetShuffleMode(msg.shuffle());
|
||||
break;
|
||||
case pb::remote::CONNECT:
|
||||
ClientConnect(msg);
|
||||
break;
|
||||
case pb::remote::DISCONNECT:
|
||||
close_connection_ = true;
|
||||
break;
|
||||
case pb::remote::REQUEST_PLAYLISTS:
|
||||
SendPlaylists(msg);
|
||||
break;
|
||||
case pb::remote::REQUEST_PLAYLIST_SONGS:
|
||||
GetPlaylistSongs(msg);
|
||||
break;
|
||||
case pb::remote::SET_VOLUME:
|
||||
emit SetVolume(msg.request_set_volume().volume());
|
||||
break;
|
||||
case pb::remote::PLAY:
|
||||
emit Play();
|
||||
break;
|
||||
case pb::remote::PLAYPAUSE:
|
||||
emit PlayPause();
|
||||
break;
|
||||
case pb::remote::PAUSE:
|
||||
emit Pause();
|
||||
break;
|
||||
case pb::remote::STOP:
|
||||
emit Stop();
|
||||
break;
|
||||
case pb::remote::STOP_AFTER:
|
||||
emit StopAfterCurrent();
|
||||
break;
|
||||
case pb::remote::NEXT:
|
||||
emit Next();
|
||||
break;
|
||||
case pb::remote::PREVIOUS:
|
||||
emit Previous();
|
||||
break;
|
||||
case pb::remote::CHANGE_SONG:
|
||||
ChangeSong(msg);
|
||||
break;
|
||||
case pb::remote::SHUFFLE_PLAYLIST:
|
||||
emit ShuffleCurrent();
|
||||
break;
|
||||
case pb::remote::REPEAT:
|
||||
SetRepeatMode(msg.repeat());
|
||||
break;
|
||||
case pb::remote::SHUFFLE:
|
||||
SetShuffleMode(msg.shuffle());
|
||||
break;
|
||||
case pb::remote::SET_TRACK_POSITION:
|
||||
emit SeekTo(msg.request_set_track_position().position());
|
||||
break;
|
||||
case pb::remote::INSERT_URLS: InsertUrls(msg);
|
||||
break;
|
||||
case pb::remote::REMOVE_SONGS:RemoveSongs(msg);
|
||||
break;
|
||||
emit SeekTo(msg.request_set_track_position().position());
|
||||
break;
|
||||
case pb::remote::INSERT_URLS:
|
||||
InsertUrls(msg);
|
||||
break;
|
||||
case pb::remote::REMOVE_SONGS:
|
||||
RemoveSongs(msg);
|
||||
break;
|
||||
case pb::remote::OPEN_PLAYLIST:
|
||||
OpenPlaylist(msg);
|
||||
break;
|
||||
OpenPlaylist(msg);
|
||||
break;
|
||||
case pb::remote::CLOSE_PLAYLIST:
|
||||
ClosePlaylist(msg);
|
||||
break;
|
||||
case pb::remote::LOVE: emit Love();
|
||||
break;
|
||||
case pb::remote::BAN: emit Ban();
|
||||
break;
|
||||
case pb::remote::GET_LYRICS: emit GetLyrics();
|
||||
break;
|
||||
ClosePlaylist(msg);
|
||||
break;
|
||||
case pb::remote::LOVE:
|
||||
emit Love();
|
||||
break;
|
||||
case pb::remote::BAN:
|
||||
emit Ban();
|
||||
break;
|
||||
case pb::remote::GET_LYRICS:
|
||||
emit GetLyrics();
|
||||
break;
|
||||
case pb::remote::DOWNLOAD_SONGS:
|
||||
emit SendSongs(msg.request_download_songs(), client);
|
||||
break;
|
||||
emit SendSongs(msg.request_download_songs(), client);
|
||||
break;
|
||||
case pb::remote::SONG_OFFER_RESPONSE:
|
||||
emit ResponseSongOffer(client,
|
||||
msg.response_song_offer().accepted());
|
||||
break;
|
||||
emit ResponseSongOffer(client, msg.response_song_offer().accepted());
|
||||
break;
|
||||
case pb::remote::GET_LIBRARY:
|
||||
emit SendLibrary(client);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -180,37 +203,37 @@ void IncomingDataParser::ChangeSong(const pb::remote::Message& msg) {
|
||||
|
||||
void IncomingDataParser::SetRepeatMode(const pb::remote::Repeat& repeat) {
|
||||
switch (repeat.repeat_mode()) {
|
||||
case pb::remote::Repeat_Off:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Off);
|
||||
break;
|
||||
case pb::remote::Repeat_Track:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Track);
|
||||
break;
|
||||
case pb::remote::Repeat_Album:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Album);
|
||||
break;
|
||||
case pb::remote::Repeat_Playlist:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Playlist);
|
||||
break;
|
||||
default: break;
|
||||
case pb::remote::Repeat_Off:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Off);
|
||||
break;
|
||||
case pb::remote::Repeat_Track:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Track);
|
||||
break;
|
||||
case pb::remote::Repeat_Album:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Album);
|
||||
break;
|
||||
case pb::remote::Repeat_Playlist:
|
||||
emit SetRepeatMode(PlaylistSequence::Repeat_Playlist);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void IncomingDataParser::SetShuffleMode(const pb::remote::Shuffle& shuffle) {
|
||||
switch (shuffle.shuffle_mode()) {
|
||||
case pb::remote::Shuffle_Off:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_Off);
|
||||
break;
|
||||
case pb::remote::Shuffle_All:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_All);
|
||||
break;
|
||||
case pb::remote::Shuffle_InsideAlbum:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_InsideAlbum);
|
||||
break;
|
||||
case pb::remote::Shuffle_Albums:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_Albums);
|
||||
break;
|
||||
default: break;
|
||||
case pb::remote::Shuffle_Off:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_Off);
|
||||
break;
|
||||
case pb::remote::Shuffle_All:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_All);
|
||||
break;
|
||||
case pb::remote::Shuffle_InsideAlbum:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_InsideAlbum);
|
||||
break;
|
||||
case pb::remote::Shuffle_Albums:
|
||||
emit SetShuffleMode(PlaylistSequence::Shuffle_Albums);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ signals:
|
||||
void SeekTo(int seconds);
|
||||
void SendSongs(const pb::remote::RequestDownloadSongs& request, RemoteClient* client);
|
||||
void ResponseSongOffer(RemoteClient* client, bool accepted);
|
||||
void SendLibrary(RemoteClient* client);
|
||||
|
||||
private:
|
||||
Application* app_;
|
||||
|
@ -170,6 +170,11 @@ void NetworkRemote::AcceptConnection() {
|
||||
SIGNAL(ResponseSongOffer(RemoteClient*, bool)),
|
||||
outgoing_data_creator_.get(),
|
||||
SLOT(ResponseSongOffer(RemoteClient*, bool)));
|
||||
|
||||
connect(incoming_data_parser_.get(),
|
||||
SIGNAL(SendLibrary(RemoteClient*)),
|
||||
outgoing_data_creator_.get(),
|
||||
SLOT(SendLibrary(RemoteClient*)));
|
||||
}
|
||||
|
||||
QTcpServer* server = qobject_cast<QTcpServer*>(sender());
|
||||
|
@ -22,8 +22,13 @@
|
||||
#include "networkremote.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "core/utilities.h"
|
||||
#include "library/librarybackend.h"
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include "core/database.h"
|
||||
|
||||
const quint32 OutgoingDataCreator::kFileChunkSize = 100000; // in Bytes
|
||||
|
||||
OutgoingDataCreator::OutgoingDataCreator(Application* app)
|
||||
@ -707,3 +712,58 @@ void OutgoingDataCreator::SendPlaylist(RemoteClient *client, int playlist_id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OutgoingDataCreator::SendLibrary(RemoteClient *client) {
|
||||
// Get a temporary file name
|
||||
QString temp_file_name = Utilities::GetTempFileName();
|
||||
|
||||
// Attach this file to the database
|
||||
Database::AttachedDatabase adb(temp_file_name, "", true);
|
||||
app_->database()->AttachDatabase("songs_export", adb);
|
||||
QSqlDatabase db(app_->database()->Connect());
|
||||
|
||||
// Copy the content of the song table to this temporary database
|
||||
QSqlQuery q(QString("create table songs_export.songs as SELECT * FROM songs;"), db);
|
||||
q.exec();
|
||||
|
||||
if (app_->database()->CheckErrors(q)) return;
|
||||
|
||||
// Detach the database
|
||||
app_->database()->DetachDatabase("songs_export");
|
||||
|
||||
// Open the file
|
||||
QFile file(temp_file_name);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
QByteArray data;
|
||||
pb::remote::Message msg;
|
||||
pb::remote::ResponseLibraryChunk* chunk = msg.mutable_response_library_chunk();
|
||||
msg.set_type(pb::remote::LIBRARY_CHUNK);
|
||||
|
||||
// Calculate the number of chunks
|
||||
int chunk_count = qRound((file.size() / kFileChunkSize) + 0.5);
|
||||
int chunk_number = 1;
|
||||
|
||||
while (!file.atEnd()) {
|
||||
// Read file chunk
|
||||
data = file.read(kFileChunkSize);
|
||||
|
||||
// Set chunk data
|
||||
chunk->set_chunk_count(chunk_count);
|
||||
chunk->set_chunk_number(chunk_number);
|
||||
chunk->set_size(file.size());
|
||||
chunk->set_data(data.data(), data.size());
|
||||
|
||||
// Send data directly to the client
|
||||
client->SendData(&msg);
|
||||
|
||||
// Clear working data
|
||||
chunk->Clear();
|
||||
data.clear();
|
||||
|
||||
chunk_number++;
|
||||
}
|
||||
|
||||
// Remove temporary file
|
||||
file.remove();
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ public slots:
|
||||
void SendLyrics(int id, const SongInfoFetcher::Result& result);
|
||||
void SendSongs(const pb::remote::RequestDownloadSongs& request, RemoteClient* client);
|
||||
void ResponseSongOffer(RemoteClient* client, bool accepted);
|
||||
void SendLibrary(RemoteClient* client);
|
||||
|
||||
private:
|
||||
Application* app_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user