diff --git a/extras/Makefile b/extras/Makefile index 6d4c9eea..0b51e15a 100644 --- a/extras/Makefile +++ b/extras/Makefile @@ -1,5 +1,5 @@ CXX=g++ -CXXFLAGS=-O2 -g +CXXFLAGS=-O2 -march=native -pipe -std=c++0x -Wall -Wextra -Wshadow -Werror CPPFLAGS=`taglib-config --cflags` LDFLAGS=`taglib-config --libs` diff --git a/extras/artist_to_albumartist.cpp b/extras/artist_to_albumartist.cpp index ee361287..ae87435f 100644 --- a/extras/artist_to_albumartist.cpp +++ b/extras/artist_to_albumartist.cpp @@ -21,117 +21,121 @@ #include #include -#include "xiphcomment.h" -#include "id3v2tag.h" -#include "textidentificationframe.h" -#include "fileref.h" -#include "mpegfile.h" -#include "vorbisfile.h" -#include "flacfile.h" +#include +#include +#include +#include +#include +#include +#include -using std::cout; +enum class CopyResult { Success, NoArtist, AlbumArtistAlreadyInPlace }; -bool framelist_empty(const TagLib::ID3v2::FrameList &fl) +CopyResult copy_album_artist(TagLib::ID3v2::Tag *tag) { - TagLib::ID3v2::FrameList::ConstIterator it = fl.begin(); - while (it != fl.end()) - if (!((*it++)->toString() == TagLib::String::null)) - return false; - return true; + typedef TagLib::ID3v2::TextIdentificationFrame TextFrame; + + TagLib::ByteVector album_artist = "TPE2"; + if (!tag->frameList(album_artist).isEmpty()) + return CopyResult::AlbumArtistAlreadyInPlace; + + auto artists = tag->frameList("TPE1"); + if (artists.isEmpty()) + return CopyResult::NoArtist; + + for (auto it = artists.begin(); it != artists.end(); ++it) + { + auto frame = new TextFrame(album_artist, TagLib::String::UTF8); + frame->setText((*it)->toString()); + tag->addFrame(frame); + } + + return CopyResult::Success; } -bool write_id3v2_aa(TagLib::ID3v2::Tag *tag, const TagLib::String &artist) +CopyResult copy_album_artist(TagLib::Ogg::XiphComment *tag) { - using TagLib::ID3v2::TextIdentificationFrame; - TagLib::ByteVector type = "TPE2"; - if (!framelist_empty(tag->frameList(type))) - return false; - TextIdentificationFrame *frame = new TextIdentificationFrame(type, TagLib::String::UTF8); - frame->setText(artist); - tag->addFrame(frame); - return true; -} - -bool write_xiphcomment_aa(TagLib::Ogg::XiphComment *tag, const TagLib::String &artist) -{ - if (tag->contains("ALBUM ARTIST")) - return false; - tag->addField("ALBUM ARTIST", artist, true); - return true; + if (tag->contains("ALBUM ARTIST") || tag->contains("ALBUMARTIST")) + return CopyResult::AlbumArtistAlreadyInPlace; + + auto artists = tag->fieldListMap()["ARTIST"]; + if (artists.isEmpty()) + return CopyResult::NoArtist; + + for (auto it = artists.begin(); it != artists.end(); ++it) + tag->addField("ALBUMARTIST", *it, true); + + return CopyResult::Success; } void convert(int n, char **files, bool dry_run) { - if (n == 0) - { - cout << "No files to convert, exiting.\n"; - return; - } - if (dry_run) - cout << "Dry run mode enabled, pretending to modify files.\n"; - - for (int i = 0; i < n; ++i) - { - cout << "Modifying " << files[i] << "... "; - - TagLib::FileRef f(files[i]); - if (!f.isNull()) - { - TagLib::String artist = f.tag()->artist(); - if (!(artist == TagLib::String::null)) - { - TagLib::MPEG::File *mp3_f = 0; - TagLib::Ogg::Vorbis::File *ogg_f = 0; - TagLib::FLAC::File *flac_f = 0; - - bool success; - if ((mp3_f = dynamic_cast(f.file()))) - { - success = write_id3v2_aa(mp3_f->ID3v2Tag(true), artist); - } - else if ((ogg_f = dynamic_cast(f.file()))) - { - success = write_xiphcomment_aa(ogg_f->tag(), artist); - } - else if ((flac_f = dynamic_cast(f.file()))) - { - success = write_xiphcomment_aa(flac_f->xiphComment(true), artist); - } - else - { - cout << "Not mp3/ogg/flac file, skipping.\n"; - continue; - } - - if (success) - { - if (!dry_run) - f.save(); - cout << "Done.\n"; - } - else - cout << "AlbumArtist is already here, skipping.\n"; - } - else - cout << "Artist not found, skipping.\n"; - } - else - cout << "Could not open file, skipping.\n"; - } + if (n == 0) + { + std::cout << "No files to convert, exiting.\n"; + return; + } + if (dry_run) + std::cout << "Dry run mode enabled, pretending to modify files.\n"; + + for (int i = 0; i < n; ++i) + { + std::cout << "Modifying " << files[i] << "... "; + + TagLib::FileRef f(files[i]); + if (!f.isNull()) + { + CopyResult result; + if (auto mp3_f = dynamic_cast(f.file())) + { + result = copy_album_artist(mp3_f->ID3v2Tag(true)); + } + else if (auto ogg_f = dynamic_cast(f.file())) + { + result = copy_album_artist(ogg_f->tag()); + } + else if (auto flac_f = dynamic_cast(f.file())) + { + result = copy_album_artist(flac_f->xiphComment(true)); + } + else + { + std::cout << "Not mp3/ogg/flac file, skipping.\n"; + continue; + } + + switch (result) + { + case CopyResult::Success: + if (!dry_run) + f.save(); + std::cout << "Done.\n"; + break; + case CopyResult::NoArtist: + std::cout << "Artist not found, skipping.\n"; + break; + case CopyResult::AlbumArtistAlreadyInPlace: + std::cout << "AlbumArtist is already there, skipping.\n"; + break; + } + } + else + std::cout << "Could not open file, skipping.\n"; + } } int main(int argc, char **argv) { - if (argc < 2) - { - cout << "This little program copies Artist tag (if present) to\n"; - cout << "AlbumArtist (if not present) for given mp3/ogg/flac files.\n\n"; - cout << "Usage: " << argv[0] << " [--dry-run] files\n"; - } - else - { - bool dry_run = !strcmp(argv[1], "--dry-run"); - convert(argc-1-dry_run, &argv[1+dry_run], dry_run); - } - return 0; + if (argc < 2) + { + std::cout << "This little script copies Artist tag (if present) to\n"; + std::cout << "AlbumArtist (if not present) for given mp3/ogg/flac files.\n\n"; + std::cout << "Usage: " << argv[0] << " [--dry-run] files\n"; + } + else + { + bool dry_run = !strcmp(argv[1], "--dry-run"); + convert(argc-1-dry_run, &argv[1+dry_run], dry_run); + } + return 0; }