| |   |
| 64 | 64 | #include <QStringList> |
| 65 | 65 | #include <QTime> |
| 66 | 66 | |
| //Taglib: |
| #include <apetag.h> |
| #include <fileref.h> |
| #include <flacfile.h> |
| #include <id3v1tag.h> |
| #include <id3v2tag.h> |
| #include <mpcfile.h> |
| #include <mpegfile.h> |
| #include <oggfile.h> |
| #include <oggflacfile.h> |
| #include <speexfile.h> |
| #include <tlist.h> |
| #include <tstring.h> |
| #include <vorbisfile.h> |
|
| #ifdef TAGLIB_EXTRAS_FOUND |
| #include <mp4file.h> |
| #include <mp4tag.h> |
| #include <mp4item.h> |
| #include <audiblefiletyperesolver.h> |
| #include <asffiletyperesolver.h> |
| #include <wavfiletyperesolver.h> |
| #include <realmediafiletyperesolver.h> |
| #include <mp4filetyperesolver.h> |
| #endif |
|
| 93 | 67 | using namespace Meta; |
| 94 | 68 | |
| 95 | 69 | /// IpodHandler |
| … | … | |
| 1163 | 1163 | } |
| 1164 | 1164 | |
| 1165 | 1165 | return orphanedTracks; |
| } |
|
| AttributeHash |
| IpodHandler::readTags( const QString &path, TagLib::AudioProperties::ReadStyle readStyle ) |
| { |
| // Tests reveal the following: |
| // |
| // TagLib::AudioProperties Relative Time Taken |
| // |
| // No AudioProp Reading 1 |
| // Fast 1.18 |
| // Average Untested |
| // Accurate Untested |
|
|
| #ifdef COMPLEX_TAGLIB_FILENAME |
| const wchar_t * encodedName = reinterpret_cast<const wchar_t *>(path.utf16()); |
| #else |
| QByteArray fileName = QFile::encodeName( path ); |
| const char * encodedName = fileName.constData(); // valid as long as fileName exists |
| #endif |
|
| TagLib::FileRef fileref; |
| TagLib::Tag *tag = 0; |
| fileref = TagLib::FileRef( encodedName, true, readStyle ); |
|
| AttributeHash attributes; |
| bool isValid = false; |
| FileType fileType = ogg; |
| if( !fileref.isNull() ) |
| { |
| tag = fileref.tag(); |
| if ( tag ) |
| { |
| #define strip( x ) TStringToQString( x ).trimmed() |
|
| attributes["title"] = strip( tag->title() ); |
| attributes["artist"] = strip( tag->artist() ); |
| attributes["album"] = strip( tag->album() ); |
| attributes["comment"] = strip( tag->comment() ); |
| attributes["genre"] = strip( tag->genre() ); |
| attributes["year"] = QString::number( tag->year() ); |
| attributes["track"] = QString::number( tag->track() ); |
| isValid = true; |
| } |
| /* |
| Meta::ReplayGainTagMap replayGainTags = Meta::readReplayGainTags( fileref ); |
| if ( replayGainTags.contains( Meta::ReplayGain_Track_Gain ) ) |
| { |
| attributes["trackgain"] = QString::number( replayGainTags[Meta::ReplayGain_Track_Gain] ); |
| if ( replayGainTags.contains( Meta::ReplayGain_Track_Peak ) ) |
| attributes["trackpeakgain"] = QString::number( replayGainTags[Meta::ReplayGain_Track_Peak] ); |
| } |
| if ( replayGainTags.contains( Meta::ReplayGain_Album_Gain ) ) |
| { |
| attributes["albumgain"] = QString::number( replayGainTags[Meta::ReplayGain_Album_Gain] ); |
| if ( replayGainTags.contains( Meta::ReplayGain_Album_Peak ) ) |
| attributes["albumpeakgain"] = QString::number( replayGainTags[Meta::ReplayGain_Album_Peak] ); |
| } |
| */ |
| QString disc; |
| QString compilation; |
|
| /* As mpeg implementation on TagLib uses a Tag class that's not defined on the headers, |
| we have to cast the files, not the tags! */ |
| if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) ) |
| { |
| fileType = mp3; |
| if ( file->ID3v2Tag() ) |
| { |
| if ( !file->ID3v2Tag()->frameListMap()["TPOS"].isEmpty() ) |
| disc = TStringToQString( file->ID3v2Tag()->frameListMap()["TPOS"].front()->toString() ).trimmed(); |
|
| if ( !file->ID3v2Tag()->frameListMap()["TBPM"].isEmpty() ) |
| attributes["bpm"] = TStringToQString( file->ID3v2Tag()->frameListMap()["TBPM"].front()->toString() ).trimmed().toFloat(); |
|
| if ( !file->ID3v2Tag()->frameListMap()["TCOM"].isEmpty() ) |
| attributes["composer"] = TStringToQString( file->ID3v2Tag()->frameListMap()["TCOM"].front()->toString() ).trimmed(); |
|
| if ( !file->ID3v2Tag()->frameListMap()["TPE2"].isEmpty() ) // non-standard: Apple, Microsoft |
| attributes["albumArtist"] = TStringToQString( file->ID3v2Tag()->frameListMap()["TPE2"].front()->toString() ).trimmed(); |
|
| if ( !file->ID3v2Tag()->frameListMap()["TCMP"].isEmpty() ) |
| compilation = TStringToQString( file->ID3v2Tag()->frameListMap()["TCMP"].front()->toString() ).trimmed(); |
|
| //FIXME: Port 2.0 |
| // if( images ) |
| // loadImagesFromTag( *file->ID3v2Tag(), *images ); |
| } |
|
| #undef strip |
| } |
|
| if ( TagLib::Ogg::Vorbis::File *file = dynamic_cast<TagLib::Ogg::Vorbis::File *>( fileref.file() ) ) |
| { |
| fileType = ogg; |
| if ( file->tag() ) |
| { |
| if ( !file->tag()->fieldListMap()[ "COMPOSER" ].isEmpty() ) |
| attributes["composer"] = TStringToQString( file->tag()->fieldListMap()["COMPOSER"].front() ).trimmed(); |
|
| if ( !file->tag()->fieldListMap()[ "BPM" ].isEmpty() ) |
| attributes["bpm"] = TStringToQString( file->tag()->fieldListMap()["BPM"].front() ).trimmed().toFloat(); |
|
| if ( !file->tag()->fieldListMap()[ "DISCNUMBER" ].isEmpty() ) |
| disc = TStringToQString( file->tag()->fieldListMap()["DISCNUMBER"].front() ).trimmed(); |
|
| if ( !file->tag()->fieldListMap()[ "COMPILATION" ].isEmpty() ) |
| compilation = TStringToQString( file->tag()->fieldListMap()["COMPILATION"].front() ).trimmed(); |
| } |
| } |
| else if ( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) ) |
| { |
| fileType = flac; |
| if ( file->xiphComment() ) |
| { |
| if ( !file->xiphComment()->fieldListMap()[ "COMPOSER" ].isEmpty() ) |
| attributes["composer"] = TStringToQString( file->xiphComment()->fieldListMap()["COMPOSER"].front() ).trimmed(); |
|
| if ( !file->xiphComment()->fieldListMap()[ "BPM" ].isEmpty() ) |
| attributes["bpm"] = TStringToQString( file->xiphComment()->fieldListMap()["BPM"].front() ).trimmed().toFloat(); |
|
| if ( !file->xiphComment()->fieldListMap()[ "DISCNUMBER" ].isEmpty() ) |
| disc = TStringToQString( file->xiphComment()->fieldListMap()["DISCNUMBER"].front() ).trimmed(); |
|
| if ( !file->xiphComment()->fieldListMap()[ "COMPILATION" ].isEmpty() ) |
| compilation = TStringToQString( file->xiphComment()->fieldListMap()["COMPILATION"].front() ).trimmed(); |
| } |
| // if ( images && file->ID3v2Tag() ) |
| // loadImagesFromTag( *file->ID3v2Tag(), *images ); |
| } |
| #ifdef TAGLIB_EXTRAS_FOUND |
| else if ( TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File *>( fileref.file() ) ) |
| { |
| fileType = mp4; |
| TagLib::MP4::Tag *mp4tag = dynamic_cast<TagLib::MP4::Tag *>( file->tag() ); |
| if( mp4tag ) |
| { |
| if ( mp4tag->itemListMap().contains( "\xA9wrt" ) ) |
| attributes["composer"] = TStringToQString( mp4tag->itemListMap()["\xa9wrt"].toStringList().front() ); |
|
| if ( mp4tag->itemListMap().contains( "tmpo" ) ) |
| attributes["bpm"] = QString::number( mp4tag->itemListMap()["tmpo"].toInt() ); |
|
| if ( mp4tag->itemListMap().contains( "disk" ) ) |
| disc = QString::number( mp4tag->itemListMap()["disk"].toIntPair().first ); |
|
| if ( mp4tag->itemListMap().contains( "cpil" ) ) |
| compilation = QString::number( mp4tag->itemListMap()["cpil"].toBool() ? '1' : '0' ); |
|
| // if ( images && mp4tag->cover().size() ) |
| // images->push_back( EmbeddedImage( mp4tag->cover(), "" ) ); |
| } |
| } |
| #endif |
|
| if ( !disc.isEmpty() ) |
| { |
| int i = disc.indexOf('/'); |
| // guard against b0rked tags |
| int discnumber; |
| if ( i != -1 ) |
| // disc.right( i ).toInt() is total number of discs, we don't use this at the moment |
| discnumber = disc.left( i ).toInt(); |
| else |
| discnumber = disc.toInt(); |
| attributes["discnumber"] = QString::number( discnumber ); |
| } |
|
| // Sometimes the file is explicitly tagged with compilation details. When it is not, |
| // then we need to delegate checking whether this files is in a compilation to Amarok. |
| if ( compilation.isEmpty() ) |
| { |
| // well, it wasn't set, but if the artist is VA assume it's a compilation |
| //TODO: If we get pure-Qt translation support, put this back in; else functionality moved to the processor |
| //if ( attributes["artist"] == QObject::tr( "Various Artists" ) ) |
| // attributes["compilation"] = QString::number( 1 ); |
| attributes["compilation"] = "checkforvarious"; |
| } |
| else |
| { |
| int i = compilation.toInt(); |
| attributes["compilation"] = QString::number( i ); |
| } |
| } |
|
| if ( !isValid ) |
| { |
| std::cout << "<dud/>"; |
| return attributes; |
| } |
|
| attributes["filetype"] = QString::number( fileType ); |
|
| static const int Undetermined = -2; |
|
| int bitrate = Undetermined; |
| int length = Undetermined; |
| int samplerate = Undetermined; |
| if( fileref.audioProperties() ) |
| { |
| bitrate = fileref.audioProperties()->bitrate(); |
| length = fileref.audioProperties()->length(); |
| samplerate = fileref.audioProperties()->sampleRate(); |
| } |
| if ( bitrate == Undetermined || length == Undetermined || samplerate == Undetermined ) |
| attributes["audioproperties"] = "false"; |
| else |
| { |
| attributes["audioproperties"] = "true"; |
| attributes["bitrate"] = QString::number( bitrate ); |
| attributes["length"] = QString::number( length ); |
| attributes["samplerate"] = QString::number( samplerate ); |
| } |
|
| const int size = QFile( path ).size(); |
| if( size >= 0 ) |
| attributes["filesize"] = QString::number( size ); |
|
| return attributes; |
| 1386 | 1166 | } |
| 1387 | 1167 | |
| 1388 | 1168 | bool |