diff --git a/include/tomahawk/tomahawkapp.h b/include/tomahawk/tomahawkapp.h index 8409d033b..36235edd7 100644 --- a/include/tomahawk/tomahawkapp.h +++ b/include/tomahawk/tomahawkapp.h @@ -19,10 +19,10 @@ #include "tomahawk/tomahawkplugin.h" #include "typedefs.h" #include "playlist.h" +#include "resolver.h" #include "utils/tomahawkutils.h" -class ScriptResolver; class AudioEngine; class Database; class SipHandler; @@ -92,7 +92,7 @@ private: QList m_collections; QList m_plugins; - QList m_scriptResolvers; + QList m_scriptResolvers; Database* m_database; AudioEngine* m_audioEngine; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index da4a31d83..184dfe414 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,7 @@ ENDIF() SET( QT_USE_QTSQL TRUE ) SET( QT_USE_QTNETWORK TRUE ) SET( QT_USE_QTXML TRUE ) +SET( QT_USE_QTWEBKIT TRUE ) INCLUDE( ${QT_USE_FILE} ) INCLUDE( ${CMAKE_MODULE_PATH}/AddAppIconMacro.cmake ) @@ -39,10 +40,11 @@ SET( tomahawkSources ${tomahawkSources} web/api_v1.cpp - musicscanner.cpp - scriptresolver.cpp - shortcuthandler.cpp + resolvers/scriptresolver.cpp + resolvers/qtscriptresolver.cpp + musicscanner.cpp + shortcuthandler.cpp scanmanager.cpp tomahawkapp.cpp main.cpp @@ -77,11 +79,12 @@ SET( tomahawkHeaders ${tomahawkHeaders} infosystem/infoplugins/echonestplugin.h infosystem/infoplugins/musixmatchplugin.h - web/api_v1.h + resolvers/scriptresolver.h + resolvers/qtscriptresolver.h + musicscanner.h - scriptresolver.h scanmanager.h shortcuthandler.h ) diff --git a/src/libtomahawk/playlist/infobar/infobar.cpp b/src/libtomahawk/playlist/infobar/infobar.cpp index 8ebd5893f..cb442b6ac 100644 --- a/src/libtomahawk/playlist/infobar/infobar.cpp +++ b/src/libtomahawk/playlist/infobar/infobar.cpp @@ -71,7 +71,7 @@ InfoBar::changeEvent( QEvent* e ) switch ( e->type() ) { case QEvent::LanguageChange: - ui->retranslateUi( this ); +// ui->retranslateUi( this ); break; default: diff --git a/src/libtomahawk/resolver.h b/src/libtomahawk/resolver.h index d69be45d0..68528a1e3 100644 --- a/src/libtomahawk/resolver.h +++ b/src/libtomahawk/resolver.h @@ -24,7 +24,7 @@ class DLLEXPORT Resolver : public QObject Q_OBJECT public: - Resolver() {}; + Resolver() {} virtual QString name() const = 0; virtual unsigned int weight() const = 0; @@ -41,6 +41,22 @@ private: PluginAPI * m_api; }; +class DLLEXPORT ExternalResolver : public Resolver +{ +Q_OBJECT + +public: + ExternalResolver( const QString& filePath ) { m_filePath = filePath; } + + virtual QString filePath() const { return m_filePath; } + +public slots: + virtual void stop() = 0; + +private: + QString m_filePath; +}; + }; //ns #endif // RESOLVER_H diff --git a/src/resolvers/qtscriptresolver.cpp b/src/resolvers/qtscriptresolver.cpp new file mode 100644 index 000000000..cf4ec225e --- /dev/null +++ b/src/resolvers/qtscriptresolver.cpp @@ -0,0 +1,101 @@ +#include "qtscriptresolver.h" + +#include "artist.h" +#include "album.h" +#include "pipeline.h" +#include "sourcelist.h" +#include "utils/tomahawkutils.h" + + +QtScriptResolver::QtScriptResolver( const QString& scriptPath ) + : Tomahawk::ExternalResolver( scriptPath ) + , m_engine( new ScriptEngine( this ) ) + , m_ready( false ) + , m_stopped( false ) +{ + qDebug() << Q_FUNC_INFO << scriptPath; + + QFile scriptFile( scriptPath ); + scriptFile.open( QIODevice::ReadOnly ); + m_engine->mainFrame()->setHtml( "" ); + m_engine->mainFrame()->evaluateJavaScript( scriptFile.readAll() ); + scriptFile.close(); + + QVariantMap m = m_engine->mainFrame()->evaluateJavaScript( "getSettings();" ).toMap(); + m_name = m.value( "name" ).toString(); + m_weight = m.value( "weight", 0 ).toUInt(); + m_timeout = m.value( "timeout", 25 ).toUInt() * 1000; + m_preference = m.value( "preference", 0 ).toUInt(); + + qDebug() << "QTSCRIPT" << filePath() << "READY," << endl + << "name" << m_name << endl + << "weight" << m_weight << endl + << "timeout" << m_timeout << endl + << "preference" << m_preference; + + m_ready = true; + Tomahawk::Pipeline::instance()->addResolver( this ); +} + + +QtScriptResolver::~QtScriptResolver() +{ + Tomahawk::Pipeline::instance()->removeResolver( this ); +} + + +void +QtScriptResolver::resolve( const Tomahawk::query_ptr& query ) +{ + qDebug() << Q_FUNC_INFO << query->toString(); + QString eval = QString( "resolve( '%1', '%2', '%3', '%4' );" ) + .arg( query->id().replace( "'", "\\'" ) ) + .arg( query->artist().replace( "'", "\\'" ) ) + .arg( query->album().replace( "'", "\\'" ) ) + .arg( query->track().replace( "'", "\\'" ) ); + + QList< Tomahawk::result_ptr > results; + + QVariantMap m = m_engine->mainFrame()->evaluateJavaScript( eval ).toMap(); + qDebug() << "JavaScript Result:" << m; + + const QString qid = m.value( "qid" ).toString(); + const QVariantList reslist = m.value( "results" ).toList(); + + foreach( const QVariant& rv, reslist ) + { + QVariantMap m = rv.toMap(); + qDebug() << "RES" << m; + + Tomahawk::result_ptr rp( new Tomahawk::Result() ); + Tomahawk::artist_ptr ap = Tomahawk::Artist::get( 0, m.value( "artist" ).toString() ); + rp->setArtist( ap ); + rp->setAlbum( Tomahawk::Album::get( 0, m.value( "album" ).toString(), ap ) ); + rp->setTrack( m.value( "track" ).toString() ); + rp->setDuration( m.value( "duration" ).toUInt() ); + rp->setBitrate( m.value( "bitrate" ).toUInt() ); + rp->setUrl( m.value( "url" ).toString() ); + rp->setSize( m.value( "size" ).toUInt() ); + rp->setScore( m.value( "score" ).toFloat() * ( (float)weight() / 100.0 ) ); + rp->setRID( uuid() ); + rp->setFriendlySource( m_name ); + + rp->setMimetype( m.value( "mimetype" ).toString() ); + if ( rp->mimetype().isEmpty() ) + { + rp->setMimetype( TomahawkUtils::extensionToMimetype( m.value( "extension" ).toString() ) ); + Q_ASSERT( !rp->mimetype().isEmpty() ); + } + + results << rp; + } + + Tomahawk::Pipeline::instance()->reportResults( qid, results ); +} + + +void +QtScriptResolver::stop() +{ + m_stopped = true; +} diff --git a/src/resolvers/qtscriptresolver.h b/src/resolvers/qtscriptresolver.h new file mode 100644 index 000000000..cb791ad5a --- /dev/null +++ b/src/resolvers/qtscriptresolver.h @@ -0,0 +1,64 @@ +#ifndef QTSCRIPTRESOLVER_H +#define QTSCRIPTRESOLVER_H + +#include "resolver.h" +#include "query.h" +#include "result.h" + +#include +#include +#include +#include +#include + +class ScriptEngine : public QWebPage +{ +Q_OBJECT + +public: + explicit ScriptEngine( QObject* parent ) + : QWebPage( parent ) + {} + +public slots: + bool shouldInterruptJavaScript() + { + QApplication::processEvents( QEventLoop::AllEvents, 42 ); + return false; + } + +protected: + virtual void javaScriptConsoleMessage( const QString & message, int lineNumber, const QString & sourceID ) + { qDebug() << "JAVASCRIPT ERROR:" << message << lineNumber << sourceID; } +}; + +class QtScriptResolver : public Tomahawk::ExternalResolver +{ +Q_OBJECT + +public: + explicit QtScriptResolver( const QString& scriptPath ); + virtual ~QtScriptResolver(); + + virtual QString name() const { return m_name; } + virtual unsigned int weight() const { return m_weight; } + virtual unsigned int preference() const { return m_preference; } + virtual unsigned int timeout() const { return m_timeout; } + + virtual void resolve( const Tomahawk::query_ptr& query ); + +public slots: + virtual void stop(); + +private slots: + +private: + ScriptEngine* m_engine; + + QString m_name; + unsigned int m_weight, m_preference, m_timeout; + + bool m_ready, m_stopped; +}; + +#endif // QTSCRIPTRESOLVER_H diff --git a/src/scriptresolver.cpp b/src/resolvers/scriptresolver.cpp similarity index 95% rename from src/scriptresolver.cpp rename to src/resolvers/scriptresolver.cpp index 5c5a3786a..375f301e0 100644 --- a/src/scriptresolver.cpp +++ b/src/resolvers/scriptresolver.cpp @@ -11,8 +11,7 @@ ScriptResolver::ScriptResolver( const QString& exe ) - : Tomahawk::Resolver() - , m_cmd( exe ) + : Tomahawk::ExternalResolver( exe ) , m_num_restarts( 0 ) , m_msgsize( 0 ) , m_ready( false ) @@ -23,7 +22,7 @@ ScriptResolver::ScriptResolver( const QString& exe ) connect( &m_proc, SIGNAL( readyReadStandardOutput() ), SLOT( readStdout() ) ); connect( &m_proc, SIGNAL( finished( int, QProcess::ExitStatus ) ), SLOT( cmdExited( int, QProcess::ExitStatus ) ) ); - m_proc.start( m_cmd ); + m_proc.start( filePath() ); } @@ -36,7 +35,7 @@ ScriptResolver::~ScriptResolver() void ScriptResolver::readStderr() { - qDebug() << "SCRIPT_STDERR" << m_cmd << m_proc.readAllStandardError(); + qDebug() << "SCRIPT_STDERR" << filePath() << m_proc.readAllStandardError(); } @@ -155,7 +154,7 @@ void ScriptResolver::cmdExited( int code, QProcess::ExitStatus status ) { m_ready = false; - qDebug() << Q_FUNC_INFO << "SCRIPT EXITED, code" << code << "status" << status << m_cmd; + qDebug() << Q_FUNC_INFO << "SCRIPT EXITED, code" << code << "status" << status << filePath(); Tomahawk::Pipeline::instance()->removeResolver( this ); if( m_stopped ) @@ -170,7 +169,7 @@ ScriptResolver::cmdExited( int code, QProcess::ExitStatus status ) { m_num_restarts++; qDebug() << "*** Restart num" << m_num_restarts; - m_proc.start( m_cmd ); + m_proc.start( filePath() ); } else { @@ -205,7 +204,7 @@ ScriptResolver::doSetup( const QVariantMap& m ) m_weight = m.value( "weight", 0 ).toUInt(); m_timeout = m.value( "timeout", 25 ).toUInt() * 1000; m_preference = m.value( "preference", 0 ).toUInt(); - qDebug() << "SCRIPT" << m_cmd << "READY," << endl + qDebug() << "SCRIPT" << filePath() << "READY," << endl << "name" << m_name << endl << "weight" << m_weight << endl << "timeout" << m_timeout << endl diff --git a/src/scriptresolver.h b/src/resolvers/scriptresolver.h similarity index 90% rename from src/scriptresolver.h rename to src/resolvers/scriptresolver.h index c349936ff..097a4a39e 100644 --- a/src/scriptresolver.h +++ b/src/resolvers/scriptresolver.h @@ -11,7 +11,7 @@ #include "query.h" #include "result.h" -class ScriptResolver : public Tomahawk::Resolver +class ScriptResolver : public Tomahawk::ExternalResolver { Q_OBJECT @@ -26,14 +26,11 @@ public: virtual void resolve( const Tomahawk::query_ptr& query ); - void stop(); - - QString exe() const { return m_cmd; } - signals: void finished(); public slots: + virtual void stop(); private slots: void readStderr(); @@ -48,7 +45,7 @@ private: void doSetup( const QVariantMap& m ); QProcess m_proc; - QString m_name, m_cmd; + QString m_name; unsigned int m_weight, m_preference, m_timeout, m_num_restarts; quint32 m_msgsize; diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 6fffad066..4aaafc324 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -24,7 +24,8 @@ #include "playlist/dynamic/echonest/EchonestGenerator.h" #include "utils/tomahawkutils.h" #include "web/api_v1.h" -#include "scriptresolver.h" +#include "resolvers/scriptresolver.h" +#include "resolvers/qtscriptresolver.h" #include "sourcelist.h" #include "shortcuthandler.h" #include "scanmanager.h" @@ -246,10 +247,10 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) } #endif - qDebug() << "Init Pipeline."; - setupPipeline(); qDebug() << "Init Local Collection."; initLocalCollection(); + qDebug() << "Init Pipeline."; + setupPipeline(); qDebug() << "Init Servent."; startServent(); //loadPlugins(); @@ -389,23 +390,31 @@ TomahawkApp::setupPipeline() { // setup resolvers for local content, and (cached) remote collection content Pipeline::instance()->addResolver( new DatabaseResolver( 100 ) ); - + // load script resolvers - foreach( QString resolver,TomahawkSettings::instance()->scriptResolvers() ) + foreach( QString resolver, TomahawkSettings::instance()->scriptResolvers() ) addScriptResolver( resolver ); } + void TomahawkApp::addScriptResolver( const QString& path ) { - m_scriptResolvers << new ScriptResolver( path ); + const QFileInfo fi( path ); + if ( fi.suffix() == "js" || fi.suffix() == "script" ) + m_scriptResolvers << new QtScriptResolver( path ); + else + m_scriptResolvers << new ScriptResolver( path ); } + void TomahawkApp::removeScriptResolver( const QString& path ) { - foreach( ScriptResolver* r, m_scriptResolvers ) { - if( r->exe() == path ) { + foreach( Tomahawk::ExternalResolver* r, m_scriptResolvers ) + { + if( r->filePath() == path ) + { m_scriptResolvers.removeAll( r ); connect( r, SIGNAL( finished() ), r, SLOT( deleteLater() ) ); r->stop(); @@ -414,6 +423,7 @@ TomahawkApp::removeScriptResolver( const QString& path ) } } + void TomahawkApp::initLocalCollection() {