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 }