1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-01-29 12:39:28 +01:00

Move lookupUrl stuff from JSResolverHelper to JSResolver, to be moved to own plugin type

This commit is contained in:
Dominik Schmidt 2015-11-16 18:19:51 +01:00
parent 846699c03c
commit c1eadce374
8 changed files with 211 additions and 218 deletions

View File

@ -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.

View File

@ -175,7 +175,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
// Check Scriptresolvers
foreach ( QPointer<ExternalResolver> 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<ExternalResolver> 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<ExternalResolver> 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<ExternalResolver> 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<ExternalResolver> 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<ExternalResolver> 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<QObject> ) ), this, SLOT( informationForUrl( QString, QSharedPointer<QObject> ) ) );

View File

@ -167,7 +167,7 @@ GlobalActionManager::openUrl( const QString& url )
QList< QPointer< ExternalResolver > > possibleResolvers;
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url, ExternalResolver::Any ) )
if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeAny ) )
{
canParse = true;
possibleResolvers << resolver;

View File

@ -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 )

View File

@ -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 <QDir>
#include <QFile>
#include <QFileInfo>
@ -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<QObject>() );
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<QObject>() );
}
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::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
SLOT( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) );
if ( !album->tracks().isEmpty() )
{
emit informationFound( url, album.objectCast<QObject>() );
}
}
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<QObject>() );
}
else
{
emit informationFound( url, query.objectCast<QObject>() );
}
}
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<QObject>() );
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<query_ptr> 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<QObject>() );
}
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<QObject>() );
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<XspfPlaylistTemplate> pltemplate( new XspfPlaylistTemplate( xspfUrl, source, guid ) );
NewClosure( pltemplate, SIGNAL( tracksLoaded( QList< Tomahawk::query_ptr > ) ),
this, SLOT( pltemplateTracksLoadedForUrl( QString, Tomahawk::playlisttemplate_ptr ) ),
url, pltemplate.objectCast<Tomahawk::PlaylistTemplate>() );
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<QObject>() );
}
}
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<query_ptr>&, 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<QObject>() );
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<QObject>() );
}
@ -589,3 +739,10 @@ JSResolver::onResolveRequestDone( const QVariantMap& data )
sender()->deleteLater();
}
QString
JSResolver::instanceUUID()
{
return Tomahawk::Database::instance()->impl()->dbid();
}

View File

@ -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<JSResolverPrivate> 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<Tomahawk::query_ptr>& tracks, const Tomahawk::ModelMode, const Tomahawk::collection_ptr& collection );
void pltemplateTracksLoadedForUrl( const QString& url, const Tomahawk::playlisttemplate_ptr& pltemplate );
};
} // ns: Tomahawk

View File

@ -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<QObject>() );
}
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::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
SLOT( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) );
if ( !album->tracks().isEmpty() )
{
emit m_resolver->informationFound( url, album.objectCast<QObject>() );
}
}
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<QObject>() );
}
else
{
emit m_resolver->informationFound( url, query.objectCast<QObject>() );
}
}
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<QObject>() );
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<query_ptr> 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<QObject>() );
}
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<QObject>() );
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<XspfPlaylistTemplate> pltemplate( new XspfPlaylistTemplate( xspfUrl, source, guid ) );
NewClosure( pltemplate, SIGNAL( tracksLoaded( QList< Tomahawk::query_ptr > ) ),
this, SLOT( pltemplateTracksLoadedForUrl( QString, Tomahawk::playlisttemplate_ptr ) ),
url, pltemplate.objectCast<Tomahawk::PlaylistTemplate>() );
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<QObject>() );
}
}
void
JSResolverHelper::nativeReportCapabilities( const QVariant& v )
{
@ -614,27 +466,6 @@ JSResolverHelper::unregisterScriptPlugin( const QString& type, const QString& ob
}
void
JSResolverHelper::tracksAdded( const QList<query_ptr>&, 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<QObject>() );
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<QObject>() );
}
void
JSResolverHelper::setResolverConfig( const QVariantMap& config )
{

View File

@ -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<Tomahawk::query_ptr>& 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<QString, QString>& 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