1 /****************************************************************************************
2  * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org>                                *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #include "ScriptableService.h"
18 
19 #include "scripting/scriptmanager/ScriptManager.h"
20 #include "browsers/CollectionTreeItem.h"
21 #include "browsers/SingleCollectionTreeItemModel.h"
22 #include "browsers/servicebrowser/ServiceBrowser.h"
23 #include "core/support/Amarok.h"
24 #include "core/support/Debug.h"
25 #include "services/scriptable/ScriptableServiceCollectionTreeModel.h"
26 #include "services/scriptable/ScriptableServiceInfoParser.h"
27 #include "widgets/SearchWidget.h"
28 
29 #include <QStandardPaths>
30 
31 using namespace Meta;
32 
ScriptableService(const QString & name)33 ScriptableService::ScriptableService( const QString & name )
34     : ServiceBase( name, nullptr )
35     , m_polished( false )
36     , m_name( name )
37     , m_trackIdCounter( 0 )
38     , m_albumIdCounter( 0 )
39     , m_artistIdCounter( 0 )
40     , m_genreIdCounter( 0 )
41 {
42     DEBUG_BLOCK
43     debug() << "creating ScriptableService " << name;
44     m_collection = nullptr;
45     m_bottomPanel->hide();
46 }
47 
~ScriptableService()48 ScriptableService::~ScriptableService()
49 {
50     m_collection->deleteLater();
51 }
52 
init(int levels,const QString & rootHtml,bool showSearchBar)53 void ScriptableService::init( int levels, const QString & rootHtml, bool showSearchBar )
54 {
55     DEBUG_BLOCK
56     m_levels = levels;
57     m_rootHtml = rootHtml;
58     m_hasSearchBar = showSearchBar;
59     m_searchWidget->showAdvancedButton( false );
60     setInfoParser( new ScriptableServiceInfoParser( m_name ) );
61     m_collection = new Collections::ScriptableServiceCollection( m_name );
62     m_collection->setLevels( levels );
63 
64     if ( !showSearchBar )
65         m_searchWidget->hide();
66 }
67 
collection()68 Collections::ServiceCollection * ScriptableService::collection()
69 {
70     return m_collection;
71 }
72 
73 
insertItem(int level,int parentId,const QString & name,const QString & infoHtml,const QString & callbackData,const QString & playableUrl,const QString & albumOverride,const QString & artistOverride,const QString & genreOverride,const QString & composerOverride,int yearOverride,const QString & coverUrl)74 int ScriptableService::insertItem( int level, int parentId, const QString & name, const QString & infoHtml, const QString & callbackData, const QString & playableUrl,
75                                    const QString & albumOverride, const QString & artistOverride, const QString & genreOverride,
76                                    const QString & composerOverride, int yearOverride, const QString &coverUrl  )
77 {
78 
79     /*
80     please don't remove this block as I regularly need it for debugging - nhn
81     DEBUG_BLOCK
82     debug() << "level: " << level;
83     debug() << "parentId: " << parentId;
84     debug() << "name: " << name;
85     debug() << "infoHtml: " << infoHtml;
86     debug() << "callbackData: " << callbackData;
87     debug() << "playableUrl: " << playableUrl;
88 
89     debug() << "albumOverride: " << albumOverride;
90     debug() << "artistOverride: " << artistOverride;
91     debug() << "coverUrl: " << coverUrl;*/
92 
93     if ( ( level +1 > m_levels ) || level < 0 )
94         return -1;
95 
96     switch ( level ) {
97 
98         case 0:
99         {
100             if( !callbackData.isEmpty() || playableUrl.isEmpty() )
101                 return -1;
102 
103             AmarokSharedPointer<ScriptableServiceTrack> track( new ScriptableServiceTrack( name ) );
104             track->setAlbumId( parentId );
105             track->setUidUrl( playableUrl );
106             track->setServiceName( m_name );
107             track->setDescription( infoHtml );
108 
109             if ( !m_customEmblem.isNull() )
110                 track->setServiceEmblem( m_customEmblem );
111             else
112                 track->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
113 
114             if ( !m_customScalableEmblem.isEmpty() )
115                 track->setServiceScalableEmblem( m_customScalableEmblem );
116             else
117                 track->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
118 
119             if ( !albumOverride.isEmpty() )
120                 track->setAlbumName( albumOverride );
121             if ( !artistOverride.isEmpty() )
122                 track->setArtistName( artistOverride );
123             if ( !genreOverride.isEmpty() )
124                 track->setGenreName( genreOverride );
125             if ( !composerOverride.isEmpty() )
126                 track->setComposerName( composerOverride );
127             if ( yearOverride != 0 )
128                 track->setYearNumber( yearOverride );
129             if ( !coverUrl.isEmpty() )
130                 track->setCustomAlbumCoverUrl( coverUrl );
131 
132             return addTrack( track.data() );
133             break;
134 
135         } case 1:
136         {
137             if ( callbackData.isEmpty() || !playableUrl.isEmpty() )
138                 return -1;
139 
140             ScriptableServiceAlbum * album = new ScriptableServiceAlbum( name );
141             album->setCallbackString( callbackData );
142             album->setArtistId( parentId );
143             album->setDescription( infoHtml );
144             album->setServiceName( m_name );
145             //debug() << "setting coverUrl: " << coverUrl;
146             album->setCoverUrl( coverUrl );
147 
148             album->setServiceName( m_name );
149             album->setDescription( infoHtml );
150 
151             if ( !m_customEmblem.isNull() )
152                 album->setServiceEmblem( m_customEmblem );
153             else
154                 album->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
155 
156             if ( !m_customScalableEmblem.isEmpty() )
157                 album->setServiceScalableEmblem( m_customScalableEmblem );
158             else
159                 album->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
160 
161             return addAlbum( album );
162 
163         } case 2:
164         {
165             if ( callbackData.isEmpty() || !playableUrl.isEmpty() )
166                 return -1;
167 
168             ScriptableServiceArtist * artist = new ScriptableServiceArtist( name );
169             artist->setCallbackString( callbackData );
170             artist->setGenreId( parentId );
171             artist->setDescription( infoHtml );
172             artist->setServiceName( m_name );
173 
174             artist->setServiceName( m_name );
175             artist->setDescription( infoHtml );
176 
177             if ( !m_customEmblem.isNull() )
178                 artist->setServiceEmblem( m_customEmblem );
179             else
180                 artist->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
181 
182             if ( !m_customScalableEmblem.isEmpty() )
183                 artist->setServiceScalableEmblem( m_customScalableEmblem );
184             else
185                 artist->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
186 
187 
188             return addArtist( artist );
189 
190         } case 3:
191         {
192 
193             if ( callbackData.isEmpty() ||  !playableUrl.isEmpty() || parentId != -1 )
194                 return -1;
195 
196             ScriptableServiceGenre * genre = new ScriptableServiceGenre( name );
197             genre->setCallbackString( callbackData );
198             genre->setDescription( infoHtml );
199             genre->setServiceName( m_name );
200 
201             genre->setServiceName( m_name );
202             genre->setDescription( infoHtml );
203 
204             if ( !m_customEmblem.isNull() )
205                 genre->setServiceEmblem( m_customEmblem );
206             else
207                 genre->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
208 
209             if ( !m_customScalableEmblem.isEmpty() )
210                 genre->setServiceScalableEmblem( m_customScalableEmblem );
211             else
212                 genre->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
213 
214 
215             return addGenre( genre );
216 
217         }
218     }
219     return -1;
220 }
221 
222 
addTrack(ScriptableServiceTrack * track)223 int ScriptableService::addTrack( ScriptableServiceTrack * track )
224 {
225     int artistId = -1;
226     int genreId = -1;
227 
228     TrackPtr trackPtr = TrackPtr( track );
229     m_collection->acquireWriteLock();
230     m_collection->addTrack( trackPtr );
231     m_collection->releaseLock();
232 
233     m_trackIdCounter++;
234     track->setId( m_trackIdCounter );
235 
236 
237     int albumId = track->albumId();
238 
239     //handle albums
240     if ( m_levels > 1 ) {
241 
242         if ( !m_ssAlbumIdMap.contains( albumId ) ){
243             return -1;
244         }
245 
246         ScriptableServiceAlbum * album = m_ssAlbumIdMap.value( albumId );
247 
248         track->setAlbum( album->prettyName() );
249         track->setAlbumPtr( AlbumPtr( album ) );
250         album->addTrack( trackPtr );
251 
252         artistId = album->artistId();
253 
254      }
255 
256      if ( m_levels > 2 ) {
257 
258          if ( !m_ssArtistIdMap.contains( artistId ) ) {
259              return -1;
260          }
261 
262          ScriptableServiceArtist * artist = m_ssArtistIdMap.value( artistId );
263          track->setArtist( artist->prettyName() );
264          track->setArtist( ArtistPtr( artist ) );
265          artist->addTrack( trackPtr );
266 
267          genreId = artist->genreId();
268      }
269 
270      if ( m_levels == 4) {
271 
272          if ( !m_ssGenreIdMap.contains( genreId ) ) {
273              return -1;
274          }
275 
276          ScriptableServiceGenre * genre = m_ssGenreIdMap.value( genreId );
277          track->setGenre( genre->prettyName() );
278          track->setGenre( GenrePtr( genre ) );
279          genre->addTrack( trackPtr );
280 
281      }
282 
283     m_ssTrackIdMap.insert( m_trackIdCounter, track );
284     m_collection->acquireWriteLock();
285     m_collection->addTrack( trackPtr );
286     m_collection->releaseLock();
287 
288     //m_collection->emitUpdated();
289 
290     return m_trackIdCounter;
291 }
292 
addAlbum(ScriptableServiceAlbum * album)293 int ScriptableService::addAlbum( ScriptableServiceAlbum * album )
294 {
295     int artistId = album->artistId();
296     if ( m_levels > 2 && !m_ssArtistIdMap.contains( artistId ) ) {
297         delete album;
298         return -1;
299     }
300 
301     album->setAlbumArtist( ArtistPtr( m_ssArtistIdMap.value( artistId ) ) );
302 
303     AlbumPtr albumPtr = AlbumPtr( album );
304     m_albumIdCounter++;
305     album->setId( m_albumIdCounter );
306     m_ssAlbumIdMap.insert( m_albumIdCounter, album );
307     m_collection->acquireWriteLock();
308     m_collection->addAlbum( albumPtr );
309     m_collection->releaseLock();
310     //m_collection->emitUpdated();
311     return m_albumIdCounter;
312 }
313 
addArtist(Meta::ScriptableServiceArtist * artist)314 int ScriptableService::addArtist( Meta::ScriptableServiceArtist * artist )
315 {
316     int genreId = artist->genreId();
317     if (  m_levels > 3 && !m_ssGenreIdMap.contains( genreId ) ) {
318         delete artist;
319         return -1;
320     }
321 
322     ArtistPtr artistPtr = ArtistPtr( artist );
323     m_artistIdCounter++;
324     artist->setId( m_artistIdCounter );
325     m_ssArtistIdMap.insert( m_artistIdCounter, artist );
326     m_collection->acquireWriteLock();
327     m_collection->addArtist( artistPtr );
328     m_collection->releaseLock();
329 
330     return m_artistIdCounter;
331 
332 }
333 
addGenre(Meta::ScriptableServiceGenre * genre)334 int ScriptableService::addGenre( Meta::ScriptableServiceGenre * genre )
335 {
336     GenrePtr genrePtr = GenrePtr( genre );
337     m_genreIdCounter++;
338 
339     //debug() << "adding genre: " << genre->name() << ", with id: " << m_genreIdCounter;
340 
341     genre->setId( m_genreIdCounter );
342     m_ssGenreIdMap.insert( m_genreIdCounter, genre );
343     m_collection->acquireWriteLock();
344     m_collection->addGenre( genrePtr );
345     m_collection->releaseLock();
346 
347     return m_genreIdCounter;
348 }
349 
donePopulating(int parentId)350 void ScriptableService::donePopulating( int parentId )
351 {
352     m_collection->donePopulating( parentId );
353 }
354 
polish()355 void ScriptableService::polish()
356 {
357 
358     if ( !m_polished ) {
359         QList<CategoryId::CatMenuId> viewLevels;
360 
361         switch ( m_levels ) {
362             case 1:
363                 break;
364             case 2:
365                 viewLevels << CategoryId::Album;
366                 break;
367             case 3:
368                 viewLevels << CategoryId::Artist << CategoryId::Album;
369                 break;
370             case 4:
371                 viewLevels << CategoryId::Genre << CategoryId::Artist << CategoryId::Album;
372                 break;
373             default:
374                 return;
375         }
376 
377         m_contentView->setModel( new ScriptableServiceCollectionTreeModel( m_collection, viewLevels ) );
378         m_polished = true;
379 
380     }
381 
382     infoChanged( m_rootHtml );
383 }
384 
setCustomEmblem(const QPixmap & emblem)385 void ScriptableService::setCustomEmblem( const QPixmap &emblem )
386 {
387     m_customEmblem = emblem;
388 }
389 
customEmblem()390 QPixmap ScriptableService::customEmblem()
391 {
392     return m_customEmblem;
393 }
394 
395 
customScalableEmblem()396 QString ScriptableService::customScalableEmblem()
397 {
398     return m_customScalableEmblem;
399 }
400 
401 
setCustomScalableEmblem(const QString & emblemPath)402 void ScriptableService::setCustomScalableEmblem ( const QString& emblemPath )
403 {
404     m_customScalableEmblem = emblemPath;
405 }
406 
407 
408 
setCurrentInfo(const QString & info)409 void ScriptableService::setCurrentInfo( const QString & info )
410 {
411     infoChanged( info );
412 }
413 
414 
415 
416 
417 
418