2 * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 #define DEBUG_PREFIX "CollectionManager"
20 #include "CollectionManager.h"
24 #include "BlockingQuery.h"
25 #include "Collection.h"
26 #include "MetaQueryBuilder.h"
27 #include "meta/file/File.h"
28 #include "meta/stream/Stream.h"
29 #include "meta/lastfm/LastFmMeta.h"
30 #include "pluginmanager.h"
31 #include "scrobbler.h"
32 #include "SqlStorage.h"
34 #include <QtAlgorithms>
41 struct CollectionManager::Private
43 QList
<Collection
*> collections
;
44 QList
<CollectionFactory
*> factories
;
45 SqlStorage
*sqlDatabase
;
46 QList
<Collection
*> unmanagedCollections
;
47 QList
<Collection
*> managedCollections
;
50 class CollectionManagerSingleton
53 CollectionManager instance
;
56 K_GLOBAL_STATIC( CollectionManagerSingleton
, privateInstance
)
60 CollectionManager::instance( )
62 return &privateInstance
->instance
;
65 CollectionManager::CollectionManager()
72 CollectionManager::~CollectionManager()
74 d
->collections
.clear();
75 d
->unmanagedCollections
.clear();
76 qDeleteAll( d
->managedCollections
);
78 foreach( CollectionFactory
*fac
, d
->factories
)
79 PluginManager::unload( fac
);
85 CollectionManager::init()
90 KService::List plugins
= PluginManager::query( "[X-KDE-Amarok-plugintype] == 'collection'" );
91 debug() << "Received [" << QString::number( plugins
.count() ) << "] collection plugin offers";
92 foreach( KService::Ptr service
, plugins
)
94 Amarok::Plugin
*plugin
= PluginManager::createFromService( service
);
97 CollectionFactory
* factory
= dynamic_cast<CollectionFactory
*>( plugin
);
100 connect( factory
, SIGNAL( newCollection( Collection
* ) ), this, SLOT( slotNewCollection( Collection
* ) ) );
101 d
->factories
.append( factory
);
106 debug() << "Plugin has wrong factory class";
114 CollectionManager::startFullScan()
116 foreach( Collection
*coll
, d
->collections
)
118 coll
->startFullScan();
123 CollectionManager::checkCollectionChanges()
125 foreach( Collection
*coll
, d
->collections
)
127 coll
->startIncrementalScan();
132 CollectionManager::queryMaker()
134 return new MetaQueryBuilder( d
->collections
);
138 CollectionManager::slotNewCollection( Collection
* newCollection
)
142 debug() << "Warning, newCollection in slotNewCollection is 0";
145 debug() << "New collection with collectionId: " << newCollection
->collectionId();
146 d
->collections
.append( newCollection
);
147 d
->managedCollections
.append( newCollection
);
148 connect( newCollection
, SIGNAL( remove() ), SLOT( slotRemoveCollection() ), Qt::QueuedConnection
);
149 connect( newCollection
, SIGNAL( updated() ), SLOT( slotCollectionChanged() ), Qt::QueuedConnection
);
150 SqlStorage
*sqlCollection
= dynamic_cast<SqlStorage
*>( newCollection
);
155 if( d
->sqlDatabase
->sqlDatabasePriority() < sqlCollection
->sqlDatabasePriority() )
156 d
->sqlDatabase
= sqlCollection
;
159 d
->sqlDatabase
= sqlCollection
;
161 emit
collectionAdded( newCollection
);
165 CollectionManager::slotRemoveCollection()
167 Collection
* collection
= dynamic_cast<Collection
*>( sender() );
170 d
->collections
.removeAll( collection
);
171 d
->managedCollections
.removeAll( collection
);
172 SqlStorage
*sqlDb
= dynamic_cast<SqlStorage
*>( collection
);
173 if( sqlDb
&& sqlDb
== d
->sqlDatabase
)
175 SqlStorage
*newSqlDatabase
= 0;
176 foreach( Collection
* tmp
, d
->collections
)
178 SqlStorage
*sqlDb
= dynamic_cast<SqlStorage
*>( tmp
);
183 if( newSqlDatabase
->sqlDatabasePriority() < sqlDb
->sqlDatabasePriority() )
184 newSqlDatabase
= sqlDb
;
187 newSqlDatabase
= sqlDb
;
190 d
->sqlDatabase
= newSqlDatabase
;
192 emit
collectionRemoved( collection
->collectionId() );
193 QTimer::singleShot( 0, collection
, SLOT( deleteLater() ) );
198 CollectionManager::slotCollectionChanged()
200 Collection
*collection
= dynamic_cast<Collection
*>( sender() );
203 emit
collectionDataChanged( collection
);
208 CollectionManager::collections()
210 return d
->collections
;
214 CollectionManager::sqlStorage() const
216 return d
->sqlDatabase
;
220 CollectionManager::tracksForUrls( const KUrl::List
&urls
)
222 Meta::TrackList tracks
;
223 foreach( KUrl url
, urls
)
224 tracks
.append( trackForUrl( url
) );
229 CollectionManager::trackForUrl( const KUrl
&url
)
232 //check all collections
233 //might be a podcast, in that case we'll have additional meta information
234 //might be a lastfm track, another stream
235 //or a file which is not in any collection
236 debug() << "track for url: " << url
.url();
238 if( url
.protocol() == "lastfm" )
239 return Meta::TrackPtr( new LastFm::Track( url
.url() ) );
241 foreach( Collection
*coll
, d
->collections
)
243 if( coll
->possiblyContainsTrack( url
) )
245 Meta::TrackPtr track
= coll
->trackForUrl( url
);
251 if( url
.protocol() == "http" || url
.protocol() == "mms" )
252 return Meta::TrackPtr( new MetaStream::Track( url
) );
254 if( url
.protocol() == "file" )
255 return Meta::TrackPtr( new MetaFile::Track( url
) );
257 return Meta::TrackPtr( 0 );
261 CollectionManager::relatedArtists( Meta::ArtistPtr artist
, int maxArtists
)
263 SqlStorage
*sql
= sqlStorage();
264 QString query
= QString( "SELECT suggestion FROM related_artists WHERE artist = '%1' ORDER BY %2 LIMIT %3 OFFSET 0;" )
265 .arg( sql
->escape( artist
->name() ), sql
->randomFunc(), QString::number( maxArtists
) );
267 QStringList artistNames
= sql
->query( query
);
268 //TODO: figure out a way to retrieve similar artists from last.fm here
269 /*if( artistNames.isEmpty() )
271 artistNames = Scrobbler::instance()->similarArtists( artist->name() );
273 QueryMaker
*qm
= queryMaker();
274 foreach( QString artist
, artistNames
)
276 qm
->addFilter( QueryMaker::valArtist
, artist
, true, true );
278 qm
->startArtistQuery();
279 qm
->limitMaxResultSize( maxArtists
);
280 BlockingQuery
bq( qm
);
283 QStringList ids
= bq
.collectionIds();
284 Meta::ArtistList result
;
285 QSet
<QString
> artistNameSet
;
286 foreach( QString collectionId
, ids
)
288 Meta::ArtistList artists
= bq
.artists( collectionId
);
289 foreach( Meta::ArtistPtr artist
, artists
)
291 if( !artistNameSet
.contains( artist
->name() ) )
293 result
.append( artist
);
294 artistNameSet
.insert( artist
->name() );
295 if( result
.size() == maxArtists
)
299 if( result
.size() == maxArtists
)
306 CollectionManager::addUnmanagedCollection( Collection
*newCollection
)
308 if( newCollection
&& d
->collections
.indexOf( newCollection
) == -1 )
310 d
->unmanagedCollections
.append( newCollection
);
311 d
->collections
.append( newCollection
);
312 emit
collectionAdded( newCollection
);
317 CollectionManager::removeUnmanagedCollection( Collection
*collection
)
319 //do not remove it from collection if it is not in unmanagedCollections
320 if( collection
&& d
->unmanagedCollections
.removeAll( collection
) )
322 d
->collections
.removeAll( collection
);
323 emit
collectionRemoved( collection
->collectionId() );
327 #include "CollectionManager.moc"