From 919e9215c44dc9bcb0ef201d5f514ce4a37bc469 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 13 Dec 2012 14:27:21 +0100 Subject: [PATCH] Support indexing files from Skydrive. --- data/data.qrc | 1 + data/schema/schema-42.sql | 48 +++++++++++++ ext/clementine-tagreader/cloudstream.cpp | 2 +- src/core/database.cpp | 2 +- src/internet/cloudfileservice.cpp | 15 ++++ src/internet/cloudfileservice.h | 1 + src/internet/skydriveservice.cpp | 89 +++++++++++++++++++++++- src/internet/skydriveservice.h | 12 ++++ src/internet/ubuntuoneservice.cpp | 19 ----- 9 files changed, 165 insertions(+), 24 deletions(-) create mode 100644 data/schema/schema-42.sql diff --git a/data/data.qrc b/data/data.qrc index d68a182b9..b3cc9f408 100644 --- a/data/data.qrc +++ b/data/data.qrc @@ -336,6 +336,7 @@ schema/schema-3.sql schema/schema-40.sql schema/schema-41.sql + schema/schema-42.sql schema/schema-4.sql schema/schema-5.sql schema/schema-6.sql diff --git a/data/schema/schema-42.sql b/data/schema/schema-42.sql new file mode 100644 index 000000000..9c5d954cb --- /dev/null +++ b/data/schema/schema-42.sql @@ -0,0 +1,48 @@ +CREATE TABLE skydrive_songs( + title TEXT, + album TEXT, + artist TEXT, + albumartist TEXT, + composer TEXT, + track INTEGER, + disc INTEGER, + bpm REAL, + year INTEGER, + genre TEXT, + comment TEXT, + compilation INTEGER, + + length INTEGER, + bitrate INTEGER, + samplerate INTEGER, + + directory INTEGER NOT NULL, + filename TEXT NOT NULL, + mtime INTEGER NOT NULL, + ctime INTEGER NOT NULL, + filesize INTEGER NOT NULL, + sampler INTEGER NOT NULL DEFAULT 0, + art_automatic TEXT, + art_manual TEXT, + filetype INTEGER NOT NULL DEFAULT 0, + playcount INTEGER NOT NULL DEFAULT 0, + lastplayed INTEGER, + rating INTEGER, + forced_compilation_on INTEGER NOT NULL DEFAULT 0, + forced_compilation_off INTEGER NOT NULL DEFAULT 0, + effective_compilation NOT NULL DEFAULT 0, + skipcount INTEGER NOT NULL DEFAULT 0, + score INTEGER NOT NULL DEFAULT 0, + beginning INTEGER NOT NULL DEFAULT 0, + cue_path TEXT, + unavailable INTEGER DEFAULT 0, + effective_albumartist TEXT, + etag TEXT +); + +CREATE VIRTUAL TABLE skydrive_songs_fts USING fts3 ( + ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsgenre, ftscomment, + tokenize=unicode +); + +UPDATE schema_version SET version=42; diff --git a/ext/clementine-tagreader/cloudstream.cpp b/ext/clementine-tagreader/cloudstream.cpp index 86ad2ae22..100174cca 100644 --- a/ext/clementine-tagreader/cloudstream.cpp +++ b/ext/clementine-tagreader/cloudstream.cpp @@ -110,7 +110,7 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { } QNetworkRequest request = QNetworkRequest(url_); - if (!auth_.isNull()) { + if (!auth_.isEmpty()) { request.setRawHeader("Authorization", auth_.toUtf8()); } request.setRawHeader( diff --git a/src/core/database.cpp b/src/core/database.cpp index 58d410fe9..c30b2362f 100644 --- a/src/core/database.cpp +++ b/src/core/database.cpp @@ -37,7 +37,7 @@ #include const char* Database::kDatabaseFilename = "clementine.db"; -const int Database::kSchemaVersion = 41; +const int Database::kSchemaVersion = 42; const char* Database::kMagicAllSongsTables = "%allsongstables"; int Database::sNextConnectionId = 1; diff --git a/src/internet/cloudfileservice.cpp b/src/internet/cloudfileservice.cpp index 0f6273b29..c48c12768 100644 --- a/src/internet/cloudfileservice.cpp +++ b/src/internet/cloudfileservice.cpp @@ -180,3 +180,18 @@ bool CloudFileService::IsSupportedMimeType(const QString& mime_type) const { mime_type == "application/x-flac" || mime_type == "audio/x-ms-wma"; } + +QString CloudFileService::GuessMimeTypeForFile(const QString& filename) const { + if (filename.endsWith(".mp3")) { + return "audio/mpeg"; + } else if (filename.endsWith(".m4a")) { + return "audio/mpeg"; + } else if (filename.endsWith(".ogg")) { + return "application/ogg"; + } else if (filename.endsWith(".flac")) { + return "application/x-flac"; + } else if (filename.endsWith(".wma")) { + return "audio/x-ms-wma"; + } + return QString::null; +} diff --git a/src/internet/cloudfileservice.h b/src/internet/cloudfileservice.h index 5c6f9dbdc..ef3627cc5 100644 --- a/src/internet/cloudfileservice.h +++ b/src/internet/cloudfileservice.h @@ -41,6 +41,7 @@ class CloudFileService : public InternetService { const QUrl& download_url, const QString& authorisation); virtual bool IsSupportedMimeType(const QString& mime_type) const; + QString GuessMimeTypeForFile(const QString& filename) const; protected slots: diff --git a/src/internet/skydriveservice.cpp b/src/internet/skydriveservice.cpp index 6f490e60a..838645b6e 100644 --- a/src/internet/skydriveservice.cpp +++ b/src/internet/skydriveservice.cpp @@ -1,5 +1,7 @@ #include "skydriveservice.h" +#include + #include "oauthenticator.h" namespace { @@ -17,6 +19,9 @@ static const char* kOAuthTokenEndpoint = "https://login.live.com/oauth20_token.srf"; static const char* kOAuthScope = "wl.basic wl.skydrive wl.offline_access"; +static const char* kLiveUserInfo = "https://apis.live.net/v5.0/me"; +static const char* kSkydriveBase = "https://apis.live.net/v5.0/"; + } // namespace SkydriveService::SkydriveService( @@ -51,11 +56,89 @@ void SkydriveService::Connect() { } void SkydriveService::ConnectFinished(OAuthenticator* oauth) { - qLog(Debug) << oauth->access_token() - << oauth->refresh_token(); + oauth->deleteLater(); QSettings s; s.beginGroup(kSettingsGroup); - s.setValue("refresh_token", oauth->refresh_token()); + + access_token_ = oauth->access_token(); + expiry_time_ = oauth->expiry_time(); + + QUrl url(kLiveUserInfo); + QNetworkRequest request(url); + AddAuthorizationHeader(&request); + + QNetworkReply* reply = network_->get(request); + NewClosure(reply, SIGNAL(finished()), + this, SLOT(FetchUserInfoFinished(QNetworkReply*)), reply); +} + +void SkydriveService::AddAuthorizationHeader(QNetworkRequest* request) { + request->setRawHeader( + "Authorization", QString("Bearer %1").arg(access_token_).toUtf8()); +} + +void SkydriveService::FetchUserInfoFinished(QNetworkReply* reply) { + reply->deleteLater(); + QJson::Parser parser; + QVariantMap response = parser.parse(reply).toMap(); + qLog(Debug) << response; + + QString name = response["name"].toString(); + if (!name.isEmpty()) { + QSettings s; + s.beginGroup(kSettingsGroup); + s.setValue("name", name); + } + + ListFiles("me/skydrive"); +} + +void SkydriveService::ListFiles(const QString& folder) { + QUrl url(QString(kSkydriveBase) + folder + "/files"); + url.addQueryItem("filter", "audio,folders"); + QNetworkRequest request(url); + AddAuthorizationHeader(&request); + + QNetworkReply* reply = network_->get(request); + NewClosure(reply, SIGNAL(finished()), + this, SLOT(ListFilesFinished(QNetworkReply*)), reply); +} + +void SkydriveService::ListFilesFinished(QNetworkReply* reply) { + reply->deleteLater(); + QJson::Parser parser; + QVariantMap response = parser.parse(reply).toMap(); + qLog(Debug) << response; + + QVariantList files = response["data"].toList(); + foreach (const QVariant& f, files) { + QVariantMap file = f.toMap(); + if (file["type"].toString() == "audio") { + QString mime_type = GuessMimeTypeForFile(file["name"].toString()); + QUrl url; + url.setScheme("skydrive"); + url.setPath(file["id"].toString()); + + Song song; + song.set_url(url); + song.set_ctime(file["created_time"].toDateTime().toTime_t()); + song.set_mtime(file["updated_time"].toDateTime().toTime_t()); + song.set_comment(file["description"].toString()); + song.set_filesize(file["size"].toInt()); + song.set_title(file["name"].toString()); + + QUrl download_url = file["source"].toUrl(); + // HTTPS appears to be broken somehow between Qt & Skydrive downloads. + // Fortunately, just changing the scheme to HTTP works. + download_url.setScheme("http"); + MaybeAddFileToDatabase( + song, + mime_type, + download_url, + QString::null); + + } + } } diff --git a/src/internet/skydriveservice.h b/src/internet/skydriveservice.h index 190ecc457..a6b0245ac 100644 --- a/src/internet/skydriveservice.h +++ b/src/internet/skydriveservice.h @@ -3,7 +3,11 @@ #include "cloudfileservice.h" +#include + class OAuthenticator; +class QNetworkRequest; +class QNetworkReply; class SkydriveService : public CloudFileService { Q_OBJECT @@ -20,7 +24,15 @@ class SkydriveService : public CloudFileService { private slots: void ConnectFinished(OAuthenticator* oauth); + void FetchUserInfoFinished(QNetworkReply* reply); + void ListFilesFinished(QNetworkReply* reply); + private: + void AddAuthorizationHeader(QNetworkRequest* request); + void ListFiles(const QString& folder); + + QString access_token_; + QDateTime expiry_time_; }; #endif // SKYDRIVESERVICE_H diff --git a/src/internet/ubuntuoneservice.cpp b/src/internet/ubuntuoneservice.cpp index cc0266c89..d9718e23d 100644 --- a/src/internet/ubuntuoneservice.cpp +++ b/src/internet/ubuntuoneservice.cpp @@ -128,25 +128,6 @@ void UbuntuOneService::RequestFileList(const QString& path) { this, SLOT(FileListRequestFinished(QNetworkReply*)), files_reply); } -namespace { - -QString GuessMimeTypeForFile(const QString& filename) { - if (filename.endsWith(".mp3")) { - return "audio/mpeg"; - } else if (filename.endsWith(".m4a")) { - return "audio/mpeg"; - } else if (filename.endsWith(".ogg")) { - return "application/ogg"; - } else if (filename.endsWith(".flac")) { - return "application/x-flac"; - } else if (filename.endsWith(".wma")) { - return "audio/x-ms-wma"; - } - return QString::null; -} - -} // namespace - void UbuntuOneService::FileListRequestFinished(QNetworkReply* reply) { reply->deleteLater(); QJson::Parser parser;