From c1eadce3742ce9439044a32b87da784c95735014 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Mon, 16 Nov 2015 18:19:51 +0100 Subject: [PATCH] Move lookupUrl stuff from JSResolverHelper to JSResolver, to be moved to own plugin type --- data/js/tomahawk.js | 3 +- src/libtomahawk/DropJob.cpp | 12 +- src/libtomahawk/GlobalActionManager.cpp | 2 +- src/libtomahawk/resolvers/ExternalResolver.h | 11 +- src/libtomahawk/resolvers/JSResolver.cpp | 213 +++++++++++++++--- src/libtomahawk/resolvers/JSResolver.h | 11 + .../resolvers/JSResolverHelper.cpp | 169 -------------- src/libtomahawk/resolvers/JSResolverHelper.h | 8 - 8 files changed, 211 insertions(+), 218 deletions(-) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index b88ac8cda..3d2456a8d 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -173,7 +173,8 @@ var TomahawkUrlType = { Playlist: 1, Track: 2, Album: 4, - Artist: 8 + Artist: 8, + Xspf: 16 }; //Deprecated for 0.9 resolvers. Use Tomahawk.ConfigTestResultType instead. diff --git a/src/libtomahawk/DropJob.cpp b/src/libtomahawk/DropJob.cpp index 13421b011..c301bb610 100644 --- a/src/libtomahawk/DropJob.cpp +++ b/src/libtomahawk/DropJob.cpp @@ -175,7 +175,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType // Check Scriptresolvers foreach ( QPointer resolver, Pipeline::instance()->scriptResolvers() ) { - if ( resolver->canParseUrl( url, ExternalResolver::Playlist ) ) + if ( resolver->canParseUrl( url, ExternalResolver::UrlTypePlaylist ) ) return true; } } @@ -201,7 +201,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType // Check Scriptresolvers foreach ( QPointer resolver, Pipeline::instance()->scriptResolvers() ) { - if ( resolver->canParseUrl( url, ExternalResolver::Track ) ) + if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeTrack ) ) return true; } } @@ -218,7 +218,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType // Check Scriptresolvers foreach ( QPointer resolver, Pipeline::instance()->scriptResolvers() ) { - if ( resolver->canParseUrl( url, ExternalResolver::Album ) ) + if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeAlbum ) ) return true; } } @@ -235,7 +235,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType // Check Scriptresolvers foreach ( QPointer resolver, Pipeline::instance()->scriptResolvers() ) { - if ( resolver->canParseUrl( url, ExternalResolver::Artist ) ) + if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeArtist ) ) return true; } } @@ -306,7 +306,7 @@ DropJob::isDropType( DropJob::DropType desired, const QMimeData* data ) // Check Scriptresolvers foreach ( QPointer resolver, Pipeline::instance()->scriptResolvers() ) { - if ( resolver->canParseUrl( url, ExternalResolver::Playlist ) ) + if ( resolver->canParseUrl( url, ExternalResolver::UrlTypePlaylist ) ) { tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Accepting current drop as a playlist" << resolver->name(); return true; @@ -763,7 +763,7 @@ DropJob::handleTrackUrls( const QString& urls ) { foreach ( QPointer resolver, Pipeline::instance()->scriptResolvers() ) { - if ( resolver->canParseUrl( track, ExternalResolver::Any ) ) + if ( resolver->canParseUrl( track, ExternalResolver::UrlTypeAny ) ) { ScriptCommand_LookupUrl* cmd = new ScriptCommand_LookupUrl( resolver, track ); connect( cmd, SIGNAL( information( QString, QSharedPointer ) ), this, SLOT( informationForUrl( QString, QSharedPointer ) ) ); diff --git a/src/libtomahawk/GlobalActionManager.cpp b/src/libtomahawk/GlobalActionManager.cpp index c341bb8f6..d8131397e 100644 --- a/src/libtomahawk/GlobalActionManager.cpp +++ b/src/libtomahawk/GlobalActionManager.cpp @@ -167,7 +167,7 @@ GlobalActionManager::openUrl( const QString& url ) QList< QPointer< ExternalResolver > > possibleResolvers; foreach ( QPointer resolver, Pipeline::instance()->scriptResolvers() ) { - if ( resolver->canParseUrl( url, ExternalResolver::Any ) ) + if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeAny ) ) { canParse = true; possibleResolvers << resolver; diff --git a/src/libtomahawk/resolvers/ExternalResolver.h b/src/libtomahawk/resolvers/ExternalResolver.h index 57a1eeb74..71e786946 100644 --- a/src/libtomahawk/resolvers/ExternalResolver.h +++ b/src/libtomahawk/resolvers/ExternalResolver.h @@ -68,11 +68,12 @@ public: enum UrlType { - Any = 0x00, - Playlist = 0x01, - Track = 0x02, - Album = 0x04, - Artist = 0x08 + UrlTypeAny = 0x00, + UrlTypePlaylist = 0x01, + UrlTypeTrack = 0x02, + UrlTypeAlbum = 0x04, + UrlTypeArtist = 0x08, + UrlTypeXspf = 0x10 }; Q_DECLARE_FLAGS( UrlTypes, UrlType ) Q_FLAGS( UrlTypes ) diff --git a/src/libtomahawk/resolvers/JSResolver.cpp b/src/libtomahawk/resolvers/JSResolver.cpp index 118f34cca..e2ec13b20 100644 --- a/src/libtomahawk/resolvers/JSResolver.cpp +++ b/src/libtomahawk/resolvers/JSResolver.cpp @@ -46,6 +46,12 @@ #include "JSAccount.h" #include "ScriptJob.h" +// lookupUrl stuff +#include "playlist/PlaylistTemplate.h" +#include "playlist/XspfPlaylistTemplate.h" +#include "database/Database.h" +#include "database/DatabaseImpl.h" + #include #include #include @@ -319,20 +325,13 @@ JSResolver::canParseUrl( const QString& url, UrlType type ) { Q_D( const JSResolver ); - // FIXME: How can we do this? - /*if ( QThread::currentThread() != thread() ) - { - QMetaObject::invokeMethod( this, "canParseUrl", Qt::QueuedConnection, - Q_ARG( QString, url ) ); - return; - }*/ - if ( d->capabilities.testFlag( UrlLookup ) ) { - QString eval = QString( "canParseUrl( '%1', %2 )" ) - .arg( JSAccount::escape( QString( url ) ) ) - .arg( (int) type ); - return callOnResolver( eval ).toBool(); + QVariantMap arguments; + arguments["url"] = url; + arguments["type"] = (int) type; + + return scriptObject()->syncInvoke( "canParseUrl", arguments ).toBool(); } else { @@ -345,34 +344,185 @@ JSResolver::canParseUrl( const QString& url, UrlType type ) void JSResolver::lookupUrl( const QString& url ) { - if ( QThread::currentThread() != thread() ) - { - QMetaObject::invokeMethod( this, "lookupUrl", Qt::QueuedConnection, - Q_ARG( QString, url ) ); - return; - } - Q_D( const JSResolver ); + if ( !d->capabilities.testFlag( UrlLookup ) ) { emit informationFound( url, QSharedPointer() ); return; } - QString eval = QString( "lookupUrl( '%1' )" ) - .arg( JSAccount::escape( QString( url ) ) ); + QVariantMap arguments; + arguments["url"] = url; + Tomahawk::ScriptJob* job = scriptObject()->invoke( "lookupUrl", arguments ); + connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onLookupUrlRequestDone( QVariantMap ) ) ); + job->setProperty( "url", url ); + job->start(); +} - QVariantMap m = callOnResolver( eval ).toMap(); - if ( m.isEmpty() ) + +void +JSResolver::onLookupUrlRequestDone( const QVariantMap& result ) +{ + sender()->deleteLater(); + + QString url = sender()->property( "url" ).toString(); + + tLog() << "ON LOOKUP URL REQUEST DONE" << url << result; + + // It may seem a bit weird, but currently no slot should do anything + // more as we starting on a new URL and not task are waiting for it yet. + m_pendingUrl = QString(); + m_pendingAlbum = album_ptr(); + + UrlTypes type = (UrlTypes) result.value( "type" ).toInt(); + if ( type == UrlTypeArtist ) { - // if the resolver doesn't return anything, async api is used - return; + QString name = result.value( "name" ).toString(); + Q_ASSERT( !name.isEmpty() ); + emit informationFound( url, Artist::get( name, true ).objectCast() ); + } + else if ( type == UrlTypeAlbum ) + { + QString name = result.value( "name" ).toString(); + QString artist = result.value( "artist" ).toString(); + album_ptr album = Album::get( Artist::get( artist, true ), name ); + m_pendingUrl = url; + m_pendingAlbum = album; + connect( album.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + SLOT( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) ); + if ( !album->tracks().isEmpty() ) + { + emit informationFound( url, album.objectCast() ); + } + } + else if ( type == UrlTypeTrack ) + { + Tomahawk::query_ptr query = parseTrack( result ); + if ( query.isNull() ) + { + // A valid track result shoud have non-empty title and artist. + tLog() << Q_FUNC_INFO << name() << "Got empty track information for " << url; + emit informationFound( url, QSharedPointer() ); + } + else + { + emit informationFound( url, query.objectCast() ); + } + } + else if ( type == UrlTypePlaylist ) + { + QString guid = result.value( "guid" ).toString(); + Q_ASSERT( !guid.isEmpty() ); + // Append nodeid to guid to make it globally unique. + guid += instanceUUID(); + + // Do we already have this playlist loaded? + { + playlist_ptr playlist = Playlist::get( guid ); + if ( !playlist.isNull() ) + { + emit informationFound( url, playlist.objectCast() ); + return; + } + } + + // Get all information to build a new playlist but do not build it until we know, + // if it is really handled as a playlist and not as a set of tracks. + Tomahawk::source_ptr source = SourceList::instance()->getLocal(); + const QString title = result.value( "title" ).toString(); + const QString info = result.value( "info" ).toString(); + const QString creator = result.value( "creator" ).toString(); + QList queries; + foreach( QVariant track, result.value( "tracks" ).toList() ) + { + query_ptr query = parseTrack( track.toMap() ); + if ( !query.isNull() ) + { + queries << query; + } + } + tLog( LOGVERBOSE ) << Q_FUNC_INFO << name() << "Got playlist for " << url; + playlisttemplate_ptr pltemplate( new PlaylistTemplate( source, guid, title, info, creator, false, queries ) ); + emit informationFound( url, pltemplate.objectCast() ); + } + else if ( type == UrlTypeXspf ) + { + QString xspfUrl = result.value( "url" ).toString(); + Q_ASSERT( !xspfUrl.isEmpty() ); + QString guid = QString( "xspf-%1-%2" ).arg( xspfUrl.toUtf8().toBase64().constData() ).arg( instanceUUID() ); + + // Do we already have this playlist loaded? + { + playlist_ptr playlist = Playlist::get( guid ); + if ( !playlist.isNull() ) + { + emit informationFound( url, playlist.objectCast() ); + return; + } + } + + + // Get all information to build a new playlist but do not build it until we know, + // if it is really handled as a playlist and not as a set of tracks. + Tomahawk::source_ptr source = SourceList::instance()->getLocal(); + QSharedPointer pltemplate( new XspfPlaylistTemplate( xspfUrl, source, guid ) ); + NewClosure( pltemplate, SIGNAL( tracksLoaded( QList< Tomahawk::query_ptr > ) ), + this, SLOT( pltemplateTracksLoadedForUrl( QString, Tomahawk::playlisttemplate_ptr ) ), + url, pltemplate.objectCast() ); + tLog( LOGVERBOSE ) << Q_FUNC_INFO << name() << "Got playlist for " << url; + pltemplate->load(); + } + else + { + tLog( LOGVERBOSE ) << Q_FUNC_INFO << name() << "No usable information found for " << url; + emit informationFound( url, QSharedPointer() ); + } +} + + +query_ptr +JSResolver::parseTrack( const QVariantMap& track ) +{ + QString title = track.value( "track" ).toString(); + QString artist = track.value( "artist" ).toString(); + QString album = track.value( "album" ).toString(); + if ( title.isEmpty() || artist.isEmpty() ) + { + return query_ptr(); } - QString errorMessage = tr( "Script Resolver Warning: API call %1 returned data synchronously." ).arg( eval ); - JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorMessage ) ); - tDebug() << errorMessage << m; + Tomahawk::query_ptr query = Tomahawk::Query::get( artist, title, album ); + QString resultHint = track.value( "hint" ).toString(); + if ( !resultHint.isEmpty() ) + { + query->setResultHint( resultHint ); + query->setSaveHTTPResultHint( true ); + } + + return query; +} + + +void +JSResolver::tracksAdded( const QList&, const ModelMode, const collection_ptr&) +{ + // Check if we still are actively waiting + if ( m_pendingAlbum.isNull() || m_pendingUrl.isNull() ) + return; + + emit informationFound( m_pendingUrl, m_pendingAlbum.objectCast() ); + m_pendingAlbum = album_ptr(); + m_pendingUrl = QString(); +} + + +void +JSResolver::pltemplateTracksLoadedForUrl( const QString& url, const playlisttemplate_ptr& pltemplate ) +{ + tLog() << Q_FUNC_INFO; + emit informationFound( url, pltemplate.objectCast() ); } @@ -589,3 +739,10 @@ JSResolver::onResolveRequestDone( const QVariantMap& data ) sender()->deleteLater(); } + + +QString +JSResolver::instanceUUID() +{ + return Tomahawk::Database::instance()->impl()->dbid(); +} diff --git a/src/libtomahawk/resolvers/JSResolver.h b/src/libtomahawk/resolvers/JSResolver.h index ab6b5a4a0..da3c51cb8 100644 --- a/src/libtomahawk/resolvers/JSResolver.h +++ b/src/libtomahawk/resolvers/JSResolver.h @@ -91,6 +91,7 @@ protected: private slots: void onResolveRequestDone(const QVariantMap& data); + void onLookupUrlRequestDone(const QVariantMap& data); private: void init(); @@ -105,6 +106,16 @@ private: Q_DECLARE_PRIVATE( JSResolver ) QScopedPointer d_ptr; + + +// TODO: move lookupUrl stuff to its own plugin type + QString instanceUUID(); + static Tomahawk::query_ptr parseTrack( const QVariantMap& track ); + QString m_pendingUrl; + Tomahawk::album_ptr m_pendingAlbum; +private slots: + void tracksAdded( const QList& tracks, const Tomahawk::ModelMode, const Tomahawk::collection_ptr& collection ); + void pltemplateTracksLoadedForUrl( const QString& url, const Tomahawk::playlisttemplate_ptr& pltemplate ); }; } // ns: Tomahawk diff --git a/src/libtomahawk/resolvers/JSResolverHelper.cpp b/src/libtomahawk/resolvers/JSResolverHelper.cpp index 881cfd023..1a67d46d4 100644 --- a/src/libtomahawk/resolvers/JSResolverHelper.cpp +++ b/src/libtomahawk/resolvers/JSResolverHelper.cpp @@ -21,10 +21,6 @@ #include "JSResolverHelper.h" -#include "database/Database.h" -#include "database/DatabaseImpl.h" -#include "playlist/PlaylistTemplate.h" -#include "playlist/XspfPlaylistTemplate.h" #include "resolvers/ScriptEngine.h" #include "network/Servent.h" #include "utils/Closure.h" @@ -140,36 +136,6 @@ JSResolverHelper::log( const QString& message ) } -query_ptr -JSResolverHelper::parseTrack( const QVariantMap& track ) -{ - QString title = track.value( "title" ).toString(); - QString artist = track.value( "artist" ).toString(); - QString album = track.value( "album" ).toString(); - if ( title.isEmpty() || artist.isEmpty() ) - { - return query_ptr(); - } - - Tomahawk::query_ptr query = Tomahawk::Query::get( artist, title, album ); - QString resultHint = track.value( "hint" ).toString(); - if ( !resultHint.isEmpty() ) - { - query->setResultHint( resultHint ); - query->setSaveHTTPResultHint( true ); - } - - return query; -} - - -QString -JSResolverHelper::instanceUUID() -{ - return Tomahawk::Database::instance()->impl()->dbid(); -} - - QString JSResolverHelper::uuid() const { @@ -464,120 +430,6 @@ JSResolverHelper::currentCountry() const } -void -JSResolverHelper::addUrlResult( const QString& url, const QVariantMap& result ) -{ - // It may seem a bit weird, but currently no slot should do anything - // more as we starting on a new URL and not task are waiting for it yet. - m_pendingUrl = QString(); - m_pendingAlbum = album_ptr(); - - QString type = result.value( "type" ).toString(); - if ( type == "artist" ) - { - QString name = result.value( "name" ).toString(); - Q_ASSERT( !name.isEmpty() ); - emit m_resolver->informationFound( url, Artist::get( name, true ).objectCast() ); - } - else if ( type == "album" ) - { - QString name = result.value( "name" ).toString(); - QString artist = result.value( "artist" ).toString(); - album_ptr album = Album::get( Artist::get( artist, true ), name ); - m_pendingUrl = url; - m_pendingAlbum = album; - connect( album.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), - SLOT( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) ); - if ( !album->tracks().isEmpty() ) - { - emit m_resolver->informationFound( url, album.objectCast() ); - } - } - else if ( type == "track" ) - { - Tomahawk::query_ptr query = parseTrack( result ); - if ( query.isNull() ) - { - // A valid track result shoud have non-empty title and artist. - tLog() << Q_FUNC_INFO << m_resolver->name() << "Got empty track information for " << url; - emit m_resolver->informationFound( url, QSharedPointer() ); - } - else - { - emit m_resolver->informationFound( url, query.objectCast() ); - } - } - else if ( type == "playlist" ) - { - QString guid = result.value( "guid" ).toString(); - Q_ASSERT( !guid.isEmpty() ); - // Append nodeid to guid to make it globally unique. - guid += instanceUUID(); - - // Do we already have this playlist loaded? - { - playlist_ptr playlist = Playlist::get( guid ); - if ( !playlist.isNull() ) - { - emit m_resolver->informationFound( url, playlist.objectCast() ); - return; - } - } - - // Get all information to build a new playlist but do not build it until we know, - // if it is really handled as a playlist and not as a set of tracks. - Tomahawk::source_ptr source = SourceList::instance()->getLocal(); - const QString title = result.value( "title" ).toString(); - const QString info = result.value( "info" ).toString(); - const QString creator = result.value( "creator" ).toString(); - QList queries; - foreach( QVariant track, result.value( "tracks" ).toList() ) - { - query_ptr query = parseTrack( track.toMap() ); - if ( !query.isNull() ) - { - queries << query; - } - } - tLog( LOGVERBOSE ) << Q_FUNC_INFO << m_resolver->name() << "Got playlist for " << url; - playlisttemplate_ptr pltemplate( new PlaylistTemplate( source, guid, title, info, creator, false, queries ) ); - emit m_resolver->informationFound( url, pltemplate.objectCast() ); - } - else if ( type == "xspf-url" ) - { - QString xspfUrl = result.value( "url" ).toString(); - Q_ASSERT( !xspfUrl.isEmpty() ); - QString guid = QString( "xspf-%1-%2" ).arg( xspfUrl.toUtf8().toBase64().constData() ).arg( instanceUUID() ); - - // Do we already have this playlist loaded? - { - playlist_ptr playlist = Playlist::get( guid ); - if ( !playlist.isNull() ) - { - emit m_resolver->informationFound( url, playlist.objectCast() ); - return; - } - } - - - // Get all information to build a new playlist but do not build it until we know, - // if it is really handled as a playlist and not as a set of tracks. - Tomahawk::source_ptr source = SourceList::instance()->getLocal(); - QSharedPointer pltemplate( new XspfPlaylistTemplate( xspfUrl, source, guid ) ); - NewClosure( pltemplate, SIGNAL( tracksLoaded( QList< Tomahawk::query_ptr > ) ), - this, SLOT( pltemplateTracksLoadedForUrl( QString, Tomahawk::playlisttemplate_ptr ) ), - url, pltemplate.objectCast() ); - tLog( LOGVERBOSE ) << Q_FUNC_INFO << m_resolver->name() << "Got playlist for " << url; - pltemplate->load(); - } - else - { - tLog( LOGVERBOSE ) << Q_FUNC_INFO << m_resolver->name() << "No usable information found for " << url; - emit m_resolver->informationFound( url, QSharedPointer() ); - } -} - - void JSResolverHelper::nativeReportCapabilities( const QVariant& v ) { @@ -614,27 +466,6 @@ JSResolverHelper::unregisterScriptPlugin( const QString& type, const QString& ob } -void -JSResolverHelper::tracksAdded( const QList&, const ModelMode, const collection_ptr&) -{ - // Check if we still are actively waiting - if ( m_pendingAlbum.isNull() || m_pendingUrl.isNull() ) - return; - - emit m_resolver->informationFound( m_pendingUrl, m_pendingAlbum.objectCast() ); - m_pendingAlbum = album_ptr(); - m_pendingUrl = QString(); -} - - -void -JSResolverHelper::pltemplateTracksLoadedForUrl( const QString& url, const playlisttemplate_ptr& pltemplate ) -{ - tLog() << Q_FUNC_INFO; - emit m_resolver->informationFound( url, pltemplate.objectCast() ); -} - - void JSResolverHelper::setResolverConfig( const QVariantMap& config ) { diff --git a/src/libtomahawk/resolvers/JSResolverHelper.h b/src/libtomahawk/resolvers/JSResolverHelper.h index b69c92135..08fedb09f 100644 --- a/src/libtomahawk/resolvers/JSResolverHelper.h +++ b/src/libtomahawk/resolvers/JSResolverHelper.h @@ -133,7 +133,6 @@ public slots: QByteArray readRaw( const QString& fileName ); QString readBase64( const QString& fileName ); QString readCompressed( const QString& fileName ); - QString instanceUUID(); QString uuid() const; int currentCountry() const; QString compress( const QString& data ); @@ -142,8 +141,6 @@ public slots: void log( const QString& message ); bool fakeEnv() { return false; } - void addUrlResult( const QString& url, const QVariantMap& result ); - void nativeReportCapabilities( const QVariant& capabilities ); void reportScriptJobResults( const QVariantMap& result ); @@ -153,12 +150,9 @@ public slots: private slots: void gotStreamUrl( IODeviceCallback callback, NetworkReply* reply ); - void tracksAdded( const QList& tracks, const Tomahawk::ModelMode, const Tomahawk::collection_ptr& collection ); - void pltemplateTracksLoadedForUrl( const QString& url, const Tomahawk::playlisttemplate_ptr& pltemplate ); void nativeAsyncRequestDone( int requestId, NetworkReply* reply ); private: - Tomahawk::query_ptr parseTrack( const QVariantMap& track ); void returnStreamUrl( const QString& streamUrl, const QMap& headers, std::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback ); @@ -171,8 +165,6 @@ private: QHash< QString, std::function< void( const QString&, QSharedPointer< QIODevice >& ) > > m_streamCallbacks; QHash< QString, std::function< void( const QString& ) > > m_translatorCallbacks; bool m_urlCallbackIsAsync; - QString m_pendingUrl; - Tomahawk::album_ptr m_pendingAlbum; }; } // ns: Tomahawk