From 4ed9493abd63e8b89198c498cfb444fce50ca288 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Sat, 23 Jan 2010 20:04:02 +0100 Subject: [PATCH] add support for album artist tag --- doc/config | 1 + doc/ncmpcpp.1 | 1 + src/conv.cpp | 6 +++++ src/display.cpp | 25 ++++++++++++------ src/info.cpp | 23 ++++++++-------- src/ncmpcpp.cpp | 4 +-- src/song.cpp | 13 +++++++++ src/song.h | 2 ++ src/tag_editor.cpp | 70 ++++++++++++++++++++++++++++++++++--------------- src/tiny_tag_editor.cpp | 22 ++++++++-------- 10 files changed, 114 insertions(+), 53 deletions(-) diff --git a/doc/config b/doc/config index 754819e..26177b9 100644 --- a/doc/config +++ b/doc/config @@ -88,6 +88,7 @@ ## %f - filename ## %D - directory ## %a - artist +## %A - album artist ## %t - title ## %b - album ## %y - year diff --git a/doc/ncmpcpp.1 b/doc/ncmpcpp.1 index 38154a7..503978e 100644 --- a/doc/ncmpcpp.1 +++ b/doc/ncmpcpp.1 @@ -328,6 +328,7 @@ For song format you can use: %f - filename %D - directory %a - artist + %A - album artist %t - title %b - album %y - year diff --git a/src/conv.cpp b/src/conv.cpp index b71c65e..0525a64 100644 --- a/src/conv.cpp +++ b/src/conv.cpp @@ -48,6 +48,8 @@ std::string IntoStr(mpd_tag_type tag) // this is only for left column's title in return "Artist"; case MPD_TAG_ALBUM: return "Album"; + case MPD_TAG_ALBUM_ARTIST: + return "Album Artist"; case MPD_TAG_TITLE: return "Title"; case MPD_TAG_TRACK: @@ -125,6 +127,8 @@ mpd_tag_type IntoTagItem(char c) { case 'a': return MPD_TAG_ARTIST; + case 'A': + return MPD_TAG_ALBUM_ARTIST; case 'b': return MPD_TAG_ALBUM; case 'y': @@ -149,6 +153,8 @@ MPD::Song::SetFunction IntoSetFunction(mpd_tag_type tag) return &MPD::Song::SetArtist; case MPD_TAG_ALBUM: return &MPD::Song::SetAlbum; + case MPD_TAG_ALBUM_ARTIST: + return &MPD::Song::SetAlbumArtist; case MPD_TAG_TITLE: return &MPD::Song::SetTitle; case MPD_TAG_TRACK: diff --git a/src/display.cpp b/src/display.cpp index 292438a..6cdfa62 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -60,6 +60,9 @@ std::string Display::Columns() case 'a': tag = "Artist"; break; + case 'A': + tag = "Album Artist"; + break; case 't': tag = "Title"; break; @@ -160,6 +163,9 @@ void Display::SongsInColumns(const MPD::Song &s, void *, Menu *menu) case 'a': get = &MPD::Song::GetArtist; break; + case 'A': + get = &MPD::Song::GetAlbumArtist; + break; case 'b': get = &MPD::Song::GetAlbum; break; @@ -286,30 +292,33 @@ void Display::Tags(const MPD::Song &s, void *data, Menu *menu) ShowTag(*menu, s.GetTags(&MPD::Song::GetArtist)); return; case 2: - ShowTag(*menu, s.GetTags(&MPD::Song::GetAlbum)); + ShowTag(*menu, s.GetTags(&MPD::Song::GetAlbumArtist)); return; case 3: - ShowTag(*menu, s.GetTags(&MPD::Song::GetDate)); + ShowTag(*menu, s.GetTags(&MPD::Song::GetAlbum)); return; case 4: - ShowTag(*menu, s.GetTags(&MPD::Song::GetTrack)); + ShowTag(*menu, s.GetTags(&MPD::Song::GetDate)); return; case 5: - ShowTag(*menu, s.GetTags(&MPD::Song::GetGenre)); + ShowTag(*menu, s.GetTags(&MPD::Song::GetTrack)); return; case 6: - ShowTag(*menu, s.GetTags(&MPD::Song::GetComposer)); + ShowTag(*menu, s.GetTags(&MPD::Song::GetGenre)); return; case 7: - ShowTag(*menu, s.GetTags(&MPD::Song::GetPerformer)); + ShowTag(*menu, s.GetTags(&MPD::Song::GetComposer)); return; case 8: - ShowTag(*menu, s.GetTags(&MPD::Song::GetDisc)); + ShowTag(*menu, s.GetTags(&MPD::Song::GetPerformer)); return; case 9: + ShowTag(*menu, s.GetTags(&MPD::Song::GetDisc)); + return; + case 10: ShowTag(*menu, s.GetTags(&MPD::Song::GetComment)); return; - case 11: + case 12: if (s.GetNewName().empty()) *menu << s.GetName(); else diff --git a/src/info.cpp b/src/info.cpp index 2bf40c3..279935e 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -60,17 +60,18 @@ Info *myInfo = new Info; const Info::Metadata Info::Tags[] = { - { "Title", &MPD::Song::GetTitle, &MPD::Song::SetTitle }, - { "Artist", &MPD::Song::GetArtist, &MPD::Song::SetArtist }, - { "Album", &MPD::Song::GetAlbum, &MPD::Song::SetAlbum }, - { "Year", &MPD::Song::GetDate, &MPD::Song::SetDate }, - { "Track", &MPD::Song::GetTrack, &MPD::Song::SetTrack }, - { "Genre", &MPD::Song::GetGenre, &MPD::Song::SetGenre }, - { "Composer", &MPD::Song::GetComposer, &MPD::Song::SetComposer }, - { "Performer", &MPD::Song::GetPerformer, &MPD::Song::SetPerformer }, - { "Disc", &MPD::Song::GetDisc, &MPD::Song::SetDisc }, - { "Comment", &MPD::Song::GetComment, &MPD::Song::SetComment }, - { 0, 0, 0 } + { "Title", &MPD::Song::GetTitle, &MPD::Song::SetTitle }, + { "Artist", &MPD::Song::GetArtist, &MPD::Song::SetArtist }, + { "Album Artist", &MPD::Song::GetAlbumArtist, &MPD::Song::SetAlbumArtist }, + { "Album", &MPD::Song::GetAlbum, &MPD::Song::SetAlbum }, + { "Year", &MPD::Song::GetDate, &MPD::Song::SetDate }, + { "Track", &MPD::Song::GetTrack, &MPD::Song::SetTrack }, + { "Genre", &MPD::Song::GetGenre, &MPD::Song::SetGenre }, + { "Composer", &MPD::Song::GetComposer, &MPD::Song::SetComposer }, + { "Performer", &MPD::Song::GetPerformer, &MPD::Song::SetPerformer }, + { "Disc", &MPD::Song::GetDisc, &MPD::Song::SetDisc }, + { "Comment", &MPD::Song::GetComment, &MPD::Song::SetComment }, + { 0, 0, 0 } }; void Info::Init() diff --git a/src/ncmpcpp.cpp b/src/ncmpcpp.cpp index 9c780d5..a0a0d8a 100644 --- a/src/ncmpcpp.cpp +++ b/src/ncmpcpp.cpp @@ -1876,7 +1876,7 @@ int main(int argc, char *argv[]) || (myLibrary->Columns() == 2 && myScreen->ActiveWindow() == myLibrary->Albums)) { LockStatusbar(); - Statusbar() << "Tag type ? [" << fmtBold << 'a' << fmtBoldEnd << "rtist/" << fmtBold << 'y' << fmtBoldEnd << "ear/" << fmtBold << 'g' << fmtBoldEnd << "enre/" << fmtBold << 'c' << fmtBoldEnd << "omposer/" << fmtBold << 'p' << fmtBoldEnd << "erformer] "; + Statusbar() << "Tag type ? [" << fmtBold << 'a' << fmtBoldEnd << "rtist/album" << fmtBold << 'A' << fmtBoldEnd << "rtist/" << fmtBold << 'y' << fmtBoldEnd << "ear/" << fmtBold << 'g' << fmtBoldEnd << "enre/" << fmtBold << 'c' << fmtBoldEnd << "omposer/" << fmtBold << 'p' << fmtBoldEnd << "erformer] "; wFooter->Refresh(); int answer = 0; do @@ -1884,7 +1884,7 @@ int main(int argc, char *argv[]) TraceMpdStatus(); wFooter->ReadKey(answer); } - while (answer != 'a' && answer != 'y' && answer != 'g' && answer != 'c' && answer != 'p'); + while (answer != 'a' && answer != 'A' && answer != 'y' && answer != 'g' && answer != 'c' && answer != 'p'); UnlockStatusbar(); mpd_tag_type new_tagitem = IntoTagItem(answer); if (new_tagitem != Config.media_lib_primary_tag) diff --git a/src/song.cpp b/src/song.cpp index 5440144..fcb5bce 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -190,6 +190,11 @@ std::string MPD::Song::GetAlbum(unsigned pos) const return GetTag(MPD_TAG_ALBUM, pos); } +std::string MPD::Song::GetAlbumArtist(unsigned pos) const +{ + return GetTag(MPD_TAG_ALBUM_ARTIST, pos); +} + std::string MPD::Song::GetTrack(unsigned pos) const { std::string track = GetTag(MPD_TAG_TRACK, pos); @@ -263,6 +268,11 @@ void MPD::Song::SetAlbum(const std::string &str, unsigned pos) SetTag(MPD_TAG_ALBUM, pos, str); } +void MPD::Song::SetAlbumArtist(const std::string &str, unsigned pos) +{ + SetTag(MPD_TAG_ALBUM_ARTIST, pos, str); +} + void MPD::Song::SetTrack(const std::string &str, unsigned pos) { SetTag(MPD_TAG_TRACK, pos, str); @@ -374,6 +384,9 @@ std::string MPD::Song::ParseFormat(std::string::const_iterator &it, const char * case 'a': get = &MPD::Song::GetArtist; break; + case 'A': + get = &MPD::Song::GetAlbumArtist; + break; case 'b': get = &MPD::Song::GetAlbum; break; diff --git a/src/song.h b/src/song.h index 5a06bef..4a10a20 100644 --- a/src/song.h +++ b/src/song.h @@ -47,6 +47,7 @@ namespace MPD std::string GetArtist(unsigned = 0) const; std::string GetTitle(unsigned = 0) const; std::string GetAlbum(unsigned = 0) const; + std::string GetAlbumArtist(unsigned = 0) const; std::string GetTrack(unsigned = 0) const; std::string GetTrackNumber(unsigned = 0) const; std::string GetDate(unsigned = 0) const; @@ -69,6 +70,7 @@ namespace MPD void SetArtist(const std::string &, unsigned = 0); void SetTitle(const std::string &, unsigned = 0); void SetAlbum(const std::string &, unsigned = 0); + void SetAlbumArtist(const std::string &, unsigned = 0); void SetTrack(const std::string &, unsigned = 0); void SetTrack(unsigned, unsigned = 0); void SetDate(const std::string &, unsigned = 0); diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index c765d4d..c601ed8 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -84,6 +84,7 @@ void TagEditor::Init() TagTypes->AddOption("Title"); TagTypes->AddOption("Artist"); + TagTypes->AddOption("Album Artist"); TagTypes->AddOption("Album"); TagTypes->AddOption("Year"); TagTypes->AddOption("Track"); @@ -316,7 +317,10 @@ void TagEditor::Update() Tags->Refresh(); } else if (TagTypes->Choice() >= 13) + { Tags->Window::Clear(); + Tags->Window::Refresh(); + } } void TagEditor::EnterPressed() @@ -352,6 +356,7 @@ void TagEditor::EnterPressed() FParserLegend->Clear(); *FParserLegend << "%a - artist\n"; + *FParserLegend << "%A - album artist\n"; *FParserLegend << "%t - title\n"; *FParserLegend << "%b - album\n"; *FParserLegend << "%y - year\n"; @@ -523,14 +528,18 @@ void TagEditor::EnterPressed() set = &MPD::Song::SetArtist; break; case 2: + get = &MPD::Song::GetAlbumArtist; + set = &MPD::Song::SetAlbumArtist; + break; + case 3: get = &MPD::Song::GetAlbum; set = &MPD::Song::SetAlbum; break; - case 3: + case 4: get = &MPD::Song::GetDate; set = &MPD::Song::SetDate; break; - case 4: + case 5: get = &MPD::Song::GetTrack; set = &MPD::Song::SetTrack; if (w == TagTypes) @@ -562,27 +571,27 @@ void TagEditor::EnterPressed() ShowMessage("Aborted!"); } break; - case 5: + case 6: get = &MPD::Song::GetGenre; set = &MPD::Song::SetGenre; break; - case 6: + case 7: get = &MPD::Song::GetComposer; set = &MPD::Song::SetComposer; break; - case 7: + case 8: get = &MPD::Song::GetPerformer; set = &MPD::Song::SetPerformer; break; - case 8: + case 9: get = &MPD::Song::GetDisc; set = &MPD::Song::SetDisc; break; - case 9: + case 10: get = &MPD::Song::GetComment; set = &MPD::Song::SetComment; break; - case 10: + case 11: { if (w == TagTypes) { @@ -611,13 +620,13 @@ void TagEditor::EnterPressed() } return; } - case 11: // reset + case 12: // reset { Tags->Clear(); ShowMessage("Changes reset"); return; } - case 12: // save + case 13: // save { bool success = 1; ShowMessage("Writing changes..."); @@ -646,7 +655,7 @@ void TagEditor::EnterPressed() Tags->Clear(); return; } - case 13: // capitalize first letters + case 14: // capitalize first letters { ShowMessage("Processing..."); for (MPD::SongList::iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it) @@ -654,7 +663,7 @@ void TagEditor::EnterPressed() ShowMessage("Done!"); break; } - case 14: // lower all letters + case 15: // lower all letters { ShowMessage("Processing..."); for (MPD::SongList::iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it) @@ -666,7 +675,7 @@ void TagEditor::EnterPressed() break; } - if (w == TagTypes && id != 0 && id != 4 && set) + if (w == TagTypes && id != 0 && id != 5 && set) { LockStatusbar(); Statusbar() << fmtBold << TagTypes->Current() << fmtBoldEnd << ": "; @@ -900,6 +909,7 @@ void TagEditor::ReadTags(MPD::Song &s) s.SetGenre(f.tag()->genre().to8Bit(1)); if (mpegf) { + s.SetAlbumArtist(!mpegf->ID3v2Tag()->frameListMap()["TPE2"].isEmpty() ? mpegf->ID3v2Tag()->frameListMap()["TPE2"].front()->toString().to8Bit(1) : ""); s.SetComposer(!mpegf->ID3v2Tag()->frameListMap()["TCOM"].isEmpty() ? mpegf->ID3v2Tag()->frameListMap()["TCOM"].front()->toString().to8Bit(1) : ""); s.SetPerformer(!mpegf->ID3v2Tag()->frameListMap()["TOPE"].isEmpty() ? mpegf->ID3v2Tag()->frameListMap()["TOPE"].front()->toString().to8Bit(1) : ""); s.SetDisc(!mpegf->ID3v2Tag()->frameListMap()["TPOS"].isEmpty() ? mpegf->ID3v2Tag()->frameListMap()["TPOS"].front()->toString().to8Bit(1) : ""); @@ -925,6 +935,11 @@ void TagEditor::WriteXiphComments(const MPD::Song &s, TagLib::Ogg::XiphComment * tag->addField("DISCNUMBER", ToWString(s.GetDisc())); // disc + tag->removeField("ALBUM ARTIST"); // album artist + GetTagList(list, s, &MPD::Song::GetAlbumArtist); + for (TagLib::StringList::ConstIterator it = list.begin(); it != list.end(); ++it) + tag->addField("ALBUM ARTIST", *it, 0); + tag->removeField("COMPOSER"); // composer GetTagList(list, s, &MPD::Song::GetComposer); for (TagLib::StringList::ConstIterator it = list.begin(); it != list.end(); ++it) @@ -967,6 +982,9 @@ bool TagEditor::WriteTags(MPD::Song &s) WriteID3v2("TCON", tag, ToWString(s.GetGenre())); // genre WriteID3v2("TPOS", tag, ToWString(s.GetDisc())); // disc + GetTagList(list, s, &MPD::Song::GetAlbumArtist); + WriteID3v2("TPE2", tag, list); // album artist + GetTagList(list, s, &MPD::Song::GetComposer); WriteID3v2("TCOM", tag, list); // composer @@ -1041,6 +1059,7 @@ void TagEditor::CapitalizeFirstLetters(MPD::Song &s) s.SetTitle(CapitalizeFirstLetters(s.GetTitle())); s.SetArtist(CapitalizeFirstLetters(s.GetArtist())); s.SetAlbum(CapitalizeFirstLetters(s.GetAlbum())); + s.SetAlbumArtist(CapitalizeFirstLetters(s.GetAlbumArtist())); s.SetGenre(CapitalizeFirstLetters(s.GetGenre())); s.SetComposer(CapitalizeFirstLetters(s.GetComposer())); s.SetPerformer(CapitalizeFirstLetters(s.GetPerformer())); @@ -1062,6 +1081,10 @@ void TagEditor::LowerAllLetters(MPD::Song &s) ToLower(conv); s.SetAlbum(conv); + conv = s.GetAlbumArtist(); + ToLower(conv); + s.SetAlbumArtist(conv); + conv = s.GetGenre(); ToLower(conv); s.SetGenre(conv); @@ -1103,30 +1126,33 @@ std::string TagEditor::TagToString(const MPD::Song &s, void *data) result = s.GetArtist(); break; case 2: - result = s.GetAlbum(); + result = s.GetAlbumArtist(); break; case 3: - result = s.GetDate(); + result = s.GetAlbum(); break; case 4: - result = s.GetTrack(); + result = s.GetDate(); break; case 5: - result = s.GetGenre(); + result = s.GetTrack(); break; case 6: - result = s.GetComposer(); + result = s.GetGenre(); break; case 7: - result = s.GetPerformer(); + result = s.GetComposer(); break; case 8: - result = s.GetDisc(); + result = s.GetPerformer(); break; case 9: + result = s.GetDisc(); + break; + case 10: result = s.GetComment(); break; - case 11: + case 12: result = s.GetNewName().empty() ? s.GetName() : s.GetName() + " -> " + s.GetNewName(); break; default: @@ -1169,6 +1195,8 @@ MPD::Song::SetFunction TagEditor::IntoSetFunction(char c) { case 'a': return &MPD::Song::SetArtist; + case 'A': + return &MPD::Song::SetAlbumArtist; case 't': return &MPD::Song::SetTitle; case 'b': diff --git a/src/tiny_tag_editor.cpp b/src/tiny_tag_editor.cpp index 34a0edc..c1b63e6 100644 --- a/src/tiny_tag_editor.cpp +++ b/src/tiny_tag_editor.cpp @@ -97,7 +97,7 @@ void TinyTagEditor::EnterPressed() MPD::Song &s = itsEdited; LockStatusbar(); - if (option < 17) // separator after comment + if (option < 19) // separator after comment { size_t pos = option-8; Statusbar() << fmtBold << Info::Tags[pos].Name << ": " << fmtBoldEnd; @@ -106,7 +106,7 @@ void TinyTagEditor::EnterPressed() w->at(option) << fmtBold << Info::Tags[pos].Name << ':' << fmtBoldEnd << ' '; ShowTag(w->at(option), s.GetTags(Info::Tags[pos].Get)); } - else if (option == 19) + else if (option == 20) { Statusbar() << fmtBold << "Filename: " << fmtBoldEnd; std::string filename = s.GetNewName().empty() ? s.GetName() : s.GetNewName(); @@ -120,7 +120,7 @@ void TinyTagEditor::EnterPressed() } UnlockStatusbar(); - if (option == 21) + if (option == 22) { ShowMessage("Updating tags..."); if (TagEditor::WriteTags(s)) @@ -143,7 +143,7 @@ void TinyTagEditor::EnterPressed() else ShowMessage("Error while writing tags!"); } - if (option > 20) + if (option > 21) myOldScreen->SwitchTo(); } @@ -198,17 +198,17 @@ bool TinyTagEditor::GetTags() w->Clear(); w->Reset(); - w->ResizeList(23); + w->ResizeList(24); for (size_t i = 0; i < 7; ++i) w->Static(i, 1); w->IntoSeparator(7); - w->IntoSeparator(18); - w->IntoSeparator(20); + w->IntoSeparator(19); + w->IntoSeparator(21); if (!extendedTagsSupported(f.file())) - for (size_t i = 14; i <= 16; ++i) + for (size_t i = 15; i <= 17; ++i) w->Static(i, 1); w->Highlight(8); @@ -229,10 +229,10 @@ bool TinyTagEditor::GetTags() ShowTag(w->at(pos), s.GetTags(m->Get)); } - w->at(19) << fmtBold << "Filename:" << fmtBoldEnd << ' ' << s.GetName(); + w->at(20) << fmtBold << "Filename:" << fmtBoldEnd << ' ' << s.GetName(); - w->at(21) << "Save"; - w->at(22) << "Cancel"; + w->at(22) << "Save"; + w->at(23) << "Cancel"; return true; } -- 2.11.4.GIT