File indexing completed on 2024-05-19 04:49:29
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com> * 0003 * Copyright (c) 2007 Ian Monroe <ian@monroe.nu> * 0004 * Copyright (c) 2008 Mark Kretschmann <kretschmann@kde.org> * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify it under * 0007 * the terms of the GNU General Public License as published by the Free Software * 0008 * Foundation; either version 2 of the License, or (at your option) any later * 0009 * version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0013 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License along with * 0016 * this program. If not, see <http://www.gnu.org/licenses/>. * 0017 ****************************************************************************************/ 0018 0019 #include "core/meta/Meta.h" 0020 0021 #include "core/collections/Collection.h" 0022 #include "core/collections/QueryMaker.h" 0023 #include "core/meta/Observer.h" 0024 #include "core/meta/Statistics.h" 0025 #include "core/meta/TrackEditor.h" 0026 #include "core/support/Amarok.h" 0027 #include "core/support/Debug.h" 0028 0029 #include <QImage> 0030 #include <QNetworkConfigurationManager> 0031 0032 #include <KLocalizedString> 0033 0034 using namespace Meta; 0035 0036 //Meta::Track 0037 0038 QString 0039 Meta::Track::prettyName() const 0040 { 0041 if( !name().isEmpty() ) 0042 return name(); 0043 return prettyUrl(); 0044 } 0045 0046 bool 0047 Meta::Track::inCollection() const 0048 { 0049 return false; 0050 } 0051 0052 Collections::Collection* 0053 Meta::Track::collection() const 0054 { 0055 return nullptr; 0056 } 0057 0058 Meta::LabelList 0059 Meta::Track::labels() const 0060 { 0061 return Meta::LabelList(); 0062 } 0063 0064 QString 0065 Meta::Track::cachedLyrics() const 0066 { 0067 return QString(); 0068 } 0069 0070 void 0071 Meta::Track::setCachedLyrics( const QString &lyrics ) 0072 { 0073 Q_UNUSED( lyrics ) 0074 } 0075 0076 void 0077 Meta::Track::addLabel( const QString &label ) 0078 { 0079 Q_UNUSED( label ) 0080 } 0081 0082 void 0083 Meta::Track::addLabel( const Meta::LabelPtr &label ) 0084 { 0085 Q_UNUSED( label ) 0086 } 0087 0088 void 0089 Meta::Track::removeLabel( const Meta::LabelPtr &label ) 0090 { 0091 Q_UNUSED( label ) 0092 } 0093 0094 QDateTime 0095 Meta::Track::createDate() const 0096 { 0097 return QDateTime(); 0098 } 0099 0100 QDateTime 0101 Meta::Track::modifyDate() const 0102 { 0103 return QDateTime(); 0104 } 0105 0106 qreal 0107 Meta::Track::replayGain( Meta::ReplayGainTag mode ) const 0108 { 0109 Q_UNUSED( mode ) 0110 return 0.0; 0111 } 0112 0113 void 0114 Meta::Track::prepareToPlay() 0115 { 0116 } 0117 0118 void 0119 Meta::Track::finishedPlaying( double playedFraction ) 0120 { 0121 qint64 len = length(); 0122 bool updatePlayCount; 0123 if( len <= 30 * 1000 ) 0124 updatePlayCount = ( playedFraction >= 1.0 ); 0125 else 0126 // at least half the song or at least 5 minutes played 0127 updatePlayCount = ( playedFraction >= 0.5 || ( playedFraction * len ) >= 5 * 60 * 1000 ); 0128 0129 StatisticsPtr stats = statistics(); 0130 stats->beginUpdate(); 0131 // we should update score even if updatePlayCount is false to record skips 0132 stats->setScore( Amarok::computeScore( stats->score(), stats->playCount(), playedFraction ) ); 0133 if( updatePlayCount ) 0134 { 0135 stats->setPlayCount( stats->playCount() + 1 ); 0136 if( !stats->firstPlayed().isValid() ) 0137 stats->setFirstPlayed( QDateTime::currentDateTime() ); 0138 stats->setLastPlayed( QDateTime::currentDateTime() ); 0139 } 0140 stats->endUpdate(); 0141 } 0142 0143 void 0144 Meta::Track::notifyObservers() const 0145 { 0146 notifyObserversHelper<Track, Observer>( this ); 0147 } 0148 0149 bool 0150 Meta::Track::operator==( const Meta::Track &track ) const 0151 { 0152 return dynamic_cast<const void*>( this ) == dynamic_cast<const void*>( &track ); 0153 } 0154 0155 bool 0156 Meta::Track::lessThan( const Meta::TrackPtr& left, const Meta::TrackPtr& right ) 0157 { 0158 if( !left || !right ) // These should never be 0, but it can apparently happen (https://bugs.kde.org/show_bug.cgi?id=181187) 0159 return false; 0160 0161 if( left->album() && right->album() ) 0162 if( left->album()->name() == right->album()->name() ) 0163 { 0164 if( left->discNumber() < right->discNumber() ) 0165 return true; 0166 else if( left->discNumber() > right->discNumber() ) 0167 return false; 0168 0169 if( left->trackNumber() < right->trackNumber() ) 0170 return true; 0171 if( left->trackNumber() > right->trackNumber() ) 0172 return false; 0173 } 0174 0175 if( left->artist() && right->artist() ) 0176 { 0177 int compare = QString::localeAwareCompare( left->artist()->prettyName(), right->artist()->prettyName() ); 0178 if ( compare < 0 ) 0179 return true; 0180 else if ( compare > 0 ) 0181 return false; 0182 } 0183 0184 if( left->album() && right->album() ) 0185 { 0186 int compare = QString::localeAwareCompare( left->album()->prettyName(), right->album()->prettyName() ); 0187 if ( compare < 0 ) 0188 return true; 0189 else if ( compare > 0 ) 0190 return false; 0191 } 0192 0193 return QString::localeAwareCompare( left->prettyName(), right->prettyName() ) < 0; 0194 } 0195 0196 bool 0197 Track::isPlayable() const 0198 { 0199 return notPlayableReason().isEmpty(); 0200 } 0201 0202 QString 0203 Track::networkNotPlayableReason() const 0204 { 0205 QNetworkConfigurationManager mgr; 0206 if( !mgr.isOnline() ) 0207 return i18n( "No network connection" ); 0208 0209 return QString(); 0210 } 0211 0212 QString 0213 Track::localFileNotPlayableReason( const QString &path ) const 0214 { 0215 QFileInfo trackFileInfo = QFileInfo( path ); 0216 if( !trackFileInfo.exists() ) 0217 return i18n( "File does not exist" ); 0218 if( !trackFileInfo.isFile() ) 0219 return i18n( "Not a file" ); 0220 if( !trackFileInfo.isReadable() ) 0221 return i18n( "No read permissions" ); 0222 return QString(); 0223 } 0224 0225 TrackEditorPtr 0226 Track::editor() 0227 { 0228 return TrackEditorPtr(); 0229 } 0230 0231 StatisticsPtr 0232 Track::statistics() 0233 { 0234 // return dummy implementation 0235 return StatisticsPtr( new Statistics() ); 0236 } 0237 0238 ConstStatisticsPtr 0239 Track::statistics() const 0240 { 0241 StatisticsPtr statistics = const_cast<Track *>( this )->statistics(); 0242 return ConstStatisticsPtr( statistics.data() ); 0243 } 0244 0245 0246 //Meta::Artist 0247 0248 QString 0249 Meta::Artist::prettyName() const 0250 { 0251 if( !name().isEmpty() ) 0252 return name(); 0253 return i18n("Unknown Artist"); 0254 } 0255 0256 void 0257 Meta::Artist::notifyObservers() const 0258 { 0259 m_sortableName.clear(); // name() may have changed, recompute sortableName next time 0260 notifyObserversHelper<Artist, Observer>( this ); 0261 } 0262 0263 bool 0264 Meta::Artist::operator==( const Meta::Artist &artist ) const 0265 { 0266 return dynamic_cast<const void*>( this ) == dynamic_cast<const void*>( &artist ); 0267 } 0268 0269 QString 0270 Meta::Artist::sortableName() const 0271 { 0272 if( !m_sortableName.isEmpty() ) 0273 return m_sortableName; 0274 0275 const QString &n = name(); 0276 if( n.startsWith( QLatin1String("the "), Qt::CaseInsensitive ) ) 0277 { 0278 QStringRef article = n.leftRef( 3 ); 0279 QStringRef subject = n.midRef( 4 ); 0280 m_sortableName = QStringLiteral( "%1, %2" ).arg( subject.toString(), article.toString() ); 0281 } 0282 else if( n.startsWith( QLatin1String("dj "), Qt::CaseInsensitive ) ) 0283 { 0284 QStringRef article = n.leftRef( 2 ); 0285 QStringRef subject = n.midRef( 3 ); 0286 m_sortableName = QStringLiteral( "%1, %2" ).arg( subject.toString(), article.toString() ); 0287 } 0288 else 0289 m_sortableName = n; 0290 return m_sortableName; 0291 } 0292 0293 //Meta::Album 0294 0295 QString 0296 Meta::Album::prettyName() const 0297 { 0298 if( !name().isEmpty() ) 0299 return name(); 0300 return i18n("Unknown Album"); 0301 } 0302 0303 void 0304 Meta::Album::notifyObservers() const 0305 { 0306 notifyObserversHelper<Album, Observer>( this ); 0307 } 0308 0309 /* 0310 * This is the base class's image() function, which returns just an null image. 0311 * Retrieval of the cover for the actual album is done by subclasses. 0312 */ 0313 QImage 0314 Meta::Album::image( int size ) const 0315 { 0316 Q_UNUSED( size ); 0317 return QImage(); 0318 } 0319 0320 bool 0321 Meta::Album::operator==( const Meta::Album &album ) const 0322 { 0323 return dynamic_cast<const void*>( this ) == dynamic_cast<const void*>( &album ); 0324 } 0325 0326 //Meta::Genre 0327 0328 QString 0329 Meta::Genre::prettyName() const 0330 { 0331 if( !name().isEmpty() ) 0332 return name(); 0333 return i18n("Unknown Genre"); 0334 } 0335 0336 void 0337 Meta::Genre::notifyObservers() const 0338 { 0339 notifyObserversHelper<Genre, Observer>( this ); 0340 } 0341 0342 bool 0343 Meta::Genre::operator==( const Meta::Genre &genre ) const 0344 { 0345 return dynamic_cast<const void*>( this ) == dynamic_cast<const void*>( &genre ); 0346 } 0347 0348 //Meta::Composer 0349 0350 QString 0351 Meta::Composer::prettyName() const 0352 { 0353 if( !name().isEmpty() ) 0354 return name(); 0355 return i18n("Unknown Composer"); 0356 } 0357 0358 void 0359 Meta::Composer::notifyObservers() const 0360 { 0361 notifyObserversHelper<Composer, Observer>( this ); 0362 } 0363 0364 bool 0365 Meta::Composer::operator==( const Meta::Composer &composer ) const 0366 { 0367 return dynamic_cast<const void*>( this ) == dynamic_cast<const void*>( &composer ); 0368 } 0369 0370 //Meta::Year 0371 0372 void 0373 Meta::Year::notifyObservers() const 0374 { 0375 notifyObserversHelper<Year, Observer>( this ); 0376 } 0377 0378 bool 0379 Meta::Year::operator==( const Meta::Year &year ) const 0380 { 0381 return dynamic_cast<const void*>( this ) == dynamic_cast<const void*>( &year ); 0382 }