From 68d445fed28da375eb5a43ead5652e195f29737e Mon Sep 17 00:00:00 2001 From: Mattias Andersson Date: Sat, 24 May 2014 13:33:32 +0200 Subject: [PATCH] Parse discid xml from MusicBrainz correctly. Fixes #4025. --- src/musicbrainz/musicbrainzclient.cpp | 113 ++++++++++++++++++++++---- src/musicbrainz/musicbrainzclient.h | 5 +- 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/src/musicbrainz/musicbrainzclient.cpp b/src/musicbrainz/musicbrainzclient.cpp index 0f5797ed3..4b1d5a566 100644 --- a/src/musicbrainz/musicbrainzclient.cpp +++ b/src/musicbrainz/musicbrainzclient.cpp @@ -70,7 +70,8 @@ void MusicBrainzClient::StartDiscIdRequest(const QString& discid) { QNetworkReply* reply = network_->get(req); NewClosure(reply, SIGNAL(finished()), this, - SLOT(DiscIdRequestFinished(QNetworkReply*)), reply); + SLOT(DiscIdRequestFinished(const QString&, QNetworkReply*)), + discid, reply); timeouts_->AddReply(reply); } @@ -82,7 +83,8 @@ void MusicBrainzClient::CancelAll() { requests_.clear(); } -void MusicBrainzClient::DiscIdRequestFinished(QNetworkReply* reply) { +void MusicBrainzClient::DiscIdRequestFinished(const QString& discid, + QNetworkReply* reply) { reply->deleteLater(); ResultList ret; @@ -99,6 +101,8 @@ void MusicBrainzClient::DiscIdRequestFinished(QNetworkReply* reply) { // -get title // -get artist // -get all the tracks' tags + // Note: If there are multiple releases for the discid, the first + // release is chosen. QXmlStreamReader reader(reply); while (!reader.atEnd()) { QXmlStreamReader::TokenType type = reader.readNext(); @@ -106,9 +110,9 @@ void MusicBrainzClient::DiscIdRequestFinished(QNetworkReply* reply) { QStringRef name = reader.name(); if (name == "title") { album = reader.readElementText(); - } else if (name == "artist") { + } else if (name == "artist-credit") { ParseArtist(&reader, &artist); - } else if (name == "track-list") { + } else if (name == "medium-list") { break; } } @@ -116,16 +120,20 @@ void MusicBrainzClient::DiscIdRequestFinished(QNetworkReply* reply) { while (!reader.atEnd()) { QXmlStreamReader::TokenType token = reader.readNext(); - if (token == QXmlStreamReader::StartElement && - reader.name() == "recording") { - ResultList tracks = ParseTrack(&reader); - for (const Result& track : tracks) { - if (!track.title_.isEmpty()) { - ret << track; + if (token == QXmlStreamReader::StartElement && reader.name() == "medium") { + // Get the medium with a matching discid. + if (MediumHasDiscid(discid, &reader)) { + ResultList tracks = ParseMedium(&reader); + for (const Result& track : tracks) { + if (!track.title_.isEmpty()) { + ret << track; + } } + } else { + Utilities::ConsumeCurrentElement(&reader); } } else if (token == QXmlStreamReader::EndElement && - reader.name() == "track-list") { + reader.name() == "medium-list") { break; } } @@ -160,6 +168,72 @@ void MusicBrainzClient::RequestFinished(QNetworkReply* reply, int id) { emit Finished(id, UniqueResults(ret)); } +bool MusicBrainzClient::MediumHasDiscid(const QString& discid, + QXmlStreamReader* reader) { + while (!reader->atEnd()) { + QXmlStreamReader::TokenType type = reader->readNext(); + + if (type == QXmlStreamReader::StartElement && reader->name() == "disc" && + reader->attributes().value("id").toString() == discid) { + return true; + } else if (type == QXmlStreamReader::EndElement && + reader->name() == "disc-list") { + return false; + } + } + qLog(Debug) << "Reached end of xml stream without encountering "; + return false; +} + +MusicBrainzClient::ResultList MusicBrainzClient::ParseMedium( + QXmlStreamReader* reader) { + ResultList ret; + while (!reader->atEnd()) { + QXmlStreamReader::TokenType type = reader->readNext(); + + if (type == QXmlStreamReader::StartElement) { + if (reader->name() == "track") { + Result result; + result = ParseTrackFromDisc(reader); + ret << result; + } + } + + if (type == QXmlStreamReader::EndElement && + reader->name() == "track-list") { + break; + } + } + + return ret; +} + +MusicBrainzClient::Result MusicBrainzClient::ParseTrackFromDisc( + QXmlStreamReader* reader) { + Result result; + + while (!reader->atEnd()) { + QXmlStreamReader::TokenType type = reader->readNext(); + + if (type == QXmlStreamReader::StartElement) { + QStringRef name = reader->name(); + if (name == "position") { + result.track_ = reader->readElementText().toInt(); + } else if (name == "length") { + result.duration_msec_ = reader->readElementText().toInt(); + } else if (name == "title") { + result.title_ = reader->readElementText(); + } + } + + if (type == QXmlStreamReader::EndElement && reader->name() == "track") { + break; + } + } + + return result; +} + MusicBrainzClient::ResultList MusicBrainzClient::ParseTrack( QXmlStreamReader* reader) { Result result; @@ -175,7 +249,7 @@ MusicBrainzClient::ResultList MusicBrainzClient::ParseTrack( result.title_ = reader->readElementText(); } else if (name == "length") { result.duration_msec_ = reader->readElementText().toInt(); - } else if (name == "artist") { + } else if (name == "artist-credit") { ParseArtist(reader, &result.artist_); } else if (name == "release") { releases << ParseRelease(reader); @@ -198,15 +272,24 @@ MusicBrainzClient::ResultList MusicBrainzClient::ParseTrack( return ret; } +// Parse the artist. Multiple artists are joined together with the +// joinphrase from musicbrainz. void MusicBrainzClient::ParseArtist(QXmlStreamReader* reader, QString* artist) { + QString join_phrase; while (!reader->atEnd()) { QXmlStreamReader::TokenType type = reader->readNext(); - if (type == QXmlStreamReader::StartElement && reader->name() == "name") { - *artist = reader->readElementText(); + if (type == QXmlStreamReader::StartElement && + reader->name() == "name-credit") { + join_phrase = reader->attributes().value("joinphrase").toString(); } - if (type == QXmlStreamReader::EndElement && reader->name() == "artist") { + if (type == QXmlStreamReader::StartElement && reader->name() == "name") { + *artist += reader->readElementText() + join_phrase; + } + + if (type == QXmlStreamReader::EndElement && + reader->name() == "artist-credit") { return; } } diff --git a/src/musicbrainz/musicbrainzclient.h b/src/musicbrainz/musicbrainzclient.h index 6b526b68b..c91b5da12 100644 --- a/src/musicbrainz/musicbrainzclient.h +++ b/src/musicbrainz/musicbrainzclient.h @@ -97,7 +97,7 @@ signals: private slots: void RequestFinished(QNetworkReply* reply, int id); - void DiscIdRequestFinished(QNetworkReply* reply); + void DiscIdRequestFinished(const QString& discid, QNetworkReply* reply); private: struct Release { @@ -116,6 +116,9 @@ signals: int year_; }; + static bool MediumHasDiscid(const QString& discid, QXmlStreamReader* reader); + static ResultList ParseMedium(QXmlStreamReader* reader); + static Result ParseTrackFromDisc(QXmlStreamReader* reader); static ResultList ParseTrack(QXmlStreamReader* reader); static void ParseArtist(QXmlStreamReader* reader, QString* artist); static Release ParseRelease(QXmlStreamReader* reader);