예제 #1
0
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);
  }
}
예제 #2
0
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);
}
예제 #3
0
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");
}
예제 #4
0
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);
}
예제 #5
0
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);
}
예제 #6
0
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;
}