diff --git a/src/tangara/database/index.cpp b/src/tangara/database/index.cpp index 58a7ead4..b3af716b 100644 --- a/src/tangara/database/index.cpp +++ b/src/tangara/database/index.cpp @@ -116,13 +116,12 @@ class Indexer { case Tag::kTitle: return titleOrFilename(track_data_, track_tags_); case Tag::kArtist: + case Tag::kAlbumArtist: return "Unknown Artist"; case Tag::kAlbum: return "Unknown Album"; - case Tag::kAlbumArtist: - return track_tags_.artist().value_or("Unknown Artist"); case Tag::kAllArtists: - return track_tags_.artist().value_or("Unknown Artist"); + return std::pmr::vector{}; case Tag::kGenres: return std::pmr::vector{}; case Tag::kDisc: diff --git a/src/tangara/database/track.cpp b/src/tangara/database/track.cpp index 9f7da2d5..ad9db1ba 100644 --- a/src/tangara/database/track.cpp +++ b/src/tangara/database/track.cpp @@ -155,23 +155,23 @@ auto valueOrMonostate(std::optional t) -> TagValue { auto TrackTags::get(Tag t) const -> TagValue { switch (t) { case Tag::kTitle: - return valueOrMonostate(title_); + return valueOrMonostate(title()); case Tag::kArtist: - return valueOrMonostate(artist_); + return valueOrMonostate(artist()); case Tag::kAllArtists: - return allArtists_; + return allArtists(); case Tag::kAlbum: - return valueOrMonostate(album_); + return valueOrMonostate(album()); case Tag::kAlbumArtist: - return valueOrMonostate(album_artist_); + return valueOrMonostate(albumArtist()); case Tag::kDisc: - return valueOrMonostate(disc_); + return valueOrMonostate(disc()); case Tag::kTrack: - return valueOrMonostate(track_); + return valueOrMonostate(track()); case Tag::kAlbumOrder: return albumOrder(); case Tag::kGenres: - return genres_; + return genres(); } return std::monostate{}; } @@ -240,6 +240,7 @@ auto TrackTags::artist() const -> const std::optional& { auto TrackTags::artist(std::string_view s) -> void { artist_ = s; + maybeSynthesizeAllArtists(); } auto TrackTags::allArtists() const -> std::span { @@ -248,6 +249,7 @@ auto TrackTags::allArtists() const -> std::span { auto TrackTags::allArtists(const std::string_view s) -> void { parseDelimitedTags(s, kAllArtistDelimiters, allArtists_); + maybeSynthesizeAllArtists(); } auto TrackTags::album() const -> const std::optional& { @@ -259,6 +261,9 @@ auto TrackTags::album(std::string_view s) -> void { } auto TrackTags::albumArtist() const -> const std::optional& { + if (!album_artist_) { + return artist_; + } return album_artist_; } @@ -320,6 +325,17 @@ auto TrackTags::Hash() const -> uint64_t { return komihash_stream_final(&stream); } +/* + * Adds the current 'artist' tag to 'allArtists' if needed. Many tracks lack a + * fine-grained 'ARTISTS=' tag (or equivalent), but pushing down this nuance to + * consumers of TrackTags adds a lot of complexity. + */ +auto TrackTags::maybeSynthesizeAllArtists() -> void { + if (allArtists_.empty() && artist_) { + allArtists_.push_back(*artist_); + } +} + auto database::TrackData::clone() const -> std::shared_ptr { auto data = std::make_shared(); data->id = id; diff --git a/src/tangara/database/track.hpp b/src/tangara/database/track.hpp index 21d6349d..71eb44ce 100644 --- a/src/tangara/database/track.hpp +++ b/src/tangara/database/track.hpp @@ -144,6 +144,8 @@ class TrackTags { auto Hash() const -> uint64_t; private: + auto maybeSynthesizeAllArtists() -> void; + Container encoding_; std::optional title_;