Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MusicBrainz: Extended metadata support (pre-gsoc2020) #2522

Merged
merged 11 commits into from
Mar 4, 2020
9 changes: 6 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -425,13 +425,16 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/mixer/samplerbank.cpp
src/mixxx.cpp
src/mixxxapplication.cpp
src/musicbrainz/acoustidclient.cpp
src/musicbrainz/chromaprinter.cpp
src/musicbrainz/crc.c
src/musicbrainz/gzip.cpp
src/musicbrainz/musicbrainzclient.cpp
src/musicbrainz/network.cpp
src/musicbrainz/musicbrainz.cpp
src/musicbrainz/musicbrainzxml.cpp
src/musicbrainz/tagfetcher.cpp
src/musicbrainz/web/acoustidlookuptask.cpp
src/musicbrainz/web/musicbrainzrecordingstask.cpp
src/network/jsonwebtask.cpp
src/network/webtask.cpp
src/preferences/broadcastprofile.cpp
src/preferences/broadcastsettings.cpp
src/preferences/broadcastsettings_legacy.cpp
Expand Down
10 changes: 7 additions & 3 deletions build/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -996,13 +996,14 @@ def sources(self, build):
"src/widget/wsingletoncontainer.cpp",
"src/widget/wmainmenubar.cpp",

"src/musicbrainz/network.cpp",
"src/musicbrainz/tagfetcher.cpp",
"src/musicbrainz/gzip.cpp",
"src/musicbrainz/crc.c",
"src/musicbrainz/acoustidclient.cpp",
"src/musicbrainz/chromaprinter.cpp",
"src/musicbrainz/musicbrainzclient.cpp",
"src/musicbrainz/musicbrainz.cpp",
"src/musicbrainz/musicbrainzxml.cpp",
"src/musicbrainz/web/acoustidlookuptask.cpp",
"src/musicbrainz/web/musicbrainzrecordingstask.cpp",

"src/widget/wtracktableview.cpp",
"src/widget/wtracktableviewheader.cpp",
Expand Down Expand Up @@ -1128,6 +1129,9 @@ def sources(self, build):

"src/library/trackloader.cpp",

"src/network/jsonwebtask.cpp",
"src/network/webtask.cpp",

"src/widget/wwaveformviewer.cpp",

"src/waveform/sharedglcontext.cpp",
Expand Down
230 changes: 159 additions & 71 deletions src/library/dlgtagfetcher.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,60 @@
#include "library/dlgtagfetcher.h"

#include <QTreeWidget>
#include <QtDebug>

#include "library/dlgtagfetcher.h"
#include "track/tracknumbers.h"

namespace {

QStringList trackColumnValues(
const Track& track) {
mixxx::TrackMetadata trackMetadata;
track.readTrackMetadata(&trackMetadata);
const QString trackNumberAndTotal = TrackNumbers::joinAsString(
trackMetadata.getTrackInfo().getTrackNumber(),
trackMetadata.getTrackInfo().getTrackTotal());
QStringList columnValues;
columnValues.reserve(6);
columnValues
<< trackMetadata.getTrackInfo().getYear()
<< trackMetadata.getAlbumInfo().getTitle()
<< trackMetadata.getAlbumInfo().getArtist()
<< trackNumberAndTotal
<< trackMetadata.getTrackInfo().getTitle()
<< trackMetadata.getTrackInfo().getArtist();
return columnValues;
}

QStringList trackReleaseColumnValues(
const mixxx::musicbrainz::TrackRelease& trackRelease) {
const QString trackNumberAndTotal = TrackNumbers::joinAsString(
trackRelease.trackNumber,
trackRelease.trackTotal);
QStringList columnValues;
columnValues.reserve(6);
columnValues
<< trackRelease.date
<< trackRelease.albumTitle
<< trackRelease.albumArtist
<< trackNumberAndTotal
<< trackRelease.title
<< trackRelease.artist;
return columnValues;
}

void addTrack(
const QStringList& trackRow,
int resultIndex,
QTreeWidget* parent) {
QTreeWidgetItem* item = new QTreeWidgetItem(parent, trackRow);
item->setData(0, Qt::UserRole, resultIndex);
item->setData(0, Qt::TextAlignmentRole, Qt::AlignRight);
}

DlgTagFetcher::DlgTagFetcher(QWidget *parent)
} // anonymous namespace

