diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97d2b9b3a..94f2bf979 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -215,6 +215,11 @@ optional_component(SEAFILE ON "Seafile support"
DEPENDS "Taglib 1.8" "TAGLIB_VERSION VERSION_GREATER 1.7.999"
)
+optional_component(AMAZON_CLOUD_DRIVE ON "Amazon Cloud Drive support"
+ DEPENDS "Google sparsehash" SPARSEHASH_INCLUDE_DIRS
+ DEPENDS "Taglib 1.8" "TAGLIB_VERSION VERSION_GREATER 1.7.999"
+)
+
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" CDIO_FOUND
)
diff --git a/data/data.qrc b/data/data.qrc
index 162c2f7ff..afd87697b 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -310,6 +310,7 @@
playstore/uk_generic_rgb_wo_45.png
playstore/vi_generic_rgb_wo_45.png
providers/amazon.png
+ providers/amazonclouddrive.png
providers/aol.png
providers/bbc.png
providers/box.png
@@ -385,6 +386,7 @@
schema/schema-45.sql
schema/schema-46.sql
schema/schema-47.sql
+ schema/schema-48.sql
schema/schema-4.sql
schema/schema-5.sql
schema/schema-6.sql
diff --git a/data/providers/amazonclouddrive.png b/data/providers/amazonclouddrive.png
new file mode 100644
index 000000000..d3707287a
Binary files /dev/null and b/data/providers/amazonclouddrive.png differ
diff --git a/data/schema/schema-48.sql b/data/schema/schema-48.sql
new file mode 100644
index 000000000..bdff64858
--- /dev/null
+++ b/data/schema/schema-48.sql
@@ -0,0 +1,50 @@
+CREATE TABLE amazon_cloud_drive_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,
+ performer TEXT,
+ grouping TEXT
+);
+
+CREATE VIRTUAL TABLE amazon_cloud_drive_songs_fts USING fts3 (
+ ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment,
+ tokenize=unicode
+);
+
+UPDATE schema_version SET version=48;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4a80c5994..355b605db 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1178,6 +1178,20 @@ optional_source(HAVE_SEAFILE
internet/seafile/seafilesettingspage.ui
)
+# Amazon Cloud Drive support
+optional_source(HAVE_AMAZON_CLOUD_DRIVE
+ SOURCES
+ internet/amazon/amazonclouddrive.cpp
+ internet/amazon/amazonsettingspage.cpp
+ internet/amazon/amazonurlhandler.cpp
+ HEADERS
+ internet/amazon/amazonclouddrive.h
+ internet/amazon/amazonsettingspage.h
+ internet/amazon/amazonurlhandler.h
+ UI
+ internet/amazon/amazonsettingspage.ui
+)
+
# Pulse audio integration
optional_source(HAVE_LIBPULSE
diff --git a/src/config.h.in b/src/config.h.in
index f9279072f..342919fbc 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -21,6 +21,7 @@
#define CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}"
#cmakedefine ENABLE_VISUALISATIONS
+#cmakedefine HAVE_AMAZON_CLOUD_DRIVE
#cmakedefine HAVE_AUDIOCD
#cmakedefine HAVE_BOX
#cmakedefine HAVE_BREAKPAD
diff --git a/src/core/database.cpp b/src/core/database.cpp
index e351aa32e..e3bbee56a 100644
--- a/src/core/database.cpp
+++ b/src/core/database.cpp
@@ -47,7 +47,7 @@
#include
const char* Database::kDatabaseFilename = "clementine.db";
-const int Database::kSchemaVersion = 47;
+const int Database::kSchemaVersion = 48;
const char* Database::kMagicAllSongsTables = "%allsongstables";
int Database::sNextConnectionId = 1;
diff --git a/src/engines/gstenginepipeline.cpp b/src/engines/gstenginepipeline.cpp
index 7f48f1fb2..5887a6dbd 100644
--- a/src/engines/gstenginepipeline.cpp
+++ b/src/engines/gstenginepipeline.cpp
@@ -903,6 +903,15 @@ void GstEnginePipeline::SourceSetupCallback(GstURIDecodeBin* bin,
g_object_set(element, "extra-headers", headers, nullptr);
gst_structure_free(headers);
}
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(element),
+ "extra-headers") &&
+ instance->url().host().contains("amazonaws.com")) {
+ GstStructure* headers = gst_structure_new(
+ "extra-headers", "Authorization", G_TYPE_STRING,
+ instance->url().fragment().toAscii().data(), nullptr);
+ g_object_set(element, "extra-headers", headers, nullptr);
+ gst_structure_free(headers);
+ }
if (g_object_class_find_property(G_OBJECT_GET_CLASS(element), "user-agent")) {
QString user_agent =
diff --git a/src/internet/amazon/amazonclouddrive.cpp b/src/internet/amazon/amazonclouddrive.cpp
new file mode 100644
index 000000000..7b2dd1be0
--- /dev/null
+++ b/src/internet/amazon/amazonclouddrive.cpp
@@ -0,0 +1,246 @@
+/* This file is part of Clementine.
+ Copyright 2015, John Maguire
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#include "internet/amazon/amazonclouddrive.h"
+
+#include
+
+#include
+#include
+
+#include "core/application.h"
+#include "core/closure.h"
+#include "core/logging.h"
+#include "core/network.h"
+#include "core/player.h"
+#include "core/waitforsignal.h"
+#include "internet/core/oauthenticator.h"
+#include "internet/amazon/amazonurlhandler.h"
+#include "library/librarybackend.h"
+#include "ui/settingsdialog.h"
+
+const char* AmazonCloudDrive::kServiceName = "Cloud Drive";
+const char* AmazonCloudDrive::kSettingsGroup = "AmazonCloudDrive";
+
+namespace {
+static const char* kServiceId = "amazon_cloud_drive";
+static const char* kClientId =
+ "amzn1.application-oa2-client.2b1157a7dadc45c3888567882b3a9f05";
+static const char* kClientSecret =
+ "acfbf95340cc4c381dd43fb75b5e111882d7fd1b02a02f3013ab124baf8d1655";
+static const char* kOAuthScope = "clouddrive:read";
+static const char* kOAuthEndpoint = "https://www.amazon.com/ap/oa";
+static const char* kOAuthTokenEndpoint = "https://api.amazon.com/auth/o2/token";
+
+static const char* kEndpointEndpoint =
+ "https://drive.amazonaws.com/drive/v1/account/endpoint";
+static const char* kChangesEndpoint = "%1/changes";
+static const char* kDownloadEndpoint = "%1/nodes/%2/content";
+} // namespace
+
+AmazonCloudDrive::AmazonCloudDrive(Application* app, InternetModel* parent)
+ : CloudFileService(app, parent, kServiceName, kServiceId,
+ QIcon(":/providers/amazonclouddrive.png"),
+ SettingsDialog::Page_AmazonCloudDrive),
+ network_(new NetworkAccessManager) {
+ app->player()->RegisterUrlHandler(new AmazonUrlHandler(this, this));
+}
+
+bool AmazonCloudDrive::has_credentials() const {
+ QSettings s;
+ s.beginGroup(kSettingsGroup);
+ return !s.value("refresh_token").toString().isEmpty();
+}
+
+QUrl AmazonCloudDrive::GetStreamingUrlFromSongId(const QUrl& url) {
+ EnsureConnected(); // Access token must be up to date.
+ QUrl download_url(
+ QString(kDownloadEndpoint).arg(content_url_).arg(url.path()));
+ download_url.setFragment(QString("Bearer %1").arg(access_token_));
+ return download_url;
+}
+
+void AmazonCloudDrive::Connect() {
+ OAuthenticator* oauth = new OAuthenticator(
+ kClientId, kClientSecret,
+ // Amazon forbids arbitrary query parameters so REMOTE_WITH_STATE is
+ // required.
+ OAuthenticator::RedirectStyle::REMOTE_WITH_STATE, this);
+
+ QSettings s;
+ s.beginGroup(kSettingsGroup);
+ QString refresh_token = s.value("refresh_token").toString();
+ if (refresh_token.isEmpty()) {
+ oauth->StartAuthorisation(kOAuthEndpoint, kOAuthTokenEndpoint, kOAuthScope);
+ } else {
+ oauth->RefreshAuthorisation(kOAuthTokenEndpoint, refresh_token);
+ }
+
+ NewClosure(oauth, SIGNAL(Finished()), this,
+ SLOT(ConnectFinished(OAuthenticator*)), oauth);
+}
+
+void AmazonCloudDrive::EnsureConnected() {
+ if (access_token_.isEmpty() ||
+ QDateTime::currentDateTime().secsTo(expiry_time_) < 60) {
+ Connect();
+ WaitForSignal(this, SIGNAL(Connected()));
+ }
+}
+
+void AmazonCloudDrive::ForgetCredentials() {
+ QSettings s;
+ s.beginGroup(kSettingsGroup);
+ s.remove("");
+ access_token_ = QString();
+ expiry_time_ = QDateTime();
+}
+
+void AmazonCloudDrive::ConnectFinished(OAuthenticator* oauth) {
+ oauth->deleteLater();
+
+ QSettings s;
+ s.beginGroup(kSettingsGroup);
+ s.setValue("refresh_token", oauth->refresh_token());
+
+ access_token_ = oauth->access_token();
+ expiry_time_ = oauth->expiry_time();
+
+ FetchEndpoint();
+}
+
+void AmazonCloudDrive::FetchEndpoint() {
+ QUrl url(kEndpointEndpoint);
+ QNetworkRequest request(url);
+ AddAuthorizationHeader(&request);
+ QNetworkReply* reply = network_->get(request);
+ NewClosure(reply, SIGNAL(finished()), this,
+ SLOT(FetchEndpointFinished(QNetworkReply*)), reply);
+}
+
+void AmazonCloudDrive::FetchEndpointFinished(QNetworkReply* reply) {
+ reply->deleteLater();
+ QJson::Parser parser;
+ QVariantMap response = parser.parse(reply).toMap();
+ content_url_ = response["contentUrl"].toString();
+ metadata_url_ = response["metadataUrl"].toString();
+ QSettings s;
+ s.beginGroup(kSettingsGroup);
+ QString checkpoint = s.value("checkpoint", "").toString();
+ RequestChanges(checkpoint);
+
+ // We wait until we know the endpoint URLs before emitting Connected();
+ emit Connected();
+}
+
+void AmazonCloudDrive::RequestChanges(const QString& checkpoint) {
+ EnsureConnected();
+ QUrl url(QString(kChangesEndpoint).arg(metadata_url_));
+
+ QVariantMap data;
+ data["includePurged"] = "true";
+ if (!checkpoint.isEmpty()) {
+ data["checkpoint"] = checkpoint;
+ }
+ QJson::Serializer serializer;
+ QByteArray json = serializer.serialize(data);
+
+ QNetworkRequest request(url);
+ AddAuthorizationHeader(&request);
+ QNetworkReply* reply = network_->post(request, json);
+ NewClosure(reply, SIGNAL(finished()), this,
+ SLOT(RequestChangesFinished(QNetworkReply*)), reply);
+}
+
+void AmazonCloudDrive::RequestChangesFinished(QNetworkReply* reply) {
+ reply->deleteLater();
+
+ QByteArray data = reply->readAll();
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+
+ QJson::Parser parser;
+ QVariantMap response = parser.parse(&buffer).toMap();
+
+ QString checkpoint = response["checkpoint"].toString();
+ QSettings settings;
+ settings.beginGroup(kSettingsGroup);
+ settings.setValue("checkpoint", checkpoint);
+
+ QVariantList nodes = response["nodes"].toList();
+ for (const QVariant& n : nodes) {
+ QVariantMap node = n.toMap();
+ if (node["kind"].toString() == "FOLDER") {
+ // Skip directories.
+ continue;
+ }
+ QUrl url;
+ url.setScheme("amazonclouddrive");
+ url.setPath(node["id"].toString());
+
+ QString status = node["status"].toString();
+ if (status == "PURGED") {
+ // Remove no longer available files.
+ Song song = library_backend_->GetSongByUrl(url);
+ if (song.is_valid()) {
+ library_backend_->DeleteSongs(SongList() << song);
+ }
+ continue;
+ }
+ if (status != "AVAILABLE") {
+ // Ignore any other statuses.
+ continue;
+ }
+
+ QVariantMap content_properties = node["contentProperties"].toMap();
+ QString mime_type = content_properties["contentType"].toString();
+
+ if (ShouldIndexFile(url, mime_type)) {
+ QString node_id = node["id"].toString();
+ QUrl content_url(
+ QString(kDownloadEndpoint).arg(content_url_).arg(node_id));
+ QString md5 = content_properties["md5"].toString();
+
+ Song song;
+ song.set_url(url);
+ song.set_etag(md5);
+ song.set_mtime(node["modifiedDate"].toDateTime().toTime_t());
+ song.set_ctime(node["createdDate"].toDateTime().toTime_t());
+ song.set_title(node["name"].toString());
+ song.set_filesize(content_properties["size"].toInt());
+
+ MaybeAddFileToDatabase(song, mime_type, content_url, QString("Bearer %1").arg(access_token_));
+ }
+ }
+
+ // The API potentially returns a second JSON dictionary appended with a
+ // newline at the end of the response with {"end": true} indicating that our
+ // client is up to date with the latest changes.
+ const int last_newline_index = data.lastIndexOf('\n');
+ QByteArray last_line = data.mid(last_newline_index);
+ QVariantMap end_json = parser.parse(last_line).toMap();
+ if (end_json.contains("end") && end_json["end"].toBool()) {
+ return;
+ } else {
+ RequestChanges(checkpoint);
+ }
+}
+
+void AmazonCloudDrive::AddAuthorizationHeader(QNetworkRequest* request) {
+ request->setRawHeader("Authorization",
+ QString("Bearer %1").arg(access_token_).toUtf8());
+}
diff --git a/src/internet/amazon/amazonclouddrive.h b/src/internet/amazon/amazonclouddrive.h
new file mode 100644
index 000000000..49350dee1
--- /dev/null
+++ b/src/internet/amazon/amazonclouddrive.h
@@ -0,0 +1,71 @@
+/* This file is part of Clementine.
+ Copyright 2015, John Maguire
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#ifndef INTERNET_AMAZON_AMAZON_CLOUD_DRIVE_H_
+#define INTERNET_AMAZON_AMAZON_CLOUD_DRIVE_H_
+
+#include "internet/core/cloudfileservice.h"
+
+#include
+#include
+#include
+
+class NetworkAccessManager;
+class OAuthenticator;
+class QNetworkReply;
+class QNetworkRequest;
+
+class AmazonCloudDrive : public CloudFileService {
+ Q_OBJECT
+ public:
+ AmazonCloudDrive(Application* app, InternetModel* parent);
+
+ static const char* kServiceName;
+ static const char* kSettingsGroup;
+
+ virtual bool has_credentials() const;
+
+ QUrl GetStreamingUrlFromSongId(const QUrl& url);
+
+ void ForgetCredentials();
+
+ signals:
+ void Connected();
+
+ public slots:
+ void Connect();
+
+ private:
+ void FetchEndpoint();
+ void RequestChanges(const QString& checkpoint);
+ void AddAuthorizationHeader(QNetworkRequest* request);
+ void EnsureConnected();
+
+ private slots:
+ void ConnectFinished(OAuthenticator*);
+ void FetchEndpointFinished(QNetworkReply*);
+ void RequestChangesFinished(QNetworkReply*);
+
+ private:
+ NetworkAccessManager* network_;
+ QString access_token_;
+ QDateTime expiry_time_;
+ QString content_url_;
+ QString metadata_url_;
+};
+
+#endif // INTERNET_AMAZON_AMAZON_CLOUD_DRIVE_H_
diff --git a/src/internet/amazon/amazonsettingspage.cpp b/src/internet/amazon/amazonsettingspage.cpp
new file mode 100644
index 000000000..0fd41fcce
--- /dev/null
+++ b/src/internet/amazon/amazonsettingspage.cpp
@@ -0,0 +1,80 @@
+/* This file is part of Clementine.
+ Copyright 2015, John Maguire
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#include "amazonsettingspage.h"
+#include "ui_amazonsettingspage.h"
+
+#include "core/application.h"
+#include "internet/amazon/amazonclouddrive.h"
+#include "internet/core/internetmodel.h"
+#include "ui/settingsdialog.h"
+
+AmazonSettingsPage::AmazonSettingsPage(SettingsDialog* parent)
+ : SettingsPage(parent),
+ ui_(new Ui::AmazonSettingsPage),
+ service_(dialog()->app()->internet_model()->Service()) {
+ ui_->setupUi(this);
+ ui_->login_state->AddCredentialGroup(ui_->login_container);
+
+ connect(ui_->login_button, SIGNAL(clicked()), SLOT(LoginClicked()));
+ connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(LogoutClicked()));
+ connect(service_, SIGNAL(Connected()), SLOT(Connected()));
+
+ dialog()->installEventFilter(this);
+}
+
+AmazonSettingsPage::~AmazonSettingsPage() { delete ui_; }
+
+void AmazonSettingsPage::Load() {
+ QSettings s;
+ s.beginGroup(AmazonCloudDrive::kSettingsGroup);
+
+ const QString token = s.value("refresh_token").toString();
+
+ if (!token.isEmpty()) {
+ ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
+ }
+}
+
+void AmazonSettingsPage::Save() {
+ QSettings s;
+ s.beginGroup(AmazonCloudDrive::kSettingsGroup);
+}
+
+void AmazonSettingsPage::LoginClicked() {
+ service_->Connect();
+ ui_->login_button->setEnabled(false);
+ ui_->login_state->SetLoggedIn(LoginStateWidget::LoginInProgress);
+}
+
+bool AmazonSettingsPage::eventFilter(QObject* object, QEvent* event) {
+ if (object == dialog() && event->type() == QEvent::Enter) {
+ ui_->login_button->setEnabled(true);
+ return false;
+ }
+
+ return SettingsPage::eventFilter(object, event);
+}
+
+void AmazonSettingsPage::LogoutClicked() {
+ service_->ForgetCredentials();
+ ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedOut);
+}
+
+void AmazonSettingsPage::Connected() {
+ ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
+}
diff --git a/src/internet/amazon/amazonsettingspage.h b/src/internet/amazon/amazonsettingspage.h
new file mode 100644
index 000000000..8ff6b303e
--- /dev/null
+++ b/src/internet/amazon/amazonsettingspage.h
@@ -0,0 +1,53 @@
+/* This file is part of Clementine.
+ Copyright 2015, John Maguire
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#ifndef INTERNET_AMAZON_AMAZONSETTINGSPAGE_H_
+#define INTERNET_AMAZON_AMAZONSETTINGSPAGE_H_
+
+#include "ui/settingspage.h"
+
+#include
+#include
+
+class AmazonCloudDrive;
+class Ui_AmazonSettingsPage;
+
+class AmazonSettingsPage : public SettingsPage {
+ Q_OBJECT
+
+ public:
+ explicit AmazonSettingsPage(SettingsDialog* parent = nullptr);
+ ~AmazonSettingsPage();
+
+ void Load();
+ void Save();
+
+ // QObject
+ bool eventFilter(QObject* object, QEvent* event);
+
+ private slots:
+ void LoginClicked();
+ void LogoutClicked();
+ void Connected();
+
+ private:
+ Ui_AmazonSettingsPage* ui_;
+
+ AmazonCloudDrive* service_;
+};
+
+#endif // INTERNET_AMAZON_AMAZONSETTINGSPAGE_H_
diff --git a/src/internet/amazon/amazonsettingspage.ui b/src/internet/amazon/amazonsettingspage.ui
new file mode 100644
index 000000000..d496f3424
--- /dev/null
+++ b/src/internet/amazon/amazonsettingspage.ui
@@ -0,0 +1,110 @@
+
+
+ AmazonSettingsPage
+
+
+
+ 0
+ 0
+ 569
+ 491
+
+
+
+ Amazon
+
+
+
+ :/providers/amazonclouddrive.png:/providers/amazonclouddrive.png
+
+
+ -
+
+
+ Clementine can play music that you have uploaded to Amazon Cloud Drive
+
+
+ true
+
+
+
+ -
+
+
+ -
+
+
+
+ 28
+
+
+ 0
+
+
+ 0
+
+
-
+
+
-
+
+
+ Login
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Clicking the Login button will open a web browser. You should return to Clementine after you have logged in.
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 357
+
+
+
+
+
+
+
+
+ LoginStateWidget
+ QWidget
+ widgets/loginstatewidget.h
+ 1
+
+
+
+
+
+
+
diff --git a/src/internet/amazon/amazonurlhandler.cpp b/src/internet/amazon/amazonurlhandler.cpp
new file mode 100644
index 000000000..42433a3f1
--- /dev/null
+++ b/src/internet/amazon/amazonurlhandler.cpp
@@ -0,0 +1,28 @@
+/* This file is part of Clementine.
+ Copyright 2015, John Maguire
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#include "internet/amazon/amazonurlhandler.h"
+
+#include "internet/amazon/amazonclouddrive.h"
+
+AmazonUrlHandler::AmazonUrlHandler(AmazonCloudDrive* service, QObject* parent)
+ : UrlHandler(parent), service_(service) {}
+
+UrlHandler::LoadResult AmazonUrlHandler::StartLoading(const QUrl& url) {
+ return LoadResult(url, LoadResult::TrackAvailable,
+ service_->GetStreamingUrlFromSongId(url));
+}
diff --git a/src/internet/amazon/amazonurlhandler.h b/src/internet/amazon/amazonurlhandler.h
new file mode 100644
index 000000000..807f24732
--- /dev/null
+++ b/src/internet/amazon/amazonurlhandler.h
@@ -0,0 +1,39 @@
+/* This file is part of Clementine.
+ Copyright 2015, John Maguire
+
+ Clementine is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Clementine is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Clementine. If not, see .
+*/
+
+#ifndef INTERNET_AMAZON_AMAZONURLHANDLER_H_
+#define INTERNET_AMAZON_AMAZONURLHANDLER_H_
+
+#include "core/urlhandler.h"
+
+class AmazonCloudDrive;
+
+class AmazonUrlHandler : public UrlHandler {
+ Q_OBJECT
+ public:
+ explicit AmazonUrlHandler(
+ AmazonCloudDrive* service, QObject* parent = nullptr);
+
+ QString scheme() const { return "amazonclouddrive"; }
+ QIcon icon() const { return QIcon(":providers/amazonclouddrive.png"); }
+ LoadResult StartLoading(const QUrl& url);
+
+ private:
+ AmazonCloudDrive* service_;
+};
+
+#endif // INTERNET_AMAZON_AMAZONURLHANDLER_H_
diff --git a/src/internet/core/internetmodel.cpp b/src/internet/core/internetmodel.cpp
index 4783466ee..09754cd5e 100644
--- a/src/internet/core/internetmodel.cpp
+++ b/src/internet/core/internetmodel.cpp
@@ -64,6 +64,9 @@
#ifdef HAVE_SEAFILE
#include "internet/seafile/seafileservice.h"
#endif
+#ifdef HAVE_AMAZON_CLOUD_DRIVE
+#include "internet/amazon/amazonclouddrive.h"
+#endif
using smart_playlists::Generator;
using smart_playlists::GeneratorMimeData;
@@ -117,6 +120,9 @@ InternetModel::InternetModel(Application* app, QObject* parent)
#ifdef HAVE_VK
AddService(new VkService(app, this));
#endif
+#ifdef HAVE_AMAZON_CLOUD_DRIVE
+ AddService(new AmazonCloudDrive(app, this));
+#endif
invisibleRootItem()->sortChildren(0, Qt::AscendingOrder);
UpdateServices();
diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp
index b82e00a27..5cfb1bda8 100644
--- a/src/ui/settingsdialog.cpp
+++ b/src/ui/settingsdialog.cpp
@@ -84,6 +84,10 @@
#include "internet/seafile/seafilesettingspage.h"
#endif
+#ifdef HAVE_AMAZON_CLOUD_DRIVE
+#include "internet/amazon/amazonsettingspage.h"
+#endif
+
#include
#include
#include
@@ -193,6 +197,10 @@ SettingsDialog::SettingsDialog(Application* app, BackgroundStreams* streams,
AddPage(Page_Seafile, new SeafileSettingsPage(this), providers);
#endif
+#ifdef HAVE_AMAZON_CLOUD_DRIVE
+ AddPage(Page_AmazonCloudDrive, new AmazonSettingsPage(this), providers);
+#endif
+
AddPage(Page_Magnatune, new MagnatuneSettingsPage(this), providers);
AddPage(Page_DigitallyImported, new DigitallyImportedSettingsPage(this),
providers);
diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h
index 2c4a29db6..607ecc0e8 100644
--- a/src/ui/settingsdialog.h
+++ b/src/ui/settingsdialog.h
@@ -86,7 +86,8 @@ class SettingsDialog : public QDialog {
Page_Box,
Page_Vk,
Page_Seafile,
- Page_InternetShow
+ Page_InternetShow,
+ Page_AmazonCloudDrive,
};
enum Role { Role_IsSeparator = Qt::UserRole };