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

WFindOnWebMenu: Menu for to find track properties in online music databases #4772

Merged
merged 35 commits into from Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f170934
wtrackmenu: Searchbox feature
fatihemreyildiz May 28, 2022
fc7106a
CMakeLists: WFindOn added
fatihemreyildiz Jun 14, 2022
6c95cf1
WFindOnMenu: Separate Find On Menu class added.
fatihemreyildiz Jun 14, 2022
76153f2
WTrackMenu: Qaction deleted, Find On class added
fatihemreyildiz Jun 14, 2022
b492032
wtrackmenu wfindonmenu: CI Fix clazy / pre-commit
fatihemreyildiz Jun 15, 2022
305021c
WFindOnMenu: Inline Functions are deleted
fatihemreyildiz Jun 15, 2022
c978e0e
WFindOnMenu: Enum naming changed moved private
fatihemreyildiz Jun 15, 2022
c800b6f
WFindOnMenu: composeActionText add, order changed
fatihemreyildiz Jun 15, 2022
24ffe03
WFindOnMenu: namings refactored for all instances.
fatihemreyildiz Jun 16, 2022
a2aaa6c
WFindOnMenu: Url hidden. Search with artist added.
fatihemreyildiz Jun 17, 2022
5fd95e1
WFindOnMenu: CI Fix clazy
fatihemreyildiz Jun 17, 2022
6a2d5ff
Feature renamed. Naming refactored.
fatihemreyildiz Jun 18, 2022
df37a70
wfindonwebmenu: artistwithtitle deleted.
fatihemreyildiz Jun 18, 2022
ad5cc13
const url add. redundants deleted. func refactored
fatihemreyildiz Jun 19, 2022
83db586
WFindOnWebMenu: pre-commit fix. Action reordered.
fatihemreyildiz Jun 19, 2022
246dfbc
WTrackMenu: FindOnWeb moved as submenu of Metadata
fatihemreyildiz Jun 20, 2022
1ef7152
WTrackMenu: pre-commit fix
fatihemreyildiz Jun 20, 2022
2195417
wfindonmenu: naming changed, parentedptr added
fatihemreyildiz Jun 21, 2022
1410b2b
wfindonwebmenu: constant naming fix
fatihemreyildiz Jun 23, 2022
ed9a529
Merge remote-tracking branch 'upstream/main' into websearchbox
fatihemreyildiz Jun 23, 2022
3e54e6b
wfindonwebmenu: pServiceMenu deleted.
fatihemreyildiz Jun 23, 2022
9d08835
wfindonwebmenu: redundant switch&functions deleted
fatihemreyildiz Jun 24, 2022
4d506a5
wfindonwebmenu: url-check & switch added
fatihemreyildiz Jun 24, 2022
cfda73c
wtrackmenu: empty pTrack submenu not show added.
fatihemreyildiz Jun 24, 2022
836d740
wfindonwebmenu: if statement value aborted early
fatihemreyildiz Jun 24, 2022
25eab73
wfindonwebmenu: url validation refactored.
fatihemreyildiz Jun 26, 2022
966d7f5
wfindonwebmenu: url validation added.
fatihemreyildiz Jun 27, 2022
f5e145b
wfindonmenu: if condition added for actions
fatihemreyildiz Jun 27, 2022
5a3864f
wfindonwebmenu: bool hasEntriesForTrack added
fatihemreyildiz Jun 27, 2022
bf25e63
FindOnWeb: enableMenu added.
fatihemreyildiz Jun 28, 2022
57b2840
wfindonwebmenu: type change
fatihemreyildiz Jun 29, 2022
f684256
wfindonwebmenu: naming changed
fatihemreyildiz Jun 29, 2022
72fc625
wfindonwebmenu: Redundant connect deleted
fatihemreyildiz Jun 30, 2022
8f309b8
wfindonwebmenu: requested changes applied
fatihemreyildiz Jun 30, 2022
8be548a
wfindonwebmenu: non translatable names changed.
fatihemreyildiz Jul 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -990,6 +990,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/widget/weffectparameternamebase.cpp
src/widget/weffectpushbutton.cpp
src/widget/weffectselector.cpp
src/widget/wfindonwebmenu.cpp
src/widget/whotcuebutton.cpp
src/widget/wimagestore.cpp
src/widget/wkey.cpp
Expand Down
177 changes: 177 additions & 0 deletions src/widget/wfindonwebmenu.cpp
@@ -0,0 +1,177 @@
#include "widget/wfindonwebmenu.h"

#include <QDesktopServices>
#include <QScreen>
#include <QUrl>
#include <QUrlQuery>
#include <QtDebug>

