Added an optional role filter for 'appears on' section the artist views, fixes #824
This commit is contained in:
@@ -49,6 +49,7 @@ add_executable(lms
|
||||
ui/explore/ReleasesView.cpp
|
||||
ui/explore/ReleaseView.cpp
|
||||
ui/explore/ReleaseTypes.cpp
|
||||
ui/explore/TrackArtistTypeSelector.cpp
|
||||
ui/explore/TrackCollector.cpp
|
||||
ui/explore/TrackListHelpers.cpp
|
||||
ui/explore/TrackListView.cpp
|
||||
|
||||
@@ -459,13 +459,13 @@ namespace lms::ui
|
||||
_artistReleaseSortMethodModel->add(Wt::WString::tr("Lms.Settings.name"), db::ReleaseSortMethod::Name);
|
||||
|
||||
_artistRelationshipsModel = std::make_shared<ArtistRelationshipsModel>();
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.composer", 2), db::TrackArtistLinkType::Composer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.conductor", 2), db::TrackArtistLinkType::Conductor);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.lyricist", 2), db::TrackArtistLinkType::Lyricist);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.mixer", 2), db::TrackArtistLinkType::Mixer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.performer", 2), db::TrackArtistLinkType::Performer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.producer", 2), db::TrackArtistLinkType::Producer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.remixer", 2), db::TrackArtistLinkType::Remixer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.composer", 2), db::TrackArtistLinkType::Composer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.conductor", 2), db::TrackArtistLinkType::Conductor);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.lyricist", 2), db::TrackArtistLinkType::Lyricist);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.mixer", 2), db::TrackArtistLinkType::Mixer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.performer", 2), db::TrackArtistLinkType::Performer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.producer", 2), db::TrackArtistLinkType::Producer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.remixer", 2), db::TrackArtistLinkType::Remixer);
|
||||
|
||||
_transcodingModeModeModel = std::make_shared<TranscodingModeModel>();
|
||||
_transcodingModeModeModel->add(Wt::WString::tr("Lms.Settings.transcoding-mode.always"), MediaPlayer::Settings::Transcoding::Mode::Always);
|
||||
|
||||
+14
-14
@@ -407,17 +407,17 @@ namespace lms::ui::utils
|
||||
});
|
||||
};
|
||||
|
||||
addArtists(db::TrackArtistLinkType::Composer, "Lms.Explore.Artists.composer");
|
||||
addArtists(db::TrackArtistLinkType::Conductor, "Lms.Explore.Artists.conductor");
|
||||
addArtists(db::TrackArtistLinkType::Lyricist, "Lms.Explore.Artists.lyricist");
|
||||
addArtists(db::TrackArtistLinkType::Mixer, "Lms.Explore.Artists.mixer");
|
||||
addArtists(db::TrackArtistLinkType::Remixer, "Lms.Explore.Artists.remixer");
|
||||
addArtists(db::TrackArtistLinkType::Producer, "Lms.Explore.Artists.producer");
|
||||
addArtists(db::TrackArtistLinkType::Composer, "Lms.Explore.composer");
|
||||
addArtists(db::TrackArtistLinkType::Conductor, "Lms.Explore.conductor");
|
||||
addArtists(db::TrackArtistLinkType::Lyricist, "Lms.Explore.lyricist");
|
||||
addArtists(db::TrackArtistLinkType::Mixer, "Lms.Explore.mixer");
|
||||
addArtists(db::TrackArtistLinkType::Remixer, "Lms.Explore.remixer");
|
||||
addArtists(db::TrackArtistLinkType::Producer, "Lms.Explore.producer");
|
||||
addPerformerArtists();
|
||||
|
||||
if (!rolelessPerformers.empty())
|
||||
{
|
||||
Wt::WString performersStr{ Wt::WString::trn("Lms.Explore.Artists.performer", rolelessPerformers.size()) };
|
||||
Wt::WString performersStr{ Wt::WString::trn("Lms.Explore.performer", rolelessPerformers.size()) };
|
||||
artistMap[performersStr] = std::move(rolelessPerformers);
|
||||
}
|
||||
|
||||
@@ -458,17 +458,17 @@ namespace lms::ui::utils
|
||||
});
|
||||
};
|
||||
|
||||
addArtists(db::TrackArtistLinkType::Composer, "Lms.Explore.Artists.composer");
|
||||
addArtists(db::TrackArtistLinkType::Conductor, "Lms.Explore.Artists.conductor");
|
||||
addArtists(db::TrackArtistLinkType::Lyricist, "Lms.Explore.Artists.lyricist");
|
||||
addArtists(db::TrackArtistLinkType::Mixer, "Lms.Explore.Artists.mixer");
|
||||
addArtists(db::TrackArtistLinkType::Remixer, "Lms.Explore.Artists.remixer");
|
||||
addArtists(db::TrackArtistLinkType::Producer, "Lms.Explore.Artists.producer");
|
||||
addArtists(db::TrackArtistLinkType::Composer, "Lms.Explore.composer");
|
||||
addArtists(db::TrackArtistLinkType::Conductor, "Lms.Explore.conductor");
|
||||
addArtists(db::TrackArtistLinkType::Lyricist, "Lms.Explore.lyricist");
|
||||
addArtists(db::TrackArtistLinkType::Mixer, "Lms.Explore.mixer");
|
||||
addArtists(db::TrackArtistLinkType::Remixer, "Lms.Explore.remixer");
|
||||
addArtists(db::TrackArtistLinkType::Producer, "Lms.Explore.producer");
|
||||
addPerformerArtists();
|
||||
|
||||
if (!rolelessPerformers.empty())
|
||||
{
|
||||
Wt::WString performersStr{ Wt::WString::trn("Lms.Explore.Artists.performer", rolelessPerformers.size()) };
|
||||
Wt::WString performersStr{ Wt::WString::trn("Lms.Explore.performer", rolelessPerformers.size()) };
|
||||
artistMap[performersStr] = std::move(rolelessPerformers);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,16 +30,16 @@ namespace lms::ui
|
||||
ArtistTypeSelector(ArtistType defaultArtistType)
|
||||
: DropDownMenuSelector{ Wt::WString::tr("Lms.Explore.Artists.template.artist-type-selector"), defaultArtistType }
|
||||
{
|
||||
bindItem("artist-type-all", Wt::WString::tr("Lms.Explore.Artists.all"), AllArtistsTag{});
|
||||
bindItem("artist-type-release-artist", Wt::WString::trn("Lms.Explore.Artists.release-artist", 2), ReleaseArtistsTag{});
|
||||
bindItem("artist-type-track-artist", Wt::WString::trn("Lms.Explore.Artists.track-artist", 2), db::TrackArtistLinkType::Artist);
|
||||
bindItem("artist-type-composer", Wt::WString::trn("Lms.Explore.Artists.composer", 2), db::TrackArtistLinkType::Composer);
|
||||
bindItem("artist-type-conductor", Wt::WString::trn("Lms.Explore.Artists.conductor", 2), db::TrackArtistLinkType::Conductor);
|
||||
bindItem("artist-type-lyricist", Wt::WString::trn("Lms.Explore.Artists.lyricist", 2), db::TrackArtistLinkType::Lyricist);
|
||||
bindItem("artist-type-mixer", Wt::WString::trn("Lms.Explore.Artists.mixer", 2), db::TrackArtistLinkType::Mixer);
|
||||
bindItem("artist-type-performer", Wt::WString::trn("Lms.Explore.Artists.performer", 2), db::TrackArtistLinkType::Performer);
|
||||
bindItem("artist-type-producer", Wt::WString::trn("Lms.Explore.Artists.producer", 2), db::TrackArtistLinkType::Producer);
|
||||
bindItem("artist-type-remixer", Wt::WString::trn("Lms.Explore.Artists.remixer", 2), db::TrackArtistLinkType::Remixer);
|
||||
bindItem("artist-type-all", Wt::WString::tr("Lms.Explore.all-artists"), AllArtistsTag{});
|
||||
bindItem("artist-type-release-artist", Wt::WString::trn("Lms.Explore.release-artist", 2), ReleaseArtistsTag{});
|
||||
bindItem("artist-type-track-artist", Wt::WString::trn("Lms.Explore.track-artist", 2), db::TrackArtistLinkType::Artist);
|
||||
bindItem("artist-type-composer", Wt::WString::trn("Lms.Explore.composer", 2), db::TrackArtistLinkType::Composer);
|
||||
bindItem("artist-type-conductor", Wt::WString::trn("Lms.Explore.conductor", 2), db::TrackArtistLinkType::Conductor);
|
||||
bindItem("artist-type-lyricist", Wt::WString::trn("Lms.Explore.lyricist", 2), db::TrackArtistLinkType::Lyricist);
|
||||
bindItem("artist-type-mixer", Wt::WString::trn("Lms.Explore.mixer", 2), db::TrackArtistLinkType::Mixer);
|
||||
bindItem("artist-type-performer", Wt::WString::trn("Lms.Explore.performer", 2), db::TrackArtistLinkType::Performer);
|
||||
bindItem("artist-type-producer", Wt::WString::trn("Lms.Explore.producer", 2), db::TrackArtistLinkType::Producer);
|
||||
bindItem("artist-type-remixer", Wt::WString::trn("Lms.Explore.remixer", 2), db::TrackArtistLinkType::Remixer);
|
||||
}
|
||||
};
|
||||
} // namespace lms::ui
|
||||
|
||||
@@ -19,7 +19,10 @@
|
||||
|
||||
#include "ArtistView.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <Wt/WPushButton.h>
|
||||
#include <Wt/WStackedWidget.h>
|
||||
|
||||
#include "core/String.hpp"
|
||||
#include "database/Session.hpp"
|
||||
@@ -30,6 +33,8 @@
|
||||
#include "database/objects/Release.hpp"
|
||||
#include "database/objects/ScanSettings.hpp"
|
||||
#include "database/objects/Track.hpp"
|
||||
#include "database/objects/TrackArtistLink.hpp"
|
||||
#include "database/objects/Types.hpp"
|
||||
#include "database/objects/User.hpp"
|
||||
#include "services/feedback/IFeedbackService.hpp"
|
||||
#include "services/recommendation/IRecommendationService.hpp"
|
||||
@@ -40,6 +45,7 @@
|
||||
#include "LmsApplicationException.hpp"
|
||||
#include "PlayQueueController.hpp"
|
||||
#include "ReleaseHelpers.hpp"
|
||||
#include "TrackArtistTypeSelector.hpp"
|
||||
#include "TrackListHelpers.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "common/InfiniteScrollingContainer.hpp"
|
||||
@@ -272,30 +278,77 @@ namespace lms::ui
|
||||
|
||||
void Artist::refreshAppearsOnReleases()
|
||||
{
|
||||
_appearsOnReleases.clear();
|
||||
_appearsOnReleaseContainer = {};
|
||||
|
||||
db::Release::FindParameters params;
|
||||
params.setTrackArtist(_artistId);
|
||||
params.setSortMethod(db::ReleaseSortMethod::OriginalDateDesc);
|
||||
auto addToReleaseContainer = [&](std::optional<db::TrackArtistLinkType> linkType) -> bool {
|
||||
db::Release::FindParameters params;
|
||||
|
||||
db::Release::find(LmsApp->getDbSession(), params, [this](const db::Release::pointer& release) {
|
||||
if (!release->hasArtist(_artistId))
|
||||
_appearsOnReleaseContainer.releases.push_back(release->getId());
|
||||
});
|
||||
core::EnumSet<db::TrackArtistLinkType> linkTypes;
|
||||
if (linkType)
|
||||
linkTypes.insert(*linkType);
|
||||
|
||||
if (!_appearsOnReleaseContainer.releases.empty())
|
||||
params.setTrackArtist(_artistId, linkTypes);
|
||||
params.setSortMethod(db::ReleaseSortMethod::OriginalDateDesc);
|
||||
|
||||
bool found{};
|
||||
db::Release::find(LmsApp->getDbSession(), params, [&](const db::Release::pointer& release) {
|
||||
if (release->hasArtist(_artistId))
|
||||
return;
|
||||
|
||||
_appearsOnReleases[linkType].push_back(release->getId());
|
||||
found = true;
|
||||
});
|
||||
|
||||
return found;
|
||||
};
|
||||
|
||||
constexpr std::array<std::optional<db::TrackArtistLinkType>, 9> types{
|
||||
std::nullopt,
|
||||
db::TrackArtistLinkType::Artist,
|
||||
db::TrackArtistLinkType::Composer,
|
||||
db::TrackArtistLinkType::Conductor,
|
||||
db::TrackArtistLinkType::Lyricist,
|
||||
db::TrackArtistLinkType::Mixer,
|
||||
db::TrackArtistLinkType::Performer,
|
||||
db::TrackArtistLinkType::Producer,
|
||||
db::TrackArtistLinkType::Remixer,
|
||||
};
|
||||
|
||||
core::EnumSet<db::TrackArtistLinkType> foundTypes;
|
||||
for (const auto type : types)
|
||||
{
|
||||
Wt::WTemplate* releaseContainer{ bindNew<Wt::WTemplate>("appears-on-releases", Wt::WString::tr("Lms.Explore.Artist.template.release-container")) };
|
||||
releaseContainer->bindString("release-type", Wt::WString::tr("Lms.Explore.Artist.appears-on"));
|
||||
_appearsOnReleaseContainer.container = releaseContainer->bindNew<InfiniteScrollingContainer>("releases", Wt::WString::tr("Lms.Explore.Releases.template.container"));
|
||||
_appearsOnReleaseContainer.container->onRequestElements.connect(this, [this] {
|
||||
if (addToReleaseContainer(type) && type)
|
||||
foundTypes.insert(*type);
|
||||
}
|
||||
|
||||
if (!_appearsOnReleases.empty())
|
||||
{
|
||||
std::optional<db::TrackArtistLinkType> defaultType{ std::nullopt };
|
||||
if (_appearsOnReleases.size() == 2)
|
||||
{
|
||||
auto it{ std::find_if(std::cbegin(_appearsOnReleases), std::cend(_appearsOnReleases), [=](const auto& entry) { return entry.first != defaultType; }) };
|
||||
if (it != std::cend(_appearsOnReleases))
|
||||
defaultType = it->first;
|
||||
}
|
||||
|
||||
Wt::WTemplate* appearsOnContainer{ bindNew<Wt::WTemplate>("appears-on-releases", Wt::WString::tr("Lms.Explore.Artist.template.appears-on-container")) };
|
||||
appearsOnContainer->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
|
||||
_appearsOnReleaseContainer.container = appearsOnContainer->bindNew<InfiniteScrollingContainer>("releases", Wt::WString::tr("Lms.Explore.Releases.template.container"));
|
||||
_appearsOnReleaseContainer.releases = _appearsOnReleases[defaultType];
|
||||
_appearsOnReleaseContainer.container->onRequestElements.connect(this, [&] {
|
||||
addSomeReleases(_appearsOnReleaseContainer, { releaseListHelpers::DisplayOptions::ShowYearAndOriginalYear, releaseListHelpers::DisplayOptions::ShowArtist });
|
||||
});
|
||||
|
||||
TrackArtistTypeSelector* trackArtistTypeSelector{ appearsOnContainer->bindNew<TrackArtistTypeSelector>("artist-type", defaultType, foundTypes) };
|
||||
trackArtistTypeSelector->itemSelected.connect([this](std::optional<db::TrackArtistLinkType> newArtistLinkType) {
|
||||
_appearsOnReleaseContainer.releases = _appearsOnReleases[newArtistLinkType];
|
||||
_appearsOnReleaseContainer.container->reset();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bindEmpty("appears-on-releases");
|
||||
}
|
||||
}
|
||||
|
||||
void Artist::refreshNonReleaseTracks()
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
|
||||
@@ -31,6 +32,7 @@
|
||||
#include "ReleaseHelpers.hpp"
|
||||
#include "ReleaseTypes.hpp"
|
||||
#include "common/Template.hpp"
|
||||
#include "database/objects/Types.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
@@ -76,7 +78,8 @@ namespace lms::ui
|
||||
std::vector<db::ReleaseId> releases;
|
||||
};
|
||||
std::map<ReleaseType, ReleaseContainer> _releaseContainers;
|
||||
ReleaseContainer _appearsOnReleaseContainer{};
|
||||
std::map<std::optional<db::TrackArtistLinkType>, std::vector<db::ReleaseId>> _appearsOnReleases;
|
||||
ReleaseContainer _appearsOnReleaseContainer;
|
||||
InfiniteScrollingContainer* _trackContainer{};
|
||||
db::ArtistId _artistId{};
|
||||
std::string _artistName;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TrackArtistTypeSelector.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace lms::ui
|
||||
{
|
||||
TrackArtistTypeSelector::TrackArtistTypeSelector(std::optional<db::TrackArtistLinkType> defaultRole, core::EnumSet<db::TrackArtistLinkType> types)
|
||||
: DropDownMenuSelector{ Wt::WString::tr("Lms.Explore.Artist.template.track-artist-type-selector"), defaultRole }
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
std::string var;
|
||||
Wt::WString title;
|
||||
std::optional<db::TrackArtistLinkType> linkType;
|
||||
core::LiteralString condition;
|
||||
};
|
||||
|
||||
auto bindItemWithCondition = [&](const std::string& var, const Wt::WString& title, std::optional<db::TrackArtistLinkType> item, core::LiteralString condition) {
|
||||
if (!condition.empty())
|
||||
setCondition(condition.c_str(), true);
|
||||
bindItem(var, title, item);
|
||||
};
|
||||
const std::array entries{
|
||||
Entry{ "artist-type-all", Wt::WString::tr("Lms.Explore.all-roles"), std::nullopt, core::LiteralString{} },
|
||||
Entry{ "artist-type-track-artist", Wt::WString::trn("Lms.Explore.track-artist", 1), db::TrackArtistLinkType::Artist, "if-has-track-artist" },
|
||||
Entry{ "artist-type-composer", Wt::WString::trn("Lms.Explore.composer", 1), db::TrackArtistLinkType::Composer, "if-has-composer" },
|
||||
Entry{ "artist-type-conductor", Wt::WString::trn("Lms.Explore.conductor", 1), db::TrackArtistLinkType::Conductor, "if-has-conductor" },
|
||||
Entry{ "artist-type-lyricist", Wt::WString::trn("Lms.Explore.lyricist", 1), db::TrackArtistLinkType::Lyricist, "if-has-lyricist" },
|
||||
Entry{ "artist-type-mixer", Wt::WString::trn("Lms.Explore.mixer", 1), db::TrackArtistLinkType::Mixer, "if-has-mixer" },
|
||||
Entry{ "artist-type-performer", Wt::WString::trn("Lms.Explore.performer", 1), db::TrackArtistLinkType::Performer, "if-has-performer" },
|
||||
Entry{ "artist-type-producer", Wt::WString::trn("Lms.Explore.producer", 1), db::TrackArtistLinkType::Producer, "if-has-producer" },
|
||||
Entry{ "artist-type-remixer", Wt::WString::trn("Lms.Explore.remixer", 1), db::TrackArtistLinkType::Remixer, "if-has-remixer" },
|
||||
};
|
||||
|
||||
for (const Entry& entry : entries)
|
||||
{
|
||||
if (!entry.linkType || types.contains(*entry.linkType))
|
||||
bindItemWithCondition(entry.var, entry.title, entry.linkType, entry.condition);
|
||||
}
|
||||
}
|
||||
} // namespace lms::ui
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
|
||||
#include "database/objects/Types.hpp"
|
||||
|
||||
#include "DropDownMenuSelector.hpp"
|
||||
|
||||
namespace lms::ui
|
||||
{
|
||||
class TrackArtistTypeSelector : public DropDownMenuSelector<std::optional<db::TrackArtistLinkType>>
|
||||
{
|
||||
public:
|
||||
TrackArtistTypeSelector(std::optional<db::TrackArtistLinkType> defaultRole, core::EnumSet<db::TrackArtistLinkType> types);
|
||||
};
|
||||
} // namespace lms::ui
|
||||
Reference in New Issue
Block a user