#include "scriptengine.h" #include #include #include #include "loadrunable.h" #include "rawimage.h" #include "loadrunable.h" namespace Script { ScriptEngine::ScriptEngine(QObject *parent) : QObject(parent) , _jsEngine(new QJSEngine(this)) , _database(new Database(this)) , _pool(new QThreadPool(this)) { QJSValue engine = _jsEngine->newQObject(this); _jsEngine->globalObject().setProperty("engine", engine); _database->init(QLatin1String("scriptengine")); } void ScriptEngine::setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir) { _scriptPath = scriptPath; _paths = paths; _outputDir = outputDir + "/"; } void ScriptEngine::reportError(const QString &message) { _jsEngine->throwError(message); } const QString &ScriptEngine::outputDir() const { return _outputDir; } void ScriptEngine::interrupt() { _jsEngine->setInterrupted(true); } void ScriptEngine::logError(const QString &message) { emit newMessage(message, true); } void ScriptEngine::log(const QString &message) { emit newMessage(message, false); } void ScriptEngine::mark(File *file) { _database->mark(file->absoluteFilePath()); } void ScriptEngine::unmark(File *file) { _database->unmark(file->absoluteFilePath()); } bool ScriptEngine::isMarked(const File *file) const { return _database->isMarked(file->absoluteFilePath()); } bool ScriptEngine::convert(File *file, QString &outpath, QString format, QVariantMap params) { QString path; QDir dir(_outputDir); QFileInfo info(outpath); QString suffix = info.suffix(); if(info.isAbsolute()) path = info.absolutePath(); else path = dir.absoluteFilePath(outpath); info.setFile(path); //qDebug() << info.absolutePath() + "/" + info.completeBaseName() + "." + format.toLower(); _pool->start(new ConvertRunable(file->absoluteFilePath(), info.absolutePath() + "/" + info.completeBaseName() + "." + format.toLower(), format, params)); return true; } QJSValue ScriptEngine::newObject() { return _jsEngine->newObject(); } void ScriptEngine::run() { QJSValue jsPaths = _jsEngine->newArray(_paths.size()); for(qsizetype i=0; i<_paths.size(); i++) jsPaths.setProperty(i, _jsEngine->newQObject(new File(_paths[i], this))); _jsEngine->globalObject().setProperty("files", jsPaths); QFile scriptFile(_scriptPath); if(!scriptFile.open(QIODevice::ReadOnly)) { emit newMessage("Failed to open " + _scriptPath, true); emit finished(); return; } QTextStream stream(&scriptFile); QString contents = stream.readAll(); scriptFile.close(); QJSValue result = _jsEngine->evaluate(contents, _scriptPath); qDebug() << result.isError() << result.toString(); if(result.isError()) { QString error = result.property("name").toString() + " on line " + result.property("lineNumber").toString() + " : " + result.toString(); error += "\n" + result.property("stack").toString(); emit newMessage(error, true); } emit finished(); } void File::loadFitsKeywords() { if(!_fitsKeywordsLoaded) { _fitsKeywordsLoaded = true; ImageInfoData info; if(suffix() == "xisf") { readXISFHeader(_path, info); } else if(suffix() == "fits") { readFITSHeader(_path, info); } else return; for(const FITSRecord &record : info.fitsHeader) { _fitsKeywords[record.key] = record.value.toString(); } } } bool File::mkpath(const QString &path) const { QFileInfo info(path); if(!info.isRelative()) { _engine->logError("Destination path is not relative"); return false; } QDir dir(_engine->outputDir()); if(dir.mkpath(info.path())) { return true; } else { _engine->logError("Failed to create dir " + info.path()); return false; } } File::File(const QString &path, Script::ScriptEngine *engine) : _engine(engine), _path(path), _info(path) { } QString File::fileName() const { return _info.fileName(); } QString File::absoluteFilePath() const { return _info.absoluteFilePath(); } QString File::absolutePath() const { return _info.absolutePath(); } QString File::baseName() const { return _info.baseName(); } QString File::completeBaseName() const { return _info.completeBaseName(); } QString File::suffix() const { return _info.suffix(); } qint64 File::size() const { return _info.size(); } QStringList File::fitsKeywords() { QThread::msleep(500); loadFitsKeywords(); return _fitsKeywords.keys(); } QString File::fitsValue(const QString &key) { loadFitsKeywords(); if(_fitsKeywords.contains(key)) return _fitsKeywords[key]; else return QString(); } bool File::isMarked() const { return _engine->isMarked(this); } bool File::copy(const QString &newpath) const { if(mkpath(newpath)) { if(QFile::copy(_path, _engine->outputDir() + newpath)) return true; _engine->logError("Failed copy to " + newpath); return false; } return false; } bool File::move(const QString &newpath) const { if(mkpath(newpath)) { if(QFile::rename(_path, _engine->outputDir() + newpath)) return true; _engine->logError("Failed move to " + newpath); return false; } return false; } bool File::convertTo(const QString &format) { _engine->reportError("Not implemented"); return false; } QJSValue File::stats() { if(_stats.isUndefined()) { ImageInfoData info; std::shared_ptr rawImage; loadImage(_path, info, rawImage); rawImage->calcStats(); RawImage::Stats stats = rawImage->imageStats(); _stats = _engine->newObject(); _stats.setProperty("mean", stats.m_mean[0]); _stats.setProperty("stddev", stats.m_stdDev[0]); _stats.setProperty("median", stats.m_median[0]); _stats.setProperty("min", stats.m_min[0]); _stats.setProperty("max", stats.m_max[0]); _stats.setProperty("mad", stats.m_mean[0]); } return _stats; } ScriptEngineThread::ScriptEngineThread(QObject *parent) : QObject(parent) { _thread = new QThread(); _thread->setObjectName("ScriptEngine"); _engine = new ScriptEngine; _engine->moveToThread(_thread); connect(_engine, &ScriptEngine::finished, _thread, &QThread::quit); connect(_engine, &ScriptEngine::newMessage, this, &ScriptEngineThread::newMessage); connect(_thread, &QThread::started, _engine, &ScriptEngine::run); connect(_thread, &QThread::finished, _engine, &ScriptEngine::deleteLater); connect(_engine, &ScriptEngine::destroyed, [this](){ _engine = nullptr; }); connect(_thread, &QThread::finished, _thread, &QThread::deleteLater); connect(_thread, &QThread::finished, this, &ScriptEngineThread::finished); } ScriptEngineThread::~ScriptEngineThread() { if(_engine)_engine->interrupt(); } void ScriptEngineThread::setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir) { _engine->setParams(scriptPath, paths, outputDir); } void ScriptEngineThread::start() { _thread->start(); } void ScriptEngineThread::interrupt() { if(_engine)_engine->interrupt(); } }