File indexing completed on 2025-01-05 04:26:11

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com>            *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #include "MetaProxy.h"
0018 
0019 #include "core/meta/Statistics.h"
0020 #include "core-impl/collections/support/CollectionManager.h"
0021 #include "core-impl/meta/proxy/MetaProxy_p.h"
0022 #include "core-impl/meta/proxy/MetaProxyWorker.h"
0023 
0024 #include "AmarokSharedPointer.h"
0025 #include <ThreadWeaver/Queue>
0026 #include <ThreadWeaver/Job>
0027 #include <KLocalizedString>
0028 
0029 #include <QCoreApplication>
0030 #include <QThread>
0031 #include <QTimer>
0032 #include <QWeakPointer>
0033 
0034 using namespace MetaProxy;
0035 
0036 class ProxyArtist;
0037 class ProxyFmAlbum;
0038 class ProxyGenre;
0039 class ProxyComposer;
0040 class ProxyYear;
0041 
0042 MetaProxy::Track::Track( const QUrl &url, LookupType lookupType )
0043     : Meta::Track()
0044     , d( new Private() )
0045 {
0046     d->url = url;
0047     d->proxy = this;
0048     d->cachedLength = 0;
0049     d->albumPtr = Meta::AlbumPtr( new ProxyAlbum( d ) );
0050     d->artistPtr = Meta::ArtistPtr( new ProxyArtist( d ) );
0051     d->genrePtr = Meta::GenrePtr( new ProxyGenre( d ) );
0052     d->composerPtr = Meta::ComposerPtr( new ProxyComposer( d ) );
0053     d->yearPtr = Meta::YearPtr( new ProxyYear( d ) );
0054 
0055     QThread *mainThread = QCoreApplication::instance()->thread();
0056     bool foreignThread = QThread::currentThread() != mainThread;
0057     if( foreignThread )
0058         d->moveToThread( mainThread );
0059 
0060     if( lookupType == AutomaticLookup )
0061     {
0062         Worker *worker = new Worker( d->url );
0063         if( foreignThread )
0064             worker->moveToThread( mainThread );
0065 
0066         QObject::connect( worker, &Worker::finishedLookup,
0067                           d, &Track::Private::slotUpdateTrack );
0068         ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(worker) );
0069     }
0070 }
0071 
0072 MetaProxy::Track::~Track()
0073 {
0074     delete d;
0075 }
0076 
0077 void
0078 MetaProxy::Track::lookupTrack( Collections::TrackProvider *provider )
0079 {
0080     Worker *worker = new Worker( d->url, provider );
0081     QThread *mainThread = QCoreApplication::instance()->thread();
0082     if( QThread::currentThread() != mainThread )
0083         worker->moveToThread( mainThread );
0084 
0085     QObject::connect( worker, &MetaProxy::Worker::finishedLookup,
0086                       d, &Private::slotUpdateTrack );
0087     ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(worker) );
0088 }
0089 
0090 QString
0091 MetaProxy::Track::name() const
0092 {
0093     if( d->realTrack )
0094         return d->realTrack->name();
0095     else
0096         return d->cachedName;
0097 }
0098 
0099 void
0100 MetaProxy::Track::setTitle( const QString &name )
0101 {
0102     d->cachedName = name;
0103 }
0104 
0105 QString
0106 MetaProxy::Track::prettyName() const
0107 {
0108     if( d->realTrack )
0109         return d->realTrack->prettyName();
0110     else
0111         return Meta::Track::prettyName();
0112 }
0113 
0114 QString
0115 MetaProxy::Track::sortableName() const
0116 {
0117     if( d->realTrack )
0118         return d->realTrack->sortableName();
0119     else
0120         return Meta::Track::sortableName();
0121 }
0122 
0123 QUrl
0124 MetaProxy::Track::playableUrl() const
0125 {
0126     if( d->realTrack )
0127         return d->realTrack->playableUrl();
0128     else
0129         /* don't return d->url here, it may be something like
0130          * amarok-sqltrackuid://2f9277bb7e49962c1c4c5612811807a1 and Phonon may choke
0131          * on such urls trying to find a codec and causing hang (bug 308371) */
0132         return QUrl();
0133 }
0134 
0135 QString
0136 MetaProxy::Track::prettyUrl() const
0137 {
0138     if( d->realTrack )
0139         return d->realTrack->prettyUrl();
0140     else
0141         return d->url.toDisplayString();
0142 }
0143 
0144 QString
0145 MetaProxy::Track::uidUrl() const
0146 {
0147     if( d->realTrack )
0148         return d->realTrack->uidUrl();
0149     else
0150         return d->url.url();
0151 }
0152 
0153 QString
0154 MetaProxy::Track::notPlayableReason() const
0155 {
0156     if( !d->realTrack )
0157         return i18n( "When Amarok was last closed, this track was at %1, but Amarok "
0158                 "cannot find this track on the filesystem or in any of your collections "
0159                 "anymore. You may try plugging in the device this track might be on.",
0160                 prettyUrl() );
0161     return d->realTrack->notPlayableReason();
0162 }
0163 
0164 Meta::AlbumPtr
0165 MetaProxy::Track::album() const
0166 {
0167     return d->albumPtr;
0168 }
0169 
0170 void
0171 MetaProxy::Track::setAlbum( const QString &album )
0172 {
0173     d->cachedAlbum = album;
0174 }
0175 
0176 void
0177 Track::setAlbumArtist( const QString &artist )
0178 {
0179     Q_UNUSED( artist );
0180 }
0181 
0182 Meta::ArtistPtr
0183 MetaProxy::Track::artist() const
0184 {
0185     return d->artistPtr;
0186 }
0187 
0188 void
0189 MetaProxy::Track::setArtist( const QString &artist )
0190 {
0191     d->cachedArtist = artist;
0192 }
0193 
0194 Meta::GenrePtr
0195 MetaProxy::Track::genre() const
0196 {
0197     return d->genrePtr;
0198 }
0199 
0200 void
0201 MetaProxy::Track::setGenre( const QString &genre )
0202 {
0203     d->cachedGenre = genre;
0204 }
0205 
0206 Meta::ComposerPtr
0207 MetaProxy::Track::composer() const
0208 {
0209     return d->composerPtr;
0210 }
0211 
0212 void
0213 MetaProxy::Track::setComposer( const QString &composer )
0214 {
0215     d->cachedComposer = composer;
0216 }
0217 
0218 Meta::YearPtr
0219 MetaProxy::Track::year() const
0220 {
0221     return d->yearPtr;
0222 }
0223 
0224 void
0225 MetaProxy::Track::setYear( int year )
0226 {
0227     d->cachedYear = year;
0228 }
0229 
0230 Meta::LabelList
0231 Track::labels() const
0232 {
0233     if( d->realTrack )
0234         return d->realTrack->labels();
0235     else
0236         return Meta::Track::labels();
0237 }
0238 
0239 qreal
0240 MetaProxy::Track::bpm() const
0241 {
0242     if( d->realTrack )
0243         return d->realTrack->bpm();
0244     else
0245         return d->cachedBpm;
0246 }
0247 
0248 void
0249 MetaProxy::Track::setBpm( const qreal bpm )
0250 {
0251     d->cachedBpm = bpm;
0252 }
0253 
0254 QString
0255 MetaProxy::Track::comment() const
0256 {
0257     if( d->realTrack )
0258         return d->realTrack->comment();
0259     else
0260         return QString(); // we don't cache comment
0261 }
0262 
0263 void
0264 Track::setComment( const QString & )
0265 {
0266     // we don't cache comment
0267 }
0268 
0269 int
0270 MetaProxy::Track::trackNumber() const
0271 {
0272     if( d->realTrack )
0273         return d->realTrack->trackNumber();
0274     else
0275         return d->cachedTrackNumber;
0276 }
0277 
0278 void
0279 MetaProxy::Track::setTrackNumber( int number )
0280 {
0281     d->cachedTrackNumber = number;
0282 }
0283 
0284 int
0285 MetaProxy::Track::discNumber() const
0286 {
0287     if( d->realTrack )
0288         return d->realTrack->discNumber();
0289     else
0290         return d->cachedDiscNumber;
0291 }
0292 
0293 void
0294 MetaProxy::Track::setDiscNumber( int discNumber )
0295 {
0296     d->cachedDiscNumber = discNumber;
0297 }
0298 
0299 qint64
0300 MetaProxy::Track::length() const
0301 {
0302     if( d->realTrack )
0303         return d->realTrack->length();
0304     else
0305         return d->cachedLength;
0306 }
0307 
0308 void
0309 MetaProxy::Track::setLength( qint64 length )
0310 {
0311     d->cachedLength = length;
0312 }
0313 
0314 int
0315 MetaProxy::Track::filesize() const
0316 {
0317     if( d->realTrack )
0318         return d->realTrack->filesize();
0319     else
0320         return 0;
0321 }
0322 
0323 int
0324 MetaProxy::Track::sampleRate() const
0325 {
0326     if( d->realTrack )
0327         return d->realTrack->sampleRate();
0328     else
0329         return 0;
0330 }
0331 
0332 int
0333 MetaProxy::Track::bitrate() const
0334 {
0335     if( d->realTrack )
0336         return d->realTrack->bitrate();
0337     else
0338         return 0;
0339 }
0340 
0341 QDateTime
0342 MetaProxy::Track::createDate() const
0343 {
0344     if( d->realTrack )
0345         return d->realTrack->createDate();
0346     else
0347         return Meta::Track::createDate();
0348 }
0349 
0350 QDateTime
0351 Track::modifyDate() const
0352 {
0353     if( d->realTrack )
0354         return d->realTrack->modifyDate();
0355     else
0356         return Meta::Track::modifyDate();
0357 }
0358 
0359 qreal
0360 Track::replayGain( Meta::ReplayGainTag mode ) const
0361 {
0362     if( d->realTrack )
0363         return d->realTrack->replayGain( mode );
0364     else
0365         return Meta::Track::replayGain( mode );
0366 }
0367 
0368 QString
0369 MetaProxy::Track::type() const
0370 {
0371     if( d->realTrack )
0372         return d->realTrack->type();
0373     else
0374         // just debugging, normal users shouldn't hit this
0375         return QStringLiteral( "MetaProxy::Track" );
0376 }
0377 
0378 void
0379 Track::prepareToPlay()
0380 {
0381     if( d->realTrack )
0382         d->realTrack->prepareToPlay();
0383 }
0384 
0385 void
0386 MetaProxy::Track::finishedPlaying( double playedFraction )
0387 {
0388     if( d->realTrack )
0389         d->realTrack->finishedPlaying( playedFraction );
0390 }
0391 
0392 bool
0393 MetaProxy::Track::inCollection() const
0394 {
0395     if( d->realTrack )
0396         return d->realTrack->inCollection();
0397     else
0398         return false;
0399 }
0400 
0401 Collections::Collection *
0402 MetaProxy::Track::collection() const
0403 {
0404     if( d->realTrack )
0405         return d->realTrack->collection();
0406     else
0407         return nullptr;
0408 }
0409 
0410 QString
0411 Track::cachedLyrics() const
0412 {
0413     if( d->realTrack )
0414         return d->realTrack->cachedLyrics();
0415     else
0416         return Meta::Track::cachedLyrics();
0417 }
0418 
0419 void
0420 Track::setCachedLyrics(const QString& lyrics)
0421 {
0422     if( d->realTrack )
0423         d->realTrack->setCachedLyrics( lyrics );
0424     else
0425         Meta::Track::setCachedLyrics( lyrics );
0426 }
0427 
0428 void
0429 Track::addLabel( const QString &label )
0430 {
0431     if( d->realTrack )
0432         d->realTrack->addLabel( label );
0433     else
0434         Meta::Track::addLabel( label );
0435 }
0436 
0437 void
0438 Track::addLabel( const Meta::LabelPtr &label )
0439 {
0440     if( d->realTrack )
0441         d->realTrack->addLabel( label );
0442     else
0443         Meta::Track::addLabel( label );
0444 }
0445 
0446 void
0447 Track::removeLabel( const Meta::LabelPtr &label )
0448 {
0449     if( d->realTrack )
0450         d->realTrack->removeLabel( label );
0451     else
0452         Meta::Track::removeLabel( label );
0453 }
0454 
0455 void
0456 MetaProxy::Track::updateTrack( const Meta::TrackPtr &track )
0457 {
0458     d->slotUpdateTrack( track );
0459 }
0460 
0461 bool
0462 MetaProxy::Track::hasCapabilityInterface( Capabilities::Capability::Type type ) const
0463 {
0464     if( d->realTrack )
0465         return d->realTrack->hasCapabilityInterface( type );
0466     else
0467         return false;
0468 }
0469 
0470 Capabilities::Capability *
0471 MetaProxy::Track::createCapabilityInterface( Capabilities::Capability::Type type )
0472 {
0473     if( d->realTrack )
0474         return d->realTrack->createCapabilityInterface( type );
0475     else
0476         return nullptr;
0477 }
0478 
0479 bool
0480 MetaProxy::Track::operator==( const Meta::Track &track ) const
0481 {
0482     const MetaProxy::Track *proxy = dynamic_cast<const MetaProxy::Track *>( &track );
0483     if( proxy && d->realTrack )
0484         return d->realTrack == proxy->d->realTrack;
0485     else if( proxy )
0486         return d->url == proxy->d->url;
0487 
0488     return d->realTrack && d->realTrack.data() == &track;
0489 }
0490 
0491 Meta::TrackEditorPtr
0492 Track::editor()
0493 {
0494     if( d->realTrack )
0495         return d->realTrack->editor();
0496     else
0497         return Meta::TrackEditorPtr( this );
0498 }
0499 
0500 Meta::StatisticsPtr
0501 Track::statistics()
0502 {
0503     if( d->realTrack )
0504         return d->realTrack->statistics();
0505     else
0506         return Meta::Track::statistics();
0507 }
0508 
0509 void
0510 Track::beginUpdate()
0511 {
0512     // nothing to do
0513 }
0514 
0515 void
0516 Track::endUpdate()
0517 {
0518     // we intentionally don't call metadataUpdated() so that the first thing that
0519     // triggers metadataUpdated() is when the real track is found.
0520 }
0521 
0522 bool
0523 Track::isResolved() const
0524 {
0525     return d->realTrack;
0526 }