DlgTagFetcher::DlgTagFetcher(QWidget* parent)
: QDialog(parent),
m_tagFetcher(parent),
m_networkResult(NetworkResult::Ok) {
Expand All @@ -13,30 +64,23 @@ DlgTagFetcher::DlgTagFetcher(QWidget *parent)
void DlgTagFetcher::init() {
setupUi(this);

connect(btnApply, &QPushButton::clicked,
this, &DlgTagFetcher::apply);
connect(btnQuit, &QPushButton::clicked,
this, &DlgTagFetcher::quit);
connect(btnPrev, &QPushButton::clicked,
this, &DlgTagFetcher::previous);
connect(btnNext, &QPushButton::clicked,
this, &DlgTagFetcher::next);
connect(results, &QTreeWidget::currentItemChanged,
this, &DlgTagFetcher::resultSelected);

connect(&m_tagFetcher, &TagFetcher::resultAvailable,
this, &DlgTagFetcher::fetchTagFinished);
connect(&m_tagFetcher, &TagFetcher::fetchProgress,
this, &DlgTagFetcher::fetchTagProgress);
connect(&m_tagFetcher, &TagFetcher::networkError,
this, &DlgTagFetcher::slotNetworkResult);
connect(btnApply, &QPushButton::clicked, this, &DlgTagFetcher::apply);
connect(btnQuit, &QPushButton::clicked, this, &DlgTagFetcher::quit);
connect(btnPrev, &QPushButton::clicked, this, &DlgTagFetcher::previous);
connect(btnNext, &QPushButton::clicked, this, &DlgTagFetcher::next);
connect(results, &QTreeWidget::currentItemChanged, this, &DlgTagFetcher::resultSelected);

connect(&m_tagFetcher, &TagFetcher::resultAvailable, this, &DlgTagFetcher::fetchTagFinished);
connect(&m_tagFetcher, &TagFetcher::fetchProgress, this, &DlgTagFetcher::fetchTagProgress);
connect(&m_tagFetcher, &TagFetcher::networkError, this, &DlgTagFetcher::slotNetworkResult);

// Resize columns, this can't be set in the ui file
results->setColumnWidth(0, 50); // Track column
results->setColumnWidth(1, 50); // Year column
results->setColumnWidth(2, 160); // Title column
results->setColumnWidth(3, 160); // Artist column
results->setColumnWidth(4, 160); // Album column
results->setColumnWidth(0, 50); // Year column
results->setColumnWidth(1, 160); // Album column
results->setColumnWidth(2, 160); // Album artist column
results->setColumnWidth(3, 50); // Track (numbers) column
results->setColumnWidth(4, 160); // Title column
results->setColumnWidth(5, 160); // Artist column
}

void DlgTagFetcher::loadTrack(const TrackPointer& track) {
Expand Down Expand Up @@ -70,25 +114,69 @@ void DlgTagFetcher::slotTrackChanged(TrackId trackId) {

void DlgTagFetcher::apply() {
int resultIndex = m_data.m_selectedResult;
if (resultIndex > -1) {
if (!m_data.m_results[resultIndex]->getAlbum().isEmpty()) {
m_track->setAlbum(m_data.m_results[resultIndex]->getAlbum());
}
if (!m_data.m_results[resultIndex]->getArtist().isEmpty()) {
m_track->setArtist(m_data.m_results[resultIndex]->getArtist());
}
if (!m_data.m_results[resultIndex]->getTitle().isEmpty()) {
m_track->setTitle(m_data.m_results[resultIndex]->getTitle());
}
if (!m_data.m_results[resultIndex]->getYear().isEmpty() &&
m_data.m_results[resultIndex]->getYear() != "0") {
m_track->setYear(m_data.m_results[resultIndex]->getYear());
}
if (!m_data.m_results[resultIndex]->getTrackNumber().isEmpty() &&
m_data.m_results[resultIndex]->getTrackNumber() != "0") {
m_track->setTrackNumber(m_data.m_results[resultIndex]->getTrackNumber());
}
if (resultIndex < 0) {
return;
}
DEBUG_ASSERT(resultIndex < m_data.m_results.size());
const mixxx::musicbrainz::TrackRelease& trackRelease =
m_data.m_results[resultIndex];
mixxx::TrackMetadata trackMetadata;
m_track->readTrackMetadata(&trackMetadata);
if (!trackRelease.artist.isEmpty()) {
trackMetadata.refTrackInfo().setArtist(
trackRelease.artist);
}
if (!trackRelease.title.isEmpty()) {
trackMetadata.refTrackInfo().setTitle(
trackRelease.title);
}
if (!trackRelease.trackNumber.isEmpty()) {
trackMetadata.refTrackInfo().setTrackNumber(
trackRelease.trackNumber);
}
if (!trackRelease.trackTotal.isEmpty()) {
trackMetadata.refTrackInfo().setTrackTotal(
trackRelease.trackTotal);
}
if (!trackRelease.date.isEmpty()) {
trackMetadata.refTrackInfo().setYear(
trackRelease.date);
}
if (!trackRelease.albumArtist.isEmpty()) {
trackMetadata.refAlbumInfo().setArtist(
trackRelease.albumArtist);
}
if (!trackRelease.albumTitle.isEmpty()) {
trackMetadata.refAlbumInfo().setTitle(
trackRelease.albumTitle);
}
#if defined(__EXTRA_METADATA__)
if (!trackRelease.artistId.isNull()) {
trackMetadata.refTrackInfo().setMusicBrainzArtistId(
trackRelease.artistId);
}
if (!trackRelease.recordingId.isNull()) {
trackMetadata.refTrackInfo().setMusicBrainzRecordingId(
trackRelease.recordingId);
}
if (!trackRelease.trackReleaseId.isNull()) {
trackMetadata.refTrackInfo().setMusicBrainzReleaseId(
trackRelease.trackReleaseId);
}
if (!trackRelease.albumArtistId.isNull()) {
trackMetadata.refAlbumInfo().setMusicBrainzArtistId(
trackRelease.albumArtistId);
}
if (!trackRelease.albumReleaseId.isNull()) {
trackMetadata.refAlbumInfo().setMusicBrainzReleaseId(
trackRelease.albumReleaseId);
}
if (!trackRelease.releaseGroupId.isNull()) {
trackMetadata.refAlbumInfo().setMusicBrainzReleaseGroupId(
trackRelease.releaseGroupId);
}
#endif // __EXTRA_METADATA__
m_track->importMetadata(std::move(trackMetadata));
}

void DlgTagFetcher::quit() {
Expand All @@ -101,21 +189,20 @@ void DlgTagFetcher::fetchTagProgress(QString text) {
loadingStatus->setText(status.arg(text));
}

void DlgTagFetcher::fetchTagFinished(const TrackPointer track,
const QList<TrackPointer>& tracks) {
// check if the answer is for this track
if (m_track->getLocation() != track->getLocation()) {
void DlgTagFetcher::fetchTagFinished(
TrackPointer pTrack,
QList<mixxx::musicbrainz::TrackRelease> guessedTrackReleases) {
VERIFY_OR_DEBUG_ASSERT(pTrack == m_track) {
return;
}

m_data.m_pending = false;
m_data.m_results = tracks;
// qDebug() << "number of results = " << tracks.size();
m_data.m_results = guessedTrackReleases;
// qDebug() << "number of results = " << guessedTrackReleases.size();
updateStack();
}

void DlgTagFetcher::slotNetworkResult(int httpError, QString app, QString message, int code) {
m_networkResult = httpError == 0 ? NetworkResult::UnknownError : NetworkResult::HttpError;
m_networkResult = httpError == 0 ? NetworkResult::UnknownError : NetworkResult::HttpError;
m_data.m_pending = false;
QString strError = tr("HTTP Status: %1");
QString strCode = tr("Code: %1");
Expand Down Expand Up @@ -146,18 +233,30 @@ void DlgTagFetcher::updateStack() {

results->clear();

VERIFY_OR_DEBUG_ASSERT(m_track) {
return;
}

addDivider(tr("Original tags"), results);
addTrack(m_track, -1, results);
addTrack(trackColumnValues(*m_track), -1, results);

addDivider(tr("Suggested tags"), results);

int trackIndex = 0;
foreach (const TrackPointer track, m_data.m_results) {
addTrack(track, trackIndex++, results);
{
int trackIndex = 0;
QSet<QStringList> allColumnValues; // deduplication
for (const auto& trackRelease : qAsConst(m_data.m_results)) {
const auto columnValues = trackReleaseColumnValues(trackRelease);
// Ignore duplicate results
if (!allColumnValues.contains(columnValues)) {
allColumnValues.insert(columnValues);
addTrack(columnValues, trackIndex, results);
}
++trackIndex;
}
}

// Find the item that was selected last time
for (int i=0 ; i<results->model()->rowCount() ; ++i) {
for (int i = 0; i < results->model()->rowCount(); ++i) {
const QModelIndex index = results->model()->index(i, 0);
const QVariant id = index.data(Qt::UserRole);
if (!id.isNull() && id.toInt() == m_data.m_selectedResult) {
Expand All @@ -167,17 +266,6 @@ void DlgTagFetcher::updateStack() {
}
}

void DlgTagFetcher::addTrack(const TrackPointer track, int resultIndex,
QTreeWidget* parent) const {
QStringList values;
values << track->getTrackNumber() << track->getYear() << track->getTitle()
<< track->getArtist() << track->getAlbum();

QTreeWidgetItem* item = new QTreeWidgetItem(parent, values);
item->setData(0, Qt::UserRole, resultIndex);
item->setData(0, Qt::TextAlignmentRole, Qt::AlignRight);
}

void DlgTagFetcher::addDivider(const QString& text, QTreeWidget* parent) const {
QTreeWidgetItem* item = new QTreeWidgetItem(parent);
item->setFirstColumnSpanned(true);
Expand All @@ -191,9 +279,9 @@ void DlgTagFetcher::addDivider(const QString& text, QTreeWidget* parent) const {
}

void DlgTagFetcher::resultSelected() {
if (!results->currentItem())
return;
if (!results->currentItem())
return;

const int resultIndex = results->currentItem()->data(0, Qt::UserRole).toInt();
m_data.m_selectedResult = resultIndex;
const int resultIndex = results->currentItem()->data(0, Qt::UserRole).toInt();
m_data.m_selectedResult = resultIndex;
}
8 changes: 4 additions & 4 deletions src/library/dlgtagfetcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class DlgTagFetcher : public QDialog, public Ui::DlgTagFetcher {
void previous();

private slots:
void fetchTagFinished(const TrackPointer,const QList<TrackPointer>& tracks);
void fetchTagFinished(
TrackPointer pTrack,
QList<mixxx::musicbrainz::TrackRelease> guessedTrackReleases);
void resultSelected();
void fetchTagProgress(QString);
void slotNetworkResult(int httpStatus, QString app, QString message, int code);
Expand All @@ -36,8 +38,6 @@ class DlgTagFetcher : public QDialog, public Ui::DlgTagFetcher {
private:
void updateStack();
void addDivider(const QString& text, QTreeWidget* parent) const;
void addTrack(const TrackPointer track, int resultIndex,
QTreeWidget* parent) const;

TagFetcher m_tagFetcher;

Expand All @@ -48,7 +48,7 @@ class DlgTagFetcher : public QDialog, public Ui::DlgTagFetcher {

bool m_pending;
int m_selectedResult;
QList<TrackPointer> m_results;
QList<mixxx::musicbrainz::TrackRelease> m_results;
};
Data m_data;

Expand Down
Loading