commit 599e1e972b5e61da9741b23e46afa61589aa46e6 branch master Author: Sergey Ivanov <123kash@gmail.com> Date: Mon Nov 1 01:48:31 2010 +0300 Make MusicBrainz tagger return multiple results in single-track search mode to let user choose the right one. diff --git a/src/dialogs/MusicBrainzTagger.cpp b/src/dialogs/MusicBrainzTagger.cpp index d1e5d67..d327ea6 100644 --- a/src/dialogs/MusicBrainzTagger.cpp +++ b/src/dialogs/MusicBrainzTagger.cpp @@ -83,7 +83,7 @@ MusicBrainzTagger::init() SLOT( trackFound( const Meta::TrackPtr, const QVariantMap ) ) ); connect( mb_finder, SIGNAL( done() ), SLOT( searchDone() ) ); connect( mb_finder, SIGNAL( trackFound( const Meta::TrackPtr, const QVariantMap ) ), - q_resultsModel, SLOT( trackFound( const Meta::TrackPtr, const QVariantMap ) ) ); + q_resultsModel, SLOT( addTrack( const Meta::TrackPtr, const QVariantMap ) ) ); connect( mb_finder, SIGNAL( progressStep() ), SLOT( progressStep() ) ); connect( ui->treeView_Result->header(), SIGNAL( sectionClicked( int ) ), q_resultsModel, SLOT( selectAll( int ) ) ); diff --git a/src/musicbrainz/MusicBrainzFinder.cpp b/src/musicbrainz/MusicBrainzFinder.cpp index bfe001c..82d31bd 100644 --- a/src/musicbrainz/MusicBrainzFinder.cpp +++ b/src/musicbrainz/MusicBrainzFinder.cpp @@ -127,6 +127,8 @@ MusicBrainzFinder::run( const Meta::TrackList &tracks ) } m_requests.append( qMakePair( track, compileRequest( track ) ) ); } + + m_singleTrackSearch = tracks.count() == 1; _timer->start(); } @@ -290,7 +292,17 @@ MusicBrainzFinder::parsingDone( ThreadWeaver::Job *_parser ) } float sim = float( s ) / maxPossibleScore; - if( ( sim > maxSimilarity ) && ( sim > 0.6 ) ) + + if( sim < 0.6 ) + continue; + + if( m_singleTrackSearch ) + { + sendTrack( trackPtr, track ); + continue; + } + + if( sim > maxSimilarity ) { maxSimilarity = sim; chosenTrack = track; @@ -298,7 +310,7 @@ MusicBrainzFinder::parsingDone( ThreadWeaver::Job *_parser ) } m_parsedMetaData.remove( trackPtr ); - if( chosenTrack.isEmpty() ) + if( chosenTrack.isEmpty() || m_singleTrackSearch ) { parser->deleteLater(); checkDone(); @@ -307,7 +319,28 @@ MusicBrainzFinder::parsingDone( ThreadWeaver::Job *_parser ) curTrack = chosenTrack; } else - curTrack = parser->grabTrackByLength( trackPtr->length() ); + { + if( m_singleTrackSearch ) + { + foreach( QString trackID, parser->tracks.keys() ) + { + QVariantMap track = parser->grabTrackByID( trackID ); + if( track.contains( Meta::Field::SCORE ) ) + { + if( track.value( Meta::Field::SCORE ).toInt() >= 50 ) + sendTrack( trackPtr, track ); + } + else + sendTrack( trackPtr, track ); + } + + parser->deleteLater(); + checkDone(); + return; + } + else + curTrack = parser->grabTrackByLength( trackPtr->length() ); + } sendTrack( trackPtr, curTrack ); } @@ -395,6 +428,9 @@ MusicBrainzFinder::guessMetadata( const Meta::TrackPtr &track ) void MusicBrainzFinder::sendTrack( const Meta::TrackPtr track, const QVariantMap &info ) { + if( info.isEmpty() ) + return; + QVariantMap tags = info; if( tags.contains( MusicBrainz::RELEASEID ) ) { diff --git a/src/musicbrainz/MusicBrainzFinder.h b/src/musicbrainz/MusicBrainzFinder.h index fdd44db..49c8f6b 100644 --- a/src/musicbrainz/MusicBrainzFinder.h +++ b/src/musicbrainz/MusicBrainzFinder.h @@ -48,7 +48,6 @@ class MusicBrainzFinder : public QObject void lookUpByPUID( const Meta::TrackPtr &track, const QString &puid ); private slots: - void sendNewRequest(); void gotReply( QNetworkReply *reply ); void authenticationRequest( QNetworkReply *reply, QAuthenticator *authenticator ); @@ -74,6 +73,8 @@ class MusicBrainzFinder : public QObject QString mb_username; QString mb_password; + bool m_singleTrackSearch; + QMap < Meta::TrackPtr, QVariantMap > m_parsedMetaData; QNetworkAccessManager *net; diff --git a/src/musicbrainz/MusicBrainzTagsModel.cpp b/src/musicbrainz/MusicBrainzTagsModel.cpp index 4b388b4..1bf7389 100644 --- a/src/musicbrainz/MusicBrainzTagsModel.cpp +++ b/src/musicbrainz/MusicBrainzTagsModel.cpp @@ -23,12 +23,92 @@ #include "core/meta/support/MetaConstants.h" #include "core/meta/support/MetaUtility.h" +MusciBrainzTagsItem::MusciBrainzTagsItem( Meta::TrackPtr track, const QVariantMap tags ) + : m_track( track ) + , m_data( tags ) + , m_checked( false ) +{ +} + +Qt::ItemFlags +MusciBrainzTagsItem::flags() +{ + if( m_data.isEmpty() ) + return Qt::NoItemFlags; + + return Qt::ItemIsUserCheckable; +} + +QVariant +MusciBrainzTagsItem::data( int column ) +{ + if( m_data.isEmpty() ) + return QVariant(); + + switch( column ) + { + case 1: return m_data.contains( Meta::Field::TITLE ) + ? m_data.value( Meta::Field::TITLE ) + : QVariant(); + case 2: return m_data.contains( Meta::Field::ARTIST ) + ? m_data.value( Meta::Field::ARTIST ) + : QVariant(); + case 3: return m_data.contains( Meta::Field::ALBUM ) + ? m_data.value( Meta::Field::ALBUM ) + : QVariant(); + case 4: return m_data.contains( Meta::Field::ALBUMARTIST ) + ? m_data.value( Meta::Field::ALBUMARTIST ) + : QVariant(); + } + + return QVariant(); +} + +QVariantMap +MusciBrainzTagsItem::data() +{ + return m_data; +} + +void +MusciBrainzTagsItem::setData( QVariantMap tags ) +{ + m_data = tags; +} + +bool +MusciBrainzTagsItem::checked() +{ + return m_checked; +} + +void +MusciBrainzTagsItem::setChecked( bool checked ) +{ + if( m_data.isEmpty() ) + return; + m_checked = checked; +} + +Meta::TrackPtr +MusciBrainzTagsItem::track() +{ + return m_track; +} + + MusicBrainzTagsModel::MusicBrainzTagsModel( Meta::TrackList tracks, QObject* parent) - : QAbstractItemModel(parent) - , m_tracks( tracks ) + : QAbstractItemModel( parent ) { - for( int i = 0; i < m_tracks.count(); i++ ) - m_tracksToSave.append( Qt::Unchecked ); + if( tracks.count() == 1 ) + { + m_singleTrackMode = true; + return; + } + + m_singleTrackMode = false; + foreach( Meta::TrackPtr track, tracks ) + m_items.append( MusciBrainzTagsItem( track ) ); } MusicBrainzTagsModel::~MusicBrainzTagsModel() @@ -55,25 +135,11 @@ MusicBrainzTagsModel::data( const QModelIndex &index, int role ) const return QVariant(); if( role == Qt::DisplayRole ) - { - if( m_tags.contains( m_tracks.value( index.row() ) ) ) - { - QVariantMap tags = m_tags.value( m_tracks.value( index.row() ) ); - switch( index.column() ) - { - case 1: return tags.value( Meta::Field::TITLE ); - case 2: return tags.contains( Meta::Field::ALBUM )? tags.value( Meta::Field::ARTIST ) : ""; - case 3: return tags.contains( Meta::Field::ALBUM )? tags.value( Meta::Field::ALBUM ) : ""; - default: return QVariant(); - } - } - } + return m_items.value( index.row() ).data( index.column() ); else if( role == Qt::CheckStateRole && - m_tags.contains( m_tracks.value( index.row() ) ) && - index.column() == 0 ) - { - return m_tracksToSave.value( index.row() ); - } + index.column() == 0 && + m_items.value( index.row() ).flags() == Qt::ItemIsUserCheckable ) + return m_items.value( index.row() ).checked() ? Qt::Checked : Qt::Unchecked; else if( role == Qt::SizeHintRole && index.column() == 0 ) return QSize( 0, 21 ); return QVariant(); @@ -85,13 +151,13 @@ MusicBrainzTagsModel::setData( const QModelIndex &index, const QVariant &value, if( !index.isValid() || role != Qt::CheckStateRole || index.column() != 0 ) return false; - if( m_tags.contains( m_tracks.value( index.row() ) ) && index.column() == 0 ) - { - m_tracksToSave[ index.row() ] = static_cast< Qt::CheckState >( value.toInt() ); - return true; - } - else - return false; + if( m_singleTrackMode ) + for( int i = 0; i < m_items.count(); i++ ) + m_items[ i ].setChecked( false ); + + m_items[ index.row() ].setChecked( value.toBool() ); + emit dataChanged( createIndex( 0, 0 ), createIndex( m_items.count() - 1, 0 ) ); + return true; } QVariant @@ -115,16 +181,13 @@ MusicBrainzTagsModel::flags( const QModelIndex &index ) const if( !index.isValid() ) return QAbstractItemModel::flags( index ); - if( m_tags.contains( m_tracks.value( index.row() ) ) && index.column() == 0 ) - return Qt::ItemIsUserCheckable | QAbstractItemModel::flags( index ); - - return QAbstractItemModel::flags( index ); + return m_items.value( index.row() ).flags() | QAbstractItemModel::flags( index ); } int MusicBrainzTagsModel::rowCount( const QModelIndex &parent ) const { - return parent.isValid()? -1 : m_tracks.count(); + return parent.isValid()? -1 : m_items.count(); } int @@ -134,39 +197,43 @@ MusicBrainzTagsModel::columnCount( const QModelIndex & ) const } void -MusicBrainzTagsModel::trackFound( const Meta::TrackPtr track, const QVariantMap tags ) +MusicBrainzTagsModel::addTrack( const Meta::TrackPtr track, const QVariantMap tags ) { - if( !m_tracks.contains( track ) ) - return; - - m_tags.insert( track, tags ); + if( m_singleTrackMode ) + { + m_items.append( MusciBrainzTagsItem( track, tags ) ); + emit layoutChanged(); + } + else + for( int i = 0; i < m_items.count(); i++ ) + if( m_items.value( i ).track() == track ) + { + m_items[ i ].setData( tags ); + break; + } - emit dataChanged( createIndex( 0, 0 ), createIndex( m_tracks.count() - 1, 4) ); + emit dataChanged( createIndex( 0, 0 ), createIndex( m_items.count() - 1, 4 ) ); } void MusicBrainzTagsModel::selectAll( int section ) { - if( section != 0 ) + if( section != 0 || m_singleTrackMode ) return; - for( int i = 0; i < m_tracks.count(); i++ ) - if( m_tags.contains( m_tracks.value( i ) ) ) - m_tracksToSave[i] = Qt::Checked; + for( int i = 0; i < m_items.count(); i++ ) + m_items[ i ].setChecked( true ); - emit dataChanged( createIndex( 0, 0), createIndex( m_tracks.count() - 1, 0 ) ); + emit dataChanged( createIndex( 0, 0), createIndex( m_items.count() - 1, 0 ) ); } QMap < Meta::TrackPtr, QVariantMap > MusicBrainzTagsModel::getAllChecked() { QMap < Meta::TrackPtr, QVariantMap > result; - for( int i = 0; i < m_tracks.count(); i++ ) - if( m_tags.contains( m_tracks.value( i ) ) && - m_tracksToSave.value( i ) == Qt::Checked ) - { - result.insert( m_tracks.value( i ), m_tags.value( m_tracks.value( i ) ) ); - } + foreach( MusciBrainzTagsItem item, m_items ) + if( item.checked() ) + result.insert( item.track(), item.data() ); return result; } diff --git a/src/musicbrainz/MusicBrainzTagsModel.h b/src/musicbrainz/MusicBrainzTagsModel.h index e79373c..a93929a 100644 --- a/src/musicbrainz/MusicBrainzTagsModel.h +++ b/src/musicbrainz/MusicBrainzTagsModel.h @@ -21,6 +21,30 @@ #include #include +class MusciBrainzTagsItem +{ + public: + MusciBrainzTagsItem( Meta::TrackPtr track, const QVariantMap tags = QVariantMap() ); + MusciBrainzTagsItem() {} + + Meta::TrackPtr track(); + + Qt::ItemFlags flags(); + + QVariant data( int column ); + QVariantMap data(); + void setData( QVariantMap tags ); + + bool checked(); + void setChecked( bool checked ); + + private: + Meta::TrackPtr m_track; + QVariantMap m_data; + + bool m_checked; +}; + class MusicBrainzTagsModel : public QAbstractItemModel { Q_OBJECT @@ -32,7 +56,7 @@ class MusicBrainzTagsModel : public QAbstractItemModel QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; QModelIndex parent( const QModelIndex &index ) const; - Qt::ItemFlags flags ( const QModelIndex &index ) const; + Qt::ItemFlags flags( const QModelIndex &index ) const; QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const; bool setData( const QModelIndex &index, const QVariant &value, int role ); QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; @@ -43,13 +67,13 @@ class MusicBrainzTagsModel : public QAbstractItemModel QMap < Meta::TrackPtr, QVariantMap > getAllChecked(); public slots: - void trackFound( const Meta::TrackPtr track, const QVariantMap tags ); + void addTrack( const Meta::TrackPtr track, const QVariantMap tags ); void selectAll( int section ); private: - Meta::TrackList m_tracks; - QMap < Meta::TrackPtr, QVariantMap > m_tags; - QList < Qt::CheckState > m_tracksToSave; + QList < MusciBrainzTagsItem > m_items; + + bool m_singleTrackMode; }; #endif // MUSICBRAINZTAGSMODEL_H diff --git a/src/musicbrainz/MusicBrainzXmlParser.cpp b/src/musicbrainz/MusicBrainzXmlParser.cpp index 732bd8f..7043bea 100644 --- a/src/musicbrainz/MusicBrainzXmlParser.cpp +++ b/src/musicbrainz/MusicBrainzXmlParser.cpp @@ -353,3 +353,21 @@ MusicBrainzXmlParser::grabTrackByLength( const quint64 length ) track.remove( MusicBrainz::TRACKOFFSET ); return track; } + +QVariantMap +MusicBrainzXmlParser::grabTrackByID( const QString &ID ) +{ + if( !tracks.contains( ID ) ) + return QVariantMap(); + + QVariantMap track = tracks.value( ID ); + QString release = track.value( MusicBrainz::RELEASELIST ).toStringList().first(); + track.insert( MusicBrainz::RELEASEID, release ); + track.insert( Meta::Field::ALBUM, + releases.value( release ).value( Meta::Field::TITLE ).toString() ); + track.insert( Meta::Field::TRACKNUMBER, + track.value( MusicBrainz::TRACKOFFSET ).toMap().value( release ).toInt() ); + track.remove( MusicBrainz::RELEASELIST ); + track.remove( MusicBrainz::TRACKOFFSET ); + return track; +} diff --git a/src/musicbrainz/MusicBrainzXmlParser.h b/src/musicbrainz/MusicBrainzXmlParser.h index 2218fa4..37f1fcd 100644 --- a/src/musicbrainz/MusicBrainzXmlParser.h +++ b/src/musicbrainz/MusicBrainzXmlParser.h @@ -40,6 +40,7 @@ class MusicBrainzXmlParser : public ThreadWeaver::Job int type(); QVariantMap grabTrackByLength( const quint64 length ); + QVariantMap grabTrackByID( const QString &ID ); QMap< QString, QVariantMap > tracks; QMap< QString, QString > artists;