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 }