void TagReader::SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const { TagLib::ByteVector id_vector("USLT"); QVector<TagLib::ByteVector> frames_buffer; // Store and clear existing frames while (tag->frameListMap().contains(id_vector) && tag->frameListMap()[id_vector].size() != 0) { frames_buffer.push_back(tag->frameListMap()[id_vector].front()->render()); tag->removeFrame(tag->frameListMap()[id_vector].front()); } // If no frames stored create empty frame if (frames_buffer.isEmpty()) { TagLib::ID3v2::UnsynchronizedLyricsFrame frame(TagLib::String::UTF8); frame.setDescription("Clementine editor"); frames_buffer.push_back(frame.render()); } // Update and add the frames for (int lyrics_index = 0; lyrics_index < frames_buffer.size(); lyrics_index++) { TagLib::ID3v2::UnsynchronizedLyricsFrame* frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame( frames_buffer.at(lyrics_index)); if (lyrics_index == 0) { frame->setText(StdStringToTaglibString(value)); } // add frame takes ownership and clears the memory tag->addFrame(frame); } }
void TagReader::SetUserTextFrame(const std::string& description, const std::string& value, TagLib::ID3v2::Tag* tag) const { const TagLib::String t_description = StdStringToTaglibString(description); // Remove the frame if it already exists TagLib::ID3v2::UserTextIdentificationFrame* frame = TagLib::ID3v2::UserTextIdentificationFrame::find(tag, t_description); if (frame) { tag->removeFrame(frame); } // Create and add a new frame frame = new TagLib::ID3v2::UserTextIdentificationFrame(TagLib::String::UTF8); frame->setDescription(t_description); frame->setText(StdStringToTaglibString(value)); tag->addFrame(frame); }
void TagReader::SetVorbisComments( TagLib::Ogg::XiphComment* vorbis_comments, const pb::tagreader::SongMetadata& song) const { vorbis_comments->addField("COMPOSER", StdStringToTaglibString(song.composer()), true); vorbis_comments->addField("PERFORMER", StdStringToTaglibString(song.performer()), true); vorbis_comments->addField("CONTENT GROUP", StdStringToTaglibString(song.grouping()), true); vorbis_comments->addField( "BPM", QStringToTaglibString(song.bpm() <= 0 - 1 ? QString() : QString::number(song.bpm())), true); vorbis_comments->addField( "DISCNUMBER", QStringToTaglibString( song.disc() <= 0 - 1 ? QString() : QString::number(song.disc())), true); vorbis_comments->addField( "COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"), true); // Try to be coherent, the two forms are used but the first one is preferred vorbis_comments->addField("ALBUMARTIST", StdStringToTaglibString(song.albumartist()), true); vorbis_comments->removeField("ALBUM ARTIST"); vorbis_comments->addField("LYRICS", StdStringToTaglibString(song.lyrics()), true); vorbis_comments->removeField("UNSYNCEDLYRICS"); }
void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments, const pb::tagreader::SongMetadata& song) const { vorbis_comments->addField("COMPOSER", StdStringToTaglibString(song.composer()), true); vorbis_comments->addField("PERFORMER", StdStringToTaglibString(song.performer()), true); vorbis_comments->addField("CONTENT GROUP", StdStringToTaglibString(song.grouping()), true); vorbis_comments->addField( "BPM", QStringToTaglibString( song.bpm() <= 0 - 1 ? QString() : QString::number(song.bpm())), true); vorbis_comments->addField( "DISCNUMBER", QStringToTaglibString( song.disc() <= 0 - 1 ? QString() : QString::number(song.disc())), true); vorbis_comments->addField( "COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"), true); }
void TagReader::SetTextFrame(const char* id, const std::string& value, TagLib::ID3v2::Tag* tag) const { TagLib::ByteVector id_vector(id); // Remove the frame if it already exists while (tag->frameListMap().contains(id_vector) && tag->frameListMap()[id_vector].size() != 0) { tag->removeFrame(tag->frameListMap()[id_vector].front()); } // Create and add a new frame TagLib::ID3v2::TextIdentificationFrame* frame = new TagLib::ID3v2::TextIdentificationFrame(id_vector, TagLib::String::UTF8); frame->setText(StdStringToTaglibString(value)); tag->addFrame(frame); }
bool TagReader::SaveFile(const QString& filename, const pb::tagreader::SongMetadata& song) const { if (filename.isNull()) return false; qLog(Debug) << "Saving tags to" << filename; std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) // The file probably doesn't exist return false; fileref->tag()->setTitle(StdStringToTaglibString(song.title())); fileref->tag()->setArtist(StdStringToTaglibString(song.artist())); // TPE1 fileref->tag()->setAlbum(StdStringToTaglibString(song.album())); fileref->tag()->setGenre(StdStringToTaglibString(song.genre())); fileref->tag()->setComment(StdStringToTaglibString(song.comment())); fileref->tag()->setYear(song.year()); fileref->tag()->setTrack(song.track()); if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) { TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true); SetTextFrame( "TPOS", song.disc() <= 0 - 1 ? QString() : QString::number(song.disc()), tag); SetTextFrame("TBPM", song.bpm() <= 0 - 1 ? QString() : QString::number(song.bpm()), tag); SetTextFrame("TCOM", song.composer(), tag); SetTextFrame("TIT1", song.grouping(), tag); // Skip TPE1 (which is the artist) here because we already set it SetTextFrame("TPE2", song.albumartist(), tag); SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag); } else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) { TagLib::Ogg::XiphComment* tag = file->xiphComment(); SetVorbisComments(tag, song); } else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) { TagLib::MP4::Tag* tag = file->tag(); tag->itemListMap()["disk"] = TagLib::MP4::Item(song.disc() <= 0 - 1 ? 0 : song.disc(), 0); tag->itemListMap()["tmpo"] = TagLib::StringList( song.bpm() <= 0 - 1 ? "0" : TagLib::String::number(song.bpm())); tag->itemListMap()["\251wrt"] = TagLib::StringList(song.composer()); tag->itemListMap()["\251grp"] = TagLib::StringList(song.grouping()); tag->itemListMap()["aART"] = TagLib::StringList(song.albumartist()); tag->itemListMap()["cpil"] = TagLib::StringList(song.compilation() ? "1" : "0"); } // Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same // way; // apart, so we keep specific behavior for some formats by adding another // "else if" block above. if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) { SetVorbisComments(tag, song); } bool ret = fileref->save(); #ifdef Q_OS_LINUX if (ret) { // Linux: inotify doesn't seem to notice the change to the file unless we // change the timestamps as well. (this is what touch does) utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0); } #endif // Q_OS_LINUX return ret; }