#include "track/track.h"
#include "util/math.h"
#include "util/parented_ptr.h"
#include "util/qt.h"
#include "util/widgethelper.h"

namespace {

QString composeActionText(const QString& prefix, const QString& trackProperty) {
return prefix + QStringLiteral(" | ") + trackProperty;
}

QString composeSearchQuery(const QString& trackAlbumOrTitle, const QString& artist) {
return trackAlbumOrTitle + QStringLiteral(" ") + artist;
}

QString composePrefixAction(WFindOnWebMenu::TrackSearchProperties trackSearchProperties) {
switch (trackSearchProperties) {
case WFindOnWebMenu::TrackSearchProperties::Title:
return QObject::tr("Title");
case WFindOnWebMenu::TrackSearchProperties::Artist:
return QObject::tr("Artist");
case WFindOnWebMenu::TrackSearchProperties::ArtistAndTitle:
return QObject::tr("Title + Artist");
case WFindOnWebMenu::TrackSearchProperties::ArtistAndAlbum:
return QObject::tr("Album + Artist");
default:
return QObject::tr("Album");
}
}

const QString kSearchUrlSoundCloudArtist = QStringLiteral("https://soundcloud.com/search/people?");

const QString kSearchUrlSoundCloudTitle = QStringLiteral("https://soundcloud.com/search/sounds?");

const QString kSearchUrlSoundCloudAlbum = QStringLiteral("https://soundcloud.com/search/albums?");

const QString kSearchUrlDiscogsGen = QStringLiteral("https://www.discogs.com/search/?");

const QString kSearchUrlLastFmArtist = QStringLiteral("https://www.last.fm/search/artists?");

const QString kSearchUrlLastFmTitle = QStringLiteral("https://www.last.fm/search/tracks?");

const QString kSearchUrlLastFmAlbum = QStringLiteral("https://www.last.fm/search/albums?");

const QString kSearchUrlDefault = QStringLiteral("https://soundcloud.com/search?");

QString getServiceUrl(WFindOnWebMenu::Service service,
WFindOnWebMenu::TrackSearchProperties trackSearchProperties) {
switch (service) {
case WFindOnWebMenu::Service::Discogs:
return kSearchUrlDiscogsGen;
case WFindOnWebMenu::Service::LastFm:
if (trackSearchProperties == WFindOnWebMenu::TrackSearchProperties::Title ||
trackSearchProperties == WFindOnWebMenu::TrackSearchProperties::ArtistAndTitle) {
return kSearchUrlLastFmTitle;
} else if (trackSearchProperties == WFindOnWebMenu::TrackSearchProperties::Artist) {
return kSearchUrlLastFmArtist;
} else {
return kSearchUrlLastFmAlbum;
}
case WFindOnWebMenu::Service::SoundCloud:
if (trackSearchProperties == WFindOnWebMenu::TrackSearchProperties::Title ||
trackSearchProperties == WFindOnWebMenu::TrackSearchProperties::ArtistAndTitle) {
return kSearchUrlSoundCloudTitle;
} else if (trackSearchProperties == WFindOnWebMenu::TrackSearchProperties::Artist) {
return kSearchUrlSoundCloudArtist;
} else {
return kSearchUrlSoundCloudAlbum;
}
default:
return kSearchUrlDefault;
}
}
} // namespace

WFindOnWebMenu::WFindOnWebMenu(QWidget* parent)
: QMenu(tr("Find on Web"), parent) {
}

void WFindOnWebMenu::addSubmenusForServices(const Track& track) {
WFindOnWebMenu::populateFromTrackProperties(
track,
QStringLiteral("SoundCloud"),
Service::SoundCloud);
WFindOnWebMenu::populateFromTrackProperties(
track, QStringLiteral("LastFm"), Service::LastFm);
WFindOnWebMenu::populateFromTrackProperties(
track, QStringLiteral("Discogs"), Service::Discogs);
}

void WFindOnWebMenu::addActions(Service service,
const QString& queryValue,
QMenu* pServiceMenu,
TrackSearchProperties trackSearchProperties) {
const QString prefixAction = composePrefixAction(trackSearchProperties);
pServiceMenu->addAction(
composeActionText(prefixAction, queryValue),
this,
[this, service, trackSearchProperties, queryValue]() {
openInBrowser(service, trackSearchProperties, queryValue);
});
}

void WFindOnWebMenu::openInBrowser(Service service,
TrackSearchProperties trackSearchProperties,
const QString& queryValue) {
const QString serviceUrl = getServiceUrl(service, trackSearchProperties);
QUrlQuery urlQuery;
urlQuery.addQueryItem("q", queryValue);
QUrl url(serviceUrl);
url.setQuery(urlQuery);
if (!QDesktopServices::openUrl(url)) {
qWarning() << "QDesktopServices::openUrl() failed for " << url;
DEBUG_ASSERT(false);
}
}

