~ubuntu-branches/ubuntu/saucy/clementine/saucy

« back to all changes in this revision

Viewing changes to src/covers/amazoncoverprovider.cpp

  • Committer: Package Import Robot
  • Author(s): Thomas PIERSON
  • Date: 2012-01-01 20:43:39 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120101204339-lsb6nndwhfy05sde
Tags: 1.0.1+dfsg-1
New upstream release. (Closes: #653926, #651611, #657391)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of Clementine.
 
2
   Copyright 2010, David Sansome <me@davidsansome.com>
 
3
 
 
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.
 
8
 
 
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.
 
13
 
 
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/>.
 
16
*/
 
17
 
 
18
#include "amazoncoverprovider.h"
 
19
#include "core/logging.h"
 
20
#include "core/network.h"
 
21
#include "core/utilities.h"
 
22
 
 
23
#include <QDateTime>
 
24
#include <QNetworkReply>
 
25
#include <QStringList>
 
26
#include <QXmlStreamReader>
 
27
 
 
28
const char* AmazonCoverProvider::kAccessKey = "AKIAJ4QO3GQTSM3A43BQ";
 
29
const char* AmazonCoverProvider::kSecretAccessKey = "KBlHVSNEvJrebNB/BBmGIh4a38z4cedfFvlDJ5fE";
 
30
const char* AmazonCoverProvider::kUrl = "http://ecs.amazonaws.com/onca/xml";
 
31
const char* AmazonCoverProvider::kAssociateTag = "clementine-20";
 
32
 
 
33
AmazonCoverProvider::AmazonCoverProvider(QObject* parent)
 
34
  : CoverProvider("Amazon", parent),
 
35
    network_(new NetworkAccessManager(this))
 
36
{
 
37
}
 
38
 
 
39
bool AmazonCoverProvider::StartSearch(const QString& artist, const QString& album, int id) {
 
40
  typedef QPair<QString, QString> Arg;
 
41
  typedef QList<Arg> ArgList;
 
42
 
 
43
  typedef QPair<QByteArray, QByteArray> EncodedArg;
 
44
  typedef QList<EncodedArg> EncodedArgList;
 
45
 
 
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");
 
57
 
 
58
  EncodedArgList encoded_args;
 
59
  QStringList query_items;
 
60
 
 
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;
 
67
  }
 
68
 
 
69
  // Sign the request
 
70
  QUrl url(kUrl);
 
71
 
 
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));
 
75
 
 
76
  // Add the signature to the request
 
77
  encoded_args << EncodedArg("Signature", QUrl::toPercentEncoding(signature.toBase64()));
 
78
  url.setEncodedQueryItems(encoded_args);
 
79
 
 
80
  // Make the request
 
81
  QNetworkReply* reply = network_->get(QNetworkRequest(url));
 
82
  connect(reply, SIGNAL(finished()), SLOT(QueryFinished()));
 
83
  pending_queries_[reply] = id;
 
84
 
 
85
  return true;
 
86
}
 
87
 
 
88
void AmazonCoverProvider::QueryFinished() {
 
89
  QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
 
90
  if (!reply || !pending_queries_.contains(reply))
 
91
    return;
 
92
 
 
93
  int id = pending_queries_.take(reply);
 
94
  reply->deleteLater();
 
95
 
 
96
  CoverSearchResults results;
 
97
 
 
98
  QXmlStreamReader reader(reply);
 
99
  while (!reader.atEnd()) {
 
100
    reader.readNext();
 
101
    if (reader.tokenType() == QXmlStreamReader::StartElement &&
 
102
        reader.name() == "Item") {
 
103
      ReadItem(&reader, &results);
 
104
    }
 
105
  }
 
106
 
 
107
  emit SearchFinished(id, results);
 
108
}
 
109
 
 
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);
 
116
      } else {
 
117
        reader->skipCurrentElement();
 
118
      }
 
119
      break;
 
120
 
 
121
    case QXmlStreamReader::EndElement:
 
122
      return;
 
123
 
 
124
    default:
 
125
      break;
 
126
    }
 
127
  }
 
128
}
 
129
 
 
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);
 
138
      } else {
 
139
        reader->skipCurrentElement();
 
140
      }
 
141
      break;
 
142
 
 
143
    case QXmlStreamReader::EndElement:
 
144
      return;
 
145
 
 
146
    default:
 
147
      break;
 
148
    }
 
149
  }
 
150
}