File indexing completed on 2024-05-12 16:18:07
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2005 Max Howell <max.howell@methylblue.com> * 0003 * (C) 2003-2010 Mark Kretschmann <kretschmann@kde.org> * 0004 * (C) 2005-2007 Alexandre Oliveira <aleprj@gmail.com> * 0005 * (C) 2008 Dan Meltzer <parallelgrapefruit@gmail.com> * 0006 * (C) 2008-2009 Jeff Mitchell <mitchell@kde.org> * 0007 * * 0008 * This program is free software; you can redistribute it and/or modify * 0009 * it under the terms of the GNU General Public License as published by * 0010 * the Free Software Foundation; either version 2 of the License, or * 0011 * (at your option) any later version. * 0012 * * 0013 * This program is distributed in the hope that it will be useful, * 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0016 * GNU General Public License for more details. * 0017 * * 0018 * You should have received a copy of the GNU General Public License * 0019 * along with this program; if not, write to the * 0020 * Free Software Foundation, Inc., * 0021 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0022 ***************************************************************************/ 0023 0024 #include "Track.h" 0025 #include "utils.h" 0026 0027 #include "MetaTagLib.h" 0028 #include "MetaReplayGain.h" 0029 0030 #include <QDebug> 0031 #include <QDir> 0032 #include <QFile> 0033 #include <QFileInfo> 0034 #include <QXmlStreamReader> 0035 #include <QXmlStreamWriter> 0036 0037 bool CollectionScanner::Track::s_useCharsetDetector = false; 0038 0039 0040 CollectionScanner::Track::Track( const QString &path, CollectionScanner::Directory* directory ) 0041 : m_valid( true ) 0042 , m_directory( directory ) 0043 , m_filetype( Amarok::Unknown ) 0044 , m_compilation( false ) 0045 , m_noCompilation( false ) 0046 , m_hasCover( false ) 0047 , m_year( -1 ) 0048 , m_disc( -1 ) 0049 , m_track( -1 ) 0050 , m_bpm( -1.0 ) 0051 , m_bitrate( -1 ) 0052 , m_length( -1.0 ) 0053 , m_samplerate( -1 ) 0054 , m_filesize( -1 ) 0055 0056 , m_trackGain( -1.0 ) 0057 , m_trackPeakGain( -1.0 ) 0058 , m_albumGain( -1.0 ) 0059 , m_albumPeakGain( -1.0 ) 0060 0061 , m_rating( -1.0 ) 0062 , m_score( -1.0 ) 0063 , m_playcount( -1.0 ) 0064 { 0065 static const int MAX_SENSIBLE_LENGTH = 1023; // the maximum length for normal strings. 0066 // in corner cases a longer string might cause problems see BUG:276894 0067 0068 // for the unit test. 0069 // in a debug build a file called "crash_amarok_here.ogg" will crash the collection 0070 // scanner 0071 if( path.contains(QLatin1String("crash_amarok_here.ogg")) ) 0072 { 0073 qDebug() << "Crashing at"<<path; 0074 Q_ASSERT( false ); 0075 } 0076 0077 Meta::FieldHash values = Meta::Tag::readTags( path, s_useCharsetDetector ); 0078 0079 m_valid = !values.empty(); 0080 if( values.contains(Meta::valUniqueId) ) 0081 m_uniqueid = values.value(Meta::valUniqueId).toString(); 0082 m_path = path; 0083 m_rpath = QDir::current().relativeFilePath( path ); 0084 if( values.contains(Meta::valFormat) ) 0085 m_filetype = Amarok::FileType(values.value(Meta::valFormat).toInt()); 0086 if( values.contains(Meta::valTitle) ) 0087 m_title = values.value(Meta::valTitle).toString(); 0088 if( values.contains(Meta::valArtist) ) 0089 m_artist = values.value(Meta::valArtist).toString().left(MAX_SENSIBLE_LENGTH); 0090 if( values.contains(Meta::valAlbum) ) 0091 m_album = values.value(Meta::valAlbum).toString().left(MAX_SENSIBLE_LENGTH); 0092 if( values.contains( Meta::valAlbumArtist ) ) 0093 m_albumArtist = values.value( Meta::valAlbumArtist ).toString().left(MAX_SENSIBLE_LENGTH); 0094 if( values.contains(Meta::valCompilation) ) 0095 { 0096 m_compilation = values.value(Meta::valCompilation).toBool(); 0097 m_noCompilation = !values.value(Meta::valCompilation).toBool(); 0098 } 0099 if( values.contains(Meta::valHasCover) ) 0100 m_hasCover = values.value(Meta::valHasCover).toBool(); 0101 if( values.contains(Meta::valComment) ) 0102 m_comment = values.value(Meta::valComment).toString(); 0103 if( values.contains(Meta::valGenre) ) 0104 m_genre = values.value(Meta::valGenre).toString().left(MAX_SENSIBLE_LENGTH); 0105 if( values.contains(Meta::valYear) ) 0106 m_year = values.value(Meta::valYear).toInt(); 0107 if( values.contains(Meta::valDiscNr) ) 0108 m_disc = values.value(Meta::valDiscNr).toInt(); 0109 if( values.contains(Meta::valTrackNr) ) 0110 m_track = values.value(Meta::valTrackNr).toInt(); 0111 if( values.contains(Meta::valBpm) ) 0112 m_bpm = values.value(Meta::valBpm).toReal(); 0113 if( values.contains(Meta::valBitrate) ) 0114 m_bitrate = values.value(Meta::valBitrate).toInt(); 0115 if( values.contains(Meta::valLength) ) 0116 m_length = values.value(Meta::valLength).toLongLong(); 0117 if( values.contains(Meta::valSamplerate) ) 0118 m_samplerate = values.value(Meta::valSamplerate).toInt(); 0119 if( values.contains(Meta::valFilesize) ) 0120 m_filesize = values.value(Meta::valFilesize).toLongLong(); 0121 if( values.contains(Meta::valModified) ) 0122 m_modified = values.value(Meta::valModified).toDateTime(); 0123 0124 if( values.contains(Meta::valTrackGain) ) 0125 m_trackGain = values.value(Meta::valTrackGain).toReal(); 0126 if( values.contains(Meta::valTrackGainPeak) ) 0127 m_trackPeakGain = values.value(Meta::valTrackGainPeak).toReal(); 0128 if( values.contains(Meta::valAlbumGain) ) 0129 m_albumGain = values.value(Meta::valAlbumGain).toReal(); 0130 if( values.contains(Meta::valAlbumGainPeak) ) 0131 m_albumPeakGain = values.value(Meta::valAlbumGainPeak).toReal(); 0132 while( m_uniqueid.startsWith(QLatin1Char('/')) ) 0133 m_uniqueid = m_uniqueid.mid(1); 0134 0135 if( values.contains(Meta::valComposer) ) 0136 m_composer = values.value(Meta::valComposer).toString().left(MAX_SENSIBLE_LENGTH); 0137 0138 if( values.contains(Meta::valRating) ) 0139 m_rating = values.value(Meta::valRating).toReal(); 0140 if( values.contains(Meta::valScore) ) 0141 m_score = values.value(Meta::valScore).toReal(); 0142 if( values.contains(Meta::valPlaycount) ) 0143 m_playcount = values.value(Meta::valPlaycount).toReal(); 0144 } 0145 0146 CollectionScanner::Track::Track( QXmlStreamReader *reader, CollectionScanner::Directory* directory ) 0147 : m_valid( true ) 0148 , m_directory( directory ) 0149 , m_filetype( Amarok::Unknown ) 0150 , m_compilation( false ) 0151 , m_noCompilation( false ) 0152 , m_hasCover( false ) 0153 , m_year( -1 ) 0154 , m_disc( -1 ) 0155 , m_track( -1 ) 0156 , m_bpm( -1 ) 0157 , m_bitrate( -1 ) 0158 , m_length( -1 ) 0159 , m_samplerate( -1 ) 0160 , m_filesize( -1 ) 0161 0162 , m_trackGain( -1 ) 0163 , m_trackPeakGain( -1 ) 0164 , m_albumGain( -1 ) 0165 , m_albumPeakGain( -1 ) 0166 0167 , m_rating( -1 ) 0168 , m_score( -1 ) 0169 , m_playcount( -1 ) 0170 { 0171 // improve scanner with skipCurrentElement as soon as Amarok requires Qt 4.6 0172 while (!reader->atEnd()) { 0173 reader->readNext(); 0174 0175 if( reader->isStartElement() ) 0176 { 0177 QStringRef name = reader->name(); 0178 if( name == QLatin1String("uniqueid") ) 0179 m_uniqueid = reader->readElementText(QXmlStreamReader::SkipChildElements); 0180 else if( name == QLatin1String("path") ) 0181 m_path = reader->readElementText(QXmlStreamReader::SkipChildElements); 0182 else if( name == QLatin1String("rpath") ) 0183 m_rpath = reader->readElementText(QXmlStreamReader::SkipChildElements); 0184 0185 else if( name == QLatin1String("filetype") ) 0186 m_filetype = (Amarok::FileType)reader->readElementText(QXmlStreamReader::SkipChildElements).toInt(); 0187 else if( name == QLatin1String("title") ) 0188 m_title = reader->readElementText(QXmlStreamReader::SkipChildElements); 0189 else if( name == QLatin1String("artist") ) 0190 m_artist = reader->readElementText(QXmlStreamReader::SkipChildElements); 0191 else if( name == QLatin1String("albumArtist") ) 0192 m_albumArtist = reader->readElementText(QXmlStreamReader::SkipChildElements); 0193 else if( name == QLatin1String("album") ) 0194 m_album = reader->readElementText(); 0195 else if( name == QLatin1String("compilation") ) 0196 { 0197 m_compilation = true; 0198 reader->skipCurrentElement(); 0199 } 0200 else if( name == QLatin1String("noCompilation") ) 0201 { 0202 m_noCompilation = true; 0203 reader->skipCurrentElement(); 0204 } 0205 else if( name == QLatin1String("hasCover") ) 0206 { 0207 m_hasCover = true; 0208 reader->skipCurrentElement(); 0209 } 0210 else if( name == QLatin1String("comment") ) 0211 m_comment = reader->readElementText(QXmlStreamReader::SkipChildElements); 0212 else if( name == QLatin1String("genre") ) 0213 m_genre = reader->readElementText(QXmlStreamReader::SkipChildElements); 0214 else if( name == QLatin1String("year") ) 0215 m_year = reader->readElementText(QXmlStreamReader::SkipChildElements).toInt(); 0216 else if( name == QLatin1String("disc") ) 0217 m_disc = reader->readElementText(QXmlStreamReader::SkipChildElements).toInt(); 0218 else if( name == QLatin1String("track") ) 0219 m_track = reader->readElementText(QXmlStreamReader::SkipChildElements).toInt(); 0220 else if( name == QLatin1String("bpm") ) 0221 m_bpm = reader->readElementText(QXmlStreamReader::SkipChildElements).toFloat(); 0222 else if( name == QLatin1String("bitrate") ) 0223 m_bitrate = reader->readElementText(QXmlStreamReader::SkipChildElements).toInt(); 0224 else if( name == QLatin1String("length") ) 0225 m_length = reader->readElementText(QXmlStreamReader::SkipChildElements).toLong(); 0226 else if( name == QLatin1String("samplerate") ) 0227 m_samplerate = reader->readElementText(QXmlStreamReader::SkipChildElements).toInt(); 0228 else if( name == QLatin1String("filesize") ) 0229 m_filesize = reader->readElementText(QXmlStreamReader::SkipChildElements).toLong(); 0230 else if( name == QLatin1String("mtime") ) 0231 m_modified = QDateTime::fromSecsSinceEpoch(reader->readElementText(QXmlStreamReader::SkipChildElements).toLong()); 0232 0233 else if( name == QLatin1String("trackGain") ) 0234 m_trackGain = reader->readElementText(QXmlStreamReader::SkipChildElements).toFloat(); 0235 else if( name == QLatin1String("trackPeakGain") ) 0236 m_trackPeakGain = reader->readElementText(QXmlStreamReader::SkipChildElements).toFloat(); 0237 else if( name == QLatin1String("albumGain") ) 0238 m_albumGain = reader->readElementText(QXmlStreamReader::SkipChildElements).toFloat(); 0239 else if( name == QLatin1String("albumPeakGain") ) 0240 m_albumPeakGain = reader->readElementText(QXmlStreamReader::SkipChildElements).toFloat(); 0241 0242 else if( name == QLatin1String("composer") ) 0243 m_composer = reader->readElementText(QXmlStreamReader::SkipChildElements); 0244 0245 else if( name == QLatin1String("rating") ) 0246 m_rating = reader->readElementText(QXmlStreamReader::SkipChildElements).toFloat(); 0247 else if( name == QLatin1String("score") ) 0248 m_score = reader->readElementText(QXmlStreamReader::SkipChildElements).toFloat(); 0249 else if( name == QLatin1String("playcount") ) 0250 m_playcount = reader->readElementText(QXmlStreamReader::SkipChildElements).toInt(); 0251 0252 else 0253 { 0254 qDebug() << "Unexpected xml start element"<<name<<"in input"; 0255 reader->skipCurrentElement(); 0256 } 0257 } 0258 0259 else if( reader->isEndElement() ) 0260 { 0261 break; 0262 } 0263 } 0264 } 0265 0266 void 0267 CollectionScanner::Track::write( QXmlStreamWriter *writer, 0268 const QString &tag, const QString &str ) const 0269 { 0270 if( !str.isEmpty() ) 0271 writer->writeTextElement( tag, escapeXml10(str) ); 0272 } 0273 0274 0275 void 0276 CollectionScanner::Track::toXml( QXmlStreamWriter *writer ) const 0277 { 0278 if( !m_valid ) 0279 return; 0280 0281 write( writer, QStringLiteral("uniqueid"), m_uniqueid ); 0282 write( writer, QStringLiteral("path"), m_path ); 0283 write( writer, QStringLiteral("rpath"), m_rpath ); 0284 0285 write(writer, QStringLiteral("filetype"), QString::number( (int)m_filetype ) ); 0286 0287 write( writer, QStringLiteral("title"), m_title); 0288 write( writer, QStringLiteral("artist"), m_artist); 0289 write( writer, QStringLiteral("albumArtist"), m_albumArtist); 0290 write( writer, QStringLiteral("album"), m_album); 0291 if( m_compilation ) 0292 writer->writeEmptyElement( QStringLiteral("compilation") ); 0293 if( m_noCompilation ) 0294 writer->writeEmptyElement( QStringLiteral("noCompilation") ); 0295 if( m_hasCover ) 0296 writer->writeEmptyElement( QStringLiteral("hasCover") ); 0297 write( writer, QStringLiteral("comment"), m_comment); 0298 write( writer, QStringLiteral("genre"), m_genre); 0299 if( m_year != -1 ) 0300 write(writer, QStringLiteral("year"), QString::number( m_year ) ); 0301 if( m_disc != -1 ) 0302 write(writer, QStringLiteral("disc"), QString::number( m_disc ) ); 0303 if( m_track != -1 ) 0304 write(writer, QStringLiteral("track"), QString::number( m_track ) ); 0305 if( m_bpm != -1 ) 0306 write(writer, QStringLiteral("bpm"), QString::number( m_bpm ) ); 0307 if( m_bitrate != -1 ) 0308 write(writer, QStringLiteral("bitrate"), QString::number( m_bitrate ) ); 0309 if( m_length != -1 ) 0310 write(writer, QStringLiteral("length"), QString::number( m_length ) ); 0311 if( m_samplerate != -1 ) 0312 write(writer, QStringLiteral("samplerate"), QString::number( m_samplerate ) ); 0313 if( m_filesize != -1 ) 0314 write(writer, QStringLiteral("filesize"), QString::number( m_filesize ) ); 0315 if( m_modified.isValid() ) 0316 write(writer, QStringLiteral("mtime"), QString::number( m_modified.toSecsSinceEpoch() ) ); 0317 0318 if( m_trackGain != 0 ) 0319 write(writer, QStringLiteral("trackGain"), QString::number( m_trackGain ) ); 0320 if( m_trackPeakGain != 0 ) 0321 write(writer, QStringLiteral("trackPeakGain"), QString::number( m_trackPeakGain ) ); 0322 if( m_albumGain != 0 ) 0323 write(writer, QStringLiteral("albumGain"), QString::number( m_albumGain ) ); 0324 if( m_albumPeakGain != 0 ) 0325 write(writer, QStringLiteral("albumPeakGain"), QString::number( m_albumPeakGain ) ); 0326 0327 write( writer, QStringLiteral("composer"), m_composer); 0328 0329 if( m_rating != -1 ) 0330 write(writer, QStringLiteral("rating"), QString::number( m_rating ) ); 0331 if( m_score != -1 ) 0332 write(writer, QStringLiteral("score"), QString::number( m_score ) ); 0333 if( m_playcount != -1 ) 0334 write(writer, QStringLiteral("playcount"), QString::number( m_playcount ) ); 0335 0336 } 0337 0338 bool 0339 CollectionScanner::Track::isValid() const 0340 { 0341 return m_valid; 0342 } 0343 0344 CollectionScanner::Directory* 0345 CollectionScanner::Track::directory() const 0346 { 0347 return m_directory; 0348 } 0349 0350 QString 0351 CollectionScanner::Track::uniqueid() const 0352 { 0353 return m_uniqueid; 0354 } 0355 0356 QString 0357 CollectionScanner::Track::path() const 0358 { 0359 return m_path; 0360 } 0361 0362 QString 0363 CollectionScanner::Track::rpath() const 0364 { 0365 return m_rpath; 0366 } 0367 0368 Amarok::FileType 0369 CollectionScanner::Track::filetype() const 0370 { 0371 return m_filetype; 0372 } 0373 0374 QString 0375 CollectionScanner::Track::title() const 0376 { 0377 return m_title; 0378 } 0379 0380 QString 0381 CollectionScanner::Track::artist() const 0382 { 0383 return m_artist; 0384 } 0385 0386 QString 0387 CollectionScanner::Track::albumArtist() const 0388 { 0389 return m_albumArtist; 0390 } 0391 0392 QString 0393 CollectionScanner::Track::album() const 0394 { 0395 return m_album; 0396 } 0397 0398 bool 0399 CollectionScanner::Track::isCompilation() const 0400 { 0401 return m_compilation; 0402 } 0403 0404 bool 0405 CollectionScanner::Track::isNoCompilation() const 0406 { 0407 return m_noCompilation; 0408 } 0409 0410 0411 bool 0412 CollectionScanner::Track::hasCover() const 0413 { 0414 return m_hasCover; 0415 } 0416 0417 QString 0418 CollectionScanner::Track::comment() const 0419 { 0420 return m_comment; 0421 } 0422 0423 QString 0424 CollectionScanner::Track::genre() const 0425 { 0426 return m_genre; 0427 } 0428 0429 int 0430 CollectionScanner::Track::year() const 0431 { 0432 return m_year; 0433 } 0434 0435 int 0436 CollectionScanner::Track::disc() const 0437 { 0438 return m_disc; 0439 } 0440 0441 int 0442 CollectionScanner::Track::track() const 0443 { 0444 return m_track; 0445 } 0446 0447 int 0448 CollectionScanner::Track::bpm() const 0449 { 0450 return m_bpm; 0451 } 0452 0453 int 0454 CollectionScanner::Track::bitrate() const 0455 { 0456 return m_bitrate; 0457 } 0458 0459 qint64 0460 CollectionScanner::Track::length() const 0461 { 0462 return m_length; 0463 } 0464 0465 int 0466 CollectionScanner::Track::samplerate() const 0467 { 0468 return m_samplerate; 0469 } 0470 0471 qint64 0472 CollectionScanner::Track::filesize() const 0473 { 0474 return m_filesize; 0475 } 0476 0477 QDateTime 0478 CollectionScanner::Track::modified() const 0479 { 0480 return m_modified; 0481 } 0482 0483 0484 QString 0485 CollectionScanner::Track::composer() const 0486 { 0487 return m_composer; 0488 } 0489 0490 0491 qreal 0492 CollectionScanner::Track::replayGain( Meta::ReplayGainTag mode ) const 0493 { 0494 switch( mode ) 0495 { 0496 case Meta::ReplayGain_Track_Gain: 0497 return m_trackGain; 0498 case Meta::ReplayGain_Track_Peak: 0499 return m_trackPeakGain; 0500 case Meta::ReplayGain_Album_Gain: 0501 return m_albumGain; 0502 case Meta::ReplayGain_Album_Peak: 0503 return m_albumPeakGain; 0504 } 0505 return 0.0; 0506 } 0507 0508 qreal 0509 CollectionScanner::Track::rating() const 0510 { 0511 return m_rating; 0512 } 0513 0514 qreal 0515 CollectionScanner::Track::score() const 0516 { 0517 return m_score; 0518 } 0519 0520 int 0521 CollectionScanner::Track::playcount() const 0522 { 0523 return m_playcount; 0524 } 0525 0526 void 0527 CollectionScanner::Track::setUseCharsetDetector( bool value ) 0528 { 0529 s_useCharsetDetector = value; 0530 }