bool WFindOnWebMenu::hasEntriesForTrack(const Track& track) {
return !(track.getArtist().isEmpty() &&
track.getAlbum().isEmpty() &&
track.getTitle().isEmpty());
}

void WFindOnWebMenu::populateFromTrackProperties(
const Track& track,
const QString& serviceTitle,
Service service) {
const QString artist = track.getArtist();
const QString trackTitle = track.getTitle();
const QString album = track.getAlbum();
auto pServiceMenu = make_parented<QMenu>(this);
pServiceMenu->setTitle(serviceTitle);
addMenu(pServiceMenu);
addSeparator();
if (!artist.isEmpty()) {
addActions(service,
artist,
pServiceMenu,
WFindOnWebMenu::TrackSearchProperties::Artist);
}
if (!trackTitle.isEmpty()) {
daschuer marked this conversation as resolved.
Show resolved Hide resolved
if (!artist.isEmpty()) {
const QString artistWithTrackTitle = composeSearchQuery(trackTitle, artist);
addActions(service,
artistWithTrackTitle,
pServiceMenu,
WFindOnWebMenu::TrackSearchProperties::ArtistAndTitle);
}
addActions(service,
trackTitle,
pServiceMenu,
WFindOnWebMenu::TrackSearchProperties::Title);
}
if (!album.isEmpty()) {
if (!artist.isEmpty()) {
const QString artistWithAlbum = composeSearchQuery(album, artist);
addActions(service,
artistWithAlbum,
pServiceMenu,
WFindOnWebMenu::TrackSearchProperties::ArtistAndAlbum);
} else {
addActions(service,
album,
pServiceMenu,
WFindOnWebMenu::TrackSearchProperties::Album);
}
}
}
48 changes: 48 additions & 0 deletions src/widget/wfindonwebmenu.h
@@ -0,0 +1,48 @@
#pragma once

#include <QAction>
#include <QMenu>
#include <QUrlQuery>

class Track;

class WFindOnWebMenu : public QMenu {
Q_OBJECT
public:
explicit WFindOnWebMenu(
QWidget* parent = nullptr);
~WFindOnWebMenu() override = default;

enum class Service {
SoundCloud,
LastFm,
Discogs
};

enum class TrackSearchProperties {
Artist,
ArtistAndTitle,
ArtistAndAlbum,
Album,
Title
};

static bool hasEntriesForTrack(const Track& track);

void addSubmenusForServices(const Track& track);

private:
void openInBrowser(WFindOnWebMenu::Service service,
WFindOnWebMenu::TrackSearchProperties trackSearchProperties,
const QString& queryValue);

void populateFromTrackProperties(
const Track& track,
const QString& serviceTitle,
Service service);

void addActions(Service service,
const QString& queryValue,
QMenu* pServiceMenu,
TrackSearchProperties trackSearchProperties);
};
32 changes: 32 additions & 0 deletions src/widget/wtrackmenu.cpp
Expand Up @@ -37,6 +37,7 @@
#include "widget/wcolorpickeraction.h"
#include "widget/wcoverartlabel.h"
#include "widget/wcoverartmenu.h"
#include "widget/wfindonwebmenu.h"
#include "widget/wsearchrelatedtracksmenu.h"
#include "widget/wskincolor.h"
#include "widget/wstarrating.h"
Expand Down Expand Up @@ -185,6 +186,25 @@ void WTrackMenu::createMenus() {
});
}

if (featureIsEnabled(Feature::FindOnWeb)) {
DEBUG_ASSERT(!m_pFindOnMenu);
m_pFindOnMenu =
make_parented<WFindOnWebMenu>(this);

connect(m_pFindOnMenu,
&QMenu::aboutToShow,
this,
[this] {
fatihemreyildiz marked this conversation as resolved.
Show resolved Hide resolved
m_pFindOnMenu->clear();
const auto pTrack = getFirstTrackPointer();
if (pTrack) {
m_pFindOnMenu->addSubmenusForServices(*pTrack);
}
m_pFindOnMenu->setEnabled(
daschuer marked this conversation as resolved.
Show resolved Hide resolved
!m_pFindOnMenu->isEmpty());
});
}

