diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 1441d06a5..eecb7490c 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -624,6 +624,14 @@ Tomahawk.PluginManager = { resolve: [], invokeSync: function (requestId, objectId, methodName, params) { + if (!Tomahawk.resolver.instance.apiVersion || Tomahawk.resolver.instance.apiVersion < 0.9) { + if (methodName === 'artistAlbums') { + methodName = 'albums'; + } else if ( methodName === 'albumTracks' ) { + methodName = 'tracks'; + } + } + var pluginManager = this; if (!this.objects[objectId]) { Tomahawk.log("Object not found! objectId: " + objectId + " methodName: " + methodName); @@ -694,6 +702,15 @@ Tomahawk.ConfigTestResultType = { }; +Tomahawk.Collection = { + BrowseCapability: { + Artists: 1, + Albums: 2, + Tracks: 4 + } +}; + + // Legacy compability for 0.8 and before Tomahawk.reportCapabilities = function (capabilities) { if (capabilities & TomahawkResolverCapability.Browsable) { diff --git a/src/libtomahawk/collection/Collection.cpp b/src/libtomahawk/collection/Collection.cpp index de9c2d2a7..55dfb3759 100644 --- a/src/libtomahawk/collection/Collection.cpp +++ b/src/libtomahawk/collection/Collection.cpp @@ -67,6 +67,13 @@ Collection::weakRef() const } +QSet< Collection::BrowseCapability > +Collection::browseCapabilities() const +{ + return m_browseCapabilities; +} + + const QString Collection::name() const { diff --git a/src/libtomahawk/collection/Collection.h b/src/libtomahawk/collection/Collection.h index c83b4e685..225ad3097 100644 --- a/src/libtomahawk/collection/Collection.h +++ b/src/libtomahawk/collection/Collection.h @@ -27,10 +27,6 @@ #ifndef TOMAHAWK_COLLECTION_H #define TOMAHAWK_COLLECTION_H -#include -#include -#include - #include "Typedefs.h" #include "Playlist.h" #include "playlist/dynamic/DynamicPlaylist.h" @@ -41,6 +37,12 @@ #include "DllMacro.h" +#include +#include +#include +#include + + namespace Tomahawk { @@ -55,6 +57,16 @@ public: void setWeakRef( const collection_wptr& weakRef ); const collection_wptr weakRef() const; + enum BrowseCapability + { + CapabilityBrowseNull = 0x0, + CapabilityBrowseArtists = 0x1, + CapabilityBrowseAlbums = 0x2, + CapabilityBrowseTracks = 0x4 + }; + + QSet< BrowseCapability > browseCapabilities() const; + enum BackendType { NullCollectionType = 0, @@ -127,6 +139,7 @@ public slots: protected: QString m_name; unsigned int m_lastmodified; // unix time of last change to collection + QSet< BrowseCapability > m_browseCapabilities; private slots: void onSynced(); diff --git a/src/libtomahawk/resolvers/ScriptCollection.cpp b/src/libtomahawk/resolvers/ScriptCollection.cpp index b1bd718b5..c9d707e67 100644 --- a/src/libtomahawk/resolvers/ScriptCollection.cpp +++ b/src/libtomahawk/resolvers/ScriptCollection.cpp @@ -229,6 +229,27 @@ ScriptCollection::parseMetaData( const QVariantMap& metadata ) fetchIcon( metadata.value( "iconurl" ).toString() ); } + + if ( metadata.contains( "capabilities" ) ) + { + QVariantList list = metadata[ "capabilities" ].toList(); + + foreach( const QVariant& type, list ) + { + bool ok; + int intType = type.toInt( &ok ); + if ( ok ) + { + tLog() << intType; + m_browseCapabilities << static_cast< BrowseCapability >( intType ); + } + } + + } + else + { + m_browseCapabilities << CapabilityBrowseArtists; + } } diff --git a/src/libtomahawk/resolvers/ScriptCommand_AllAlbums.cpp b/src/libtomahawk/resolvers/ScriptCommand_AllAlbums.cpp index ba6ba27b1..0aaffef9b 100644 --- a/src/libtomahawk/resolvers/ScriptCommand_AllAlbums.cpp +++ b/src/libtomahawk/resolvers/ScriptCommand_AllAlbums.cpp @@ -26,6 +26,7 @@ #include "PlaylistEntry.h" #include "ScriptCollection.h" #include "ScriptJob.h" +#include "ScriptCommand_AllArtists.h" using namespace Tomahawk; @@ -70,16 +71,18 @@ ScriptCommand_AllAlbums::exec() return; } - if ( !m_artist ) + ScriptJob* job; + if ( m_artist ) { - reportFailure(); - return; + QVariantMap arguments; + arguments[ "artist" ] = m_artist->name(); + job = collection->scriptObject()->invoke( "artistAlbums", arguments ); + } + else + { + job = collection->scriptObject()->invoke( "albums" ); } - QVariantMap arguments; - arguments[ "artist" ] = m_artist->name(); - - ScriptJob* job = collection->scriptObject()->invoke( "albums", arguments ); connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onAlbumsJobDone( QVariantMap ) ), Qt::QueuedConnection ); job->start(); } @@ -108,8 +111,17 @@ ScriptCommand_AllAlbums::onAlbumsJobDone(const QVariantMap& result) return; } - QList< Tomahawk::album_ptr > a = parseAlbumVariantList( m_artist, result[ "albums" ].toList() ); + QList< Tomahawk::artist_ptr > resultArtists; + if ( result["artists"].toList().length() > 0 ) + { + resultArtists = ScriptCommand_AllArtists::parseArtistVariantList( result[ "artists" ].toList() ); + } + else + { + resultArtists << m_artist; + } + QList< Tomahawk::album_ptr > a = parseAlbumVariantList( resultArtists, result[ "albums" ].toList() ); if ( m_filter.isEmpty() ) emit albums( a ); else @@ -130,19 +142,34 @@ ScriptCommand_AllAlbums::onAlbumsJobDone(const QVariantMap& result) QList< Tomahawk::album_ptr > -ScriptCommand_AllAlbums::parseAlbumVariantList( const Tomahawk::artist_ptr& artist, const QVariantList& reslist ) +ScriptCommand_AllAlbums::parseAlbumVariantList( const QList< Tomahawk::artist_ptr >& artists, const QVariantList& reslist ) { QList< Tomahawk::album_ptr > results; - foreach( const QVariant& rv, reslist ) + if (artists.length() != 1 && reslist.length() != artists.length()) { - const QString val = rv.toString(); + tLog() << "artists" << artists.length(); + tLog() << "albums" << reslist.length(); + Q_ASSERT(false); + tLog() << "Got invalid collection albums response where artists and albums don't match"; + return results; + } + + bool useArtistList = ( artists.length() > 1 ); + for( int i=0; i parseAlbumVariantList( const Tomahawk::artist_ptr& artist, + static QList< Tomahawk::album_ptr > parseAlbumVariantList( const QList< Tomahawk::artist_ptr >& artists, const QVariantList& reslist ); Tomahawk::collection_ptr m_collection; Tomahawk::artist_ptr m_artist; diff --git a/src/libtomahawk/resolvers/ScriptCommand_AllArtists.h b/src/libtomahawk/resolvers/ScriptCommand_AllArtists.h index 7dad2b382..4225284f4 100644 --- a/src/libtomahawk/resolvers/ScriptCommand_AllArtists.h +++ b/src/libtomahawk/resolvers/ScriptCommand_AllArtists.h @@ -29,7 +29,9 @@ namespace Tomahawk class ScriptCommand_AllArtists : public ScriptCommand, public Tomahawk::ArtistsRequest { - Q_OBJECT +Q_OBJECT + friend class ScriptCommand_AllAlbums; + public: explicit ScriptCommand_AllArtists( const Tomahawk::collection_ptr& collection, QObject* parent = nullptr ); diff --git a/src/libtomahawk/resolvers/ScriptCommand_AllTracks.cpp b/src/libtomahawk/resolvers/ScriptCommand_AllTracks.cpp index 67b375c84..0315fc04e 100644 --- a/src/libtomahawk/resolvers/ScriptCommand_AllTracks.cpp +++ b/src/libtomahawk/resolvers/ScriptCommand_AllTracks.cpp @@ -64,17 +64,21 @@ ScriptCommand_AllTracks::exec() return; } - if ( m_album.isNull() ) + ScriptJob* job; + if( m_album ) { - reportFailure(); - return; + QVariantMap arguments; + arguments[ "artist" ] = m_album->artist()->name(); + arguments[ "album" ] = m_album->name(); + + job = collection->scriptObject()->invoke( "albumTracks", arguments ); + } + else + { + job = collection->scriptObject()->invoke( "tracks" ); } - QVariantMap arguments; - arguments[ "artist" ] = m_album->artist()->name(); - arguments[ "album" ] = m_album->name(); - ScriptJob* job = collection->scriptObject()->invoke( "tracks", arguments ); connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onTracksJobDone( QVariantMap ) ), Qt::QueuedConnection ); job->start(); } diff --git a/src/libtomahawk/viewpages/CollectionViewPage.cpp b/src/libtomahawk/viewpages/CollectionViewPage.cpp index 627a4b7c0..cb82b12fd 100644 --- a/src/libtomahawk/viewpages/CollectionViewPage.cpp +++ b/src/libtomahawk/viewpages/CollectionViewPage.cpp @@ -88,9 +88,15 @@ CollectionViewPage::CollectionViewPage( const Tomahawk::collection_ptr& collecti m_header->ui->anchor1Label->setText( tr( "Artists" ) ); m_header->ui->anchor2Label->setText( tr( "Albums" ) ); m_header->ui->anchor3Label->setText( tr( "Songs" ) ); - m_header->ui->anchor1Label->show(); - m_header->ui->anchor2Label->show(); - m_header->ui->anchor3Label->show(); + + if( collection->browseCapabilities().contains( Collection::CapabilityBrowseArtists ) ) + m_header->ui->anchor1Label->show(); + + if( collection->browseCapabilities().contains( Collection::CapabilityBrowseAlbums ) ) + m_header->ui->anchor2Label->show(); + + if( collection->browseCapabilities().contains( Collection::CapabilityBrowseTracks ) ) + m_header->ui->anchor3Label->show(); const float lowOpacity = 0.8; m_header->ui->anchor1Label->setOpacity( 1 ); @@ -335,7 +341,33 @@ CollectionViewPage::restoreViewMode() m_mode = static_cast< CollectionViewPageMode >( modeNumber ); TomahawkSettings::instance()->endGroup(); - setCurrentMode( (CollectionViewPageMode)modeNumber ); + // try to set a supported mode otherwise fall back to artists view + CollectionViewPageMode mode = (CollectionViewPageMode) modeNumber; + if ( mode == CollectionViewPage::Columns && !m_collection->browseCapabilities().contains( Collection::CapabilityBrowseArtists ) ) + { + tLog() << Q_FUNC_INFO << 0; + if ( m_collection->browseCapabilities().contains( Collection::CapabilityBrowseAlbums ) ) + setCurrentMode( CollectionViewPage::Albums ); + else if ( m_collection->browseCapabilities().contains( Collection::CapabilityBrowseTracks ) ) + setCurrentMode( CollectionViewPage::Columns ); + } + else if ( mode == CollectionViewPage::Albums && !m_collection->browseCapabilities().contains( Collection::CapabilityBrowseAlbums ) ) + { + tLog() << Q_FUNC_INFO << 1; + if ( m_collection->browseCapabilities().contains( Collection::CapabilityBrowseTracks ) ) + setCurrentMode( CollectionViewPage::Flat ); + else + setCurrentMode( CollectionViewPage::Columns ); + } else if ( mode == CollectionViewPage::Flat && !m_collection->browseCapabilities().contains( Collection::CapabilityBrowseTracks ) ) + { + tLog() << Q_FUNC_INFO << 2; + if ( m_collection->browseCapabilities().contains( Collection::CapabilityBrowseArtists ) ) + setCurrentMode( CollectionViewPage::Columns ); + else if ( m_collection->browseCapabilities().contains( Collection::CapabilityBrowseAlbums ) ) + setCurrentMode( CollectionViewPage::Albums ); + } else { + setCurrentMode( mode ); + } } @@ -386,9 +418,6 @@ CollectionViewPage::onCollectionChanged() } else setEmptyTip( tr( "This collection is empty." ) ); - - if ( m_collection.objectCast() ) - m_trackView->setEmptyTip( tr( "Cloud collections aren't supported in the flat view yet. We will have them covered soon. Switch to another view to navigate them." ) ); }