File indexing completed on 2025-01-05 04:26:50

0001 /****************************************************************************************
0002  * Copyright (c) 2008 Peter ZHOU <peterzhoulei@gmail.com>                               *
0003  * Copyright (c) 2008 Leo Franchi <lfranchi@kde.org>                                    *
0004  *                                                                                      *
0005  * This program is free software; you can redistribute it and/or modify it under        *
0006  * the terms of the GNU General Public License as published by the Free Software        *
0007  * Foundation; either version 2 of the License, or (at your option) any later           *
0008  * version.                                                                             *
0009  *                                                                                      *
0010  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0011  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0012  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0013  *                                                                                      *
0014  * You should have received a copy of the GNU General Public License along with         *
0015  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0016  ****************************************************************************************/
0017 
0018 #define DEBUG_PREFIX "AmarokNetworkScript"
0019 
0020 #include "AmarokNetworkScript.h"
0021 
0022 #include "App.h"
0023 #include "core/support/Debug.h"
0024 
0025 #include <QJSEngine>
0026 #include <QTextCodec>
0027 
0028 #include <KLocalizedString>
0029 
0030 using namespace AmarokScript;
0031 
0032 AmarokDownloadHelper *AmarokDownloadHelper::s_instance = nullptr;
0033 
0034 Downloader::Downloader( QJSEngine* engine )
0035     : QObject( engine )
0036     , m_scriptEngine( engine )
0037 {
0038     QJSValue scriptObj = engine->newQObject( this );
0039     scriptObj.setPrototype( QJSValue() );
0040     const QJSValue stringDownloadCtor = scriptObj.property( "downloader_prototype_ctor" );
0041     engine->globalObject().setProperty( QStringLiteral("Downloader"), stringDownloadCtor); //kept for compat
0042     engine->globalObject().setProperty( QStringLiteral("StringDownloader"), stringDownloadCtor ); //added for clarity
0043     const QJSValue dataDownloadCtor = scriptObj.property( "dataDownloader_prototype_ctor(" );
0044     engine->globalObject().setProperty( QStringLiteral("DataDownloader"), dataDownloadCtor );
0045 }
0046 
0047 QJSValue
0048 Downloader::stringDownloader_prototype_ctor( QString urlString, QJSValue callable, QString encoding )
0049 {
0050     return init( urlString, callable, true, encoding );
0051 }
0052 
0053 QJSValue
0054 Downloader::dataDownloader_prototype_ctor( QString urlString, QJSValue callable )
0055 {
0056     return init( urlString, callable, false );
0057 }
0058 
0059 QJSValue
0060 Downloader::init( const QString &urlString, const QJSValue &callable, bool stringResult, QString encoding )
0061 {
0062     DEBUG_BLOCK
0063     QJSValue object = m_scriptEngine->newQObject( new QObject() );
0064 
0065     if( callable.isCallable() )
0066     {
0067         debug() << "ERROR! Constructor not called with a Url and function!";
0068         return object;
0069     }
0070 
0071     QUrl url = QUrl::fromEncoded( urlString.toLatin1(), QUrl::StrictMode );
0072 
0073     if( !url.isValid() )
0074     {
0075         debug() << "ERROR! Constructor not called with a valid Url!";
0076         return object;
0077     }
0078 
0079     // start download, and connect to it
0080     if( stringResult )
0081     {
0082         AmarokDownloadHelper::instance()->newStringDownload( url, m_scriptEngine, callable, encoding );
0083     }
0084     else
0085         AmarokDownloadHelper::instance()->newDataDownload( url, m_scriptEngine, callable );
0086     // connect to a local slot to extract the qstring
0087     //qScriptConnect( job, SIGNAL(result(KJob*)), object, fetchResult( job ) );
0088 
0089     return m_scriptEngine->newQObject( new QObject() );
0090 }
0091 
0092 ///////
0093 // Class AmarokDownloadHelper
0094 //////
0095 
0096 AmarokDownloadHelper::AmarokDownloadHelper()
0097 {
0098     s_instance = this;
0099     connect( The::networkAccessManager(), &NetworkAccessManagerProxy::requestRedirectedUrl,
0100              this, &AmarokDownloadHelper::requestRedirected );
0101 }
0102 
0103 void
0104 AmarokDownloadHelper::newStringDownload( const QUrl &url, QJSEngine* engine, const QJSValue &obj, const QString &encoding )
0105 {
0106     m_encodings[ url ] = encoding;
0107     newDownload( url, engine, obj, &AmarokDownloadHelper::resultString );
0108 }
0109 
0110 void
0111 AmarokDownloadHelper::newDataDownload( const QUrl &url, QJSEngine* engine, const QJSValue &obj )
0112 {
0113     newDownload( url, engine, obj, &AmarokDownloadHelper::resultData );
0114 }
0115 
0116 void
0117 AmarokDownloadHelper::requestRedirected( const QUrl &sourceUrl, const QUrl &targetUrl )
0118 {
0119     DEBUG_BLOCK
0120 
0121     // Move all entries from "url" to "targetUrl".
0122     updateUrl< QJSEngine* >( m_engines, sourceUrl, targetUrl );
0123     updateUrl< QJSValue >( m_values, sourceUrl, targetUrl );
0124     updateUrl< QString >( m_encodings, sourceUrl, targetUrl );
0125 }
0126 
0127 void
0128 AmarokDownloadHelper::resultData( const QUrl &url, const QByteArray &data, const NetworkAccessManagerProxy::Error &e )
0129 {
0130     if( !m_values.contains( url ) )
0131         return;
0132 
0133     if( e.code != QNetworkReply::NoError )
0134         warning() << "Error fetching data:" << e.description;
0135 
0136     QJSValue obj = m_values.value( url );
0137     QJSEngine* engine = m_engines.value( url );
0138     cleanUp( url );
0139 
0140     // now send the data to the associated script object
0141     if( !obj.isCallable() )
0142     {
0143         debug() << "script object is valid but not a function!!";
0144         return;
0145     }
0146 
0147     if( !engine )
0148     {
0149         debug() << "stored script engine is not valid!";
0150         return;
0151     }
0152 
0153     QJSValueList args;
0154     args << engine->toScriptValue( data );
0155     obj.call( args );
0156 }
0157 
0158 
0159 void
0160 AmarokDownloadHelper::resultString( const QUrl &url, const QByteArray &data, const NetworkAccessManagerProxy::Error &e )
0161 {
0162     if( !m_values.contains( url ) )
0163         return;
0164 
0165     if( e.code != QNetworkReply::NoError )
0166         warning() << "Error fetching string:" << e.description;
0167 
0168     QJSValue obj = m_values.value( url );
0169     QJSEngine* engine = m_engines.value( url );
0170     QString encoding = m_encodings.value( url );
0171     cleanUp( url );
0172 
0173     QString str;
0174     if( encoding.isEmpty() )
0175     {
0176         str = QString( data );
0177     }
0178     else
0179     {
0180         QTextCodec* codec = QTextCodec::codecForName( encoding.toUtf8() );
0181         str = codec->toUnicode( data );
0182     }
0183 
0184     // now send the data to the associated script object
0185     if( !obj.isCallable() )
0186     {
0187         debug() << "script object is valid but not a function!!";
0188         return;
0189     }
0190 
0191     if( !engine )
0192     {
0193         debug() << "stored script engine is not valid!";
0194         return;
0195     }
0196 
0197     QJSValueList args;
0198     args << engine->toScriptValue( str );
0199     obj.call( args );
0200 }
0201 
0202 void
0203 AmarokDownloadHelper::cleanUp( const QUrl &url )
0204 {
0205     m_values.remove( url );
0206     m_engines.remove( url );
0207     m_encodings.remove( url );
0208 }
0209 
0210 AmarokDownloadHelper*
0211 AmarokDownloadHelper::instance()
0212 {
0213     if( !s_instance )
0214         s_instance = new AmarokDownloadHelper();
0215     return s_instance;
0216 }