Added compilation tag support, fixes #520
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user