Changeset View
Changeset View
Standalone View
Standalone View
src/extractors/taglibextractor.cpp
Show All 31 Lines | |||||
32 | #include <oggfile.h> | 32 | #include <oggfile.h> | ||
33 | #include <mp4file.h> | 33 | #include <mp4file.h> | ||
34 | #include <mp4tag.h> | 34 | #include <mp4tag.h> | ||
35 | #include <taglib.h> | 35 | #include <taglib.h> | ||
36 | #include <tag.h> | 36 | #include <tag.h> | ||
37 | #include <vorbisfile.h> | 37 | #include <vorbisfile.h> | ||
38 | #include <opusfile.h> | 38 | #include <opusfile.h> | ||
39 | #include <xiphcomment.h> | 39 | #include <xiphcomment.h> | ||
40 | 40 | #include <popularimeterframe.h> | |||
41 | #include <QDateTime> | 41 | #include <QDateTime> | ||
42 | #include <QDebug> | 42 | #include <QDebug> | ||
43 | 43 | | |||
44 | using namespace KFileMetaData; | 44 | using namespace KFileMetaData; | ||
45 | 45 | | |||
46 | static QString convertWCharsToQString(const TagLib::String& t) | 46 | static QString convertWCharsToQString(const TagLib::String& t) | ||
47 | { | 47 | { | ||
48 | return QString::fromWCharArray((const wchar_t*)t.toCWString(), t.length()); | 48 | return QString::fromWCharArray((const wchar_t*)t.toCWString(), t.length()); | ||
▲ Show 20 Lines • Show All 154 Lines • ▼ Show 20 Line(s) | 77 | { | |||
203 | if (!lstID3v2.isEmpty()) { | 203 | if (!lstID3v2.isEmpty()) { | ||
204 | for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { | 204 | for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { | ||
205 | if (!data.compilation.isEmpty()) { | 205 | if (!data.compilation.isEmpty()) { | ||
206 | data.compilation += ", "; | 206 | data.compilation += ", "; | ||
207 | } | 207 | } | ||
208 | data.compilation += (*it)->toString(); | 208 | data.compilation += (*it)->toString(); | ||
209 | } | 209 | } | ||
210 | } | 210 | } | ||
211 | | ||||
212 | // Rating. | ||||
213 | /* There is no standard regarding ratings. Most of the implementations match | ||||
214 | a 5 stars rating to a range of 0-255 for MP3. | ||||
215 | Match it to baloo rating with a range of 0 - 10 */ | ||||
216 | lstID3v2 = mpegFile.ID3v2Tag()->frameListMap()["POPM"]; | ||||
217 | if (!lstID3v2.isEmpty()) { | ||||
218 | for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { | ||||
219 | TagLib::ID3v2::PopularimeterFrame *ratingFrame = static_cast<TagLib::ID3v2::PopularimeterFrame *>(*it); | ||||
220 | int rating = ratingFrame->rating(); | ||||
221 | if (rating == 0) { | ||||
222 | data.rating = 0; | ||||
223 | } else if (rating == 1) { | ||||
224 | TagLib::String ratingProvider = ratingFrame->email(); | ||||
225 | if (ratingProvider == "no@email" || ratingProvider == "org.kde.kfilemetadata") { | ||||
226 | data.rating = 1; | ||||
227 | } else { | ||||
228 | data.rating = 2; | ||||
229 | } | ||||
230 | } else if (rating >= 1 && rating <= 255) { | ||||
231 | data.rating = static_cast<int>(0.032 * rating + 2); | ||||
232 | } | ||||
233 | } | ||||
mgallien: You can and should be using all intermediate values. If I remember correctly, in dolphin, you… | |||||
The thing here is that the most common implementation don't allow half star ratings. Only Mediamonkey does it and that diverges from the rest. Also, the values are not distributed equidistantly, but I'll look into a more flexible solution. astippich: The thing here is that the most common implementation don't allow half star ratings. Only… | |||||
There is a "half interval" at the bottom and the top, every other interval is 64. rating = temp * 10 / 255 + 0.5; should work reasonably well, or, if you prefer a smaller 0 interval: rating = temp * 9.5 / 255 + 0.99; bruns: There is a "half interval" at the bottom and the top, every other interval is 64.
```
rating =… | |||||
234 | } | ||||
211 | //TODO handle TIPL tag | 235 | //TODO handle TIPL tag | ||
212 | } | 236 | } | ||
213 | 237 | | |||
214 | void TagLibExtractor::extractMP4(TagLib::FileStream& stream, ExtractedData& data) | 238 | void TagLibExtractor::extractMP4(TagLib::FileStream& stream, ExtractedData& data) | ||
215 | { | 239 | { | ||
216 | TagLib::MP4::File mp4File(&stream, true); | 240 | TagLib::MP4::File mp4File(&stream, true); | ||
217 | if (!mp4File.tag() || mp4File.tag()->isEmpty()) { | 241 | if (!mp4File.tag() || mp4File.tag()->isEmpty()) { | ||
218 | return; | 242 | return; | ||
Show All 26 Lines | 268 | if (itGenres != allTags.end()) { | |||
245 | data.genres = itGenres->second.toStringList().toString(", "); | 269 | data.genres = itGenres->second.toStringList().toString(", "); | ||
246 | } | 270 | } | ||
247 | 271 | | |||
248 | TagLib::String composerAtomName(TagLib::String("©wrt", TagLib::String::UTF8).to8Bit(), TagLib::String::Latin1); | 272 | TagLib::String composerAtomName(TagLib::String("©wrt", TagLib::String::UTF8).to8Bit(), TagLib::String::Latin1); | ||
249 | TagLib::MP4::ItemListMap::Iterator itComposers = allTags.find(composerAtomName); | 273 | TagLib::MP4::ItemListMap::Iterator itComposers = allTags.find(composerAtomName); | ||
250 | if (itComposers != allTags.end()) { | 274 | if (itComposers != allTags.end()) { | ||
251 | data.composers = itComposers->second.toStringList().toString(", "); | 275 | data.composers = itComposers->second.toStringList().toString(", "); | ||
252 | } | 276 | } | ||
277 | | ||||
278 | /* There is no standard regarding ratings. Mimic MediaMonkey's behavior | ||||
279 | with a range of 0 to 100 (stored in steps of 10) and make it compatible | ||||
280 | with baloo rating with a range from 0 to 10 */ | ||||
281 | TagLib::MP4::ItemListMap::Iterator itRating = allTags.find("rate"); | ||||
282 | if (itRating != allTags.end()) { | ||||
283 | data.rating = itRating->second.toStringList().toString().toInt() / 10; | ||||
284 | } | ||||
285 | | ||||
253 | } | 286 | } | ||
254 | 287 | | |||
255 | void TagLibExtractor::extractMusePack(TagLib::FileStream& stream, ExtractedData& data) | 288 | void TagLibExtractor::extractMusePack(TagLib::FileStream& stream, ExtractedData& data) | ||
256 | { | 289 | { | ||
257 | TagLib::MPC::File mpcFile(&stream, true); | 290 | TagLib::MPC::File mpcFile(&stream, true); | ||
258 | if (!mpcFile.tag() || mpcFile.tag()->isEmpty()) { | 291 | if (!mpcFile.tag() || mpcFile.tag()->isEmpty()) { | ||
259 | return; | 292 | return; | ||
260 | } | 293 | } | ||
▲ Show 20 Lines • Show All 141 Lines • ▼ Show 20 Line(s) | |||||
402 | if (itMPC != lstMusepack.end()) { | 435 | if (itMPC != lstMusepack.end()) { | ||
403 | data.discNumber = (*itMPC).second.toString().toInt(); | 436 | data.discNumber = (*itMPC).second.toString().toInt(); | ||
404 | } | 437 | } | ||
405 | 438 | | |||
406 | itMPC = lstMusepack.find("OPUS"); | 439 | itMPC = lstMusepack.find("OPUS"); | ||
407 | if (itMPC != lstMusepack.end()) { | 440 | if (itMPC != lstMusepack.end()) { | ||
408 | data.opus = (*itMPC).second.toString().toInt(); | 441 | data.opus = (*itMPC).second.toString().toInt(); | ||
409 | } | 442 | } | ||
443 | | ||||
444 | // Rating. | ||||
445 | itMPC = lstMusepack.find("RATING"); | ||||
446 | if (itMPC != lstMusepack.end()) { | ||||
447 | /* There is no standard regarding ratings. There is one implementation | ||||
448 | most seem to follow with a range of 0 to 100 (stored in steps of 10). | ||||
449 | Make it compatible with baloo rating with a range from 0 to 10 */ | ||||
450 | data.rating = (*itMPC).second.toString().toInt() / 10; | ||||
451 | } | ||||
410 | } | 452 | } | ||
411 | 453 | | |||
412 | void TagLibExtractor::extractOgg(TagLib::FileStream& stream, const QString& mimeType, ExtractedData& data) | 454 | void TagLibExtractor::extractOgg(TagLib::FileStream& stream, const QString& mimeType, ExtractedData& data) | ||
413 | { | 455 | { | ||
414 | TagLib::Ogg::FieldListMap lstOgg; | 456 | TagLib::Ogg::FieldListMap lstOgg; | ||
415 | 457 | | |||
416 | if (mimeType == QStringLiteral("audio/flac")) { | 458 | if (mimeType == QStringLiteral("audio/flac")) { | ||
417 | TagLib::FLAC::File flacFile(&stream, TagLib::ID3v2::FrameFactory::instance(), true); | 459 | TagLib::FLAC::File flacFile(&stream, TagLib::ID3v2::FrameFactory::instance(), true); | ||
▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Line(s) | 481 | if (!lstOgg.isEmpty()) { | |||
579 | if (itOgg != lstOgg.end()) { | 621 | if (itOgg != lstOgg.end()) { | ||
580 | data.discNumber = (*itOgg).second.toString("").toInt(); | 622 | data.discNumber = (*itOgg).second.toString("").toInt(); | ||
581 | } | 623 | } | ||
582 | 624 | | |||
583 | itOgg = lstOgg.find("OPUS"); | 625 | itOgg = lstOgg.find("OPUS"); | ||
584 | if (itOgg != lstOgg.end()) { | 626 | if (itOgg != lstOgg.end()) { | ||
585 | data.opus = (*itOgg).second.toString("").toInt(); | 627 | data.opus = (*itOgg).second.toString("").toInt(); | ||
586 | } | 628 | } | ||
629 | | ||||
630 | // Rating. | ||||
631 | itOgg = lstOgg.find("RATING"); | ||||
632 | if (itOgg != lstOgg.end()) { | ||||
633 | //there is no standard regarding ratings. There is one implementation | ||||
634 | //most seem to follow with a range of 0 to 100 (stored in steps of 10). | ||||
635 | //make it compatible with baloo rating with a range from 0 to 10 | ||||
636 | data.rating = (*itOgg).second.toString("").toInt() / 10; | ||||
637 | } | ||||
587 | } | 638 | } | ||
588 | } | 639 | } | ||
589 | 640 | | |||
590 | void TagLibExtractor::extract(ExtractionResult* result) | 641 | void TagLibExtractor::extract(ExtractionResult* result) | ||
591 | { | 642 | { | ||
592 | const QString fileUrl = result->inputUrl(); | 643 | const QString fileUrl = result->inputUrl(); | ||
593 | const QString mimeType = result->inputMimetype(); | 644 | const QString mimeType = result->inputMimetype(); | ||
594 | 645 | | |||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Line(s) | 680 | if (!tags->isEmpty()) { | |||
768 | if (data.opus.isValid()) { | 819 | if (data.opus.isValid()) { | ||
769 | result->add(Property::Opus, data.opus); | 820 | result->add(Property::Opus, data.opus); | ||
770 | } | 821 | } | ||
771 | 822 | | |||
772 | if (data.discNumber.isValid()) { | 823 | if (data.discNumber.isValid()) { | ||
773 | result->add(Property::DiscNumber, data.discNumber); | 824 | result->add(Property::DiscNumber, data.discNumber); | ||
774 | } | 825 | } | ||
775 | 826 | | |||
827 | if (data.rating.isValid()) { | ||||
828 | result->add(Property::Rating, data.rating); | ||||
829 | } | ||||
830 | | ||||
776 | TagLib::AudioProperties* audioProp = file.audioProperties(); | 831 | TagLib::AudioProperties* audioProp = file.audioProperties(); | ||
777 | if (audioProp) { | 832 | if (audioProp) { | ||
778 | if (audioProp->length()) { | 833 | if (audioProp->length()) { | ||
779 | // What about the xml duration? | 834 | // What about the xml duration? | ||
780 | result->add(Property::Duration, audioProp->length()); | 835 | result->add(Property::Duration, audioProp->length()); | ||
781 | } | 836 | } | ||
782 | 837 | | |||
783 | if (audioProp->bitrate()) { | 838 | if (audioProp->bitrate()) { | ||
Show All 40 Lines |
You can and should be using all intermediate values. If I remember correctly, in dolphin, you can set all values between 0 and 10. This is done by half blue stars.
Can you use modulo instead of embedded if ?