Added copyright info each track, fixes #793

This commit is contained in:
emeric
2026-02-26 23:00:19 +01:00
parent 74cd9e827c
commit 543dd64d20
16 changed files with 88 additions and 29 deletions
+2
View File
@@ -199,6 +199,7 @@
<message id="Lms.Explore.artists">Artists</message> <message id="Lms.Explore.artists">Artists</message>
<message id="Lms.Explore.bitrate">Bitrate</message> <message id="Lms.Explore.bitrate">Bitrate</message>
<message id="Lms.Explore.codec">Codec</message> <message id="Lms.Explore.codec">Codec</message>
<message id="Lms.Explore.copyright">Copyright</message>
<message id="Lms.Explore.cover-art">Cover art</message> <message id="Lms.Explore.cover-art">Cover art</message>
<message id="Lms.Explore.download">Download</message> <message id="Lms.Explore.download">Download</message>
<message id="Lms.Explore.duration">Duration</message> <message id="Lms.Explore.duration">Duration</message>
@@ -233,6 +234,7 @@
<message id="Lms.Explore.unstar">Unstar</message> <message id="Lms.Explore.unstar">Unstar</message>
<message id="Lms.Explore.value">Value</message> <message id="Lms.Explore.value">Value</message>
<message id="Lms.Explore.various-artists">Various artists</message> <message id="Lms.Explore.various-artists">Various artists</message>
<message id="Lms.Explore.various-copyrights">Some rights reserved. Please refer to individual tracks for copyright info</message>
<!--Explore:Artist--> <!--Explore:Artist-->
<message id="Lms.Explore.Artist.appears-on">Appears on</message> <message id="Lms.Explore.Artist.appears-on">Appears on</message>
+1 -1
View File
@@ -9,4 +9,4 @@
<message id="Lms.locale.time-format">hh:mm:ss a</message> <message id="Lms.locale.time-format">hh:mm:ss a</message>
<message id="Lms.locale.date-time-format">MM/dd/yyyy hh:mm:ss a</message> <message id="Lms.locale.date-time-format">MM/dd/yyyy hh:mm:ss a</message>
</messages> </messages>
+2
View File
@@ -199,6 +199,7 @@
<message id="Lms.Explore.artists">Artistas</message> <message id="Lms.Explore.artists">Artistas</message>
<message id="Lms.Explore.bitrate">Bitrate</message> <message id="Lms.Explore.bitrate">Bitrate</message>
<message id="Lms.Explore.codec">Codec</message> <message id="Lms.Explore.codec">Codec</message>
<message id="Lms.Explore.copyright">Derechos de autor</message>
<message id="Lms.Explore.cover-art">Carátula</message> <message id="Lms.Explore.cover-art">Carátula</message>
<message id="Lms.Explore.download">Descargar</message> <message id="Lms.Explore.download">Descargar</message>
<message id="Lms.Explore.duration">Duración</message> <message id="Lms.Explore.duration">Duración</message>
@@ -233,6 +234,7 @@
<message id="Lms.Explore.unstar">Eliminar de favoritos</message> <message id="Lms.Explore.unstar">Eliminar de favoritos</message>
<message id="Lms.Explore.value">Valor</message> <message id="Lms.Explore.value">Valor</message>
<message id="Lms.Explore.various-artists">Varios artistas</message> <message id="Lms.Explore.various-artists">Varios artistas</message>
<message id="Lms.Explore.various-copyrights">Algunos derechos reservados. Consulte las pistas para información sobre copyright</message>
<!--Explore:Artist--> <!--Explore:Artist-->
<message id="Lms.Explore.Artist.appears-on">Aparece en</message> <message id="Lms.Explore.Artist.appears-on">Aparece en</message>
+2
View File
@@ -199,6 +199,7 @@
<message id="Lms.Explore.artists">Artistes</message> <message id="Lms.Explore.artists">Artistes</message>
<message id="Lms.Explore.bitrate">Bitrate</message> <message id="Lms.Explore.bitrate">Bitrate</message>
<message id="Lms.Explore.codec">Codec</message> <message id="Lms.Explore.codec">Codec</message>
<message id="Lms.Explore.copyright">Droits d'auteur</message>
<message id="Lms.Explore.cover-art">Pochette</message> <message id="Lms.Explore.cover-art">Pochette</message>
<message id="Lms.Explore.download">Télécharger</message> <message id="Lms.Explore.download">Télécharger</message>
<message id="Lms.Explore.duration">Durée</message> <message id="Lms.Explore.duration">Durée</message>
@@ -233,6 +234,7 @@
<message id="Lms.Explore.unstar">Retirer des favoris</message> <message id="Lms.Explore.unstar">Retirer des favoris</message>
<message id="Lms.Explore.value">Valeur</message> <message id="Lms.Explore.value">Valeur</message>
<message id="Lms.Explore.various-artists">Artistes divers</message> <message id="Lms.Explore.various-artists">Artistes divers</message>
<message id="Lms.Explore.various-copyrights">Certains droits réservés. Consultez les pistes pour les informations sur les droits d'auteur</message>
<!--Explore:Artist--> <!--Explore:Artist-->
<message id="Lms.Explore.Artist.appears-on">Apparaît dans</message> <message id="Lms.Explore.Artist.appears-on">Apparaît dans</message>
+2
View File
@@ -199,6 +199,7 @@
<message id="Lms.Explore.artists">Artisti</message> <message id="Lms.Explore.artists">Artisti</message>
<message id="Lms.Explore.bitrate">Bitrate</message> <message id="Lms.Explore.bitrate">Bitrate</message>
<message id="Lms.Explore.codec">Codec</message> <message id="Lms.Explore.codec">Codec</message>
<message id="Lms.Explore.copyright">Diritti d'autore</message>
<message id="Lms.Explore.cover-art">Copertina</message> <message id="Lms.Explore.cover-art">Copertina</message>
<message id="Lms.Explore.download">Download</message> <message id="Lms.Explore.download">Download</message>
<message id="Lms.Explore.duration">Durata</message> <message id="Lms.Explore.duration">Durata</message>
@@ -233,6 +234,7 @@
<message id="Lms.Explore.unstar">Rimuovi dai preferiti</message> <message id="Lms.Explore.unstar">Rimuovi dai preferiti</message>
<message id="Lms.Explore.value">Valore</message> <message id="Lms.Explore.value">Valore</message>
<message id="Lms.Explore.various-artists">Vari artisti</message> <message id="Lms.Explore.various-artists">Vari artisti</message>
<message id="Lms.Explore.various-copyrights">Alcuni diritti riservati. Consultare le tracce per le informazioni sul copyright</message>
<!--Explore:Artist--> <!--Explore:Artist-->
<message id="Lms.Explore.Artist.appears-on">Appare su</message> <message id="Lms.Explore.Artist.appears-on">Appare su</message>
+2
View File
@@ -216,6 +216,7 @@
<message id="Lms.Explore.artists">Artyści</message> <message id="Lms.Explore.artists">Artyści</message>
<message id="Lms.Explore.bitrate">Przepływność</message> <message id="Lms.Explore.bitrate">Przepływność</message>
<message id="Lms.Explore.codec">Kodek</message> <message id="Lms.Explore.codec">Kodek</message>
<message id="Lms.Explore.copyright">Prawa autorskie</message>
<message id="Lms.Explore.cover-art">Okładka</message> <message id="Lms.Explore.cover-art">Okładka</message>
<message id="Lms.Explore.download">Pobierz</message> <message id="Lms.Explore.download">Pobierz</message>
<message id="Lms.Explore.duration">Długość</message> <message id="Lms.Explore.duration">Długość</message>
@@ -250,6 +251,7 @@
<message id="Lms.Explore.unstar">Przestań wyróżniać</message> <message id="Lms.Explore.unstar">Przestań wyróżniać</message>
<message id="Lms.Explore.value">Wartość</message> <message id="Lms.Explore.value">Wartość</message>
<message id="Lms.Explore.various-artists">Różni artyści</message> <message id="Lms.Explore.various-artists">Różni artyści</message>
<message id="Lms.Explore.various-copyrights">Niektóre prawa zastrzeżone. Sprawdź poszczególne utwory, aby uzyskać informacje o prawach autorskich</message>
<!--Explore:Artist--> <!--Explore:Artist-->
<message id="Lms.Explore.Artist.appears-on">Pojawia się na</message> <message id="Lms.Explore.Artist.appears-on">Pojawia się na</message>
+2
View File
@@ -197,6 +197,7 @@
<message id="Lms.Explore.artists">歌手</message> <message id="Lms.Explore.artists">歌手</message>
<message id="Lms.Explore.bitrate">比特率</message> <message id="Lms.Explore.bitrate">比特率</message>
<message id="Lms.Explore.codec">编码器</message> <message id="Lms.Explore.codec">编码器</message>
<message id="Lms.Explore.copyright">版权所有</message>
<message id="Lms.Explore.cover-art">封面</message> <message id="Lms.Explore.cover-art">封面</message>
<message id="Lms.Explore.download">下载</message> <message id="Lms.Explore.download">下载</message>
<message id="Lms.Explore.duration">时长</message> <message id="Lms.Explore.duration">时长</message>
@@ -231,6 +232,7 @@
<message id="Lms.Explore.unstar">取消收藏</message> <message id="Lms.Explore.unstar">取消收藏</message>
<message id="Lms.Explore.value"></message> <message id="Lms.Explore.value"></message>
<message id="Lms.Explore.various-artists">群星</message> <message id="Lms.Explore.various-artists">群星</message>
<message id="Lms.Explore.various-copyrights">部分权利保留。请查看单曲以获取版权信息</message>
<!--Explore:Artist--> <!--Explore:Artist-->
<message id="Lms.Explore.Artist.appears-on">出现于</message> <message id="Lms.Explore.Artist.appears-on">出现于</message>
+10 -1
View File
@@ -129,6 +129,16 @@
${playcount} ${playcount}
</div> </div>
</div> </div>
${<if-has-copyright>}
<div class="row align-items-center">
<div class="col-4">
${tr:Lms.Explore.copyright}
</div>
<div class="col">
${copyright}
</div>
</div>
${</if-has-copyright>}
${<if-has-comment>} ${<if-has-comment>}
<hr/> <hr/>
<pre>${comment}</pre> <pre>${comment}</pre>
@@ -143,7 +153,6 @@
</div> </div>
</message> </message>
<message id="Lms.Explore.Tracks.template.track-lyrics"> <message id="Lms.Explore.Tracks.template.track-lyrics">
<div class="modal fade" tabindex="-1"> <div class="modal fade" tabindex="-1">
<div class="modal-dialog modal-dialog-scrollable"> <div class="modal-dialog modal-dialog-scrollable">
+9 -2
View File
@@ -642,13 +642,20 @@ namespace lms::db
return *year; return *year;
} }
bool Release::hasVariousCopyrights() const
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT copyright) FROM track t").where("t.release_id = ?").bind(getId())) > 1;
}
std::optional<std::string> Release::getCopyright() const std::optional<std::string> Release::getCopyright() const
{ {
assert(session()); assert(session());
auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").groupBy("copyright").bind(getId()) }; auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").groupBy("copyright").bind(getId()) };
const auto copyrights{ utils::fetchQueryResults(query) }; auto copyrights{ utils::fetchQueryResults(query) };
// various copyrights => no copyright // various copyrights => no copyright
if (copyrights.empty() || copyrights.size() > 1 || copyrights.front().empty()) if (copyrights.empty() || copyrights.size() > 1 || copyrights.front().empty())
@@ -663,7 +670,7 @@ namespace lms::db
const auto query{ session()->query<std::string>("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()).groupBy("copyright_url") }; const auto query{ session()->query<std::string>("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()).groupBy("copyright_url") };
const auto copyrights{ utils::fetchQueryResults(query) }; auto copyrights{ utils::fetchQueryResults(query) };
// various copyright URLs => no copyright URL // various copyright URLs => no copyright URL
if (copyrights.empty() || copyrights.size() > 1 || copyrights.front().empty()) if (copyrights.empty() || copyrights.size() > 1 || copyrights.front().empty())
+4 -4
View File
@@ -643,14 +643,14 @@ namespace lms::db
return !_trackLyrics.empty(); return !_trackLyrics.empty();
} }
std::optional<std::string> Track::getCopyright() const std::string_view Track::getCopyright() const
{ {
return _copyright != "" ? std::make_optional<std::string>(_copyright) : std::nullopt; return _copyright;
} }
std::optional<std::string> Track::getCopyrightURL() const std::string_view Track::getCopyrightURL() const
{ {
return _copyrightURL != "" ? std::make_optional<std::string>(_copyrightURL) : std::nullopt; return _copyrightURL;
} }
std::vector<Artist::pointer> Track::getArtists(core::EnumSet<TrackArtistLinkType> linkTypes) const std::vector<Artist::pointer> Track::getArtists(core::EnumSet<TrackArtistLinkType> linkTypes) const
@@ -289,6 +289,7 @@ namespace lms::db
std::optional<int> getYear() const; std::optional<int> getYear() const;
core::PartialDateTime getOriginalDate() const; core::PartialDateTime getOriginalDate() const;
std::optional<int> getOriginalYear() const; std::optional<int> getOriginalYear() const;
bool hasVariousCopyrights() const;
std::optional<std::string> getCopyright() const; std::optional<std::string> getCopyright() const;
std::optional<std::string> getCopyrightURL() const; std::optional<std::string> getCopyrightURL() const;
std::size_t getMeanBitrate() const; std::size_t getMeanBitrate() const;
@@ -297,8 +297,8 @@ namespace lms::db
bool hasLyrics() const; bool hasLyrics() const;
std::optional<core::UUID> getTrackMBID() const { return core::UUID::fromString(_trackMBID); } std::optional<core::UUID> getTrackMBID() const { return core::UUID::fromString(_trackMBID); }
std::optional<core::UUID> getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); } std::optional<core::UUID> getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); }
std::optional<std::string> getCopyright() const; std::string_view getCopyright() const;
std::optional<std::string> getCopyrightURL() const; std::string_view getCopyrightURL() const;
std::string_view getArtistDisplayName() const { return _artistDisplayName; } std::string_view getArtistDisplayName() const { return _artistDisplayName; }
std::string_view getComment() const { return _comment; } std::string_view getComment() const { return _comment; }
Advisory getAdvisory() const { return _advisory; } Advisory getAdvisory() const { return _advisory; }
+27
View File
@@ -474,4 +474,31 @@ namespace lms::ui::utils
return artistMap; return artistMap;
} }
std::unique_ptr<Wt::WInteractWidget> createCopyright(std::string_view copyright, std::string_view copyrightURL)
{
std::unique_ptr<Wt::WInteractWidget> res;
if (copyright.empty() && copyrightURL.empty())
return res;
if (copyright.empty() && !copyrightURL.empty())
copyright = copyrightURL;
if (!copyrightURL.empty())
{
Wt::WLink link{ std::string{ copyrightURL } };
link.setTarget(Wt::LinkTarget::NewWindow);
auto anchor{ std::make_unique<Wt::WAnchor>(link) };
anchor->setTextFormat(Wt::TextFormat::Plain);
anchor->setText(Wt::WString::fromUTF8(std::string{ copyright }));
res = std::move(anchor);
}
else
res = std::make_unique<Wt::WText>(Wt::WString::fromUTF8(std::string{ copyright }), Wt::TextFormat::Plain);
return res;
}
} // namespace lms::ui::utils } // namespace lms::ui::utils
+2
View File
@@ -91,4 +91,6 @@ namespace lms::ui::utils
std::map<Wt::WString, std::vector<db::ObjectPtr<db::Artist>>> getArtistsByRole(db::ObjectPtr<db::Track> track, core::EnumSet<db::TrackArtistLinkType> artistLinkTypes = {}); std::map<Wt::WString, std::vector<db::ObjectPtr<db::Artist>>> getArtistsByRole(db::ObjectPtr<db::Track> track, core::EnumSet<db::TrackArtistLinkType> artistLinkTypes = {});
std::map<Wt::WString, std::vector<db::ObjectPtr<db::Artist>>> getTrackArtistsByRole(db::ObjectPtr<db::Release> release); std::map<Wt::WString, std::vector<db::ObjectPtr<db::Artist>>> getTrackArtistsByRole(db::ObjectPtr<db::Release> release);
std::unique_ptr<Wt::WInteractWidget> createCopyright(std::string_view copyright, std::string_view copyrightURL);
} // namespace lms::ui::utils } // namespace lms::ui::utils
+14 -19
View File
@@ -522,29 +522,24 @@ namespace lms::ui
void Release::refreshCopyright(const db::Release::pointer& release) void Release::refreshCopyright(const db::Release::pointer& release)
{ {
std::optional<std::string> copyright{ release->getCopyright() }; std::optional<std::string> copyright;
std::optional<std::string> copyrightURL{ release->getCopyrightURL() }; std::optional<std::string> copyrightURL;
if (!copyright && !copyrightURL) if (release->hasVariousCopyrights())
return;
setCondition("if-has-copyright", true);
std::string copyrightText{ copyright ? *copyright : "" };
if (copyrightText.empty() && copyrightURL)
copyrightText = *copyrightURL;
if (copyrightURL)
{ {
Wt::WLink link{ *copyrightURL }; copyright = Wt::WString::tr("Lms.Explore.various-copyrights").toUTF8();
link.setTarget(Wt::LinkTarget::NewWindow);
Wt::WAnchor* anchor{ bindNew<Wt::WAnchor>("copyright", link) };
anchor->setTextFormat(Wt::TextFormat::Plain);
anchor->setText(Wt::WString::fromUTF8(copyrightText));
} }
else else
bindString("copyright", Wt::WString::fromUTF8(*copyright), Wt::TextFormat::Plain); {
copyright = release->getCopyright();
copyrightURL = release->getCopyrightURL();
}
if (auto copyrightWidget{ utils::createCopyright(copyright ? *copyright : "", copyrightURL ? *copyrightURL : "") })
{
setCondition("if-has-copyright", true);
bindWidget("copyright", std::move(copyrightWidget));
}
} }
void Release::refreshLinks(const db::Release::pointer& release) void Release::refreshLinks(const db::Release::pointer& release)
+6
View File
@@ -96,6 +96,12 @@ namespace lms::ui::TrackListHelpers
trackInfo->bindString("comment", Wt::WString::fromUTF8(std::string{ comment }), Wt::TextFormat::Plain); trackInfo->bindString("comment", Wt::WString::fromUTF8(std::string{ comment }), Wt::TextFormat::Plain);
} }
if (auto copyrightWidget{ utils::createCopyright(track->getCopyright(), track->getCopyrightURL()) })
{
trackInfo->setCondition("if-has-copyright", true);
trackInfo->bindWidget("copyright", std::move(copyrightWidget));
}
Wt::WContainerWidget* clusterContainer{ trackInfo->bindWidget("clusters", utils::createFilterClustersForTrack(track, filters)) }; Wt::WContainerWidget* clusterContainer{ trackInfo->bindWidget("clusters", utils::createFilterClustersForTrack(track, filters)) };
if (clusterContainer->count() > 0) if (clusterContainer->count() > 0)
trackInfo->setCondition("if-has-clusters", true); trackInfo->setCondition("if-has-clusters", true);