v3.3.t1
-removed the web interface. this project will instead continue to focus on backend operations. external applications can interface with the buf/rec directories to provide frontend operations. -removed the magick binary file from the project. magick will instead be built from source on the target machine for maximum support for the target architecture. -stream codec and format are now user configurable. -recording thumbnail and video formats are now user configurable.
This commit is contained in:
parent
b09ff1a19a
commit
41ccf1d1e7
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -57,5 +57,4 @@ compile_commands.json
|
|||
|
||||
# Build folders
|
||||
/.build-mow
|
||||
/.build-opencv
|
||||
/src/opencv
|
||||
/.build-imagemagick
|
||||
|
|
|
@ -20,8 +20,6 @@ add_executable(mow
|
|||
src/main.cpp
|
||||
src/common.h
|
||||
src/common.cpp
|
||||
src/web.h
|
||||
src/web.cpp
|
||||
src/logger.h
|
||||
src/logger.cpp
|
||||
src/camera.h
|
||||
|
|
File diff suppressed because one or more lines are too long
BIN
bin/magick
BIN
bin/magick
Binary file not shown.
13
imgmagick_build.sh
Normal file
13
imgmagick_build.sh
Normal file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
if ! command -v magick &> /dev/null
|
||||
then
|
||||
apt install -y git
|
||||
git clone https://github.com/ImageMagick/ImageMagick.git .build-imagemagick
|
||||
cd .build-imagemagick
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
ldconfig /usr/local/lib
|
||||
fi
|
21
install.sh
21
install.sh
|
@ -19,26 +19,11 @@ if [ ! -d "/var/opt/mow/buf" ]; then
|
|||
mkdir /var/opt/mow/buf
|
||||
fi
|
||||
|
||||
if [ ! -d "/var/opt/mow/web" ]; then
|
||||
mkdir /var/opt/mow/web
|
||||
if [ ! -d "/var/opt/mow/rec" ]; then
|
||||
mkdir /var/opt/mow/rec
|
||||
fi
|
||||
|
||||
if [ -e "/var/opt/mow/web/index.html" ]; then
|
||||
rm -v /var/opt/mow/web/index.html
|
||||
fi
|
||||
|
||||
if [ -e "/var/opt/mow/web/theme.css" ]; then
|
||||
rm -v /var/opt/mow/web/theme.css
|
||||
fi
|
||||
|
||||
touch /var/opt/mow/buf/index.html
|
||||
touch /var/opt/mow/buf/theme.css
|
||||
|
||||
ln -sv /var/opt/mow/buf/index.html /var/opt/mow/web/index.html
|
||||
ln -sv /var/opt/mow/buf/theme.css /var/opt/mow/web/theme.css
|
||||
|
||||
cp -v ./.build-mow/mow /opt/mow/bin
|
||||
cp -v ./bin/hls.js /var/opt/mow/web/hls.js
|
||||
|
||||
echo "writing /opt/mow/run"
|
||||
printf "#!/bin/sh\n" > /opt/mow/run
|
||||
|
@ -63,3 +48,5 @@ chmod -v +x /opt/mow/bin
|
|||
chmod -v +x /opt/mow/uninst
|
||||
|
||||
ln -sv /opt/mow/run /usr/bin/mow
|
||||
|
||||
sh imgmagick_build.sh
|
||||
|
|
3
setup.sh
3
setup.sh
|
@ -3,5 +3,4 @@ export DEBIAN_FRONTEND=noninteractive
|
|||
apt update -y
|
||||
apt install -y pkg-config cmake make g++
|
||||
apt install -y ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev x264 libx264-dev libilmbase-dev qt6-base-dev qtchooser qmake6 qt6-base-dev-tools libxkbcommon-dev libfuse-dev fuse3
|
||||
cp ./bin/magick /usr/bin/magick
|
||||
chmod +x /usr/bin/magick
|
||||
sh imgmagick_build.sh
|
||||
|
|
|
@ -16,37 +16,28 @@ Camera::Camera(QObject *parent) : QObject(parent) {}
|
|||
|
||||
void Camera::cleanup()
|
||||
{
|
||||
QProcess::execute("rm", {shared.outDir + "/live"});
|
||||
QProcess::execute("rm", {shared.outDir + "/logs"});
|
||||
QProcess::execute("rm", {shared.outDir + "/img"});
|
||||
QProcess::execute("rm", {shared.outDir + "/index.html"});
|
||||
QProcess::execute("rm", {shared.outDir + "/stream.m3u8"});
|
||||
QProcess::execute("rm", {shared.tmpDir + "/events"});
|
||||
if (QFileInfo::exists(shared.tmpDir + "/rec"))
|
||||
{
|
||||
QProcess::execute("rm", {shared.tmpDir + "/rec"});
|
||||
}
|
||||
}
|
||||
|
||||
int Camera::start(const QStringList &args)
|
||||
{
|
||||
if (rdConf(getParam("-c", args), &shared))
|
||||
{
|
||||
QDir().mkpath(shared.outDir);
|
||||
QDir().mkpath(shared.tmpDir);
|
||||
QProcess::execute("mkdir", {"-p", shared.outDir});
|
||||
QProcess::execute("mkdir", {"-p", shared.tmpDir});
|
||||
|
||||
QDir().mkpath(shared.outDir + "/events");
|
||||
QDir().mkpath(shared.tmpDir + "/live");
|
||||
QDir().mkpath(shared.tmpDir + "/logs");
|
||||
QDir().mkpath(shared.tmpDir + "/img");
|
||||
QProcess::execute("mkdir", {"-p", shared.tmpDir + "/live"});
|
||||
QProcess::execute("mkdir", {"-p", shared.tmpDir + "/logs"});
|
||||
QProcess::execute("mkdir", {"-p", shared.tmpDir + "/img"});
|
||||
|
||||
cleanup();
|
||||
|
||||
touch(shared.tmpDir + "/index.html");
|
||||
touch(shared.tmpDir + "/stream.m3u8");
|
||||
|
||||
QProcess::execute("ln", {"-s", shared.tmpDir + "/live", shared.outDir + "/live"});
|
||||
QProcess::execute("ln", {"-s", shared.tmpDir + "/logs", shared.outDir + "/logs"});
|
||||
QProcess::execute("ln", {"-s", shared.tmpDir + "/img", shared.outDir + "/img"});
|
||||
QProcess::execute("ln", {"-s", shared.tmpDir + "/index.html", shared.outDir + "/index.html"});
|
||||
QProcess::execute("ln", {"-s", shared.tmpDir + "/stream.m3u8", shared.outDir + "/stream.m3u8"});
|
||||
QProcess::execute("ln", {"-s", shared.outDir + "/events", shared.tmpDir + "/events"});
|
||||
QProcess::execute("ln", {"-s", shared.outDir, shared.tmpDir + "/rec"});
|
||||
|
||||
if (!QDir::setCurrent(shared.tmpDir))
|
||||
{
|
||||
|
@ -141,12 +132,12 @@ void RecLoop::updateCmd()
|
|||
QStringList imgArgs;
|
||||
|
||||
recArgs << "-hide_banner";
|
||||
recArgs << "-i" << shared->recordUrl;
|
||||
recArgs << "-i" << shared->recordUri;
|
||||
recArgs << "-strftime" << "1";
|
||||
recArgs << "-strftime_mkdir" << "1";
|
||||
recArgs << "-hls_segment_filename" << "live/" + QString(STRFTIME_FMT) + ".ts";
|
||||
recArgs << "-hls_segment_filename" << "live/" + QString(STRFTIME_FMT) + shared->streamExt;
|
||||
recArgs << "-y";
|
||||
recArgs << "-vcodec" << "copy";
|
||||
recArgs << "-vcodec" << shared->streamCodec;
|
||||
recArgs << "-f" << "hls";
|
||||
recArgs << "-hls_time" << "2";
|
||||
recArgs << "-hls_list_size" << "1000";
|
||||
|
@ -156,7 +147,7 @@ void RecLoop::updateCmd()
|
|||
recArgs << "stream.m3u8";
|
||||
|
||||
imgArgs << "-hide_banner";
|
||||
imgArgs << "-i" << shared->recordUrl;
|
||||
imgArgs << "-i" << shared->recordUri;
|
||||
imgArgs << "-strftime" << "1";
|
||||
imgArgs << "-strftime_mkdir" << "1";
|
||||
imgArgs << "-vf" << "fps=1,scale=320:240";
|
||||
|
@ -236,14 +227,9 @@ bool Upkeep::exec()
|
|||
shared->detLog.clear();
|
||||
shared->logMutex.unlock();
|
||||
|
||||
initLogFrontPages();
|
||||
enforceMaxEvents(shared);
|
||||
enforceMaxImages();
|
||||
enforceMaxVids();
|
||||
|
||||
genFrontPage(shared);
|
||||
genCSS(shared);
|
||||
genCamPage(shared);
|
||||
enforceMaxVids(shared);
|
||||
|
||||
return Loop::exec();
|
||||
}
|
||||
|
@ -267,14 +253,12 @@ bool EventLoop::exec()
|
|||
|
||||
if (wrOutVod())
|
||||
{
|
||||
genHTMLvod(name);
|
||||
|
||||
QProcess proc;
|
||||
QStringList args;
|
||||
|
||||
args << "convert";
|
||||
args << imgPath;
|
||||
args << "events/" + name + ".jpg";
|
||||
args << "rec/" + name + shared->thumbExt;
|
||||
|
||||
proc.start("magick", args);
|
||||
proc.waitForFinished();
|
||||
|
@ -307,8 +291,8 @@ bool EventLoop::exec()
|
|||
auto maxSecs = shared->evMaxSecs / 2;
|
||||
// half the maxsecs value to get front-back half secs
|
||||
|
||||
auto backFiles = backwardFacingFiles("live", ".ts", event->timeStamp, maxSecs);
|
||||
auto frontFiles = forwardFacingFiles("live", ".ts", event->timeStamp, maxSecs);
|
||||
auto backFiles = backwardFacingFiles("live", shared->streamExt, event->timeStamp, maxSecs);
|
||||
auto frontFiles = forwardFacingFiles("live", shared->streamExt, event->timeStamp, maxSecs);
|
||||
|
||||
vidList.append(backFiles + frontFiles);
|
||||
rmIndx.append(i);
|
||||
|
@ -367,7 +351,7 @@ bool EventLoop::wrOutVod()
|
|||
args << "-safe" << "0";
|
||||
args << "-i" << concat;
|
||||
args << "-c" << "copy";
|
||||
args << "events/" + name + ".mp4";
|
||||
args << "rec/" + name + shared->recExt;
|
||||
|
||||
proc.setProgram("ffmpeg");
|
||||
proc.setArguments(args);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "logger.h"
|
||||
#include "web.h"
|
||||
|
||||
class Camera : public QObject
|
||||
{
|
||||
|
|
107
src/common.cpp
107
src/common.cpp
|
@ -117,11 +117,9 @@ void enforceMaxEvents(shared_t *share)
|
|||
|
||||
auto mp4File = nameOnly + ".mp4";
|
||||
auto imgFile = nameOnly + ".jpg";
|
||||
auto webFile = nameOnly + ".html";
|
||||
|
||||
QFile::remove(mp4File);
|
||||
QFile::remove(imgFile);
|
||||
QFile::remove(webFile);
|
||||
|
||||
names.removeFirst();
|
||||
}
|
||||
|
@ -139,9 +137,9 @@ void enforceMaxImages()
|
|||
}
|
||||
}
|
||||
|
||||
void enforceMaxVids()
|
||||
void enforceMaxVids(shared_t *share)
|
||||
{
|
||||
auto names = lsFilesInDir("live", ".ts");
|
||||
auto names = lsFilesInDir("live", share->streamExt);
|
||||
|
||||
while (names.size() > MAX_VIDEOS)
|
||||
{
|
||||
|
@ -167,6 +165,14 @@ void rdLine(const QString ¶m, const QString &line, int *value)
|
|||
}
|
||||
}
|
||||
|
||||
void rdLine(const QString ¶m, const QString &line, bool *value)
|
||||
{
|
||||
if (line.startsWith(param))
|
||||
{
|
||||
*value = (line == "y" || line == "Y");
|
||||
}
|
||||
}
|
||||
|
||||
void touch(const QString &path)
|
||||
{
|
||||
if (!QFile::exists(path))
|
||||
|
@ -182,6 +188,14 @@ void touch(const QString &path)
|
|||
}
|
||||
}
|
||||
|
||||
void extCorrection(QString &ext)
|
||||
{
|
||||
if (!ext.startsWith("."))
|
||||
{
|
||||
ext = "." + ext;
|
||||
}
|
||||
}
|
||||
|
||||
bool rdConf(const QString &filePath, shared_t *share)
|
||||
{
|
||||
QFile varFile(filePath);
|
||||
|
@ -194,25 +208,27 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
}
|
||||
else
|
||||
{
|
||||
share->recordUrl.clear();
|
||||
share->recordUri.clear();
|
||||
share->postCmd.clear();
|
||||
share->camName.clear();
|
||||
|
||||
share->retCode = 0;
|
||||
share->imgThresh = 8000;
|
||||
share->maxEvents = 100;
|
||||
share->maxLogSize = 100000;
|
||||
share->skipCmd = false;
|
||||
share->postSecs = 60;
|
||||
share->evMaxSecs = 30;
|
||||
share->conf = filePath;
|
||||
share->buffPath = "/var/opt/" + QString(APP_BIN) + "/buf";
|
||||
share->webRoot = "/var/opt/" + QString(APP_BIN) + "/web";
|
||||
share->webBg = "#485564";
|
||||
share->webTxt = "#dee5ee";
|
||||
share->webFont = "courier";
|
||||
share->outputType = "stderr";
|
||||
share->compCmd = "magick compare -metric FUZZ " + QString(PREV_IMG) + " " + QString(NEXT_IMG) + " /dev/null";
|
||||
share->retCode = 0;
|
||||
share->imgThresh = 8000;
|
||||
share->maxEvents = 100;
|
||||
share->maxLogSize = 100000;
|
||||
share->skipCmd = false;
|
||||
share->postSecs = 60;
|
||||
share->evMaxSecs = 30;
|
||||
share->conf = filePath;
|
||||
share->buffPath = "/var/opt/" + QString(APP_BIN) + "/buf";
|
||||
share->recRoot = "/var/opt/" + QString(APP_BIN) + "/rec";
|
||||
share->outputType = "stderr";
|
||||
share->compCmd = "magick compare -metric FUZZ " + QString(PREV_IMG) + " " + QString(NEXT_IMG) + " /dev/null";
|
||||
share->streamCodec = "copy";
|
||||
share->streamExt = ".ts";
|
||||
share->recExt = ".mp4";
|
||||
share->thumbExt = ".jpg";
|
||||
share->singleTenant = false;
|
||||
|
||||
QString line;
|
||||
|
||||
|
@ -222,21 +238,23 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
|
||||
if (!line.startsWith("#"))
|
||||
{
|
||||
rdLine("cam_name = ", line, &share->camName);
|
||||
rdLine("recording_stream = ", line, &share->recordUrl);
|
||||
rdLine("buffer_path = ", line, &share->buffPath);
|
||||
rdLine("web_root = ", line, &share->webRoot);
|
||||
rdLine("web_text = ", line, &share->webTxt);
|
||||
rdLine("web_bg = ", line, &share->webBg);
|
||||
rdLine("web_font = ", line, &share->webFont);
|
||||
rdLine("max_event_secs = ", line, &share->evMaxSecs);
|
||||
rdLine("post_secs = ", line, &share->postSecs);
|
||||
rdLine("post_cmd = ", line, &share->postCmd);
|
||||
rdLine("img_thresh = ", line, &share->imgThresh);
|
||||
rdLine("max_events = ", line, &share->maxEvents);
|
||||
rdLine("max_log_size = ", line, &share->maxLogSize);
|
||||
rdLine("img_comp_out = ", line, &share->outputType);
|
||||
rdLine("img_comp_cmd = ", line, &share->compCmd);
|
||||
rdLine("cam_name = ", line, &share->camName);
|
||||
rdLine("recording_uri = ", line, &share->recordUri);
|
||||
rdLine("buffer_path = ", line, &share->buffPath);
|
||||
rdLine("rec_root = ", line, &share->recRoot);
|
||||
rdLine("max_event_secs = ", line, &share->evMaxSecs);
|
||||
rdLine("post_secs = ", line, &share->postSecs);
|
||||
rdLine("post_cmd = ", line, &share->postCmd);
|
||||
rdLine("img_thresh = ", line, &share->imgThresh);
|
||||
rdLine("max_events = ", line, &share->maxEvents);
|
||||
rdLine("max_log_size = ", line, &share->maxLogSize);
|
||||
rdLine("img_comp_out = ", line, &share->outputType);
|
||||
rdLine("img_comp_cmd = ", line, &share->compCmd);
|
||||
rdLine("stream_codec = ", line, &share->streamCodec);
|
||||
rdLine("stream_ext = ", line, &share->streamExt);
|
||||
rdLine("rec_ext = ", line, &share->recExt);
|
||||
rdLine("thumbnail_ext = ", line, &share->thumbExt);
|
||||
rdLine("single_tenant = ", line, &share->singleTenant);
|
||||
}
|
||||
|
||||
} while(!line.isEmpty());
|
||||
|
@ -246,8 +264,21 @@ bool rdConf(const QString &filePath, shared_t *share)
|
|||
share->camName = QFileInfo(share->conf).fileName();
|
||||
}
|
||||
|
||||
share->outDir = QDir().cleanPath(share->webRoot) + "/" + share->camName;
|
||||
share->tmpDir = share->buffPath + "/" + share->camName;
|
||||
extCorrection(share->streamExt);
|
||||
extCorrection(share->recExt);
|
||||
extCorrection(share->thumbExt);
|
||||
|
||||
if (share->singleTenant)
|
||||
{
|
||||
share->outDir = QDir().cleanPath(share->recRoot);
|
||||
share->tmpDir = QDir().cleanPath(share->buffPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
share->outDir = QDir().cleanPath(share->recRoot) + "/" + share->camName;
|
||||
share->tmpDir = QDir().cleanPath(share->buffPath) + "/" + share->camName;
|
||||
}
|
||||
|
||||
share->servPath = QString("/var/opt/") + APP_BIN + "/" + APP_BIN + "." + share->camName + ".service";
|
||||
}
|
||||
|
||||
|
@ -355,6 +386,8 @@ int loadServices(const QStringList &args)
|
|||
else
|
||||
{
|
||||
QTextStream(stdout) << "Successfully loaded camera service: " << servName << Qt::endl;
|
||||
|
||||
if (shared.singleTenant) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
27
src/common.h
27
src/common.h
|
@ -17,25 +17,24 @@
|
|||
#include <QProcess>
|
||||
#include <QTextStream>
|
||||
#include <QObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QDir>
|
||||
#include <QCryptographicHash>
|
||||
#include <QFile>
|
||||
#include <QDateTime>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QStringList>
|
||||
#include <QMutex>
|
||||
#include <QRegularExpression>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define APP_VER "3.2"
|
||||
#define APP_VER "3.3.t1"
|
||||
#define APP_NAME "Motion Watch"
|
||||
#define APP_BIN "mow"
|
||||
#define REC_LOG_NAME "rec_log_lines.html"
|
||||
#define DET_LOG_NAME "det_log_lines.html"
|
||||
#define UPK_LOG_NAME "upk_log_lines.html"
|
||||
#define REC_LOG_NAME "rec.log"
|
||||
#define DET_LOG_NAME "det.log"
|
||||
#define UPK_LOG_NAME "upk.log"
|
||||
#define DATETIME_FMT "yyyyMMddhhmmss"
|
||||
#define STRFTIME_FMT "%Y%m%d%H%M%S"
|
||||
#define MAX_IMAGES 1000
|
||||
|
@ -59,19 +58,21 @@ struct shared_t
|
|||
QString conf;
|
||||
QString recLog;
|
||||
QString detLog;
|
||||
QString recordUrl;
|
||||
QString recordUri;
|
||||
QString outDir;
|
||||
QString tmpDir;
|
||||
QString buffPath;
|
||||
QString postCmd;
|
||||
QString camName;
|
||||
QString webBg;
|
||||
QString webTxt;
|
||||
QString webFont;
|
||||
QString webRoot;
|
||||
QString recRoot;
|
||||
QString servPath;
|
||||
QString outputType;
|
||||
QString compCmd;
|
||||
QString streamCodec;
|
||||
QString streamExt;
|
||||
QString recExt;
|
||||
QString thumbExt;
|
||||
bool singleTenant;
|
||||
bool skipCmd;
|
||||
int evMaxSecs;
|
||||
int postSecs;
|
||||
|
@ -95,8 +96,10 @@ void rmServices();
|
|||
void touch(const QString &path);
|
||||
void rdLine(const QString ¶m, const QString &line, QString *value);
|
||||
void rdLine(const QString ¶m, const QString &line, int *value);
|
||||
void rdLine(const QString ¶m, const QString &line, bool *value);
|
||||
void enforceMaxEvents(shared_t *share);
|
||||
void enforceMaxImages();
|
||||
void enforceMaxVids();
|
||||
void enforceMaxVids(shared_t *share);
|
||||
void extCorrection(QString &ext);
|
||||
|
||||
#endif // COMMON_H
|
||||
|
|
|
@ -12,22 +12,26 @@
|
|||
|
||||
#include "logger.h"
|
||||
|
||||
void wrLogLine(const QString &line, shared_t *share, QString &body)
|
||||
{
|
||||
if (!line.isEmpty())
|
||||
{
|
||||
share->logMutex.lock();
|
||||
|
||||
body += QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh-mm-ss] ") + line + "\n";
|
||||
|
||||
share->logMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void recLog(const QString &line, shared_t *share)
|
||||
{
|
||||
share->logMutex.lock();
|
||||
|
||||
share->recLog += QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh-mm-ss] ") + line + "<br>\n";
|
||||
|
||||
share->logMutex.unlock();
|
||||
wrLogLine(line, share, share->recLog);
|
||||
}
|
||||
|
||||
void detLog(const QString &line, shared_t *share)
|
||||
{
|
||||
share->logMutex.lock();
|
||||
|
||||
share->detLog += QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh-mm-ss] ") + line + "<br>\n";
|
||||
|
||||
share->logMutex.unlock();
|
||||
wrLogLine(line, share, share->detLog);
|
||||
}
|
||||
|
||||
void enforceMaxLogSize(const QString &filePath, shared_t *share)
|
||||
|
@ -62,64 +66,3 @@ void dumpLogs(const QString &fileName, const QString &lines)
|
|||
outFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void initLogFrontPage(const QString &filePath, const QString &logLinesFile)
|
||||
{
|
||||
if (!QFile::exists(filePath))
|
||||
{
|
||||
QString htmlText = "<!DOCTYPE html>\n";
|
||||
|
||||
htmlText += "<html>\n";
|
||||
htmlText += "<script>\n";
|
||||
htmlText += "function includeHTML() {\n";
|
||||
htmlText += " var z, i, elmnt, file, xhttp;\n";
|
||||
htmlText += " z = document.getElementsByTagName(\"*\");\n";
|
||||
htmlText += " for (i = 0; i < z.length; i++) {\n";
|
||||
htmlText += " elmnt = z[i];\n";
|
||||
htmlText += " file = elmnt.getAttribute(\"include-html\");\n";
|
||||
htmlText += " if (file) {\n";
|
||||
htmlText += " xhttp = new XMLHttpRequest();\n";
|
||||
htmlText += " xhttp.onreadystatechange = function() {\n";
|
||||
htmlText += " if (this.readyState == 4) {\n";
|
||||
htmlText += " if (this.status == 200) {elmnt.innerHTML = this.responseText;}\n";
|
||||
htmlText += " if (this.status == 404) {elmnt.innerHTML = \"Page not found.\";}\n";
|
||||
htmlText += " elmnt.removeAttribute(\"include-html\");\n";
|
||||
htmlText += " includeHTML();\n";
|
||||
htmlText += " }\n";
|
||||
htmlText += " }\n";
|
||||
htmlText += " xhttp.open(\"GET\", file, true);\n";
|
||||
htmlText += " xhttp.send();\n";
|
||||
htmlText += " return;\n";
|
||||
htmlText += " }\n";
|
||||
htmlText += " }\n";
|
||||
htmlText += "};\n";
|
||||
htmlText += "</script>\n";
|
||||
htmlText += "<head>\n";
|
||||
htmlText += "<meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Pragma\" content=\"no-cache\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Expires\" content=\"0\" />\n";
|
||||
htmlText += "<link rel='stylesheet' href='/theme.css'>\n";
|
||||
htmlText += "</head>\n";
|
||||
htmlText += "<body>\n";
|
||||
htmlText += "<p>\n";
|
||||
htmlText += "<div include-html='" + logLinesFile + "'></div>\n";
|
||||
htmlText += "<script>\n";
|
||||
htmlText += "includeHTML();\n";
|
||||
htmlText += "</script>\n";
|
||||
htmlText += "</p>\n";
|
||||
htmlText += "</body>\n";
|
||||
htmlText += "</html>\n";
|
||||
|
||||
QFile outFile(filePath);
|
||||
|
||||
outFile.open(QFile::WriteOnly);
|
||||
outFile.write(htmlText.toUtf8());
|
||||
outFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void initLogFrontPages()
|
||||
{
|
||||
initLogFrontPage("logs/recording_log.html", REC_LOG_NAME);
|
||||
initLogFrontPage("logs/detection_log.html", DET_LOG_NAME);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
void wrLogLine(const QString &line, shared_t *share, QString &body);
|
||||
void recLog(const QString &line, shared_t *share);
|
||||
void detLog(const QString &line, shared_t *share);
|
||||
void dumpLogs(const QString &fileName, const QString &lines);
|
||||
void enforceMaxLogSize(const QString &filePath, shared_t *share);
|
||||
void initLogFrontPages();
|
||||
|
||||
#endif // lOGGER_H
|
||||
|
|
189
src/web.cpp
189
src/web.cpp
|
@ -1,189 +0,0 @@
|
|||
// This file is part of Motion Watch.
|
||||
|
||||
// Motion Watch is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Motion Watch is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
#include "web.h"
|
||||
|
||||
void genFrontPage(shared_t *share)
|
||||
{
|
||||
QString htmlText = "<!DOCTYPE html>\n";
|
||||
|
||||
htmlText += "<html>\n";
|
||||
htmlText += "<head>\n";
|
||||
htmlText += "<meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Pragma\" content=\"no-cache\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Expires\" content=\"0\" />\n";
|
||||
htmlText += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n";
|
||||
htmlText += "<link rel='stylesheet' href='/theme.css'>\n";
|
||||
htmlText += "</head>\n";
|
||||
htmlText += "<body>\n";
|
||||
htmlText += "<h3>" + QString(APP_NAME) + " " + QString(APP_VER) + "</h3>\n";
|
||||
|
||||
auto dirNames = lsDirsInDir(share->buffPath);
|
||||
|
||||
htmlText += "<ul>\n";
|
||||
|
||||
for (auto &&dirName : dirNames)
|
||||
{
|
||||
htmlText += " <li><a href='" + dirName + "/index.html'>" + dirName + "</a></li>\n";
|
||||
}
|
||||
|
||||
htmlText += "</ul>\n";
|
||||
htmlText += "</body>\n";
|
||||
htmlText += "</html>";
|
||||
|
||||
QFile outFile(QDir().cleanPath(share->buffPath) + "/index.html");
|
||||
|
||||
outFile.open(QFile::WriteOnly);
|
||||
outFile.write(htmlText.toUtf8());
|
||||
outFile.close();
|
||||
}
|
||||
|
||||
void genCamPage(shared_t *share)
|
||||
{
|
||||
auto outputDir = QDir().cleanPath(share->tmpDir);
|
||||
QString htmlText = "<!DOCTYPE html>\n";
|
||||
|
||||
htmlText += "<html>\n";
|
||||
htmlText += "<head>\n";
|
||||
htmlText += "<meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Pragma\" content=\"no-cache\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Expires\" content=\"0\" />\n";
|
||||
htmlText += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n";
|
||||
htmlText += "<link rel='stylesheet' href='/theme.css'>\n";
|
||||
htmlText += "</head>\n";
|
||||
htmlText += "<body>\n";
|
||||
htmlText += "<h3>" + share->camName + "</h3>\n";
|
||||
|
||||
if (QDir().exists(outputDir + "/logs"))
|
||||
{
|
||||
auto logNames = lsFilesInDir(outputDir + "/logs", "_log.html");
|
||||
|
||||
htmlText += "<h4>Logs</h4>\n";
|
||||
htmlText += "<ul>\n";
|
||||
|
||||
for (auto &&logName : logNames)
|
||||
{
|
||||
auto name = logName;
|
||||
|
||||
name.remove("_log.html");
|
||||
|
||||
htmlText += " <li><a href='logs/" + logName + "'>" + name + "</a></li>\n";
|
||||
}
|
||||
|
||||
htmlText += "</ul>\n";
|
||||
}
|
||||
|
||||
if (QDir().exists(outputDir + "/live"))
|
||||
{
|
||||
htmlText += "<h4>Live</h4>\n";
|
||||
|
||||
genHTMLstream(htmlText);
|
||||
}
|
||||
|
||||
if (QDir().exists(outputDir + "/events"))
|
||||
{
|
||||
auto eveNames = lsFilesInDir(outputDir + "/events", ".html");
|
||||
|
||||
htmlText += "<h4>Motion Events</h4>\n";
|
||||
|
||||
for (auto &&eveName : eveNames)
|
||||
{
|
||||
auto name = eveName;
|
||||
|
||||
name.remove(".html");
|
||||
|
||||
htmlText += "<a href='events/" + eveName + "'><img src='events/" + name + ".jpg" + "' style='width:25%;height:25%;'</a>\n";
|
||||
}
|
||||
}
|
||||
|
||||
htmlText += "</body>\n";
|
||||
htmlText += "</html>";
|
||||
|
||||
QFile outFile(QDir().cleanPath(outputDir) + "/index.html");
|
||||
|
||||
outFile.open(QFile::WriteOnly);
|
||||
outFile.write(htmlText.toUtf8());
|
||||
outFile.close();
|
||||
}
|
||||
|
||||
void genHTMLstream(QString &text)
|
||||
{
|
||||
text += "<script src=\"/hls.js\">\n";
|
||||
text += "</script>\n";
|
||||
text += "<video width=50% height=50% id=\"video\" controls>\n";
|
||||
text += "</video>\n";
|
||||
text += "<script>\n";
|
||||
text += " var video = document.getElementById('video');\n";
|
||||
text += " if (Hls.isSupported()) {\n";
|
||||
text += " var hls = new Hls({\n";
|
||||
text += " debug: true,\n";
|
||||
text += " });\n";
|
||||
text += " hls.loadSource('stream.m3u8');\n";
|
||||
text += " hls.attachMedia(video);\n";
|
||||
text += " hls.on(Hls.Events.MEDIA_ATTACHED, function () {\n";
|
||||
text += " video.muted = true;\n";
|
||||
text += " video.play();\n";
|
||||
text += " });\n";
|
||||
text += " }\n";
|
||||
text += " else if (video.canPlayType('application/vnd.apple.mpegurl')) {\n";
|
||||
text += " video.src = 'stream.m3u8';\n";
|
||||
text += " video.addEventListener('canplay', function () {\n";
|
||||
text += " video.play();\n";
|
||||
text += " });\n";
|
||||
text += " }\n";
|
||||
text += "</script>\n";
|
||||
}
|
||||
|
||||
void genHTMLvod(const QString &name)
|
||||
{
|
||||
QString htmlText = "<!DOCTYPE html>\n";
|
||||
|
||||
htmlText += "<html>\n";
|
||||
htmlText += "<head>\n";
|
||||
htmlText += "<meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Pragma\" content=\"no-cache\" />\n";
|
||||
htmlText += "<meta http-equiv=\"Expires\" content=\"0\" />\n";
|
||||
htmlText += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n";
|
||||
htmlText += "<link rel='stylesheet' href='/theme.css'>\n";
|
||||
htmlText += "</head>\n";
|
||||
htmlText += "<body>\n";
|
||||
htmlText += "<video width=100% height=100% controls autoplay>\n";
|
||||
htmlText += " <source src='" + name + ".mp4' type='video/mp4'>\n";
|
||||
htmlText += "</video>\n";
|
||||
htmlText += "</body>\n";
|
||||
htmlText += "</html>";
|
||||
|
||||
QFile outFile("events/" + name + ".html");
|
||||
|
||||
outFile.open(QFile::WriteOnly);
|
||||
outFile.write(htmlText.toUtf8());
|
||||
outFile.close();
|
||||
}
|
||||
|
||||
void genCSS(shared_t *share)
|
||||
{
|
||||
QString cssText = "body {\n";
|
||||
|
||||
cssText += " background-color: " + share->webBg + ";\n";
|
||||
cssText += " color: " + share->webTxt + ";\n";
|
||||
cssText += " font-family: " + share->webFont + ";\n";
|
||||
cssText += "}\n";
|
||||
cssText += "a {\n";
|
||||
cssText += " color: " + share->webTxt + ";\n";
|
||||
cssText += "}\n";
|
||||
|
||||
QFile outFile(QDir().cleanPath(share->buffPath) + "/theme.css");
|
||||
|
||||
outFile.open(QFile::WriteOnly);
|
||||
outFile.write(cssText.toUtf8());
|
||||
outFile.close();
|
||||
}
|
24
src/web.h
24
src/web.h
|
@ -1,24 +0,0 @@
|
|||
#ifndef WEB_H
|
||||
#define WEB_H
|
||||
|
||||
// This file is part of Motion Watch.
|
||||
|
||||
// Motion Watch is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Motion Watch is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void genFrontPage(shared_t *share);
|
||||
void genCamPage(shared_t *share);
|
||||
void genHTMLstream(QString &text);
|
||||
void genHTMLvod(const QString &name);
|
||||
void genCSS(shared_t *share);
|
||||
|
||||
#endif // WEB_H
|
Loading…
Reference in New Issue
Block a user