Write/Read score to/from files' tags, as "Amarok score" as we use the same algorithm

This commit is contained in:
Arnaud Bienner 2013-03-15 22:54:59 +01:00
parent dc208962f6
commit 77c6a22962
3 changed files with 50 additions and 0 deletions

View File

@ -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<TagLib::MP4::File*>(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

View File

@ -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

View File

@ -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