Fixed regression on artist/release artist handling + fixed bug when firing a signal on still connected but deleted listener

This commit is contained in:
emeric
2020-11-12 17:12:08 +01:00
parent 6a4bbd6acf
commit 6240ccf747
20 changed files with 81 additions and 49 deletions
+3
View File
@@ -65,3 +65,6 @@ __Note__: since _LMS_ stores hashed and salted passwords, it cannot handle the _
See [INSTALL.md](INSTALL.md) file. See [INSTALL.md](INSTALL.md) file.
## Contributing
Contributions are welcome! Please prepare your pull requests on the [develop](../../tree/develop) branch.
+1
View File
@@ -199,6 +199,7 @@
<message id="Lms.Settings.subsonic-artist-list-mode">Artist list mode</message> <message id="Lms.Settings.subsonic-artist-list-mode">Artist list mode</message>
<message id="Lms.Settings.subsonic-artist-list-mode.all-artists">All artists</message> <message id="Lms.Settings.subsonic-artist-list-mode.all-artists">All artists</message>
<message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Album artists</message> <message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Album artists</message>
<message id="Lms.Settings.subsonic-artist-list-mode.track-artists">Track artists</message>
<message id="Lms.Settings.subsonic-api">Subsonic API</message> <message id="Lms.Settings.subsonic-api">Subsonic API</message>
<message id="Lms.Settings.transcode">Transcoding</message> <message id="Lms.Settings.transcode">Transcoding</message>
<message id="Lms.Settings.transcode-bitrate">Transcode bitrate</message> <message id="Lms.Settings.transcode-bitrate">Transcode bitrate</message>
+1
View File
@@ -199,6 +199,7 @@
<message id="Lms.Settings.subsonic-artist-list-mode">Mode de listage des artistes</message> <message id="Lms.Settings.subsonic-artist-list-mode">Mode de listage des artistes</message>
<message id="Lms.Settings.subsonic-artist-list-mode.all-artists">Tous les artistes</message> <message id="Lms.Settings.subsonic-artist-list-mode.all-artists">Tous les artistes</message>
<message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Tous les artistes d'album</message> <message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Tous les artistes d'album</message>
<message id="Lms.Settings.subsonic-artist-list-mode.track-artists">Tous les artistes de piste</message>
<message id="Lms.Settings.subsonic-api">API Subsonic</message> <message id="Lms.Settings.subsonic-api">API Subsonic</message>
<message id="Lms.Settings.transcode">Transcodage</message> <message id="Lms.Settings.transcode">Transcodage</message>
<message id="Lms.Settings.transcode-bitrate">Bitrate du transcodage</message> <message id="Lms.Settings.transcode-bitrate">Bitrate du transcodage</message>
+3 -2
View File
@@ -509,12 +509,13 @@ Track::getArtists(EnumSet<TrackArtistLinkType> linkTypes) const
oss << ")"; oss << ")";
} }
Wt::Dbo::Query<Artist::pointer> query {session()->query<Artist::pointer>(oss.str()) Wt::Dbo::Query<Artist::pointer> query {session()->query<Artist::pointer>(oss.str())};
.where("t.id = ?").bind(self()->id())};
for (TrackArtistLinkType type : linkTypes) for (TrackArtistLinkType type : linkTypes)
query.bind(type); query.bind(type);
query.where("t.id = ?").bind(self()->id());
Wt::Dbo::collection<Artist::pointer> res = query; Wt::Dbo::collection<Artist::pointer> res = query;
return std::vector<Artist::pointer>(std::begin(res), std::end(res)); return std::vector<Artist::pointer>(std::begin(res), std::end(res));
} }
+2 -1
View File
@@ -132,8 +132,9 @@ class User : public Wt::Dbo::Dbo<User>
// Do not change enum values! // Do not change enum values!
enum class SubsonicArtistListMode enum class SubsonicArtistListMode
{ {
AllArtists = 0, AllArtists = 0,
ReleaseArtists = 1, ReleaseArtists = 1,
TrackArtists = 2,
}; };
static inline const std::size_t MinNameLength {3}; static inline const std::size_t MinNameLength {3};
+1 -1
View File
@@ -397,7 +397,7 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug)
} }
track.album = getAlbum(properties); track.album = getAlbum(properties);
track.artists = getArtists(properties, {"ARTIST", "ARTISTS"}, {"ARTISTSORT"}, {"MUSICBRAINZ_ARTISTID", "MUSICBRAINZ ARTIST ID"}); track.artists = getArtists(properties, {"ARTISTS", "ARTIST"}, {"ARTISTSORT"}, {"MUSICBRAINZ_ARTISTID", "MUSICBRAINZ ARTIST ID"});
track.albumArtists = getArtists(properties, {"ALBUMARTIST"}, {"ALBUMARTISTSORT"}, {"MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ ALBUM ARTIST ID"}); track.albumArtists = getArtists(properties, {"ALBUMARTIST"}, {"ALBUMARTISTSORT"}, {"MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ ALBUM ARTIST ID"});
track.conductorArtists = getArtists(properties, {"CONDUCTOR"}, {""}, {}); track.conductorArtists = getArtists(properties, {"CONDUCTOR"}, {""}, {});
track.composerArtists = getArtists(properties, {"COMPOSER"}, {"COMPOSERSORT"}, {}); track.composerArtists = getArtists(properties, {"COMPOSER"}, {"COMPOSERSORT"}, {});
+8 -1
View File
@@ -316,7 +316,8 @@ trackToResponseNode(const Track::pointer& track, Session& dbSession, const User:
trackResponse.setAttribute("coverArt", IdToString({Id::Type::Track, track.id()})); trackResponse.setAttribute("coverArt", IdToString({Id::Type::Track, track.id()}));
auto artists {track->getArtists({TrackArtistLinkType::Artist})}; const std::vector<Artist::pointer>& artists {track->getArtists({TrackArtistLinkType::Artist})};
LMS_LOG(API_SUBSONIC, DEBUG) << "Artists count = " << artists.size();
if (!artists.empty()) if (!artists.empty())
{ {
trackResponse.setAttribute("artist", getArtistNames(artists)); trackResponse.setAttribute("artist", getArtistNames(artists));
@@ -954,6 +955,9 @@ handleGetArtistsRequest(RequestContext& context)
case User::SubsonicArtistListMode::ReleaseArtists: case User::SubsonicArtistListMode::ReleaseArtists:
linkType = TrackArtistLinkType::ReleaseArtist; linkType = TrackArtistLinkType::ReleaseArtist;
break; break;
case User::SubsonicArtistListMode::TrackArtists:
linkType = TrackArtistLinkType::Artist;
break;
} }
bool more {}; bool more {};
@@ -1098,6 +1102,9 @@ handleGetIndexesRequest(RequestContext& context)
case User::SubsonicArtistListMode::ReleaseArtists: case User::SubsonicArtistListMode::ReleaseArtists:
linkType = TrackArtistLinkType::ReleaseArtist; linkType = TrackArtistLinkType::ReleaseArtist;
break; break;
case User::SubsonicArtistListMode::TrackArtists:
linkType = TrackArtistLinkType::Artist;
break;
} }
bool more {}; bool more {};
+3 -3
View File
@@ -541,7 +541,7 @@ LmsApplication::createHome()
{ {
const std::string sessionId {LmsApp->sessionId()}; const std::string sessionId {LmsApp->sessionId()};
Service<Scanner::IMediaScanner>::get()->scanStarted().connect(this, [=] () Service<Scanner::IMediaScanner>::get()->scanStarted().connect(this, [=]
{ {
Wt::WServer::instance()->post(sessionId, [=] Wt::WServer::instance()->post(sessionId, [=]
{ {
@@ -550,9 +550,9 @@ LmsApplication::createHome()
}); });
}); });
Service<Scanner::IMediaScanner>::get()->scanComplete().connect(this, [=] () Service<Scanner::IMediaScanner>::get()->scanComplete().connect(this, [=]
{ {
Wt::WServer::instance()->post(sessionId, [=] Wt::WServer::instance()->post(sessionId, [this]
{ {
_events.dbScanned.emit(); _events.dbScanned.emit();
triggerUpdate(); triggerUpdate();
+3 -2
View File
@@ -333,6 +333,7 @@ class SettingsModel : public Wt::WFormModel
_subsonicArtistListModeModel = std::make_shared<ValueStringModel<User::SubsonicArtistListMode>>(); _subsonicArtistListModeModel = std::make_shared<ValueStringModel<User::SubsonicArtistListMode>>();
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.all-artists"), User::SubsonicArtistListMode::AllArtists); _subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.all-artists"), User::SubsonicArtistListMode::AllArtists);
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.release-artists"), User::SubsonicArtistListMode::ReleaseArtists); _subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.release-artists"), User::SubsonicArtistListMode::ReleaseArtists);
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.track-artists"), User::SubsonicArtistListMode::TrackArtists);
} }
bool _withOldPassword {}; bool _withOldPassword {};
@@ -346,12 +347,12 @@ class SettingsModel : public Wt::WFormModel
SettingsView::SettingsView() SettingsView::SettingsView()
{ {
wApp->internalPathChanged().connect([=] wApp->internalPathChanged().connect(this, [this]
{ {
refreshView(); refreshView();
}); });
LmsApp->getMediaPlayer().settingsLoaded.connect([=]() LmsApp->getMediaPlayer().settingsLoaded.connect([this]
{ {
refreshView(); refreshView();
}); });
+2 -2
View File
@@ -167,10 +167,10 @@ class DatabaseSettingsModel : public Wt::WFormModel
DatabaseSettingsView::DatabaseSettingsView() DatabaseSettingsView::DatabaseSettingsView()
{ {
wApp->internalPathChanged().connect(std::bind([=] wApp->internalPathChanged().connect(this, [this]
{ {
refreshView(); refreshView();
})); });
refreshView(); refreshView();
} }
+1 -1
View File
@@ -139,7 +139,7 @@ ScannerController::ScannerController()
auto onDbEvent = [&]() { refreshContents(); }; auto onDbEvent = [&]() { refreshContents(); };
LmsApp->getEvents().dbScanStarted.connect(this, []() LmsApp->getEvents().dbScanStarted.connect(this, []
{ {
LmsApp->notifyMsg(MsgType::Info, Wt::WString::tr("Lms.Admin.Database.scan-launched")); LmsApp->notifyMsg(MsgType::Info, Wt::WString::tr("Lms.Admin.Database.scan-launched"));
}); });
+1 -1
View File
@@ -242,7 +242,7 @@ class UserModel : public Wt::WFormModel
UserView::UserView() UserView::UserView()
{ {
wApp->internalPathChanged().connect([this]() wApp->internalPathChanged().connect(this, [this]()
{ {
refreshView(); refreshView();
}); });
+1 -1
View File
@@ -44,7 +44,7 @@ UsersView::UsersView()
LmsApp->setInternalPath("/admin/user", true); LmsApp->setInternalPath("/admin/user", true);
}); });
wApp->internalPathChanged().connect([this]() wApp->internalPathChanged().connect(this, [this]()
{ {
refreshView(); refreshView();
}); });
+6
View File
@@ -73,6 +73,12 @@ class ValueStringModel : public Wt::WStringListModel
setData(rowCount() - 1, 0, str, Wt::ItemDataRole::Display); setData(rowCount() - 1, 0, str, Wt::ItemDataRole::Display);
} }
void
clear()
{
removeRows(0, rowCount());
}
}; };
} // namespace UserInterface } // namespace UserInterface
+2 -2
View File
@@ -50,12 +50,12 @@ Artist::Artist(Filters* filters)
{ {
addFunction("tr", &Wt::WTemplate::Functions::tr); addFunction("tr", &Wt::WTemplate::Functions::tr);
LmsApp->internalPathChanged().connect([=] LmsApp->internalPathChanged().connect(this, [this]
{ {
refreshView(); refreshView();
}); });
filters->updated().connect([=] filters->updated().connect([this]
{ {
refreshView(); refreshView();
}); });
+38 -28
View File
@@ -69,35 +69,14 @@ Artists::Artists(Filters* filters)
} }
_linkType = bindNew<Wt::WComboBox>("link-type"); _linkType = bindNew<Wt::WComboBox>("link-type");
_linkType->setModel(std::make_shared<ArtistLinkModel>());
{
auto linkTypeModel {std::make_shared<ArtistLinkModel>()};
EnumSet<Database::TrackArtistLinkType> usedLinkTypes;
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
usedLinkTypes = Database::TrackArtistLink::getUsedTypes(LmsApp->getDbSession());
}
auto addTypeIfUsed {[&](Database::TrackArtistLinkType linkType, std::string_view stringKey)
{
if (!usedLinkTypes.contains(linkType))
return;
linkTypeModel->add(Wt::WString::tr(std::string {stringKey}), linkType);
}};
linkTypeModel->add(Wt::WString::tr("Lms.Explore.Artists.linktype-all"), {});
addTypeIfUsed(TrackArtistLinkType::Artist, "Lms.Explore.Artists.linktype-artist");
addTypeIfUsed(TrackArtistLinkType::ReleaseArtist, "Lms.Explore.Artists.linktype-releaseartist");
addTypeIfUsed(TrackArtistLinkType::Composer, "Lms.Explore.Artists.linktype-composer");
addTypeIfUsed(TrackArtistLinkType::Lyricist, "Lms.Explore.Artists.linktype-lyricist");
addTypeIfUsed(TrackArtistLinkType::Mixer, "Lms.Explore.Artists.linktype-mixer");
addTypeIfUsed(TrackArtistLinkType::Producer, "Lms.Explore.Artists.linktype-producer");
addTypeIfUsed(TrackArtistLinkType::Remixer, "Lms.Explore.Artists.linktype-remixer");
_linkType->setModel(linkTypeModel);
}
_linkType->changed().connect([this] { refreshView(); }); _linkType->changed().connect([this] { refreshView(); });
refreshArtistLinkTypes();
LmsApp->getEvents().dbScanned.connect(this, [this]
{
refreshArtistLinkTypes();
});
_container = bindNew<Wt::WContainerWidget>("artists"); _container = bindNew<Wt::WContainerWidget>("artists");
hideLoadingIndicator(); hideLoadingIndicator();
@@ -122,6 +101,37 @@ Artists::refreshView(Mode mode)
refreshView(); refreshView();
} }
void
Artists::refreshArtistLinkTypes()
{
std::shared_ptr<ArtistLinkModel> linkTypeModel {std::static_pointer_cast<ArtistLinkModel>(_linkType->model())};
EnumSet<Database::TrackArtistLinkType> usedLinkTypes;
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
usedLinkTypes = Database::TrackArtistLink::getUsedTypes(LmsApp->getDbSession());
}
auto addTypeIfUsed {[&](Database::TrackArtistLinkType linkType, std::string_view stringKey)
{
if (!usedLinkTypes.contains(linkType))
return;
linkTypeModel->add(Wt::WString::tr(std::string {stringKey}), linkType);
}};
linkTypeModel->clear();
linkTypeModel->add(Wt::WString::tr("Lms.Explore.Artists.linktype-all"), {});
addTypeIfUsed(TrackArtistLinkType::Artist, "Lms.Explore.Artists.linktype-artist");
addTypeIfUsed(TrackArtistLinkType::ReleaseArtist, "Lms.Explore.Artists.linktype-releaseartist");
addTypeIfUsed(TrackArtistLinkType::Composer, "Lms.Explore.Artists.linktype-composer");
addTypeIfUsed(TrackArtistLinkType::Lyricist, "Lms.Explore.Artists.linktype-lyricist");
addTypeIfUsed(TrackArtistLinkType::Mixer, "Lms.Explore.Artists.linktype-mixer");
addTypeIfUsed(TrackArtistLinkType::Producer, "Lms.Explore.Artists.linktype-producer");
addTypeIfUsed(TrackArtistLinkType::Remixer, "Lms.Explore.Artists.linktype-remixer");
}
void void
Artists::displayLoadingIndicator() Artists::displayLoadingIndicator()
{ {
+1
View File
@@ -56,6 +56,7 @@ class Artists : public Wt::WTemplate
void refreshView(); void refreshView();
void refreshView(Mode mode); void refreshView(Mode mode);
void refreshArtistLinkTypes();
void displayLoadingIndicator(); void displayLoadingIndicator();
void hideLoadingIndicator(); void hideLoadingIndicator();
void addSome(); void addSome();
+1 -1
View File
@@ -113,7 +113,7 @@ Explore::Explore(Filters* filters)
tracks->tracksAction.connect(this, &Explore::handleTracksAction); tracks->tracksAction.connect(this, &Explore::handleTracksAction);
contentsStack->addWidget(std::move(tracks)); contentsStack->addWidget(std::move(tracks));
wApp->internalPathChanged().connect([=] wApp->internalPathChanged().connect(this, [=]
{ {
handleContentsPathChange(contentsStack); handleContentsPathChange(contentsStack);
}); });
+2 -2
View File
@@ -54,12 +54,12 @@ Release::Release(Filters* filters)
{ {
addFunction("tr", &Wt::WTemplate::Functions::tr); addFunction("tr", &Wt::WTemplate::Functions::tr);
wApp->internalPathChanged().connect([=] wApp->internalPathChanged().connect(this, [this]
{ {
refreshView(); refreshView();
}); });
filters->updated().connect([=] filters->updated().connect([this]
{ {
refreshView(); refreshView();
}); });
+1 -1
View File
@@ -290,7 +290,7 @@ testSingleTrackSingleArtist(Session& session)
CHECK(track->getArtists({TrackArtistLinkType::Artist}).size() == 1); CHECK(track->getArtists({TrackArtistLinkType::Artist}).size() == 1);
CHECK(track->getArtists({TrackArtistLinkType::ReleaseArtist}).empty()); CHECK(track->getArtists({TrackArtistLinkType::ReleaseArtist}).empty());
CHECK(track->getArtists({}).empty()); CHECK(track->getArtists({}).size() == 1);
} }
{ {