tag editor: improve tag writing abilities
This commit is contained in:
@@ -169,8 +169,11 @@ void MutableSong::setDuration(unsigned int duration)
|
|||||||
void MutableSong::setTags(SetFunction set, const std::string &value, const std::string &delimiter)
|
void MutableSong::setTags(SetFunction set, const std::string &value, const std::string &delimiter)
|
||||||
{
|
{
|
||||||
auto tags = split(value, delimiter);
|
auto tags = split(value, delimiter);
|
||||||
for (size_t i = 0; i < tags.size(); ++i)
|
size_t i = 0;
|
||||||
|
for (; i < tags.size(); ++i)
|
||||||
(this->*set)(tags[i], i);
|
(this->*set)(tags[i], i);
|
||||||
|
// set next tag to be empty, so tags with bigger indexes won't be read
|
||||||
|
(this->*set)("", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MutableSong::isModified() const
|
bool MutableSong::isModified() const
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
// taglib includes
|
// taglib includes
|
||||||
|
#include "id3v1tag.h"
|
||||||
#include "id3v2tag.h"
|
#include "id3v2tag.h"
|
||||||
#include "textidentificationframe.h"
|
#include "textidentificationframe.h"
|
||||||
#include "mpegfile.h"
|
#include "mpegfile.h"
|
||||||
@@ -79,11 +80,13 @@ bool isAnyModified(const NC::Menu<MPD::MutableSong> &m);
|
|||||||
std::string CapitalizeFirstLetters(const std::string &s);
|
std::string CapitalizeFirstLetters(const std::string &s);
|
||||||
void CapitalizeFirstLetters(MPD::MutableSong &s);
|
void CapitalizeFirstLetters(MPD::MutableSong &s);
|
||||||
void LowerAllLetters(MPD::MutableSong &s);
|
void LowerAllLetters(MPD::MutableSong &s);
|
||||||
void GetTagList(TagLib::StringList &list, const MPD::MutableSong &s, MPD::Song::GetFunction f);
|
|
||||||
|
|
||||||
template <typename T>
|
TagLib::StringList tagList(const MPD::MutableSong &s, MPD::Song::GetFunction f);
|
||||||
void WriteID3v2(const TagLib::ByteVector &type, TagLib::ID3v2::Tag *tag, const T &list);
|
|
||||||
void WriteXiphComments(const MPD::MutableSong &s, TagLib::Ogg::XiphComment *tag);
|
void clearID3v1Tags(TagLib::ID3v1::Tag *tag);
|
||||||
|
void writeCommonTags(const MPD::MutableSong &s, TagLib::Tag *tag);
|
||||||
|
void writeID3v2Tags(const MPD::MutableSong &s, TagLib::ID3v2::Tag *tag);
|
||||||
|
void writeXiphComments(const MPD::MutableSong &s, TagLib::Ogg::XiphComment *tag);
|
||||||
|
|
||||||
void GetPatternList();
|
void GetPatternList();
|
||||||
void SavePatternList();
|
void SavePatternList();
|
||||||
@@ -1039,43 +1042,21 @@ bool TagEditor::WriteTags(MPD::MutableSong &s)
|
|||||||
TagLib::FileRef f(path_to_file.c_str());
|
TagLib::FileRef f(path_to_file.c_str());
|
||||||
if (!f.isNull())
|
if (!f.isNull())
|
||||||
{
|
{
|
||||||
f.tag()->setTitle(ToWString(s.getTitle()));
|
if (auto mp3_file = dynamic_cast<TagLib::MPEG::File *>(f.file()))
|
||||||
f.tag()->setArtist(ToWString(s.getArtist()));
|
|
||||||
f.tag()->setAlbum(ToWString(s.getAlbum()));
|
|
||||||
f.tag()->setYear(stringToInt(s.getDate()));
|
|
||||||
f.tag()->setTrack(stringToInt(s.getTrack()));
|
|
||||||
f.tag()->setGenre(ToWString(s.getGenre()));
|
|
||||||
f.tag()->setComment(ToWString(s.getComment()));
|
|
||||||
if (TagLib::MPEG::File *mp3_file = dynamic_cast<TagLib::MPEG::File *>(f.file()))
|
|
||||||
{
|
{
|
||||||
TagLib::ID3v2::Tag *tag = mp3_file->ID3v2Tag(1);
|
clearID3v1Tags(mp3_file->ID3v1Tag());
|
||||||
TagLib::StringList list;
|
writeID3v2Tags(s, mp3_file->ID3v2Tag(true));
|
||||||
|
|
||||||
WriteID3v2("TIT2", tag, ToWString(s.getTitle())); // title
|
|
||||||
WriteID3v2("TPE1", tag, ToWString(s.getArtist())); // artist
|
|
||||||
WriteID3v2("TALB", tag, ToWString(s.getAlbum())); // album
|
|
||||||
WriteID3v2("TDRC", tag, ToWString(s.getDate())); // date
|
|
||||||
WriteID3v2("TRCK", tag, ToWString(s.getTrack())); // track
|
|
||||||
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
|
|
||||||
|
|
||||||
GetTagList(list, s, &MPD::Song::getPerformer);
|
|
||||||
WriteID3v2("TPE3", tag, list); // performer
|
|
||||||
}
|
}
|
||||||
else if (TagLib::Ogg::Vorbis::File *ogg_file = dynamic_cast<TagLib::Ogg::Vorbis::File *>(f.file()))
|
else if (auto ogg_file = dynamic_cast<TagLib::Ogg::Vorbis::File *>(f.file()))
|
||||||
{
|
{
|
||||||
WriteXiphComments(s, ogg_file->tag());
|
writeXiphComments(s, ogg_file->tag());
|
||||||
}
|
}
|
||||||
else if (TagLib::FLAC::File *flac_file = dynamic_cast<TagLib::FLAC::File *>(f.file()))
|
else if (auto flac_file = dynamic_cast<TagLib::FLAC::File *>(f.file()))
|
||||||
{
|
{
|
||||||
WriteXiphComments(s, flac_file->xiphComment(1));
|
writeXiphComments(s, flac_file->xiphComment(true));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
writeCommonTags(s, f.tag());
|
||||||
if (!f.save())
|
if (!f.save())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -1155,43 +1136,76 @@ void LowerAllLetters(MPD::MutableSong &s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetTagList(TagLib::StringList &list, const MPD::MutableSong &s, MPD::Song::GetFunction f)
|
TagLib::StringList tagList(const MPD::MutableSong &s, MPD::Song::GetFunction f)
|
||||||
{
|
{
|
||||||
list.clear();
|
TagLib::StringList result;
|
||||||
unsigned pos = 0;
|
unsigned idx = 0;
|
||||||
for (std::string value; !(value = (s.*f)(pos)).empty(); ++pos)
|
for (std::string value; !(value = (s.*f)(idx)).empty(); ++idx)
|
||||||
list.append(ToWString(value));
|
result.append(ToWString(value));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void WriteID3v2(const TagLib::ByteVector &type, TagLib::ID3v2::Tag *tag, const T &list)
|
void clearID3v1Tags(TagLib::ID3v1::Tag *tag)
|
||||||
{
|
{
|
||||||
using TagLib::ID3v2::TextIdentificationFrame;
|
tag->setTitle(TagLib::String::null);
|
||||||
tag->removeFrames(type);
|
tag->setArtist(TagLib::String::null);
|
||||||
TextIdentificationFrame *frame = new TextIdentificationFrame(type, TagLib::String::UTF8);
|
tag->setAlbum(TagLib::String::null);
|
||||||
frame->setText(list);
|
tag->setYear(0);
|
||||||
tag->addFrame(frame);
|
tag->setTrack(0);
|
||||||
|
tag->setGenre(TagLib::String::null);
|
||||||
|
tag->setComment(TagLib::String::null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteXiphComments(const MPD::MutableSong &s, TagLib::Ogg::XiphComment *tag)
|
void writeCommonTags(const MPD::MutableSong &s, TagLib::Tag *tag)
|
||||||
{
|
{
|
||||||
TagLib::StringList list;
|
tag->setTitle(ToWString(s.getTitle()));
|
||||||
|
tag->setArtist(ToWString(s.getArtist()));
|
||||||
tag->addField("DISCNUMBER", ToWString(s.getDisc())); // disc
|
tag->setAlbum(ToWString(s.getAlbum()));
|
||||||
|
tag->setYear(stringToInt(s.getDate()));
|
||||||
tag->removeField("ALBUM ARTIST"); // album artist
|
tag->setTrack(stringToInt(s.getTrack()));
|
||||||
GetTagList(list, s, &MPD::Song::getAlbumArtist);
|
tag->setGenre(ToWString(s.getGenre()));
|
||||||
for (TagLib::StringList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
tag->setComment(ToWString(s.getComment()));
|
||||||
tag->addField("ALBUM ARTIST", *it, 0);
|
}
|
||||||
|
|
||||||
tag->removeField("COMPOSER"); // composer
|
void writeID3v2Tags(const MPD::MutableSong &s, TagLib::ID3v2::Tag *tag)
|
||||||
GetTagList(list, s, &MPD::Song::getComposer);
|
{
|
||||||
for (TagLib::StringList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
auto writeID3v2 = [&](const TagLib::ByteVector &type, const TagLib::StringList &list) {
|
||||||
tag->addField("COMPOSER", *it, 0);
|
tag->removeFrames(type);
|
||||||
|
auto frame = new TagLib::ID3v2::TextIdentificationFrame(type, TagLib::String::UTF8);
|
||||||
tag->removeField("PERFORMER"); // performer
|
frame->setText(list);
|
||||||
GetTagList(list, s, &MPD::Song::getPerformer);
|
tag->addFrame(frame);
|
||||||
for (TagLib::StringList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
};
|
||||||
tag->addField("PERFORMER", *it, 0);
|
writeID3v2("TIT2", tagList(s, &MPD::Song::getTitle));
|
||||||
|
writeID3v2("TPE1", tagList(s, &MPD::Song::getArtist));
|
||||||
|
writeID3v2("TPE2", tagList(s, &MPD::Song::getAlbumArtist));
|
||||||
|
writeID3v2("TALB", tagList(s, &MPD::Song::getAlbum));
|
||||||
|
writeID3v2("TDRC", tagList(s, &MPD::Song::getDate));
|
||||||
|
writeID3v2("TRCK", tagList(s, &MPD::Song::getTrack));
|
||||||
|
writeID3v2("TCON", tagList(s, &MPD::Song::getGenre));
|
||||||
|
writeID3v2("TCOM", tagList(s, &MPD::Song::getComposer));
|
||||||
|
writeID3v2("TPE3", tagList(s, &MPD::Song::getPerformer));
|
||||||
|
writeID3v2("TPOS", tagList(s, &MPD::Song::getDisc));
|
||||||
|
writeID3v2("COMM", tagList(s, &MPD::Song::getComment));
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeXiphComments(const MPD::MutableSong &s, TagLib::Ogg::XiphComment *tag)
|
||||||
|
{
|
||||||
|
auto writeXiph = [&](const TagLib::String &type, const TagLib::StringList &list) {
|
||||||
|
tag->removeField(type);
|
||||||
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
|
tag->addField(type, *it, false);
|
||||||
|
};
|
||||||
|
writeXiph("TITLE", tagList(s, &MPD::Song::getTitle));
|
||||||
|
writeXiph("ARTIST", tagList(s, &MPD::Song::getArtist));
|
||||||
|
writeXiph("ALBUM ARTIST", tagList(s, &MPD::Song::getAlbumArtist));
|
||||||
|
writeXiph("ALBUM", tagList(s, &MPD::Song::getAlbum));
|
||||||
|
writeXiph("DATE", tagList(s, &MPD::Song::getDate));
|
||||||
|
writeXiph("TRACKNUMBER", tagList(s, &MPD::Song::getTrack));
|
||||||
|
writeXiph("GENRE", tagList(s, &MPD::Song::getGenre));
|
||||||
|
writeXiph("COMPOSER", tagList(s, &MPD::Song::getComposer));
|
||||||
|
writeXiph("PERFORMER", tagList(s, &MPD::Song::getPerformer));
|
||||||
|
writeXiph("DISC", tagList(s, &MPD::Song::getDisc));
|
||||||
|
writeXiph("COMMENT", tagList(s, &MPD::Song::getComment));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetPatternList()
|
void GetPatternList()
|
||||||
|
|||||||
Reference in New Issue
Block a user