Fixed regression on artist/release artist handling + fixed bug when firing a signal on still connected but deleted listener
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
@@ -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"}, {});
|
||||||
|
|||||||
@@ -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 {};
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ class UserModel : public Wt::WFormModel
|
|||||||
|
|
||||||
UserView::UserView()
|
UserView::UserView()
|
||||||
{
|
{
|
||||||
wApp->internalPathChanged().connect([this]()
|
wApp->internalPathChanged().connect(this, [this]()
|
||||||
{
|
{
|
||||||
refreshView();
|
refreshView();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user