Compare commits

...

8 Commits

Author SHA1 Message Date
John Maguire
23645f9fea How did you get there 2015-03-27 14:47:55 +01:00
John Maguire
8153388f19 Update copyright headers. 2015-03-27 14:45:12 +01:00
John Maguire
fa9e279259 Remove logging 2015-03-27 14:43:27 +01:00
John Maguire
47a405543c Show login state correctly for Amazon. 2015-03-27 14:42:05 +01:00
John Maguire
748d88d993 Ensure Amazon is connected before serving URLs. 2015-03-27 14:29:54 +01:00
John Maguire
25ec9c65f4 Refresh Amazon authorisation & follow changes. 2015-03-27 14:22:28 +01:00
John Maguire
27c1a37173 Revert unneeded OAuthenticator change. 2015-03-26 18:28:23 +01:00
John Maguire
3594af5be1 Initial support for Amazon Cloud Drive. 2015-03-26 18:21:15 +01:00
21 changed files with 733 additions and 4 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

@ -957,7 +957,12 @@ bool TagReader::ReadCloudFile(const QUrl& download_url, const QString& title,
int size, const QString& mime_type,
const QString& authorisation_header,
pb::tagreader::SongMetadata* song) const {
qLog(Debug) << "Loading tags from" << title;
qLog(Debug) << "Loading tags from"
<< title
<< download_url
<< size
<< mime_type
<< authorisation_header;
std::unique_ptr<CloudStream> stream(new CloudStream(
download_url, title, size, authorisation_header, network_));

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

@ -821,7 +821,7 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd,
connect(ui_->action_kittens, SIGNAL(toggled(bool)), app_->network_remote(),
SLOT(EnableKittens(bool)));
// Hide the console
// connect(ui_->action_console, SIGNAL(triggered()), SLOT(ShowConsole()));
connect(ui_->action_console, SIGNAL(triggered()), SLOT(ShowConsole()));
NowPlayingWidgetPositionChanged(ui_->now_playing->show_above_status_bar());
// Load theme

View File

@ -461,6 +461,7 @@
<addaction name="action_hypnotoad"/>
<addaction name="action_enterprise"/>
<addaction name="action_kittens"/>
<addaction name="action_console"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menu_tools">

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