Files
tenmon/scriptengine.cpp
T
2024-03-26 14:54:19 +01:00

317 lines
7.4 KiB
C++

#include "scriptengine.h"
#include <QDir>
#include <QFileInfo>
#include <QDebug>
#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"));
_semaphore.release(_pool->maxThreadCount());
}
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();
_semaphore.acquire();
_pool->start(new ConvertRunable(file->absoluteFilePath(), info.absolutePath() + "/" + info.completeBaseName() + "." + format.toLower(), format, params, &_semaphore));
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();
_pool->waitForDone();
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> 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();
}
}