Amazon Cloud Drive support.

Squashed commit of the following:

commit 451a327fabb5f9aba077d93a33d75d8a6a288f5f
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:55:36 2015 +0100

    Revert debug console changes.

commit 52f643c3dc524a837f56268b6da4881187204165
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:49:28 2015 +0100

    Revert extra logging

commit 23645f9fea
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:47:55 2015 +0100

    How did you get there

commit 8153388f19
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:45:12 2015 +0100

    Update copyright headers.

commit fa9e279259
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:43:27 2015 +0100

    Remove logging

commit 47a405543c
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:42:05 2015 +0100

    Show login state correctly for Amazon.

commit 748d88d993
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:28:55 2015 +0100

    Ensure Amazon is connected before serving URLs.

commit 25ec9c65f4
Author: John Maguire <john.maguire@gmail.com>
Date:   Fri Mar 27 14:22:28 2015 +0100

    Refresh Amazon authorisation & follow changes.

commit 27c1a37173
Author: John Maguire <john.maguire@gmail.com>
Date:   Thu Mar 26 18:27:27 2015 +0100

    Revert unneeded OAuthenticator change.

commit 3594af5be1
Author: John Maguire <john.maguire@gmail.com>
Date:   Thu Mar 26 16:52:19 2015 +0100

    Initial support for Amazon Cloud Drive.
This commit is contained in:
John Maguire 2015-03-27 14:56:08 +01:00
parent f3426c05c7
commit 8d3fd00956
18 changed files with 725 additions and 2 deletions

View File

@ -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
)

View File

@ -310,6 +310,7 @@
<file>playstore/uk_generic_rgb_wo_45.png</file>
<file>playstore/vi_generic_rgb_wo_45.png</file>
<file>providers/amazon.png</file>
<file>providers/amazonclouddrive.png</file>
<file>providers/aol.png</file>
<file>providers/bbc.png</file>
<file>providers/box.png</file>
@ -385,6 +386,7 @@
<file>schema/schema-45.sql</file>
<file>schema/schema-46.sql</file>
<file>schema/schema-47.sql</file>
<file>schema/schema-48.sql</file>
<file>schema/schema-4.sql</file>
<file>schema/schema-5.sql</file>
<file>schema/schema-6.sql</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

50
data/schema/schema-48.sql Normal file
View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -47,7 +47,7 @@
#include <QVariant>
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;

View File

@ -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 =

View File

@ -0,0 +1,246 @@
/* This file is part of Clementine.
Copyright 2015, John Maguire <john.maguire@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#include "internet/amazon/amazonclouddrive.h"
#include <QIcon>
#include <qjson/parser.h>
#include <qjson/serializer.h>
#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());
}

View File

@ -0,0 +1,71 @@
/* This file is part of Clementine.
Copyright 2015, John Maguire <john.maguire@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#ifndef INTERNET_AMAZON_AMAZON_CLOUD_DRIVE_H_
#define INTERNET_AMAZON_AMAZON_CLOUD_DRIVE_H_
#include "internet/core/cloudfileservice.h"
#include <QDateTime>
#include <QString>
#include <QUrl>
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_

View File

@ -0,0 +1,80 @@
/* This file is part of Clementine.
Copyright 2015, John Maguire <john.maguire@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#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<AmazonCloudDrive>()) {
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);
}

View File

@ -0,0 +1,53 @@
/* This file is part of Clementine.
Copyright 2015, John Maguire <john.maguire@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#ifndef INTERNET_AMAZON_AMAZONSETTINGSPAGE_H_
#define INTERNET_AMAZON_AMAZONSETTINGSPAGE_H_
#include "ui/settingspage.h"
#include <QModelIndex>
#include <QWidget>
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_

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AmazonSettingsPage</class>
<widget class="QWidget" name="AmazonSettingsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>569</width>
<height>491</height>
</rect>
</property>
<property name="windowTitle">
<string>Amazon</string>
</property>
<property name="windowIcon">
<iconset resource="../../data/data.qrc">
<normaloff>:/providers/amazonclouddrive.png</normaloff>:/providers/amazonclouddrive.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Clementine can play music that you have uploaded to Amazon Cloud Drive</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="LoginStateWidget" name="login_state" native="true"/>
</item>
<item>
<widget class="QWidget" name="login_container" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>28</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="login_button">
<property name="text">
<string>Login</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Clicking the Login button will open a web browser. You should return to Clementine after you have logged in.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>357</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LoginStateWidget</class>
<extends>QWidget</extends>
<header>widgets/loginstatewidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../data/data.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,28 @@
/* This file is part of Clementine.
Copyright 2015, John Maguire <john.maguire@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#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));
}

View File

@ -0,0 +1,39 @@
/* This file is part of Clementine.
Copyright 2015, John Maguire <john.maguire@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#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_

View File

@ -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();

View File

@ -84,6 +84,10 @@
#include "internet/seafile/seafilesettingspage.h"
#endif
#ifdef HAVE_AMAZON_CLOUD_DRIVE
#include "internet/amazon/amazonsettingspage.h"
#endif
#include <QAbstractButton>
#include <QDesktopWidget>
#include <QPainter>
@ -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);

View File

@ -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 };