1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-01-29 20:49:52 +01:00

Add urlTranslator and always pass result AND url to all handlers/factories

This commit is contained in:
Uwe L. Korn 2014-03-13 12:53:14 +00:00
parent 596794da57
commit 043867413f
10 changed files with 178 additions and 43 deletions

View File

@ -244,7 +244,7 @@ Api_v1::sid( QxtWebRequestEvent* event, QString unused )
boost::function< void ( QSharedPointer< QIODevice >& ) > callback =
boost::bind( &Api_v1::processSid, this, event, rp, _1 );
Tomahawk::UrlHandler::getIODeviceForUrl( rp, callback );
Tomahawk::UrlHandler::getIODeviceForUrl( rp, rp->url(), callback );
}

View File

@ -34,18 +34,19 @@ namespace Tomahawk {
namespace UrlHandler {
QMap< QString, IODeviceFactoryFunc > iofactories;
QMap< QString, UrlTranslatorFunc > urltranslators;
void
initialiseDefaultIOFactories()
{
{
// _1 = result, _2 = callback function for IODevice
IODeviceFactoryFunc fac = boost::bind( localFileIODeviceFactory, _1, _2 );
IODeviceFactoryFunc fac = boost::bind( localFileIODeviceFactory, _1, _2, _3 );
iofactories.insert( "file", fac );
}
{
IODeviceFactoryFunc fac = boost::bind( httpIODeviceFactory, _1, _2 );
IODeviceFactoryFunc fac = boost::bind( httpIODeviceFactory, _1, _2, _3 );
iofactories.insert( "http", fac );
iofactories.insert( "https", fac );
}
@ -65,7 +66,7 @@ registerIODeviceFactory( const QString &proto, IODeviceFactoryFunc fac )
void
getIODeviceForUrl( const Tomahawk::result_ptr& result,
getIODeviceForUrl( const Tomahawk::result_ptr& result, const QString& url,
boost::function< void ( QSharedPointer< QIODevice >& ) > callback )
{
if ( iofactories.isEmpty() )
@ -76,7 +77,7 @@ getIODeviceForUrl( const Tomahawk::result_ptr& result,
QSharedPointer<QIODevice> sp;
QRegExp rx( "^([a-zA-Z0-9]+)://(.+)$" );
if ( rx.indexIn( result->url() ) == -1 )
if ( rx.indexIn( url ) == -1 )
{
callback( sp );
return;
@ -90,16 +91,16 @@ getIODeviceForUrl( const Tomahawk::result_ptr& result,
}
// JSResolverHelper::customIODeviceFactory is async!
iofactories.value( proto )( result, callback );
iofactories.value( proto )( result, url, callback );
}
void
localFileIODeviceFactory( const Tomahawk::result_ptr& result,
localFileIODeviceFactory( const Tomahawk::result_ptr&, const QString& url,
boost::function< void ( QSharedPointer< QIODevice >& ) > callback )
{
// ignore "file://" at front of url
QFile* io = new QFile( result->url().mid( QString( "file://" ).length() ) );
QFile* io = new QFile( url.mid( QString( "file://" ).length() ) );
if ( io )
io->open( QIODevice::ReadOnly );
@ -110,10 +111,10 @@ localFileIODeviceFactory( const Tomahawk::result_ptr& result,
void
httpIODeviceFactory( const Tomahawk::result_ptr& result,
httpIODeviceFactory( const Tomahawk::result_ptr&, const QString& url,
boost::function< void ( QSharedPointer< QIODevice >& ) > callback )
{
QNetworkRequest req( result->url() );
QNetworkRequest req( url );
// Follow HTTP Redirects
NetworkReply* reply = new NetworkReply( Tomahawk::Utils::nam()->get( req ) );
qRegisterMetaType<NetworkReply*>("NetworkReply*");
@ -124,6 +125,31 @@ httpIODeviceFactory( const Tomahawk::result_ptr& result,
}
void
getUrlTranslation( const Tomahawk::result_ptr& result, const QString& url, boost::function< void ( const QString& ) > callback )
{
QRegExp rx( "^([a-zA-Z0-9]+)://(.+)$" );
if ( rx.indexIn( url ) == -1 )
{
callback( QString() );
return;
}
const QString proto = rx.cap( 1 );
if ( !urltranslators.contains( proto ) )
{
callback( url );
return;
}
urltranslators.value( proto )( result, url, callback );
}
void
registerUrlTranslator( const QString &proto, UrlTranslatorFunc fac )
{
urltranslators.insert( proto, fac );
}
} // namespace UrlHandler

View File

@ -27,8 +27,10 @@
#include <boost/function.hpp>
typedef boost::function< void( const Tomahawk::result_ptr&,
typedef boost::function< void( const Tomahawk::result_ptr&, const QString&,
boost::function< void( QSharedPointer< QIODevice >& ) > )> IODeviceFactoryFunc;
typedef boost::function< void( const Tomahawk::result_ptr&, const QString&,
boost::function< void( const QString& ) > )> UrlTranslatorFunc;
typedef boost::function< void ( QSharedPointer< QIODevice >& ) > IODeviceCallback;
@ -38,10 +40,16 @@ namespace Tomahawk
namespace UrlHandler
{
DLLEXPORT void getIODeviceForUrl( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
DLLEXPORT void registerIODeviceFactory( const QString &proto, IODeviceFactoryFunc fac );
DLLEXPORT void localFileIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
DLLEXPORT void httpIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
DLLEXPORT void getIODeviceForUrl( const Tomahawk::result_ptr&, const QString& url, boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
DLLEXPORT void registerIODeviceFactory( const QString& proto, IODeviceFactoryFunc fac );
DLLEXPORT void localFileIODeviceFactory( const Tomahawk::result_ptr& result, const QString& url,
boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
DLLEXPORT void httpIODeviceFactory( const Tomahawk::result_ptr& result, const QString& url,
boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
DLLEXPORT void getUrlTranslation( const Tomahawk::result_ptr& result, const QString& url,
boost::function< void ( const QString& ) > callback );
DLLEXPORT void registerUrlTranslator( const QString &proto, UrlTranslatorFunc fac );
} // namespace UrlHandler

View File

@ -631,20 +631,41 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
if ( !TomahawkUtils::isLocalResult( d->currentTrack->url() ) && !TomahawkUtils::isHttpResult( d->currentTrack->url() )
&& !TomahawkUtils::isRtmpResult( d->currentTrack->url() ) )
{
boost::function< void ( QSharedPointer< QIODevice >& ) > callback =
boost::bind( &AudioEngine::performLoadTrack, this, result, _1 );
Tomahawk::UrlHandler::getIODeviceForUrl( d->currentTrack, callback );
boost::function< void ( const QString& ) > callback =
boost::bind( &AudioEngine::performLoadIODevice, this, result, _1 );
Tomahawk::UrlHandler::getUrlTranslation( d->currentTrack, d->currentTrack->url(), callback );
}
else
{
QSharedPointer< QIODevice > io;
performLoadTrack( result, io );
performLoadTrack( result, result->url(), io );
}
}
void
AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointer< QIODevice >& io )
AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url )
{
Q_D( AudioEngine );
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : url );
if ( !TomahawkUtils::isLocalResult( url ) && !TomahawkUtils::isHttpResult( url )
&& !TomahawkUtils::isRtmpResult( url ) )
{
boost::function< void ( QSharedPointer< QIODevice >& ) > callback =
boost::bind( &AudioEngine::performLoadTrack, this, result, url, _1 );
Tomahawk::UrlHandler::getIODeviceForUrl( result, url, callback );
}
else
{
QSharedPointer< QIODevice > io;
performLoadTrack( result, url, io );
}
}
void
AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, const QString& url, QSharedPointer< QIODevice >& io )
{
Q_D( AudioEngine );
if ( currentTrack() != result )
@ -657,7 +678,7 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointe
bool err = false;
{
if ( !( TomahawkUtils::isLocalResult( d->currentTrack->url() ) || TomahawkUtils::isHttpResult( d->currentTrack->url() ) || TomahawkUtils::isRtmpResult( d->currentTrack->url() ) )
if ( !( TomahawkUtils::isLocalResult( url ) || TomahawkUtils::isHttpResult( url ) || TomahawkUtils::isRtmpResult( url ) )
&& ( !io || io.isNull() ) )
{
tLog() << "Error getting iodevice for" << result->url();
@ -666,12 +687,12 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointe
if ( !err )
{
tLog() << "Starting new song:" << d->currentTrack->url();
tLog() << "Starting new song:" << url;
d->state = Loading;
emit loading( d->currentTrack );
if ( !TomahawkUtils::isLocalResult( d->currentTrack->url() ) && !TomahawkUtils::isHttpResult( d->currentTrack->url() )
&& !TomahawkUtils::isRtmpResult( d->currentTrack->url() ) )
if ( !TomahawkUtils::isLocalResult( url ) && !TomahawkUtils::isHttpResult( url )
&& !TomahawkUtils::isRtmpResult( url ) )
{
QSharedPointer<QNetworkReply> qnr = io.objectCast<QNetworkReply>();
if ( !qnr.isNull() )
@ -696,13 +717,13 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointe
* TODO: Do we need this anymore as we now do HTTP streaming ourselves?
* Maybe this can be useful for letting phonon do other protocols?
*/
if ( !TomahawkUtils::isLocalResult( d->currentTrack->url() ) )
if ( !TomahawkUtils::isLocalResult( url ) )
{
QUrl furl = d->currentTrack->url();
if ( d->currentTrack->url().contains( "?" ) )
QUrl furl = url;
if ( url.contains( "?" ) )
{
furl = QUrl( d->currentTrack->url().left( d->currentTrack->url().indexOf( '?' ) ) );
TomahawkUtils::urlSetQuery( furl, QString( d->currentTrack->url().mid( d->currentTrack->url().indexOf( '?' ) + 1 ) ) );
furl = QUrl( url.left( url.indexOf( '?' ) ) );
TomahawkUtils::urlSetQuery( furl, QString( url.mid( url.indexOf( '?' ) + 1 ) ) );
}
tLog( LOGVERBOSE ) << "Passing to Phonon:" << furl;
@ -710,7 +731,7 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointe
}
else
{
QString furl = d->currentTrack->url();
QString furl = url;
if ( furl.startsWith( "file://" ) )
furl = furl.right( furl.length() - 7 );

View File

@ -132,7 +132,8 @@ signals:
private slots:
void loadTrack( const Tomahawk::result_ptr& result ); //async!
void performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointer< QIODevice >& io ); //only call from loadTrack kthxbi
void performLoadIODevice( const Tomahawk::result_ptr& result, const QString& url ); //only call from loadTrack kthxbi
void performLoadTrack( const Tomahawk::result_ptr& result, const QString& url, QSharedPointer< QIODevice >& io ); //only call from loadTrack or performLoadIODevice kthxbi
void loadPreviousTrack();
void loadNextTrack();
@ -155,7 +156,7 @@ private:
void audioDataArrived( QMap< AudioEngine::AudioChannel, QVector< qint16 > >& data );
Q_DECLARE_PRIVATE( AudioEngine );
Q_DECLARE_PRIVATE( AudioEngine )
AudioEnginePrivate* d_ptr;
};

View File

@ -88,7 +88,7 @@ Servent::Servent( QObject* parent )
setProxy( QNetworkProxy::NoProxy );
IODeviceFactoryFunc fac = boost::bind( &Servent::remoteIODeviceFactory, this, _1, _2 );
IODeviceFactoryFunc fac = boost::bind( &Servent::remoteIODeviceFactory, this, _1, _2, _3 );
Tomahawk::UrlHandler::registerIODeviceFactory( "servent", fac );
}
@ -1224,12 +1224,12 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
void
Servent::remoteIODeviceFactory( const Tomahawk::result_ptr& result,
Servent::remoteIODeviceFactory( const Tomahawk::result_ptr& result, const QString& url,
boost::function< void ( QSharedPointer< QIODevice >& ) > callback )
{
QSharedPointer<QIODevice> sp;
QStringList parts = result->url().mid( QString( "servent://" ).length() ).split( "\t" );
QStringList parts = url.mid( QString( "servent://" ).length() ).split( "\t" );
const QString sourceName = parts.at( 0 );
const QString fileId = parts.at( 1 );
source_ptr s = SourceList::instance()->get( sourceName );

View File

@ -77,7 +77,7 @@ public:
ControlConnection* lookupControlConnection( const SipInfo& sipInfo );
ControlConnection* lookupControlConnection( const QString& nodeid );
void remoteIODeviceFactory( const Tomahawk::result_ptr& result,
void remoteIODeviceFactory( const Tomahawk::result_ptr& result, const QString& url,
boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
// you may call this method as often as you like for the same peerInfo, dupe checking is done inside

View File

@ -190,7 +190,7 @@ StreamConnection::startSending( const Tomahawk::result_ptr& result )
boost::function< void ( QSharedPointer< QIODevice >& ) > callback =
boost::bind( &StreamConnection::reallyStartSending, this, result, _1 );
Tomahawk::UrlHandler::getIODeviceForUrl( m_result, callback );
Tomahawk::UrlHandler::getIODeviceForUrl( m_result, m_result->url(), callback );
}

View File

@ -49,6 +49,7 @@ using namespace Tomahawk;
JSResolverHelper::JSResolverHelper( const QString& scriptPath, JSResolver* parent )
: QObject( parent )
, m_urlCallbackIsAsync( false )
, m_urlTranslatorIsAsync( false )
{
m_scriptPath = scriptPath;
m_resolver = parent;
@ -453,15 +454,43 @@ JSResolverHelper::addCustomUrlHandler( const QString& protocol,
{
m_urlCallbackIsAsync = ( isAsynchronous.toLower() == "true" ) ? true : false;
boost::function< void( const Tomahawk::result_ptr&,
boost::function< void( const Tomahawk::result_ptr&, const QString&,
boost::function< void( QSharedPointer< QIODevice >& ) > )> fac =
boost::bind( &JSResolverHelper::customIODeviceFactory, this, _1, _2 );
boost::bind( &JSResolverHelper::customIODeviceFactory, this, _1, _2, _3 );
Tomahawk::UrlHandler::registerIODeviceFactory( protocol, fac );
m_urlCallback = callbackFuncName;
}
void
JSResolverHelper::addCustomUrlTranslator( const QString& protocol,
const QString& callbackFuncName,
const QString& isAsynchronous )
{
m_urlTranslatorIsAsync = ( isAsynchronous.toLower() == "true" ) ? true : false;
boost::function< void( const Tomahawk::result_ptr&, const QString&,
boost::function< void( const QString& ) > )> fac =
boost::bind( &JSResolverHelper::customUrlTranslator, this, _1, _2, _3 );
Tomahawk::UrlHandler::registerUrlTranslator( protocol, fac );
m_urlTranslator = callbackFuncName;
}
void
JSResolverHelper::reportUrlTranslation( const QString& qid, const QString& streamUrl )
{
if ( !m_translatorCallbacks.contains( qid ) )
return;
boost::function< void( const QString& ) > callback = m_translatorCallbacks.take( qid );
returnUrlTranslation( streamUrl, callback );
}
QByteArray
JSResolverHelper::base64Encode( const QByteArray& input )
{
@ -477,11 +506,11 @@ JSResolverHelper::base64Decode( const QByteArray& input )
void
JSResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result,
JSResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr&, const QString& url,
boost::function< void( QSharedPointer< QIODevice >& ) > callback )
{
//can be sync or async
QString origResultUrl = QString( QUrl( result->url() ).toEncoded() );
QString origResultUrl = QString( QUrl( url ).toEncoded() );
if ( m_urlCallbackIsAsync )
{
@ -505,6 +534,34 @@ JSResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result,
}
void
JSResolverHelper::customUrlTranslator( const Tomahawk::result_ptr&, const QString& url, boost::function<void (const QString& )> callback )
{
//can be sync or async
QString origResultUrl = QString( QUrl( url ).toEncoded() );
if ( m_urlTranslatorIsAsync )
{
QString qid = uuid();
QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2', '%3' );" ).arg( m_urlTranslator )
.arg( qid )
.arg( origResultUrl );
m_translatorCallbacks.insert( qid, callback );
m_resolver->d_func()->engine->mainFrame()->evaluateJavaScript( getUrl );
}
else
{
QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( m_urlTranslator )
.arg( origResultUrl );
QString urlStr = m_resolver->d_func()->engine->mainFrame()->evaluateJavaScript( getUrl ).toString();
returnUrlTranslation( urlStr, callback );
}
}
void
JSResolverHelper::reportStreamUrl( const QString& qid,
const QString& streamUrl )
@ -537,3 +594,18 @@ JSResolverHelper::returnStreamUrl( const QString& streamUrl, boost::function< vo
sp = QSharedPointer< QIODevice >( reply, &QObject::deleteLater );
callback( sp );
}
void
JSResolverHelper::returnUrlTranslation( const QString& streamUrl, boost::function<void (const QString& )> callback )
{
if ( streamUrl.isEmpty() )
{
callback( QString() );
return;
}
//boost::functions cannot accept temporaries as parameters
// sp = QSharedPointer< QString >( streamUrl , &QObject::deleteLater );
callback( streamUrl );
}

View File

@ -46,12 +46,16 @@ public:
Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, const QString& isAsynchronous = "false" );
Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl );
Q_INVOKABLE void addCustomUrlTranslator( const QString& protocol, const QString& callbackFuncName, const QString& isAsynchronous = "false" );
Q_INVOKABLE void reportUrlTranslation( const QString& qid, const QString& streamUrl );
Q_INVOKABLE QByteArray base64Encode( const QByteArray& input );
Q_INVOKABLE QByteArray base64Decode( const QByteArray& input );
void customIODeviceFactory( const Tomahawk::result_ptr& result,
void customIODeviceFactory( const Tomahawk::result_ptr&, const QString& url,
boost::function< void( QSharedPointer< QIODevice >& ) > callback ); // async
void customUrlTranslator( const Tomahawk::result_ptr&, const QString& url,
boost::function< void( const QString& ) > callback ); // async
public slots:
QByteArray readRaw( const QString& fileName );
@ -82,10 +86,13 @@ private slots:
private:
Tomahawk::query_ptr parseTrack( const QVariantMap& track );
void returnStreamUrl( const QString& streamUrl, boost::function< void( QSharedPointer< QIODevice >& ) > callback );
void returnUrlTranslation( const QString& streamUrl, boost::function< void( const QString& ) > callback );
QString m_scriptPath, m_urlCallback;
QString m_scriptPath, m_urlCallback, m_urlTranslator;
QHash< QString, boost::function< void( QSharedPointer< QIODevice >& ) > > m_streamCallbacks;
QHash< QString, boost::function< void( const QString& ) > > m_translatorCallbacks;
bool m_urlCallbackIsAsync;
bool m_urlTranslatorIsAsync;
QVariantMap m_resolverConfig;
JSResolver* m_resolver;
QString m_pendingUrl;