Skip to content

Commit

Permalink
Merge pull request #2522 from uklotzde/musicbrainz
Browse files Browse the repository at this point in the history
MusicBrainz: Extended metadata support (pre-gsoc2020)
  • Loading branch information
daschuer authored Mar 4, 2020
2 parents 18a134f + b805083 commit 1e0a1f5
Show file tree
Hide file tree
Showing 33 changed files with 2,511 additions and 1,067 deletions.
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

0 comments on commit 1e0a1f5

Please sign in to comment.