From b0d643cbd95a634926320d54577fa7c467dca2cf Mon Sep 17 00:00:00 2001 From: Arnaud Bienner Date: Sat, 2 Mar 2013 00:03:51 +0100 Subject: [PATCH] Save/read FMPS tags to/from FLAC using Vorbis comments + some refactoring to parse VorbisComments in a unique place, when possible. --- ext/libclementine-tagreader/tagreader.cpp | 84 +++++++++++------------ ext/libclementine-tagreader/tagreader.h | 5 ++ tests/song_test.cpp | 17 ++++- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/ext/libclementine-tagreader/tagreader.cpp b/ext/libclementine-tagreader/tagreader.cpp index de61e0b12..53f3326db 100644 --- a/ext/libclementine-tagreader/tagreader.cpp +++ b/ext/libclementine-tagreader/tagreader.cpp @@ -137,6 +137,14 @@ void TagReader::ReadFile(const QString& filename, QString disc; QString compilation; + + // 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 below. + if (TagLib::Ogg::XiphComment* tag = dynamic_cast(fileref->file()->tag())) { + ParseOggTag(tag->fieldListMap(), NULL, &disc, &compilation, song); + } + if (TagLib::MPEG::File* file = dynamic_cast(fileref->file())) { if (file->ID3v2Tag()) { const TagLib::ID3v2::FrameListMap& map = file->ID3v2Tag()->frameListMap(); @@ -200,21 +208,7 @@ void TagReader::ReadFile(const QString& filename, } } - } else if (TagLib::Ogg::Vorbis::File* file = dynamic_cast(fileref->file())) { - if (file->tag()) { - ParseOggTag(file->tag()->fieldListMap(), NULL, &disc, &compilation, song); - } - Decode(tag->comment(), NULL, song->mutable_comment()); - } -#ifdef TAGLIB_HAS_OPUS - else if (TagLib::Ogg::Opus::File* file = dynamic_cast(fileref->file())) { - if (file->tag()) { - ParseOggTag(file->tag()->fieldListMap(), NULL, &disc, &compilation, song); - } - Decode(tag->comment(), NULL, song->mutable_comment()); - } -#endif - else if (TagLib::FLAC::File* file = dynamic_cast(fileref->file())) { + } else if (TagLib::FLAC::File* file = dynamic_cast(fileref->file())) { if ( file->xiphComment() ) { ParseOggTag(file->xiphComment()->fieldListMap(), NULL, &disc, &compilation, song); #ifdef TAGLIB_HAS_FLAC_PICTURELIST @@ -390,6 +384,23 @@ void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap& map, song->set_playcount(TStringToQString( map["FMPS_PLAYCOUNT"].front() ).trimmed().toFloat()); } + +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("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::SetFMPSVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments, + const pb::tagreader::SongMetadata& song) const { + + vorbis_comments->addField("FMPS_RATING", QStringToTaglibString(QString::number(song.rating()))); + vorbis_comments->addField("FMPS_PLAYCOUNT", QStringToTaglibString(QString::number(song.playcount()))); +} + pb::tagreader::SongMetadata_Type TagReader::GuessFileType( TagLib::FileRef* fileref) const { #ifdef TAGLIB_WITH_ASF @@ -453,29 +464,9 @@ bool TagReader::SaveFile(const QString& filename, SetTextFrame("TCOM", song.composer(), tag); SetTextFrame("TPE2", song.albumartist(), tag); SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag); - } - else if (TagLib::Ogg::Vorbis::File* file = dynamic_cast(fileref->file())) { - TagLib::Ogg::XiphComment* tag = file->tag(); - tag->addField("COMPOSER", StdStringToTaglibString(song.composer()), true); - tag->addField("BPM", QStringToTaglibString(song.bpm() <= 0 -1 ? QString() : QString::number(song.bpm())), true); - tag->addField("DISCNUMBER", QStringToTaglibString(song.disc() <= 0 -1 ? QString() : QString::number(song.disc())), true); - tag->addField("COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"), true); - } -#ifdef TAGLIB_HAS_OPUS - else if (TagLib::Ogg::Opus::File* file = dynamic_cast(fileref->file())) { - TagLib::Ogg::XiphComment* tag = file->tag(); - tag->addField("COMPOSER", StdStringToTaglibString(song.composer()), true); - tag->addField("BPM", QStringToTaglibString(song.bpm() <= 0 -1 ? QString() : QString::number(song.bpm())), true); - tag->addField("DISCNUMBER", QStringToTaglibString(song.disc() <= 0 -1 ? QString() : QString::number(song.disc())), true); - tag->addField("COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"), true); - } -#endif - else if (TagLib::FLAC::File* file = dynamic_cast(fileref->file())) { + } else if (TagLib::FLAC::File* file = dynamic_cast(fileref->file())) { TagLib::Ogg::XiphComment* tag = file->xiphComment(); - tag->addField("COMPOSER", StdStringToTaglibString(song.composer()), true); - tag->addField("BPM", QStringToTaglibString(song.bpm() <= 0 -1 ? QString() : QString::number(song.bpm())), true); - tag->addField("DISCNUMBER", QStringToTaglibString(song.disc() <= 0 -1 ? QString() : QString::number(song.disc())), true); - tag->addField("COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"), true); + SetVorbisComments(tag, song); } else if (TagLib::MP4::File* file = dynamic_cast(fileref->file())) { TagLib::MP4::Tag* tag = file->tag(); tag->itemListMap()["disk"] = TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0); @@ -485,6 +476,13 @@ bool TagReader::SaveFile(const QString& filename, 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(fileref->file()->tag())) { + SetVorbisComments(tag, song); + } + bool ret = fileref->save(); #ifdef Q_OS_LINUX if (ret) { @@ -532,13 +530,11 @@ bool TagReader::SaveSongStatisticsToFile(const QString& filename, frame->setRating(ConvertToPOPMRating(song.rating())); frame->setCounter(song.playcount()); - } else if (TagLib::Ogg::Vorbis::File* file = dynamic_cast(fileref->file())) { - if (file->tag()) { - file->tag()->addField("FMPS_RATING", - QStringToTaglibString(QString::number(song.rating()))); - file->tag()->addField("FMPS_PLAYCOUNT", - QStringToTaglibString(QString::number(song.playcount()))); - } + } else if (TagLib::FLAC::File* file = dynamic_cast(fileref->file())) { + TagLib::Ogg::XiphComment* vorbis_comments = file->xiphComment(true); + SetFMPSVorbisComments(vorbis_comments, song); + } else if (TagLib::Ogg::XiphComment* tag = dynamic_cast(fileref->file()->tag())) { + SetFMPSVorbisComments(tag, song); } else { // Nothing to save: stop now return true; diff --git a/ext/libclementine-tagreader/tagreader.h b/ext/libclementine-tagreader/tagreader.h index e21384dac..3ae40a9a5 100644 --- a/ext/libclementine-tagreader/tagreader.h +++ b/ext/libclementine-tagreader/tagreader.h @@ -80,6 +80,11 @@ class TagReader { const QTextCodec* codec, QString* disc, QString* compilation, pb::tagreader::SongMetadata* song) const; + void SetVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments, + const pb::tagreader::SongMetadata& song) const; + void SetFMPSVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments, + const pb::tagreader::SongMetadata& song) const; + pb::tagreader::SongMetadata_Type GuessFileType(TagLib::FileRef* fileref) const; void SetUserTextFrame(const QString& description, const QString& value, diff --git a/tests/song_test.cpp b/tests/song_test.cpp index 2d31ecccd..82fa5393d 100644 --- a/tests/song_test.cpp +++ b/tests/song_test.cpp @@ -160,7 +160,7 @@ TEST_F(SongTest, BothFMPSPOPMRating) { EXPECT_FLOAT_EQ(0.42, song.rating()); } -TEST_F(SongTest, FMPSOgg) { +TEST_F(SongTest, RatingAndStatisticsOgg) { TemporaryResource r(":/testdata/beep.ogg"); { Song song = ReadSongFromFile(r.fileName()); @@ -175,4 +175,19 @@ TEST_F(SongTest, FMPSOgg) { EXPECT_EQ(1337, new_song.playcount()); } +TEST_F(SongTest, RatingAndStatisticsFLAC) { + TemporaryResource r(":/testdata/beep.flac"); + { + Song song = ReadSongFromFile(r.fileName()); + song.set_rating(0.20); + song.set_playcount(1337); + + WriteSongStatisticsToFile(song, r.fileName()); + } + + Song new_song = ReadSongFromFile(r.fileName()); + EXPECT_FLOAT_EQ(0.20, new_song.rating()); + EXPECT_EQ(1337, new_song.playcount()); +} + } // namespace