if (featureIsEnabled(Feature::RemoveFromDisk)) {
m_pRemoveFromDiskMenu = new QMenu(this);
m_pRemoveFromDiskMenu->setTitle(tr("Delete Track Files"));
Expand Down Expand Up @@ -537,6 +557,10 @@ void WTrackMenu::setupActions() {
}

m_pMetadataMenu->addMenu(m_pCoverMenu);
if (featureIsEnabled(Feature::FindOnWeb)) {
m_pMetadataMenu->addMenu(m_pFindOnMenu);
addSeparator();
}
addMenu(m_pMetadataMenu);
}

Expand Down Expand Up @@ -860,6 +884,12 @@ void WTrackMenu::updateMenus() {
if (featureIsEnabled(Feature::Properties)) {
m_pPropertiesAct->setEnabled(singleTrackSelected);
}

if (featureIsEnabled(Feature::FindOnWeb)) {
const auto pTrack = getFirstTrackPointer();
const bool enableMenu = pTrack ? WFindOnWebMenu::hasEntriesForTrack(*pTrack) : false;
m_pFindOnMenu->setEnabled(enableMenu);
}
}

void WTrackMenu::loadTrack(
Expand Down Expand Up @@ -2202,6 +2232,8 @@ bool WTrackMenu::featureIsEnabled(Feature flag) const {
return m_pTrackModel->hasCapabilities(TrackModel::Capability::RemoveFromDisk);
case Feature::FileBrowser:
return true;
case Feature::FindOnWeb:
return true;
case Feature::Properties:
return m_pTrackModel->hasCapabilities(TrackModel::Capability::EditMetadata);
case Feature::SearchRelated:
Expand Down
6 changes: 5 additions & 1 deletion src/widget/wtrackmenu.h
Expand Up @@ -24,6 +24,7 @@ class TrackModel;
class WColorPickerAction;
class WCoverArtMenu;
class WSearchRelatedTracksMenu;
class WFindOnWebMenu;

/// A context menu for track(s).
/// Can be used with individual track type widgets based on TrackPointer
Expand Down Expand Up @@ -52,10 +53,12 @@ class WTrackMenu : public QMenu {
UpdateReplayGainFromPregain = 1 << 14,
SelectInLibrary = 1 << 15,
Analyze = 1 << 16,
FindOnWeb = 1 << 17,
TrackModelFeatures = Remove | HideUnhidePurge,
All = AutoDJ | LoadTo | Playlist | Crate | Remove | Metadata | Reset | Analyze |
BPM | Color | HideUnhidePurge | RemoveFromDisk | FileBrowser |
Properties | SearchRelated | UpdateReplayGainFromPregain | SelectInLibrary
Properties | SearchRelated | UpdateReplayGainFromPregain | SelectInLibrary |
FindOnWeb
};
Q_DECLARE_FLAGS(Features, Feature)

Expand Down Expand Up @@ -228,6 +231,7 @@ class WTrackMenu : public QMenu {
QMenu* m_pColorMenu{};
WCoverArtMenu* m_pCoverMenu{};
parented_ptr<WSearchRelatedTracksMenu> m_pSearchRelatedMenu;
parented_ptr<WFindOnWebMenu> m_pFindOnMenu;
QMenu* m_pRemoveFromDiskMenu{};

// Update ReplayGain from Track
Expand Down
1 change: 1 addition & 0 deletions src/widget/wtrackproperty.cpp
Expand Up @@ -23,6 +23,7 @@ constexpr WTrackMenu::Features kTrackMenuFeatures =
WTrackMenu::Feature::FileBrowser |
WTrackMenu::Feature::Properties |
WTrackMenu::Feature::UpdateReplayGainFromPregain |
WTrackMenu::Feature::FindOnWeb |
WTrackMenu::Feature::SelectInLibrary;
} // namespace

Expand Down
1 change: 1 addition & 0 deletions src/widget/wtracktext.cpp
Expand Up @@ -22,6 +22,7 @@ constexpr WTrackMenu::Features kTrackMenuFeatures =
WTrackMenu::Feature::FileBrowser |
WTrackMenu::Feature::Properties |
WTrackMenu::Feature::UpdateReplayGainFromPregain |
WTrackMenu::Feature::FindOnWeb |
WTrackMenu::Feature::SelectInLibrary;
} // namespace

Expand Down
1 change: 1 addition & 0 deletions src/widget/wtrackwidgetgroup.cpp
Expand Up @@ -26,6 +26,7 @@ constexpr WTrackMenu::Features kTrackMenuFeatures =
WTrackMenu::Feature::FileBrowser |
WTrackMenu::Feature::Properties |
WTrackMenu::Feature::UpdateReplayGainFromPregain |
WTrackMenu::Feature::FindOnWeb |
WTrackMenu::Feature::SelectInLibrary;

} // anonymous namespace
Expand Down