From 77c6a22962948e06513a86a9a9232300bf5b6dc9 Mon Sep 17 00:00:00 2001 From: Arnaud Bienner Date: Fri, 15 Mar 2013 22:54:59 +0100 Subject: [PATCH] Write/Read score to/from files' tags, as "Amarok score" as we use the same algorithm --- ext/libclementine-tagreader/tagreader.cpp | 28 +++++++++++++++++++++++ ext/libclementine-tagreader/tagreader.h | 1 + tests/song_test.cpp | 21 +++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/ext/libclementine-tagreader/tagreader.cpp b/ext/libclementine-tagreader/tagreader.cpp index 69a7d9f29..1bd91c024 100644 --- a/ext/libclementine-tagreader/tagreader.cpp +++ b/ext/libclementine-tagreader/tagreader.cpp @@ -101,6 +101,7 @@ TagLib::String QStringToTaglibString(const QString& s) { const char* TagReader::kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating"; const char* TagReader::kMP4_FMPS_Playcount_ID = "----:com.apple.iTunes:FMPS_Playcount"; +const char* TagReader::kMP4_FMPS_Score_ID = "----:com.apple.iTunes:FMPS_Rating_Amarok_Score"; TagReader::TagReader() : factory_(new TagLibFileRefFactory), @@ -262,6 +263,12 @@ void TagReader::ReadFile(const QString& filename, song->set_playcount(playcount); } } + if (items.contains(kMP4_FMPS_Playcount_ID)) { + int score = TStringToQString(items[kMP4_FMPS_Score_ID].toStringList().toString('\n')).toFloat() * 100; + if (song->score() <= 0 && score > 0) { + song->set_score(score); + } + } if(items.contains("\251wrt")) { Decode(items["\251wrt"].toStringList().toString(", "), NULL, song->mutable_composer()); @@ -293,6 +300,15 @@ void TagReader::ReadFile(const QString& filename, } } } + if (attributes_map.contains("FMPS/Rating_Amarok_Score")) { + const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating_Amarok_Score"]; + if (!attributes.isEmpty()) { + int score = TStringToQString(attributes.front().toString()).toFloat() * 100; + if (song->score() <= 0 && score > 0) { + song->set_score(score); + } + } + } } #endif else if (tag) { @@ -398,6 +414,11 @@ void TagReader::ParseFMPSFrame(const QString& name, const QString& value, song->set_playcount(var.toDouble()); } } + } else if (name == "FMPS_Rating_Amarok_Score") { + var = parser.result()[0][0]; + if (var.type() == QVariant::Double) { + song->set_score(var.toDouble() * 100); + } } } @@ -435,6 +456,9 @@ void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap& map, if (!map["FMPS_PLAYCOUNT"].isEmpty() && song->playcount() <= 0) song->set_playcount(TStringToQString( map["FMPS_PLAYCOUNT"].front() ).trimmed().toFloat()); + + if (!map["FMPS_RATING_AMAROK_SCORE"].isEmpty() && song->score() <= 0) + song->set_score(TStringToQString( map["FMPS_RATING_AMAROK_SCORE"].front() ).trimmed().toFloat() * 100); } void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments, @@ -453,6 +477,7 @@ void TagReader::SetFMPSVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments, vorbis_comments->addField("FMPS_RATING", QStringToTaglibString(QString::number(song.rating()))); vorbis_comments->addField("FMPS_PLAYCOUNT", QStringToTaglibString(QString::number(song.playcount()))); + vorbis_comments->addField("FMPS_RATING_AMAROK_SCORE", QStringToTaglibString(QString::number(song.score() / 100.0))); } pb::tagreader::SongMetadata_Type TagReader::GuessFileType( @@ -570,6 +595,7 @@ bool TagReader::SaveSongStatisticsToFile(const QString& filename, // Save as FMPS SetUserTextFrame("FMPS_Rating", QString::number(song.rating()), tag); SetUserTextFrame("FMPS_PlayCount", QString::number(song.playcount()), tag); + SetUserTextFrame("FMPS_Rating_Amarok_Score", QString::number(song.score() / 100.0), tag); // Also save as POPM TagLib::ID3v2::PopularimeterFrame* frame = NULL; @@ -599,12 +625,14 @@ bool TagReader::SaveSongStatisticsToFile(const QString& filename, #define ConvertASF(x) TagLib::ASF::Attribute(QStringToTaglibString(QString::number(x))) tag->addAttribute("FMPS/Rating", ConvertASF(song.rating())); tag->addAttribute("FMPS/Playcount", ConvertASF(song.playcount())); + tag->addAttribute("FMPS/Rating_Amarok_Score", ConvertASF(song.score() / 100.0)); #undef ConvertASF } #endif else if (TagLib::MP4::File* file = dynamic_cast(fileref->file())) { TagLib::MP4::Tag* tag = file->tag(); tag->itemListMap()[kMP4_FMPS_Rating_ID] = TagLib::StringList(QStringToTaglibString(QString::number(song.rating()))); + tag->itemListMap()[kMP4_FMPS_Score_ID] = TagLib::StringList(QStringToTaglibString(QString::number(song.score() / 100.0))); tag->itemListMap()[kMP4_FMPS_Playcount_ID] = TagLib::StringList(TagLib::String::number(song.playcount())); } else { // Nothing to save: stop now diff --git a/ext/libclementine-tagreader/tagreader.h b/ext/libclementine-tagreader/tagreader.h index 33754ec64..3efa004f4 100644 --- a/ext/libclementine-tagreader/tagreader.h +++ b/ext/libclementine-tagreader/tagreader.h @@ -100,6 +100,7 @@ class TagReader { private: static const char* kMP4_FMPS_Rating_ID; static const char* kMP4_FMPS_Playcount_ID; + static const char* kMP4_FMPS_Score_ID; // Returns a float in [0.0..1.0] corresponding to the rating range we use in Clementine static float ConvertPOPMRating(const int POPM_rating); // Reciprocal diff --git a/tests/song_test.cpp b/tests/song_test.cpp index 0c5371ccb..1e2613c5a 100644 --- a/tests/song_test.cpp +++ b/tests/song_test.cpp @@ -146,6 +146,19 @@ TEST_F(SongTest, FMPSPlayCountBoth) { EXPECT_EQ(123, song.playcount()); } +TEST_F(SongTest, FMPSScore) { + TemporaryResource r(":/testdata/beep.mp3"); + { + Song song = ReadSongFromFile(r.fileName()); + song.set_score(43); + + WriteSongStatisticsToFile(song, r.fileName()); + } + + Song new_song = ReadSongFromFile(r.fileName()); + EXPECT_FLOAT_EQ(43, new_song.score()); +} + TEST_F(SongTest, POPMRating) { TemporaryResource r(":/testdata/popmrating.mp3"); Song song = ReadSongFromFile(r.fileName()); @@ -166,6 +179,7 @@ TEST_F(SongTest, RatingAndStatisticsOgg) { Song song = ReadSongFromFile(r.fileName()); song.set_rating(0.20); song.set_playcount(1337); + song.set_score(87); WriteSongStatisticsToFile(song, r.fileName()); } @@ -173,6 +187,7 @@ TEST_F(SongTest, RatingAndStatisticsOgg) { Song new_song = ReadSongFromFile(r.fileName()); EXPECT_FLOAT_EQ(0.20, new_song.rating()); EXPECT_EQ(1337, new_song.playcount()); + EXPECT_EQ(87, new_song.score()); } TEST_F(SongTest, RatingAndStatisticsFLAC) { @@ -181,6 +196,7 @@ TEST_F(SongTest, RatingAndStatisticsFLAC) { Song song = ReadSongFromFile(r.fileName()); song.set_rating(0.20); song.set_playcount(1337); + song.set_score(87); WriteSongStatisticsToFile(song, r.fileName()); } @@ -188,6 +204,7 @@ TEST_F(SongTest, RatingAndStatisticsFLAC) { Song new_song = ReadSongFromFile(r.fileName()); EXPECT_FLOAT_EQ(0.20, new_song.rating()); EXPECT_EQ(1337, new_song.playcount()); + EXPECT_EQ(87, new_song.score()); } #ifdef TAGLIB_WITH_ASF @@ -197,6 +214,7 @@ TEST_F(SongTest, RatingAndStatisticsASF) { Song song = ReadSongFromFile(r.fileName()); song.set_rating(0.20); song.set_playcount(1337); + song.set_score(87); WriteSongStatisticsToFile(song, r.fileName()); } @@ -204,6 +222,7 @@ TEST_F(SongTest, RatingAndStatisticsASF) { Song new_song = ReadSongFromFile(r.fileName()); EXPECT_FLOAT_EQ(0.20, new_song.rating()); EXPECT_EQ(1337, new_song.playcount()); + EXPECT_EQ(87, new_song.score()); } #endif // TAGLIB_WITH_ASF @@ -213,6 +232,7 @@ TEST_F(SongTest, RatingAndStatisticsMP4) { Song song = ReadSongFromFile(r.fileName()); song.set_rating(0.20); song.set_playcount(1337); + song.set_score(87); WriteSongStatisticsToFile(song, r.fileName()); } @@ -220,6 +240,7 @@ TEST_F(SongTest, RatingAndStatisticsMP4) { Song new_song = ReadSongFromFile(r.fileName()); EXPECT_FLOAT_EQ(0.20, new_song.rating()); EXPECT_EQ(1337, new_song.playcount()); + EXPECT_EQ(87, new_song.score()); } } // namespace