mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-11 16:44:05 +02:00
Remove ScriptResolver
This commit is contained in:
@@ -82,9 +82,6 @@ set( libGuiSources
|
|||||||
playlist/dynamic/widgets/CollapsibleControls.cpp
|
playlist/dynamic/widgets/CollapsibleControls.cpp
|
||||||
playlist/dynamic/widgets/DynamicSetupWidget.cpp
|
playlist/dynamic/widgets/DynamicSetupWidget.cpp
|
||||||
|
|
||||||
resolvers/ScriptResolver.cpp
|
|
||||||
resolvers/JSInfoPlugin.cpp
|
|
||||||
resolvers/JSInfoSystemHelper.cpp
|
|
||||||
resolvers/JSResolver.cpp
|
resolvers/JSResolver.cpp
|
||||||
resolvers/JSResolverHelper.cpp
|
resolvers/JSResolverHelper.cpp
|
||||||
resolvers/ScriptEngine.cpp
|
resolvers/ScriptEngine.cpp
|
||||||
|
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include "database/Database.h"
|
#include "database/Database.h"
|
||||||
#include "resolvers/ExternalResolver.h"
|
#include "resolvers/ExternalResolver.h"
|
||||||
#include "resolvers/ScriptResolver.h"
|
|
||||||
#include "resolvers/JSResolver.h"
|
#include "resolvers/JSResolver.h"
|
||||||
#include "utils/ResultUrlChecker.h"
|
#include "utils/ResultUrlChecker.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
@@ -1,574 +0,0 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
|
||||||
*
|
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
|
||||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
|
||||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
|
||||||
*
|
|
||||||
* 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 "ScriptResolver.h"
|
|
||||||
|
|
||||||
#include "accounts/AccountConfigWidget.h"
|
|
||||||
#include "utils/TomahawkUtils.h"
|
|
||||||
#include "utils/TomahawkUtilsGui.h"
|
|
||||||
#include "utils/Json.h"
|
|
||||||
#include "utils/Logger.h"
|
|
||||||
#include "utils/NetworkAccessManager.h"
|
|
||||||
#include "utils/NetworkProxyFactory.h"
|
|
||||||
|
|
||||||
#include "Artist.h"
|
|
||||||
#include "Album.h"
|
|
||||||
#include "Pipeline.h"
|
|
||||||
#include "Result.h"
|
|
||||||
#include "ScriptCollection.h"
|
|
||||||
#include "SourceList.h"
|
|
||||||
#include "Track.h"
|
|
||||||
|
|
||||||
#include <QtEndian>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkProxy>
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
#include <shlwapi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace Tomahawk;
|
|
||||||
|
|
||||||
ScriptResolver::ScriptResolver( const QString& exe )
|
|
||||||
: Tomahawk::ExternalResolver( exe )
|
|
||||||
, m_num_restarts( 0 )
|
|
||||||
, m_msgsize( 0 )
|
|
||||||
, m_ready( false )
|
|
||||||
, m_stopped( true )
|
|
||||||
, m_configSent( false )
|
|
||||||
, m_deleting( false )
|
|
||||||
, m_error( Tomahawk::ExternalResolver::NoError )
|
|
||||||
{
|
|
||||||
tLog() << Q_FUNC_INFO << "Created script resolver:" << exe;
|
|
||||||
connect( &m_proc, SIGNAL( readyReadStandardError() ), SLOT( readStderr() ) );
|
|
||||||
connect( &m_proc, SIGNAL( readyReadStandardOutput() ), SLOT( readStdout() ) );
|
|
||||||
connect( &m_proc, SIGNAL( finished( int, QProcess::ExitStatus ) ), SLOT( cmdExited( int, QProcess::ExitStatus ) ) );
|
|
||||||
|
|
||||||
startProcess();
|
|
||||||
|
|
||||||
if ( !Tomahawk::Utils::nam() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// set the name to the binary, if we launch properly we'll get the name the resolver reports
|
|
||||||
m_name = QFileInfo( filePath() ).baseName();
|
|
||||||
|
|
||||||
// set the icon, if we launch properly we'll get the icon the resolver reports
|
|
||||||
m_icon = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultResolver, TomahawkUtils::Original, QSize( 128, 128 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ScriptResolver::~ScriptResolver()
|
|
||||||
{
|
|
||||||
disconnect( &m_proc, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( cmdExited( int, QProcess::ExitStatus ) ) );
|
|
||||||
m_deleting = true;
|
|
||||||
|
|
||||||
QVariantMap msg;
|
|
||||||
msg[ "_msgtype" ] = "quit";
|
|
||||||
sendMessage( msg );
|
|
||||||
|
|
||||||
bool finished = m_proc.state() != QProcess::Running || m_proc.waitForFinished( 2500 ); // might call handleMsg
|
|
||||||
|
|
||||||
Tomahawk::Pipeline::instance()->removeResolver( this );
|
|
||||||
|
|
||||||
if ( !finished || m_proc.state() == QProcess::Running )
|
|
||||||
{
|
|
||||||
qDebug() << "External resolver didn't exit after waiting 2s for it to die, killing forcefully";
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
m_proc.kill();
|
|
||||||
#else
|
|
||||||
m_proc.terminate();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !m_configWidget.isNull() )
|
|
||||||
delete m_configWidget.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Tomahawk::ExternalResolver*
|
|
||||||
ScriptResolver::factory( const QString& accountId, const QString& exe, const QStringList& unused )
|
|
||||||
{
|
|
||||||
Q_UNUSED( accountId )
|
|
||||||
Q_UNUSED( unused )
|
|
||||||
|
|
||||||
ExternalResolver* res = 0;
|
|
||||||
|
|
||||||
const QFileInfo fi( exe );
|
|
||||||
if ( fi.suffix() != "js" && fi.suffix() != "script" )
|
|
||||||
{
|
|
||||||
res = new ScriptResolver( exe );
|
|
||||||
tLog() << Q_FUNC_INFO << exe << "Loaded.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::start()
|
|
||||||
{
|
|
||||||
m_stopped = false;
|
|
||||||
if ( m_ready )
|
|
||||||
Tomahawk::Pipeline::instance()->addResolver( this );
|
|
||||||
else if ( !m_configSent )
|
|
||||||
sendConfig();
|
|
||||||
// else, we've sent our config msg so are waiting for the resolver to react
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::sendConfig()
|
|
||||||
{
|
|
||||||
// Send a configutaion message with any information the resolver might need
|
|
||||||
// For now, only the proxy information is sent
|
|
||||||
QVariantMap m;
|
|
||||||
m.insert( "_msgtype", "config" );
|
|
||||||
|
|
||||||
m_configSent = true;
|
|
||||||
|
|
||||||
tDebug() << "Nam is:" << Tomahawk::Utils::nam();
|
|
||||||
tDebug() << "Nam proxy is:" << Tomahawk::Utils::nam()->proxyFactory();
|
|
||||||
Tomahawk::Utils::nam()->proxyFactory()->queryProxy();
|
|
||||||
Tomahawk::Utils::NetworkProxyFactory* factory = dynamic_cast<Tomahawk::Utils::NetworkProxyFactory*>( Tomahawk::Utils::nam()->proxyFactory() );
|
|
||||||
QNetworkProxy proxy = factory->proxy();
|
|
||||||
QString proxyType = ( proxy.type() == QNetworkProxy::Socks5Proxy ? "socks5" : "none" );
|
|
||||||
m.insert( "proxytype", proxyType );
|
|
||||||
m.insert( "proxyhost", proxy.hostName() );
|
|
||||||
m.insert( "proxyport", proxy.port() );
|
|
||||||
m.insert( "proxyuser", proxy.user() );
|
|
||||||
m.insert( "proxypass", proxy.password() );
|
|
||||||
|
|
||||||
// QJson sucks
|
|
||||||
QVariantList hosts;
|
|
||||||
foreach ( const QString& host, factory->noProxyHosts() )
|
|
||||||
hosts << host;
|
|
||||||
m.insert( "noproxyhosts", hosts );
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
QByteArray data = TomahawkUtils::toJson( m, &ok );
|
|
||||||
Q_ASSERT( ok );
|
|
||||||
sendMsg( data );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::reload()
|
|
||||||
{
|
|
||||||
startProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
ScriptResolver::running() const
|
|
||||||
{
|
|
||||||
return !m_stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::sendMessage( const QVariantMap& map )
|
|
||||||
{
|
|
||||||
bool ok;
|
|
||||||
QByteArray data = TomahawkUtils::toJson( map, &ok );
|
|
||||||
Q_ASSERT( ok );
|
|
||||||
sendMsg( data );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::readStderr()
|
|
||||||
{
|
|
||||||
tLog() << "SCRIPT_STDERR" << filePath() << m_proc.readAllStandardError();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ScriptResolver::ErrorState
|
|
||||||
ScriptResolver::error() const
|
|
||||||
{
|
|
||||||
return m_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::readStdout()
|
|
||||||
{
|
|
||||||
if ( m_msgsize == 0 )
|
|
||||||
{
|
|
||||||
if ( m_proc.bytesAvailable() < 4 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
quint32 len_nbo;
|
|
||||||
m_proc.read( (char*) &len_nbo, 4 );
|
|
||||||
m_msgsize = qFromBigEndian( len_nbo );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_msgsize > 0 )
|
|
||||||
{
|
|
||||||
m_msg.append( m_proc.read( m_msgsize - m_msg.length() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_msgsize == (quint32) m_msg.length() )
|
|
||||||
{
|
|
||||||
handleMsg( m_msg );
|
|
||||||
m_msgsize = 0;
|
|
||||||
m_msg.clear();
|
|
||||||
|
|
||||||
if ( m_proc.bytesAvailable() )
|
|
||||||
QTimer::singleShot( 0, this, SLOT( readStdout() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::sendMsg( const QByteArray& msg )
|
|
||||||
{
|
|
||||||
// qDebug() << Q_FUNC_INFO << m_ready << msg << msg.length();
|
|
||||||
if ( !m_proc.isOpen() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
quint32 len;
|
|
||||||
qToBigEndian( msg.length(), (uchar*) &len );
|
|
||||||
m_proc.write( (const char*) &len, 4 );
|
|
||||||
m_proc.write( msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::handleMsg( const QByteArray& msg )
|
|
||||||
{
|
|
||||||
// qDebug() << Q_FUNC_INFO << msg.size() << QString::fromAscii( msg );
|
|
||||||
|
|
||||||
// Might be called from waitForFinished() in ~ScriptResolver, no database in that case, abort.
|
|
||||||
if ( m_deleting )
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
QVariant v = TomahawkUtils::parseJson( msg, &ok );
|
|
||||||
if ( !ok || v.type() != QVariant::Map )
|
|
||||||
{
|
|
||||||
Q_ASSERT( false );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QVariantMap m = v.toMap();
|
|
||||||
QString msgtype = m.value( "_msgtype" ).toString();
|
|
||||||
|
|
||||||
if ( msgtype == "settings" )
|
|
||||||
{
|
|
||||||
doSetup( m );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if ( msgtype == "confwidget" )
|
|
||||||
{
|
|
||||||
setupConfWidget( m );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if ( msgtype == "results" )
|
|
||||||
{
|
|
||||||
const QString qid = m.value( "qid" ).toString();
|
|
||||||
QList< Tomahawk::result_ptr > results;
|
|
||||||
const QVariantList reslist = m.value( "results" ).toList();
|
|
||||||
|
|
||||||
foreach( const QVariant& rv, reslist )
|
|
||||||
{
|
|
||||||
QVariantMap m = rv.toMap();
|
|
||||||
tDebug( LOGVERBOSE ) << "Found result:" << m;
|
|
||||||
|
|
||||||
Tomahawk::track_ptr track = Tomahawk::Track::get( m.value( "artist" ).toString(), m.value( "track" ).toString(), m.value( "album" ).toString(), m.value( "duration" ).toUInt(), QString(), m.value( "albumpos" ).toUInt(), m.value( "discnumber" ).toUInt() );
|
|
||||||
if ( !track )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Tomahawk::result_ptr rp = Tomahawk::Result::get( m.value( "url" ).toString(), track );
|
|
||||||
if ( !rp )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rp->setBitrate( m.value( "bitrate" ).toUInt() );
|
|
||||||
rp->setSize( m.value( "size" ).toUInt() );
|
|
||||||
rp->setRID( uuid() );
|
|
||||||
rp->setFriendlySource( m_name );
|
|
||||||
rp->setPurchaseUrl( m.value( "purchaseUrl" ).toString() );
|
|
||||||
rp->setLinkUrl( m.value( "linkUrl" ).toString() );
|
|
||||||
|
|
||||||
//FIXME
|
|
||||||
if ( m.contains( "year" ) )
|
|
||||||
{
|
|
||||||
QVariantMap attr;
|
|
||||||
attr[ "releaseyear" ] = m.value( "year" );
|
|
||||||
// rp->track()->setAttributes( attr );
|
|
||||||
}
|
|
||||||
|
|
||||||
rp->setMimetype( m.value( "mimetype" ).toString() );
|
|
||||||
if ( rp->mimetype().isEmpty() )
|
|
||||||
{
|
|
||||||
rp->setMimetype( TomahawkUtils::extensionToMimetype( m.value( "extension" ).toString() ) );
|
|
||||||
Q_ASSERT( !rp->mimetype().isEmpty() );
|
|
||||||
}
|
|
||||||
|
|
||||||
rp->setResolvedBy( this );
|
|
||||||
results << rp;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tomahawk::Pipeline::instance()->reportResults( qid, results );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Unknown message, give up for custom implementations
|
|
||||||
emit customMessage( msgtype, m );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::cmdExited( int code, QProcess::ExitStatus status )
|
|
||||||
{
|
|
||||||
m_ready = false;
|
|
||||||
tLog() << Q_FUNC_INFO << "SCRIPT EXITED, code" << code << "status" << status << filePath();
|
|
||||||
Tomahawk::Pipeline::instance()->removeResolver( this );
|
|
||||||
|
|
||||||
m_error = ExternalResolver::FailedToLoad;
|
|
||||||
emit changed();
|
|
||||||
|
|
||||||
if ( m_stopped )
|
|
||||||
{
|
|
||||||
tLog() << "*** Script resolver stopped ";
|
|
||||||
emit terminated();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_num_restarts < 10 )
|
|
||||||
{
|
|
||||||
m_num_restarts++;
|
|
||||||
tLog() << "*** Restart num" << m_num_restarts;
|
|
||||||
startProcess();
|
|
||||||
sendConfig();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tLog() << "*** Reached max restarts, not restarting.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::resolve( const Tomahawk::query_ptr& query )
|
|
||||||
{
|
|
||||||
QVariantMap m;
|
|
||||||
m.insert( "_msgtype", "rq" );
|
|
||||||
|
|
||||||
if ( query->isFullTextQuery() )
|
|
||||||
{
|
|
||||||
m.insert( "fulltext", query->fullTextQuery() );
|
|
||||||
m.insert( "track", query->fullTextQuery() );
|
|
||||||
m.insert( "qid", query->id() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m.insert( "artist", query->queryTrack()->artist() );
|
|
||||||
m.insert( "track", query->queryTrack()->track() );
|
|
||||||
m.insert( "qid", query->id() );
|
|
||||||
|
|
||||||
if ( !query->resultHint().isEmpty() )
|
|
||||||
m.insert( "resultHint", query->resultHint() );
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray msg = TomahawkUtils::toJson( QVariant( m ) );
|
|
||||||
sendMsg( msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::doSetup( const QVariantMap& m )
|
|
||||||
{
|
|
||||||
// qDebug() << Q_FUNC_INFO << m;
|
|
||||||
|
|
||||||
m_name = m.value( "name" ).toString();
|
|
||||||
m_weight = m.value( "weight", 0 ).toUInt();
|
|
||||||
m_timeout = m.value( "timeout", 5 ).toUInt() * 1000;
|
|
||||||
bool compressed = m.value( "compressed", "false" ).toString() == "true";
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
int intCap = m.value( "capabilities" ).toInt( &ok );
|
|
||||||
if ( !ok )
|
|
||||||
m_capabilities = NullCapability;
|
|
||||||
else
|
|
||||||
m_capabilities = static_cast< Capabilities >( intCap );
|
|
||||||
|
|
||||||
QByteArray icoData = m.value( "icon" ).toByteArray();
|
|
||||||
if( compressed )
|
|
||||||
icoData = qUncompress( QByteArray::fromBase64( icoData ) );
|
|
||||||
else
|
|
||||||
icoData = QByteArray::fromBase64( icoData );
|
|
||||||
QPixmap ico;
|
|
||||||
ico.loadFromData( icoData );
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
if ( !ico.isNull() )
|
|
||||||
{
|
|
||||||
m_icon = ico.scaled( m_icon.size(), Qt::IgnoreAspectRatio );
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
// see if the resolver sent an icon path to not break the old (unofficial) api.
|
|
||||||
// TODO: remove this and publish a definitive api
|
|
||||||
if ( !success )
|
|
||||||
{
|
|
||||||
QString iconPath = QFileInfo( filePath() ).path() + "/" + m.value( "icon" ).toString();
|
|
||||||
success = m_icon.load( iconPath );
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "SCRIPT" << filePath() << "READY," << "name" << m_name << "weight" << m_weight << "timeout" << m_timeout << "icon received" << success;
|
|
||||||
|
|
||||||
m_ready = true;
|
|
||||||
m_configSent = false;
|
|
||||||
m_num_restarts = 0;
|
|
||||||
|
|
||||||
if ( !m_stopped )
|
|
||||||
Tomahawk::Pipeline::instance()->addResolver( this );
|
|
||||||
|
|
||||||
emit changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::setupConfWidget( const QVariantMap& m )
|
|
||||||
{
|
|
||||||
bool compressed = m.value( "compressed", "false" ).toString() == "true";
|
|
||||||
qDebug() << "Resolver has a preferences widget! compressed?" << compressed;
|
|
||||||
|
|
||||||
QByteArray uiData = m[ "widget" ].toByteArray();
|
|
||||||
if( compressed )
|
|
||||||
uiData = qUncompress( QByteArray::fromBase64( uiData ) );
|
|
||||||
else
|
|
||||||
uiData = QByteArray::fromBase64( uiData );
|
|
||||||
|
|
||||||
if ( m.contains( "images" ) )
|
|
||||||
uiData = fixDataImagePaths( uiData, compressed, m[ "images" ].toMap() );
|
|
||||||
m_configWidget = QPointer< AccountConfigWidget >( widgetFromData( uiData, 0 ) );
|
|
||||||
|
|
||||||
emit changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::startProcess()
|
|
||||||
{
|
|
||||||
if ( !QFile::exists( filePath() ) )
|
|
||||||
m_error = Tomahawk::ExternalResolver::FileNotFound;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_error = Tomahawk::ExternalResolver::NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QFileInfo fi( filePath() );
|
|
||||||
|
|
||||||
QString interpreter;
|
|
||||||
// have to enclose in quotes if path contains spaces...
|
|
||||||
const QString runPath = QString( "\"%1\"" ).arg( filePath() );
|
|
||||||
|
|
||||||
QFile file( filePath() );
|
|
||||||
file.setPermissions( file.permissions() | QFile::ExeOwner | QFile::ExeGroup | QFile::ExeOther );
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if ( fi.suffix().toLower() != "exe" )
|
|
||||||
{
|
|
||||||
DWORD dwSize = MAX_PATH;
|
|
||||||
|
|
||||||
wchar_t path[MAX_PATH] = { 0 };
|
|
||||||
wchar_t *ext = (wchar_t *) ("." + fi.suffix()).utf16();
|
|
||||||
|
|
||||||
HRESULT hr = AssocQueryStringW(
|
|
||||||
(ASSOCF) 0,
|
|
||||||
ASSOCSTR_EXECUTABLE,
|
|
||||||
ext,
|
|
||||||
L"open",
|
|
||||||
path,
|
|
||||||
&dwSize
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( ! FAILED( hr ) )
|
|
||||||
{
|
|
||||||
interpreter = QString( "\"%1\"" ).arg(QString::fromUtf16((const ushort *) path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
|
|
||||||
if ( interpreter.isEmpty() )
|
|
||||||
{
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
const QFileInfo info( filePath() );
|
|
||||||
m_proc.setWorkingDirectory( info.absolutePath() );
|
|
||||||
tLog() << "Setting working dir:" << info.absolutePath();
|
|
||||||
#endif
|
|
||||||
m_proc.start( runPath );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_proc.start( interpreter, QStringList() << filePath() );
|
|
||||||
|
|
||||||
sendConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::saveConfig()
|
|
||||||
{
|
|
||||||
Q_ASSERT( !m_configWidget.isNull() );
|
|
||||||
|
|
||||||
QVariantMap m;
|
|
||||||
m.insert( "_msgtype", "setpref" );
|
|
||||||
QVariant widgets = configMsgFromWidget( m_configWidget.data() );
|
|
||||||
m.insert( "widgets", widgets );
|
|
||||||
bool ok;
|
|
||||||
QByteArray data = TomahawkUtils::toJson( m, &ok );
|
|
||||||
Q_ASSERT( ok );
|
|
||||||
|
|
||||||
sendMsg( data );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::setIcon( const QPixmap& icon )
|
|
||||||
{
|
|
||||||
m_icon = icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AccountConfigWidget*
|
|
||||||
ScriptResolver::configUI() const
|
|
||||||
{
|
|
||||||
if ( m_configWidget.isNull() )
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return m_configWidget.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptResolver::stop()
|
|
||||||
{
|
|
||||||
m_stopped = true;
|
|
||||||
|
|
||||||
foreach ( const Tomahawk::collection_ptr& collection, m_collections )
|
|
||||||
{
|
|
||||||
emit collectionRemoved( collection );
|
|
||||||
}
|
|
||||||
m_collections.clear();
|
|
||||||
|
|
||||||
Tomahawk::Pipeline::instance()->removeResolver( this );
|
|
||||||
}
|
|
@@ -1,115 +0,0 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
|
||||||
*
|
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
|
||||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
|
||||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
|
||||||
*
|
|
||||||
* 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 SCRIPTRESOLVER_H
|
|
||||||
#define SCRIPTRESOLVER_H
|
|
||||||
|
|
||||||
#include "Query.h"
|
|
||||||
#include "Artist.h"
|
|
||||||
#include "Album.h"
|
|
||||||
#include "collection/Collection.h"
|
|
||||||
#include "ExternalResolver.h"
|
|
||||||
#include "DllMacro.h"
|
|
||||||
|
|
||||||
#include <QProcess>
|
|
||||||
|
|
||||||
class QWidget;
|
|
||||||
|
|
||||||
namespace Tomahawk
|
|
||||||
{
|
|
||||||
|
|
||||||
class DLLEXPORT ScriptResolver : public Tomahawk::ExternalResolver
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ScriptResolver( const QString& exe );
|
|
||||||
virtual ~ScriptResolver();
|
|
||||||
static ExternalResolver* factory( const QString& accountId, const QString& exe, const QStringList& );
|
|
||||||
|
|
||||||
QString name() const Q_DECL_OVERRIDE { return m_name; }
|
|
||||||
QPixmap icon() const Q_DECL_OVERRIDE { return m_icon; }
|
|
||||||
unsigned int weight() const Q_DECL_OVERRIDE { return m_weight; }
|
|
||||||
virtual unsigned int preference() const { return m_preference; }
|
|
||||||
unsigned int timeout() const Q_DECL_OVERRIDE { return m_timeout; }
|
|
||||||
Capabilities capabilities() const Q_DECL_OVERRIDE { return m_capabilities; }
|
|
||||||
|
|
||||||
void setIcon( const QPixmap& icon ) Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
AccountConfigWidget* configUI() const Q_DECL_OVERRIDE;
|
|
||||||
void saveConfig() Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
ExternalResolver::ErrorState error() const Q_DECL_OVERRIDE;
|
|
||||||
void reload() Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
bool running() const Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
void sendMessage( const QVariantMap& map );
|
|
||||||
|
|
||||||
bool canParseUrl( const QString&, UrlType ) Q_DECL_OVERRIDE { return false; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void terminated();
|
|
||||||
void customMessage( const QString& msgType, const QVariantMap& msg );
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void stop() Q_DECL_OVERRIDE;
|
|
||||||
void resolve( const Tomahawk::query_ptr& query ) Q_DECL_OVERRIDE;
|
|
||||||
void start() Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
// TODO: implement. Or not. Not really an issue while Spotify doesn't do browsable personal cloud storage.
|
|
||||||
void artists( const Tomahawk::collection_ptr& ) Q_DECL_OVERRIDE {}
|
|
||||||
void albums( const Tomahawk::collection_ptr&, const Tomahawk::artist_ptr& ) Q_DECL_OVERRIDE {}
|
|
||||||
void tracks( const Tomahawk::collection_ptr&, const Tomahawk::album_ptr& ) Q_DECL_OVERRIDE {}
|
|
||||||
void lookupUrl( const QString& ) Q_DECL_OVERRIDE {}
|
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void readStderr();
|
|
||||||
void readStdout();
|
|
||||||
void cmdExited( int code, QProcess::ExitStatus status );
|
|
||||||
|
|
||||||
private:
|
|
||||||
void sendConfig();
|
|
||||||
|
|
||||||
void handleMsg( const QByteArray& msg );
|
|
||||||
void sendMsg( const QByteArray& msg );
|
|
||||||
void doSetup( const QVariantMap& m );
|
|
||||||
void setupConfWidget( const QVariantMap& m );
|
|
||||||
|
|
||||||
void startProcess();
|
|
||||||
|
|
||||||
QProcess m_proc;
|
|
||||||
QString m_name;
|
|
||||||
QPixmap m_icon;
|
|
||||||
unsigned int m_weight, m_preference, m_timeout, m_num_restarts;
|
|
||||||
Capabilities m_capabilities;
|
|
||||||
QPointer< AccountConfigWidget > m_configWidget;
|
|
||||||
|
|
||||||
quint32 m_msgsize;
|
|
||||||
QByteArray m_msg;
|
|
||||||
|
|
||||||
bool m_ready, m_stopped, m_configSent, m_deleting;
|
|
||||||
ExternalResolver::ErrorState m_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SCRIPTRESOLVER_H
|
|
@@ -68,7 +68,6 @@
|
|||||||
#include "widgets/SplashWidget.h"
|
#include "widgets/SplashWidget.h"
|
||||||
|
|
||||||
#include "resolvers/JSResolver.h"
|
#include "resolvers/JSResolver.h"
|
||||||
#include "resolvers/ScriptResolver.h"
|
|
||||||
#include "utils/SpotifyParser.h"
|
#include "utils/SpotifyParser.h"
|
||||||
#include "AtticaManager.h"
|
#include "AtticaManager.h"
|
||||||
#include "TomahawkWindow.h"
|
#include "TomahawkWindow.h"
|
||||||
@@ -226,9 +225,6 @@ TomahawkApp::init()
|
|||||||
Pipeline::instance()->addExternalResolverFactory(
|
Pipeline::instance()->addExternalResolverFactory(
|
||||||
std::bind( &JSResolver::factory, std::placeholders::_1,
|
std::bind( &JSResolver::factory, std::placeholders::_1,
|
||||||
std::placeholders::_2, std::placeholders::_3 ) );
|
std::placeholders::_2, std::placeholders::_3 ) );
|
||||||
Pipeline::instance()->addExternalResolverFactory(
|
|
||||||
std::bind( &ScriptResolver::factory, std::placeholders::_1,
|
|
||||||
std::placeholders::_2, std::placeholders::_3 ) );
|
|
||||||
|
|
||||||
new ActionCollection( this );
|
new ActionCollection( this );
|
||||||
connect( ActionCollection::instance()->getAction( "quit" ), SIGNAL( triggered() ), SLOT( quit() ), Qt::UniqueConnection );
|
connect( ActionCollection::instance()->getAction( "quit" ), SIGNAL( triggered() ), SLOT( quit() ), Qt::UniqueConnection );
|
||||||
|
Reference in New Issue
Block a user