18
18
#include "musicbrainzclient.h"
19
#include "core/logging.h"
19
20
#include "core/network.h"
21
#include "core/utilities.h"
21
23
#include <QCoreApplication>
22
24
#include <QNetworkReply>
23
26
#include <QXmlStreamReader>
26
const char* MusicBrainzClient::kUrl = "http://musicbrainz.org/ws/1/track/";
29
const char* MusicBrainzClient::kTrackUrl = "http://musicbrainz.org/ws/2/recording/";
30
const char* MusicBrainzClient::kDiscUrl = "http://musicbrainz.org/ws/1/release/";
31
const char* MusicBrainzClient::kDateRegex = "^[12]\\d{3}";
27
32
const int MusicBrainzClient::kDefaultTimeout = 5000; // msec
29
34
MusicBrainzClient::MusicBrainzClient(QObject* parent)
36
void MusicBrainzClient::Start(int id, const QString& puid) {
41
void MusicBrainzClient::Start(int id, const QString& mbid) {
37
42
typedef QPair<QString, QString> Param;
39
44
QList<Param> parameters;
40
parameters << Param("type", "xml")
41
<< Param("puid", puid);
45
parameters << Param("inc", "artists+releases+media");
47
QUrl url(kTrackUrl + mbid);
44
48
url.setQueryItems(parameters);
45
49
QNetworkRequest req(url);
51
55
timeouts_->AddReply(reply);
58
void MusicBrainzClient::StartDiscIdRequest(const QString& discid) {
59
typedef QPair<QString, QString> Param;
61
QList<Param> parameters;
62
parameters << Param("type", "xml")
63
<< Param("discid", discid);
66
url.setQueryItems(parameters);
67
QNetworkRequest req(url);
69
QNetworkReply* reply = network_->get(req);
70
connect(reply, SIGNAL(finished()), SLOT(DiscIdRequestFinished()));
71
//requests_[reply] = id;
73
timeouts_->AddReply(reply);
54
76
void MusicBrainzClient::Cancel(int id) {
55
77
QNetworkReply* reply = requests_.key(id);
56
78
requests_.remove(reply);
87
void MusicBrainzClient::DiscIdRequestFinished() {
88
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
97
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
98
emit Finished(artist, album, ret);
105
// -get all the tracks' tags
106
QXmlStreamReader reader(reply);
107
while (!reader.atEnd()) {
108
QXmlStreamReader::TokenType type = reader.readNext();
109
if (type == QXmlStreamReader::StartElement) {
110
QStringRef name = reader.name();
111
if (name == "title") {
112
album = reader.readElementText();
113
} else if (name == "artist") {
114
ParseArtist(&reader, &artist);
115
} else if (name == "track-list") {
121
while (!reader.atEnd()) {
122
QXmlStreamReader::TokenType token = reader.readNext();
123
if (token == QXmlStreamReader::StartElement && reader.name() == "track") {
124
ResultList tracks = ParseTrack(&reader);
125
foreach (const Result& track, tracks) {
126
if (!track.title_.isEmpty()) {
130
} else if (token == QXmlStreamReader::EndElement && reader.name() == "track-list") {
135
emit Finished(artist, album, UniqueResults(ret));
65
139
void MusicBrainzClient::RequestFinished() {
66
140
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
82
156
QXmlStreamReader reader(reply);
83
157
while (!reader.atEnd()) {
84
if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "track") {
85
Result track = ParseTrack(&reader);
86
if (!track.title_.isEmpty()) {
158
if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "recording") {
159
ResultList tracks = ParseTrack(&reader);
160
foreach (const Result& track, tracks) {
161
if (!track.title_.isEmpty()) {
92
emit Finished(id, ret);
168
emit Finished(id, UniqueResults(ret));
95
MusicBrainzClient::Result MusicBrainzClient::ParseTrack(QXmlStreamReader* reader) {
171
MusicBrainzClient::ResultList MusicBrainzClient::ParseTrack(QXmlStreamReader* reader) {
173
QList<Release> releases;
98
175
while (!reader->atEnd()) {
99
176
QXmlStreamReader::TokenType type = reader->readNext();
102
179
QStringRef name = reader->name();
104
181
if (name == "title") {
105
ret.title_ = reader->readElementText();
106
} else if (name == "duration") {
107
ret.duration_msec_ = reader->readElementText().toInt();
182
result.title_ = reader->readElementText();
183
} else if (name == "length") {
184
result.duration_msec_ = reader->readElementText().toInt();
108
185
} else if (name == "artist") {
109
ParseArtist(reader, &ret.artist_);
186
ParseArtist(reader, &result.artist_);
110
187
} else if (name == "release") {
111
ParseAlbum(reader, &ret.album_, &ret.track_);
188
releases << ParseRelease(reader);
115
if (type == QXmlStreamReader::EndElement && reader->name() == "track") {
192
if (type == QXmlStreamReader::EndElement && reader->name() == "recording") {
198
foreach (const Release& release, releases) {
199
ret << release.CopyAndMergeInto(result);
137
void MusicBrainzClient::ParseAlbum(QXmlStreamReader* reader, QString* album, int* track) {
218
MusicBrainzClient::Release MusicBrainzClient::ParseRelease(QXmlStreamReader* reader) {
138
221
while (!reader->atEnd()) {
139
222
QXmlStreamReader::TokenType type = reader->readNext();
141
224
if (type == QXmlStreamReader::StartElement) {
142
225
QStringRef name = reader->name();
143
226
if (name == "title") {
144
*album = reader->readElementText();
227
ret.album_ = reader->readElementText();
228
} else if (name == "date") {
229
QRegExp regex(kDateRegex);
230
if (regex.indexIn(reader->readElementText()) == 0) {
231
ret.year_ = regex.cap(0).toInt();
145
233
} else if (name == "track-list") {
146
*track = reader->attributes().value("offset").toString().toInt() + 1;
234
ret.track_ = reader->attributes().value("offset").toString().toInt() + 1;
235
Utilities::ConsumeCurrentElement(reader);
150
239
if (type == QXmlStreamReader::EndElement && reader->name() == "release") {
247
MusicBrainzClient::ResultList MusicBrainzClient::UniqueResults(const ResultList& results) {
248
ResultList ret = QSet<Result>::fromList(results).toList();