1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-01-18 23:17:59 +01:00

Add UrlLookup functionality to JSResolvers

This commit is contained in:
Uwe L. Korn 2013-06-29 12:45:49 +02:00
parent 6c75a94479
commit 03e4570452
13 changed files with 384 additions and 2 deletions

View File

@ -83,7 +83,8 @@ var TomahawkResolverCapability = {
NullCapability: 0,
Browsable: 1,
PlaylistSync: 2,
AccountFactory: 4
AccountFactory: 4,
UrlLookup: 8
};

View File

@ -336,6 +336,7 @@ list(APPEND libSources
resolvers/ScriptCommand_AllArtists.cpp
resolvers/ScriptCommand_AllAlbums.cpp
resolvers/ScriptCommand_AllTracks.cpp
resolvers/ScriptCommand_LookupUrl.cpp
resolvers/ScriptCommandQueue.cpp
sip/SipPlugin.cpp

View File

@ -28,6 +28,7 @@
#include "ScriptCommand_AllArtists.h"
#include "ScriptCommand_AllAlbums.h"
#include "ScriptCommand_AllTracks.h"
#include "ScriptCommand_LookupUrl.h"
#include "Typedefs.h"
#include <boost/function.hpp>
@ -53,6 +54,7 @@ Q_OBJECT
friend class ::ScriptCommand_AllArtists;
friend class ::ScriptCommand_AllAlbums;
friend class ::ScriptCommand_AllTracks;
friend class ::ScriptCommand_LookupUrl;
public:
enum ErrorState {
@ -66,7 +68,8 @@ public:
NullCapability = 0x0,
Browsable = 0x1, // can be represented in one or more collection tree views
PlaylistSync = 0x2, // can sync playlists
AccountFactory = 0x4 // can configure multiple accounts at the same time
AccountFactory = 0x4, // can configure multiple accounts at the same time
UrlLookup = 0x8 // can be queried for information on an Url
};
Q_DECLARE_FLAGS( Capabilities, Capability )
Q_FLAGS( Capabilities )
@ -85,6 +88,9 @@ public:
virtual Capabilities capabilities() const = 0;
virtual QMap< QString, Tomahawk::collection_ptr > collections() { return m_collections; }
// UrlLookup, sync call
virtual bool canParseUrl( const QString& url ) = 0;
virtual void enqueue( const QSharedPointer< ScriptCommand >& req )
{ m_commandQueue->enqueue( req ); }
@ -100,6 +106,7 @@ signals:
void artistsFound( const QList< Tomahawk::artist_ptr >& );
void albumsFound( const QList< Tomahawk::album_ptr >& );
void tracksFound( const QList< Tomahawk::query_ptr >& );
void informationFound( const QString&, const QSharedPointer<QObject>& );
protected:
void setFilePath( const QString& path ) { m_filePath = path; }
@ -107,9 +114,12 @@ protected:
ScriptCommandQueue* m_commandQueue;
// Should only be called by ScriptCommands
// ScriptCollection
virtual void artists( const Tomahawk::collection_ptr& collection ) = 0;
virtual void albums( const Tomahawk::collection_ptr& collection, const Tomahawk::artist_ptr& artist ) = 0;
virtual void tracks( const Tomahawk::collection_ptr& collection, const Tomahawk::album_ptr& album ) = 0;
// UrlLookup
virtual void lookupUrl( const QString& url ) = 0;
private:
QString m_filePath;

View File

@ -406,6 +406,65 @@ JSResolver::tracks( const Tomahawk::collection_ptr& collection, const Tomahawk::
tDebug() << errorMessage << m;
}
bool JSResolver::canParseUrl( const QString& url )
{
Q_D( 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( "resolver.canParseUrl( '%1' );" )
.arg( QString( url ).replace( "'", "\\'" ) );
return d->engine->mainFrame()->evaluateJavaScript( eval ).toBool();
}
else
{
// We cannot do URL lookup.
return false;
}
}
void
JSResolver::lookupUrl( const QString& url )
{
Q_D( JSResolver );
if ( QThread::currentThread() != thread() )
{
QMetaObject::invokeMethod( this, "lookupUrl", Qt::QueuedConnection,
Q_ARG( QString, url ) );
return;
}
if ( !capabilities().testFlag( UrlLookup ) )
{
emit informationFound( url, QSharedPointer<QObject>() );
return;
}
QString eval = QString( "resolver.lookupUrl( '%1' );" )
.arg( QString( url ).replace( "'", "\\'" ) );
QVariantMap m = d->engine->mainFrame()->evaluateJavaScript( eval ).toMap();
if ( m.isEmpty() )
{
// if the resolver doesn't return anything, async api is used
return;
}
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::ExternalResolver::ErrorState
JSResolver::error() const

View File

@ -58,6 +58,8 @@ public:
virtual void setIcon( const QPixmap& icon );
virtual bool canParseUrl( const QString& url );
public slots:
virtual void resolve( const Tomahawk::query_ptr& query );
virtual void stop();
@ -67,6 +69,8 @@ public slots:
virtual void artists( const Tomahawk::collection_ptr& collection );
virtual void albums( const Tomahawk::collection_ptr& collection, const Tomahawk::artist_ptr& artist );
virtual void tracks( const Tomahawk::collection_ptr& collection, const Tomahawk::album_ptr& album );
// For UrlLookup
virtual void lookupUrl( const QString& url );
signals:
void stopped();

View File

@ -215,6 +215,40 @@ JSResolverHelper::addAlbumTrackResults( const QVariantMap& results )
}
void
JSResolverHelper::addUrlResult( const QString& url, const QVariantMap& result )
{
QString type = result.value( "type" ).toString();
if ( type == "track" )
{
QString title = result.value( "title" ).toString();
QString artist = result.value( "artist" ).toString();
QString album = result.value( "album" ).toString();
tLog( LOGVERBOSE ) << m_resolver->name() << "Got track for url" << url << title << artist << album;
if ( title.isEmpty() || artist.isEmpty() )
{
// 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>() );
}
Tomahawk::query_ptr query = Tomahawk::Query::get( artist, title, album );
QString resultHint = result.value( "hint" ).toString();
if ( !resultHint.isEmpty() )
{
query->setResultHint( resultHint );
query->setSaveHTTPResultHint( true );
}
emit m_resolver->informationFound( url, query.objectCast<QObject>() );
}
else
{
tLog( LOGVERBOSE ) << Q_FUNC_INFO << m_resolver->name() << "No usable information found for " << url;
emit m_resolver->informationFound( url, QSharedPointer<QObject>() );
}
}
void
JSResolverHelper::reportCapabilities( const QVariant& v )
{

View File

@ -70,6 +70,8 @@ public slots:
void addAlbumResults( const QVariantMap& results );
void addAlbumTrackResults( const QVariantMap& results );
void addUrlResult( const QString& url, const QVariantMap& result );
void reportCapabilities( const QVariant& capabilities );
private:

View File

@ -0,0 +1,74 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptCommand_LookupUrl_p.h"
ScriptCommand_LookupUrl::ScriptCommand_LookupUrl( Tomahawk::ExternalResolver* resolver, const QString& url, QObject* parent )
: ScriptCommand( parent )
, d_ptr( new ScriptCommand_LookupUrlPrivate( this, resolver, url ) )
{
}
ScriptCommand_LookupUrl::~ScriptCommand_LookupUrl()
{
delete d_ptr;
}
void
ScriptCommand_LookupUrl::enqueue()
{
Q_D( ScriptCommand_LookupUrl );
d->resolver->enqueue( QSharedPointer< ScriptCommand >( this ) );
}
void
ScriptCommand_LookupUrl::exec()
{
Q_D( ScriptCommand_LookupUrl );
connect( d->resolver, SIGNAL( informationFound( QString , QSharedPointer<QObject> ) ),
this, SLOT( onResolverDone( QString, QSharedPointer<QObject> ) ) );
d->resolver->lookupUrl( d->url );
}
void
ScriptCommand_LookupUrl::reportFailure()
{
Q_D( ScriptCommand_LookupUrl );
emit information( d->url, QSharedPointer<QObject>() );
emit done();
}
void
ScriptCommand_LookupUrl::onResolverDone( const QString& url, const QSharedPointer<QObject>& _information )
{
Q_D( ScriptCommand_LookupUrl );
qDebug() << Q_FUNC_INFO << url << _information.isNull();
if ( url != d->url )
{
// This data is not for us, skip.
return;
}
emit information( d->url, _information );
emit done();
}

View File

@ -0,0 +1,63 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCRIPTCOMMAND_LOOKUPURL_H
#define SCRIPTCOMMAND_LOOKUPURL_H
#include "ScriptCommand.h"
#include "DllMacro.h"
#include "Typedefs.h"
#include <QVariant>
class ScriptCommand_LookupUrlPrivate;
namespace Tomahawk
{
class ExternalResolver;
}
class DLLEXPORT ScriptCommand_LookupUrl : public ScriptCommand
{
Q_OBJECT
public:
explicit ScriptCommand_LookupUrl( Tomahawk::ExternalResolver* resolver, const QString& url, QObject* parent = 0 );
virtual ~ScriptCommand_LookupUrl();
virtual void enqueue();
signals:
void information( const QString& url, const QSharedPointer<QObject>& variant );
void done();
protected:
virtual void exec();
virtual void reportFailure();
private slots:
void onResolverDone( const QString& url, const QSharedPointer<QObject>& information );
private:
Q_DECLARE_PRIVATE( ScriptCommand_LookupUrl )
ScriptCommand_LookupUrlPrivate* d_ptr;
};
#endif // SCRIPTCOMMAND_LOOKUPURL_H

View File

@ -0,0 +1,43 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCRIPTCOMMAND_LOOKUPURL_P_H
#define SCRIPTCOMMAND_LOOKUPURL_P_H
#include "ScriptCommand_LookupUrl.h"
#include "ExternalResolver.h"
class ScriptCommand_LookupUrlPrivate
{
public:
ScriptCommand_LookupUrlPrivate( ScriptCommand_LookupUrl* q, Tomahawk::ExternalResolver* _resolver, const QString& _url )
: q_ptr ( q )
, url( _url )
, resolver( _resolver )
{
}
ScriptCommand_LookupUrl* q_ptr;
Q_DECLARE_PUBLIC ( ScriptCommand_LookupUrl )
private:
QString url;
Tomahawk::ExternalResolver* resolver;
};
#endif // SCRIPTCOMMAND_LOOKUPURL_P_H

View File

@ -64,6 +64,8 @@ public:
void sendMessage( const QVariantMap& map );
virtual bool canParseUrl( const QString& ) { return false; }
signals:
void terminated();
void customMessage( const QString& msgType, const QVariantMap& msg );
@ -77,6 +79,7 @@ public slots:
virtual void artists( const Tomahawk::collection_ptr& ) {}
virtual void albums( const Tomahawk::collection_ptr&, const Tomahawk::artist_ptr& ) {}
virtual void tracks( const Tomahawk::collection_ptr&, const Tomahawk::album_ptr& ) {}
virtual void lookupUrl( const QString& ) {}
private slots:

View File

@ -39,6 +39,7 @@
#include "network/DbSyncConnection.h"
#include "web/Api_v1.h"
#include "SourceList.h"
#include "ViewManager.h"
#include "ShortcutHandler.h"
#include "filemetadata/ScanManager.h"
#include "TomahawkSettings.h"
@ -706,6 +707,67 @@ TomahawkApp::ipDetectionFailed( QNetworkReply::NetworkError error, QString error
}
void
TomahawkApp::informationForUrl( const QString& url, const QSharedPointer<QObject>& information )
{
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Got Information for URL:" << url;
if ( m_queuedUrl != url )
{
// This url is not anymore active, result was too late.
return;
}
if ( information.isNull() )
{
// No information was transmitted, nothing to do.
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Empty information received.";
return;
}
// If we reach this point, we found information that can be parsed.
// So invalidate queued Url
m_queuedUrl = "";
// Try to interpret as Artist
Tomahawk::artist_ptr artist = information.objectCast<Tomahawk::Artist>();
if ( !artist.isNull() )
{
// The Url describes an artist
ViewManager::instance()->show( artist );
return;
}
// Try to interpret as Album
Tomahawk::album_ptr album = information.objectCast<Tomahawk::Album>();
if ( !album.isNull() )
{
// The Url describes an album
ViewManager::instance()->show( album );
return;
}
// Try to interpret as Track/Query
Tomahawk::query_ptr query = information.objectCast<Tomahawk::Query>();
if ( !query.isNull() )
{
// The Url describes a track
ViewManager::instance()->show( query );
return;
}
// Try to interpret as Playlist
Tomahawk::playlist_ptr playlist = information.objectCast<Tomahawk::Playlist>();
if ( !playlist.isNull() )
{
// The url describes a playlist
ViewManager::instance()->show( playlist );
return;
}
// Could not cast to a known type.
tLog() << Q_FUNC_INFO << "Can't load parsed information for " << url;
}
void
TomahawkApp::spotifyApiCheckFinished()
{
@ -758,6 +820,30 @@ TomahawkApp::loadUrl( const QString& url )
return true;
}
}
// Can we parse the Url using a ScriptResolver?
bool canParse = false;
QList< QPointer< ExternalResolver > > possibleResolvers;
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url ) )
{
canParse = true;
possibleResolvers << resolver;
}
}
if ( canParse )
{
m_queuedUrl = url;
foreach ( QPointer<ExternalResolver> resolver, possibleResolvers )
{
ScriptCommand_LookupUrl* cmd = new ScriptCommand_LookupUrl( resolver, url );
connect( cmd, SIGNAL( information( QString, QSharedPointer<QObject> ) ), this, SLOT( informationForUrl( QString, QSharedPointer<QObject> ) ) );
cmd->enqueue();
}
return true;
}
#endif
return false;
}

View File

@ -114,6 +114,7 @@ private slots:
void spotifyApiCheckFinished();
void onInfoSystemReady();
void informationForUrl( const QString& url, const QSharedPointer<QObject>& information );
void ipDetectionFailed( QNetworkReply::NetworkError error, QString errorString );
@ -135,6 +136,7 @@ private:
QPointer<Tomahawk::ShortcutHandler> m_shortcutHandler;
QPointer< Tomahawk::Accounts::AccountManager > m_accountManager;
bool m_scrubFriendlyName;
QString m_queuedUrl;
#ifdef LIBLASTFM_FOUND
Scrobbler* m_scrobbler;