From e8c044a41c51590c6e4227e290bb3c9975bd901c Mon Sep 17 00:00:00 2001 From: Kilian Lackhove <Kilian.lackhove@gmail.com> Date: Mon, 10 Sep 2012 02:01:27 +0200 Subject: [PATCH] MusicBrainzPlugin: Make more use of Musicbrainz search api features. This offloads filtering and sorting of the results to musicbrainz and makes the artistID retrieval step obsolte and should speed things up. --- .../generic/musicbrainz/MusicBrainzPlugin.cpp | 266 ++++++++---------- .../generic/musicbrainz/MusicBrainzPlugin.h | 8 +- 2 files changed, 118 insertions(+), 156 deletions(-) diff --git a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp index 5ea6df815..6aa905379 100644 --- a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp +++ b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp @@ -62,7 +62,6 @@ MusicBrainzPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { case InfoArtistReleases: { - Tomahawk::InfoSystem::InfoStringHash criteria; criteria["artist"] = hash["artist"]; @@ -72,7 +71,6 @@ MusicBrainzPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) case InfoAlbumSongs: { - Tomahawk::InfoSystem::InfoStringHash criteria; criteria["artist"] = hash["artist"]; criteria["album"] = hash["album"]; @@ -94,31 +92,103 @@ MusicBrainzPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) void MusicBrainzPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ) { + QString querySt; switch ( requestData.type ) { case InfoArtistReleases: { - QString requestString( "http://musicbrainz.org/ws/2/artist" ); + querySt.append( QString( "artist:\"%1\"" ).arg(criteria["artist"]) ); + querySt.append( " AND (type:album OR type:ep)" ); + querySt.append( " AND status:official" ); + querySt.append( " AND NOT secondarytype:live" ); + querySt.append( " AND NOT secondarytype:compilation" ); + // we dont handle more than 100 results atm, but not even the beatles have more than 100 ep+albums, so its probably safe + + QString requestString( "http://musicbrainz.org/ws/2/release-group" ); QUrl url( requestString ); - url.addQueryItem( "query", criteria["artist"] ); + url.addQueryItem( "query", querySt ); + url.addQueryItem( "limit", "100" ); + tDebug() << Q_FUNC_INFO << url.toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) ); - connect( reply, SIGNAL( finished() ), SLOT( artistSearchSlot() ) ); + connect( reply, SIGNAL( finished() ), SLOT( gotReleaseGroupsSlot() ) ); + break; } - case InfoAlbumSongs: { - QString requestString( "http://musicbrainz.org/ws/2/artist" ); + querySt.append( QString( "release:\"%1\"" ).arg(criteria["album"]) ); + querySt.append( QString( " AND artist:\"%1\"" ).arg(criteria["artist"]) ); + // not pre-filtering will yield more than 100 results which we dont handle atm. But since we only take the first result anyway that wont hurt + + QString requestString( "http://musicbrainz.org/ws/2/release" ); QUrl url( requestString ); - url.addQueryItem( "query", criteria["artist"] ); + url.addQueryItem( "query", querySt ); + url.addQueryItem( "limit", "100" ); + tDebug() << Q_FUNC_INFO << url.toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) ); - connect( reply, SIGNAL( finished() ), SLOT( albumSearchSlot() ) ); + connect( reply, SIGNAL( finished() ), SLOT( gotReleasesSlot() ) ); + break; } + default: + { + Q_ASSERT( false ); + break; + } + } + + +} + + +void +MusicBrainzPlugin::gotReleaseGroupsSlot() +{ + QNetworkReply* oldReply = qobject_cast<QNetworkReply*>( sender() ); + if ( !oldReply ) + return; //timeout will handle it + + QDomDocument doc; + doc.setContent( oldReply->readAll() ); + QDomNodeList releaseGroupsNL = doc.elementsByTagName( "release-group" ); + if ( releaseGroupsNL.isEmpty() ) + { + emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() ); + tDebug() << Q_FUNC_INFO << doc.toString(); + return; + } + + Tomahawk::InfoSystem::InfoRequestData requestData = oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + switch ( requestData.type ) + { + case InfoArtistReleases: + { + QStringList albums; + for ( int i = 0; i < releaseGroupsNL.count(); i++ ) + { + QString groupTitle = releaseGroupsNL.at(i).firstChildElement("title").text(); + QString a = releaseGroupsNL.at(i).firstChildElement( "artist-credit" ).firstChildElement( "name-credit" ).firstChildElement( "artist" ).firstChildElement( "name" ).text(); + if ( !albums.contains( groupTitle ) && hash["artist"] == a ) + { + albums << groupTitle; + tDebug() << Q_FUNC_INFO << groupTitle; + } + } + + QVariantMap returnedData; + returnedData["albums"] = albums; + emit info( requestData, returnedData ); + + Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>(); + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria["artist"] = origData["artist"]; + emit updateCache( criteria, 0, requestData.type, returnedData ); + } default: { @@ -130,7 +200,7 @@ MusicBrainzPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requ void -MusicBrainzPlugin::artistSearchSlot() +MusicBrainzPlugin::gotReleasesSlot() { QNetworkReply* oldReply = qobject_cast<QNetworkReply*>( sender() ); if ( !oldReply ) @@ -138,101 +208,44 @@ MusicBrainzPlugin::artistSearchSlot() QDomDocument doc; doc.setContent( oldReply->readAll() ); - QDomNodeList domNodeList = doc.elementsByTagName( "artist" ); - if ( domNodeList.isEmpty() ) + QDomNodeList releasesNL = doc.elementsByTagName( "release" ); + if ( releasesNL.isEmpty() ) { emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() ); tDebug() << Q_FUNC_INFO << doc.toString(); return; } - QString artist_id = domNodeList.at( 0 ).toElement().attribute( "id" ); - QString requestString( "http://musicbrainz.org/ws/2/release-group" ); - QUrl url( requestString ); - url.addQueryItem( "artist", artist_id ); - url.addQueryItem( "type", "album|ep" ); - url.addQueryItem( "limit", "100" ); - - QNetworkReply* newReply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); - newReply->setProperty( "requestData", oldReply->property( "requestData" ) ); - connect( newReply, SIGNAL( finished() ), SLOT( albumFoundSlot() ) ); -} - - -void -MusicBrainzPlugin::albumSearchSlot() -{ - QNetworkReply* oldReply = qobject_cast<QNetworkReply*>( sender() ); - if ( !oldReply ) - return; //timeout will handle it - - QDomDocument doc; - doc.setContent( oldReply->readAll() ); - QDomNodeList domNodeList = doc.elementsByTagName( "artist" ); - if ( domNodeList.isEmpty() ) - { - emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() ); - return; - } - - QString artist_id = domNodeList.at( 0 ).toElement().attribute( "id" ); - QString requestString( "http://musicbrainz.org/ws/2/release-group" ); - QUrl url( requestString ); - url.addQueryItem( "artist", artist_id ); - url.addQueryItem( "type", "album|ep" ); - url.addQueryItem( "limit", "100" ); - - QNetworkReply* newReply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); - newReply->setProperty( "requestData", oldReply->property( "requestData" ) ); - connect( newReply, SIGNAL( finished() ), SLOT( tracksSearchSlot() ) ); -} - - -void -MusicBrainzPlugin::tracksSearchSlot() -{ - QNetworkReply* oldReply = qobject_cast<QNetworkReply*>( sender() ); - if ( !oldReply ) - return; //timeout will handle it - - QDomDocument doc; - doc.setContent( oldReply->readAll() ); - QDomNodeList domNodeList = doc.elementsByTagName( "release" ); - if ( domNodeList.isEmpty() ) - { - emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() ); - return; - } - Tomahawk::InfoSystem::InfoRequestData requestData = oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); - InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); - - QDomElement element; - for ( int i = 0; i < domNodeList.count(); i++ ) + switch ( requestData.type ) { - QDomNodeList albumNodeList = domNodeList.at( i ).toElement().elementsByTagName( "title" ); - if ( albumNodeList.at( 0 ).toElement().text() == hash["album"] ) - element = domNodeList.at( i ).toElement(); + case InfoAlbumSongs: + { + // we can simply use the first result as they are sorted by score + QString release_id = releasesNL.at(0).toElement().attribute( "id" ); + + QString requestString = QString( "http://musicbrainz.org/ws/2/release/%1" ).arg( release_id ); + QUrl url( requestString ); + url.addQueryItem( "inc", "recordings" ); + tDebug() << Q_FUNC_INFO << url.toString(); + + QNetworkReply* newReply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); + newReply->setProperty( "requestData", oldReply->property( "requestData" ) ); + connect( newReply, SIGNAL( finished() ), SLOT( gotRecordingsSlot() ) ); + } + + default: + { + Q_ASSERT( false ); + break; + } } - if ( element.isNull() ) - { - emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() ); - return; - } - - QString release_id = element.attribute( "id" ); - QString requestString = QString( "http://musicbrainz.org/ws/2/release/%1?inc=recordings" ).arg( release_id ); - QUrl url( requestString ); - - QNetworkReply* newReply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); - newReply->setProperty( "requestData", oldReply->property( "requestData" ) ); - connect( newReply, SIGNAL( finished() ), SLOT( tracksFoundSlot() ) ); } void -MusicBrainzPlugin::albumFoundSlot() +MusicBrainzPlugin::gotRecordingsSlot() { QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); if ( !reply ) @@ -240,75 +253,26 @@ MusicBrainzPlugin::albumFoundSlot() QDomDocument doc; doc.setContent( reply->readAll() ); - QDomNodeList groups = doc.elementsByTagName( "release-group" ); - if ( groups.isEmpty() ) + QDomNodeList mediumList = doc.elementsByTagName( "medium-list" ); + if ( mediumList.isEmpty() ) { emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() ); + tDebug() << Q_FUNC_INFO << doc.toString(); return; } - QStringList albums; - for ( int i = 0; i < groups.count(); i++ ) + + QDomNodeList tracksNL = mediumList.at(0).toElement().elementsByTagName( "track" ); + QStringList tracksSL; + for ( int i = 0; i < tracksNL.count(); i++ ) { - QDomElement group = groups.at(i).toElement(); - QDomNodeList secTypesDL = group.elementsByTagName("secondary-type"); - QStringList secTypesSL; - for ( int i = 0; i < secTypesDL.count(); i++ ) - { - secTypesSL.append(secTypesDL.at(i).toElement().text()); - } - if ( !secTypesSL.contains("Live") && !secTypesSL.contains("Compilation") ) - { - QString album = group.firstChildElement("title").text(); - if ( !albums.contains( album ) ) - albums << album; - } + QString track = tracksNL.at(i).firstChildElement( "recording" ).firstChildElement( "title" ).text(); + tracksSL << track; } Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); QVariantMap returnedData; - returnedData["albums"] = albums; - emit info( requestData, returnedData ); - - Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>(); - Tomahawk::InfoSystem::InfoStringHash criteria; - criteria["artist"] = origData["artist"]; - emit updateCache( criteria, 0, requestData.type, returnedData ); -} - - -void -MusicBrainzPlugin::tracksFoundSlot() -{ - QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); - if ( !reply ) - return; //timeout will handle it - - QDomDocument doc; - doc.setContent( reply->readAll() ); - QDomNodeList domNodeList = doc.elementsByTagName( "recording" ); - if ( domNodeList.isEmpty() ) - { - emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() ); - return; - } - - QStringList tracks; - for ( int i = 0; i < domNodeList.count(); i++ ) - { - QDomNodeList trackNodeList = domNodeList.at( i ).toElement().elementsByTagName( "title" ); - - for ( int j = 0; j < trackNodeList.count(); j++ ) - { - QString track = trackNodeList.at( j ).toElement().text(); - if ( !tracks.contains( track ) ) - tracks << track; - } - } - - Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); - QVariantMap returnedData; - returnedData["tracks"] = tracks; + returnedData["tracks"] = tracksSL; emit info( requestData, returnedData ); Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>(); @@ -318,5 +282,5 @@ MusicBrainzPlugin::tracksFoundSlot() emit updateCache( criteria, 0, requestData.type, returnedData ); } - Q_EXPORT_PLUGIN2( Tomahawk::InfoSystem::InfoPlugin, Tomahawk::InfoSystem::MusicBrainzPlugin ) + diff --git a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h index 57ca6bc99..71ddb75b2 100644 --- a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h +++ b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h @@ -53,12 +53,10 @@ protected slots: private slots: - void artistSearchSlot(); - void albumSearchSlot(); - void tracksSearchSlot(); - void albumFoundSlot(); - void tracksFoundSlot(); + void gotReleaseGroupsSlot(); + void gotReleasesSlot(); + void gotRecordingsSlot(); }; }