Added compilation tag support, fixes #520

This commit is contained in:
emeric
2024-09-04 20:07:37 +02:00
parent d101cc9780
commit 39ca55e8fa
9 changed files with 47 additions and 15 deletions
+10 -1
View File
@@ -35,7 +35,7 @@ namespace lms::db
{
namespace
{
static constexpr Version LMS_DATABASE_VERSION{ 65 };
static constexpr Version LMS_DATABASE_VERSION{ 66 };
}
VersionInfo::VersionInfo()
@@ -736,6 +736,14 @@ SELECT
session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
}
void migrateFromV65(Session& session)
{
session.getDboSession()->execute("ALTER TABLE release ADD is_compilation BOOLEAN NOT NULL DEFAULT(false)");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
}
bool doDbMigration(Session& session)
{
static const std::string outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" };
@@ -777,6 +785,7 @@ SELECT
{ 62, migrateFromV62 },
{ 63, migrateFromV63 },
{ 64, migrateFromV64 },
{ 65, migrateFromV65 },
};
bool migrationPerformed{};
@@ -228,6 +228,7 @@ namespace lms::db
std::chrono::milliseconds getDuration() const;
Wt::WDateTime getLastWritten() const;
std::string_view getArtistDisplayName() const { return _artistDisplayName; }
bool isCompilation() const { return _isCompilation; }
std::size_t getTrackCount() const;
std::vector<ObjectPtr<ReleaseType>> getReleaseTypes() const;
std::vector<std::string> getLabelNames() const;
@@ -241,6 +242,7 @@ namespace lms::db
void setGroupMBID(const std::optional<core::UUID>& mbid) { _groupMBID = mbid ? mbid->getAsString() : ""; }
void setTotalDisc(std::optional<int> totalDisc) { _totalDisc = totalDisc; }
void setArtistDisplayName(std::string_view name) { _artistDisplayName = name; }
void setCompilation(bool value) { _isCompilation = value; }
void clearLabels();
void clearReleaseTypes();
void addLabel(ObjectPtr<Label> releaseType);
@@ -262,6 +264,7 @@ namespace lms::db
Wt::Dbo::field(a, _groupMBID, "group_mbid");
Wt::Dbo::field(a, _totalDisc, "total_disc");
Wt::Dbo::field(a, _artistDisplayName, "artist_display_name");
Wt::Dbo::field(a, _isCompilation, "is_compilation");
Wt::Dbo::hasMany(a, _tracks, Wt::Dbo::ManyToOne, "release");
Wt::Dbo::hasMany(a, _labels, Wt::Dbo::ManyToMany, "release_label", "", Wt::Dbo::OnDeleteCascade);
@@ -284,6 +287,7 @@ namespace lms::db
std::string _groupMBID;
std::optional<int> _totalDisc{};
std::string _artistDisplayName;
bool _isCompilation{}; // See https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html#compilation-itunes-5
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> _tracks;
Wt::Dbo::collection<Wt::Dbo::ptr<Label>> _labels;
+20
View File
@@ -745,6 +745,26 @@ namespace lms::db::tests
}
}
TEST_F(DatabaseFixture, Release_isCompilation)
{
ScopedRelease release{ session, "MyRelease" };
{
auto transaction{ session.createReadTransaction() };
EXPECT_FALSE(release.get()->isCompilation());
}
{
auto transaction{ session.createWriteTransaction() };
release.get().modify()->setCompilation(true);
}
{
auto transaction{ session.createReadTransaction() };
EXPECT_TRUE(release.get()->isCompilation());
}
}
TEST_F(DatabaseFixture, Label)
{
{
+1
View File
@@ -389,6 +389,7 @@ namespace lms::metadata
release->groupMBID = getTagValueAs<core::UUID>(tagReader, TagType::MusicBrainzReleaseGroupID);
release->artists = getArtists(tagReader, { TagType::AlbumArtists, TagType::AlbumArtist }, { TagType::AlbumArtistsSortOrder, TagType::AlbumArtistSortOrder }, { TagType::MusicBrainzReleaseArtistID }, _artistTagDelimiters);
release->mediumCount = getTagValueAs<std::size_t>(tagReader, TagType::TotalDiscs);
release->isCompilation = getTagValueAs<bool>(tagReader, TagType::Compilation).value_or(false);
release->labels = getTagValuesAs<std::string>(tagReader, TagType::RecordLabel, _defaultTagDelimiters);
if (!release->mediumCount)
{
@@ -65,6 +65,7 @@ namespace lms::metadata
std::optional<std::size_t> mediumCount;
std::vector<std::string> labels;
std::vector<std::string> releaseTypes;
bool isCompilation{};
auto operator<=>(const Release&) const = default;
};
+2
View File
@@ -42,6 +42,7 @@ namespace lms::metadata
{ TagType::AlbumArtists, { "MyAlbumArtist1", "MyAlbumArtist2" } },
{ TagType::AlbumArtistsSortOrder, { "MyAlbumArtist1SortName", "MyAlbumArtist2SortName" } },
{ TagType::Comment, { "Comment1", "Comment2" } },
{ TagType::Compilation, { "1" } },
{ TagType::Composer, { "MyComposer1", "MyComposer2" } },
{ TagType::ComposerSortOrder, { "MyComposerSortOrder1", "MyComposerSortOrder2" } },
{ TagType::Conductor, { "MyConductor1", "MyConductor2" } },
@@ -198,6 +199,7 @@ namespace lms::metadata
EXPECT_EQ(track->medium->release->artists[1].name, "MyAlbumArtist2");
EXPECT_EQ(track->medium->release->artists[1].sortName, "MyAlbumArtist2SortName");
EXPECT_EQ(track->medium->release->artists[1].mbid, core::UUID::fromString("5ed3d6b3-2aed-4a03-828c-3c4d4f7406e1"));
EXPECT_TRUE(track->medium->release->isCompilation);
ASSERT_EQ(track->medium->release->labels.size(), 2);
EXPECT_EQ(track->medium->release->labels[0], "Label1");
EXPECT_EQ(track->medium->release->labels[1], "Label2");
@@ -227,6 +227,8 @@ namespace lms::scanner
release.modify()->setTotalDisc(releaseInfo.mediumCount);
if (release->getArtistDisplayName() != releaseInfo.artistDisplayName)
release.modify()->setArtistDisplayName(releaseInfo.artistDisplayName);
if (release->isCompilation() != releaseInfo.isCompilation)
release.modify()->setCompilation(releaseInfo.isCompilation);
if (release->getReleaseTypeNames() != releaseInfo.releaseTypes)
{
release.modify()->clearReleaseTypes();
+4 -13
View File
@@ -172,20 +172,11 @@ namespace lms::api::subsonic
albumNode.setAttribute("displayArtist", release->getArtistDisplayName());
albumNode.addChild("originalReleaseDate", createItemDateNode(release->getOriginalDate(), release->getOriginalYear()));
{
bool isCompilation{};
albumNode.createEmptyArrayValue("releaseTypes");
for (std::string_view releaseType : release->getReleaseTypeNames())
{
if (core::stringUtils::stringCaseInsensitiveEqual(releaseType, "compilation"))
isCompilation = true;
albumNode.setAttribute("isCompilation", release->isCompilation());
albumNode.addArrayValue("releaseTypes", releaseType);
}
// TODO: the Compilation tag does not have the same meaning
albumNode.setAttribute("isCompilation", isCompilation);
}
albumNode.createEmptyArrayValue("releaseTypes");
for (std::string_view releaseType : release->getReleaseTypeNames())
albumNode.addArrayValue("releaseTypes", releaseType);
albumNode.createEmptyArrayChild("discTitles");
for (const DiscInfo& discInfo : release->getDiscs())
+3 -1
View File
@@ -64,7 +64,7 @@ namespace lms::metadata
os << std::endl;
for (std::string_view label : release.labels)
std::cout << "Label: " << label << std::endl;
std::cout << "\tLabel: " << label << std::endl;
if (release.mbid)
os << "\tRelease MBID = " << release.mbid->getAsString() << std::endl;
@@ -78,6 +78,8 @@ namespace lms::metadata
if (!release.artistDisplayName.empty())
std::cout << "\tDisplay artist: " << release.artistDisplayName << std::endl;
std::cout << "\tIsCompilation: " << std::boolalpha << release.isCompilation << std::endl;
for (const Artist& artist : release.artists)
std::cout << "\tRelease artist: " << artist << std::endl;