1
/* This file is part of Clementine.
2
Copyright 2010, David Sansome <me@davidsansome.com>
4
Clementine is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
9
Clementine is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
18
#include "amazoncoverprovider.h"
19
#include "core/logging.h"
20
#include "core/network.h"
21
#include "core/utilities.h"
24
#include <QNetworkReply>
25
#include <QStringList>
26
#include <QXmlStreamReader>
28
const char* AmazonCoverProvider::kAccessKey = "AKIAJ4QO3GQTSM3A43BQ";
29
const char* AmazonCoverProvider::kSecretAccessKey = "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";
30
const char* AmazonCoverProvider::kUrl = "http://ecs.amazonaws.com/onca/xml";
31
const char* AmazonCoverProvider::kAssociateTag = "clementine-20";
33
AmazonCoverProvider::AmazonCoverProvider(QObject* parent)
34
: CoverProvider("Amazon", parent),
35
network_(new NetworkAccessManager(this))
39
bool AmazonCoverProvider::StartSearch(const QString& artist, const QString& album, int id) {
40
typedef QPair<QString, QString> Arg;
41
typedef QList<Arg> ArgList;
43
typedef QPair<QByteArray, QByteArray> EncodedArg;
44
typedef QList<EncodedArg> EncodedArgList;
46
// Must be sorted by parameter name
47
ArgList args = ArgList()
48
<< Arg("AWSAccessKeyId", kAccessKey)
49
<< Arg("AssociateTag", kAssociateTag)
50
<< Arg("Keywords", artist + " " + album)
51
<< Arg("Operation", "ItemSearch")
52
<< Arg("ResponseGroup", "Images")
53
<< Arg("SearchIndex", "All")
54
<< Arg("Service", "AWSECommerceService")
55
<< Arg("Timestamp", QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss.zzzZ"))
56
<< Arg("Version", "2009-11-01");
58
EncodedArgList encoded_args;
59
QStringList query_items;
61
// Encode the arguments
62
foreach (const Arg& arg, args) {
63
EncodedArg encoded_arg(QUrl::toPercentEncoding(arg.first),
64
QUrl::toPercentEncoding(arg.second));
65
encoded_args << encoded_arg;
66
query_items << encoded_arg.first + "=" + encoded_arg.second;
72
const QByteArray data_to_sign = QString("GET\n%1\n%2\n%3").arg(
73
url.host(), url.path(), query_items.join("&")).toAscii();
74
const QByteArray signature(Utilities::HmacSha256(kSecretAccessKey, data_to_sign));
76
// Add the signature to the request
77
encoded_args << EncodedArg("Signature", QUrl::toPercentEncoding(signature.toBase64()));
78
url.setEncodedQueryItems(encoded_args);
81
QNetworkReply* reply = network_->get(QNetworkRequest(url));
82
connect(reply, SIGNAL(finished()), SLOT(QueryFinished()));
83
pending_queries_[reply] = id;
88
void AmazonCoverProvider::QueryFinished() {
89
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
90
if (!reply || !pending_queries_.contains(reply))
93
int id = pending_queries_.take(reply);
96
CoverSearchResults results;
98
QXmlStreamReader reader(reply);
99
while (!reader.atEnd()) {
101
if (reader.tokenType() == QXmlStreamReader::StartElement &&
102
reader.name() == "Item") {
103
ReadItem(&reader, &results);
107
emit SearchFinished(id, results);
110
void AmazonCoverProvider::ReadItem(QXmlStreamReader* reader, CoverSearchResults* results) {
111
while (!reader->atEnd()) {
112
switch (reader->readNext()) {
113
case QXmlStreamReader::StartElement:
114
if (reader->name() == "LargeImage") {
115
ReadLargeImage(reader, results);
117
reader->skipCurrentElement();
121
case QXmlStreamReader::EndElement:
130
void AmazonCoverProvider::ReadLargeImage(QXmlStreamReader* reader, CoverSearchResults* results) {
131
while (!reader->atEnd()) {
132
switch (reader->readNext()) {
133
case QXmlStreamReader::StartElement:
134
if (reader->name() == "URL") {
135
CoverSearchResult result;
136
result.image_url = reader->readElementText();
137
results->append(result);
139
reader->skipCurrentElement();
143
case QXmlStreamReader::EndElement: