11 Commits

24 changed files with 9310 additions and 62 deletions

View File

@ -1,5 +1,30 @@
<img alt="openCountdown Logo" height="90px" src="https://git.project-name-here.de/Project-Name-Here/openCountdown/raw/branch/master/static/logo/logoProposal.svg">
# openCountdown # openCountdown
openCountdown is a professional software for event countdowns. It can be used in a live settings such as a music event.
Support for companion is currently being worked on [here](https://github.com/bitfocus/companion-module-pnh-opencountdown).
<a href="https://bitfocus.io/companion/?ref=pnh-Opencountdown" target="_new"><img alt="Controllable by Companion" src="https://bitfocus.io/companion-badge.png?ref=pnh-Opencountdown"></a>
# Installation
You can download complete binaries from the release tab.
## Development build
1. Download the repository
2. `npm install` to install dependecies
3. `node index.js` to launch
## Packaging
This is more a comment for the future version of me. There is one command for packaging using nexe.
```bash
npx nexe index.js --build --python python3 --resource "./{lang,templates,static}/**/*" --ouput "openCountdown.exe”
```
Where `--python` is only needed in some envoirments for some reason. Also adjust `--output` for your target OS.
*Small disclaimer: Please do not use openCountdown for military or life-depending applications. Please also refrain from using openCountdown for launching rockets.*
# ToDo # ToDo
- [P] Endpoint docs Endpoint documentation is currently pretty thin. This will be changed in the future.
- [ ] Endpoint docs (in Progress)
- [ ] Better WS frames - [ ] Better WS frames

View File

@ -6,6 +6,7 @@ const helper = require("./helpers.js");
const loggy = require("./logging") const loggy = require("./logging")
const Eta = require("eta"); const Eta = require("eta");
const _ = require("underscore") const _ = require("underscore")
const path = require("path")
loggy.init(true) loggy.init(true)
@ -24,6 +25,26 @@ app.use(
}) })
); );
// Allowed urls for requests to /assets/
const allowsURLs = [
'bootstrap-icons/font/bootstrap-icons.css',
'js-cookie/dist/js.cookie.min.js',
'bootstrap/dist/css/bootstrap.min.css',
'mdbootstrap/css/style.css',
'bootstrap/dist/js/bootstrap.bundle.min.js',
'jquery/dist/jquery.min.js',
'darkreader/darkreader.js',
'bootstrap-duration-picker/dist/bootstrap-duration-picker.css',
'flatpickr/dist/flatpickr.min.css',
'bootstrap-duration-picker/dist/bootstrap-duration-picker-debug.js',
'flatpickr/dist/flatpickr.js',
'bootstrap-icons/font/fonts/bootstrap-icons.woff2',
'bootstrap/dist/css/bootstrap.min.css.map',
'less/dist/less.min.js',
'less/dist/less.min.js.map',
'mdbootstrap/js/mdb.min.js'
];
let loadedData = {} let loadedData = {}
loggy.log("Loading config", "info", "Config"); loggy.log("Loading config", "info", "Config");
@ -391,6 +412,16 @@ app.get("/api/ui/v1/lang/set", function (req, res) {
}); });
app.use("/assets/*", function handleModuleFiles(req, res) {
if(allowsURLs.indexOf(req.params[0]) > -1){
res.sendFile(path.join(__dirname, "node_modules", req.params[0]));
} else {
loggy.log("Attempt to access restricted asset file " + req.params[0], "error", "Security")
res.status(403).json({ status: "error", reason: "Access to restricted asset file denied" });
}
// console.log(recordedURLs)
})
app.use(function (req, res, next) { app.use(function (req, res, next) {
res.status(404); res.status(404);
loggy.log("Server responded with 404 error", "warn", "Server", true); loggy.log("Server responded with 404 error", "warn", "Server", true);
@ -415,6 +446,8 @@ app.use(function (req, res, next) {
/*app.use(function(err, req, res, next) { /*app.use(function(err, req, res, next) {
console.error(err.stack); console.error(err.stack);
if(String(err.stack).includes("TypeError: Cannot read properties of undefined")) { if(String(err.stack).includes("TypeError: Cannot read properties of undefined")) {
@ -430,7 +463,7 @@ app.use(function (req, res, next) {
loggy.log("Starting server", "info", "Server"); loggy.log("Starting server", "info", "Server");
const port = 3005; const port = 3006;
process.on('SIGINT', function () { process.on('SIGINT', function () {
loggy.log("Caught interrupt signal and shutting down gracefully", "info", "Shutdown"); loggy.log("Caught interrupt signal and shutting down gracefully", "info", "Shutdown");

View File

@ -1 +1 @@
[{"timestamp":"2022-07-12 18:45:39.044","level":"info","module":"Logging","message":"2022-07-12 18:45:39.044 [info] [Logging] Logging initialized"},{"timestamp":"2022-07-12 18:45:39.046","level":"info","module":"Server","message":"2022-07-12 18:45:39.046 [info] [Server] Preparing server"},{"timestamp":"2022-07-12 18:45:39.047","level":"info","module":"Server","message":"2022-07-12 18:45:39.047 [info] [Server] Preparing static routes"},{"timestamp":"2022-07-12 18:45:39.048","level":"info","module":"Server","message":"2022-07-12 18:45:39.048 [info] [Server] Preparing middlewares"},{"timestamp":"2022-07-12 18:45:39.049","level":"info","module":"Config","message":"2022-07-12 18:45:39.049 [info] [Config] Loading config"},{"timestamp":"2022-07-12 18:45:39.052","level":"info","module":"Language","message":"2022-07-12 18:45:39.052 [info] [Language] Searching for languages"},{"timestamp":"2022-07-12 18:45:39.053","level":"info","module":"Language","message":"2022-07-12 18:45:39.053 [info] [Language] Found 3 languages"},{"timestamp":"2022-07-12 18:45:39.053","level":"info","module":"Language","message":"2022-07-12 18:45:39.053 [info] [Language] Reading language file"},{"timestamp":"2022-07-12 18:45:39.053","level":"info","module":"Websocket","message":"2022-07-12 18:45:39.053 [info] [Websocket] Preparing websocket"},{"timestamp":"2022-07-12 18:45:39.054","level":"info","module":"Server","message":"2022-07-12 18:45:39.054 [info] [Server] Preparing routes"},{"timestamp":"2022-07-12 18:45:39.055","level":"info","module":"Server","message":"2022-07-12 18:45:39.055 [info] [Server] Starting server"},{"timestamp":"2022-07-12 18:54:44.820","level":"info","module":"Language","message":"2022-07-12 18:54:44.820 [info] [Language] Reloading language file"},{"timestamp":"2022-07-12 18:54:44.823","level":"info","module":"Language","message":"2022-07-12 18:54:44.823 [info] [Language] Language reloaded, loaded en@1.0.0"},{"timestamp":"2022-07-12 18:54:48.364","level":"info","module":"Language","message":"2022-07-12 18:54:48.364 [info] [Language] Reloading language file"},{"timestamp":"2022-07-12 18:54:48.365","level":"info","module":"Language","message":"2022-07-12 18:54:48.365 [info] [Language] Language reloaded, loaded none@1.0.0"},{"timestamp":"2022-07-12 18:54:53.171","level":"info","module":"Language","message":"2022-07-12 18:54:53.171 [info] [Language] Reloading language file"},{"timestamp":"2022-07-12 18:54:53.172","level":"info","module":"Language","message":"2022-07-12 18:54:53.172 [info] [Language] Language reloaded, loaded en@1.0.0"},{"timestamp":"2022-07-12 19:47:47.709","level":"info","module":"Shutdown","message":"2022-07-12 19:47:47.709 [info] [Shutdown] Caught interrupt signal and shutting down gracefully"}] [{"timestamp":"2022-08-18 16:11:01.607","level":"info","module":"Logging","message":"2022-08-18 16:11:01.607 [info] [Logging] Logging initialized"},{"timestamp":"2022-08-18 16:11:01.608","level":"info","module":"Server","message":"2022-08-18 16:11:01.608 [info] [Server] Preparing server"},{"timestamp":"2022-08-18 16:11:01.609","level":"info","module":"Server","message":"2022-08-18 16:11:01.609 [info] [Server] Preparing static routes"},{"timestamp":"2022-08-18 16:11:01.610","level":"info","module":"Server","message":"2022-08-18 16:11:01.610 [info] [Server] Preparing middlewares"},{"timestamp":"2022-08-18 16:11:01.611","level":"info","module":"Config","message":"2022-08-18 16:11:01.611 [info] [Config] Loading config"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Language","message":"2022-08-18 16:11:01.612 [info] [Language] Searching for languages"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Language","message":"2022-08-18 16:11:01.612 [info] [Language] Found 3 languages"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Language","message":"2022-08-18 16:11:01.612 [info] [Language] Reading language file"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Websocket","message":"2022-08-18 16:11:01.612 [info] [Websocket] Preparing websocket"},{"timestamp":"2022-08-18 16:11:01.613","level":"info","module":"Server","message":"2022-08-18 16:11:01.613 [info] [Server] Preparing routes"},{"timestamp":"2022-08-18 16:11:01.614","level":"info","module":"Server","message":"2022-08-18 16:11:01.614 [info] [Server] Starting server"},{"timestamp":"2022-08-18 16:13:27.222","level":"error","module":"Security","message":"2022-08-18 16:13:27.222 [error] [Security] Attempt to access restricted asset file mdbootstrap/js/mdb.min.js"},{"timestamp":"2022-08-18 16:13:27.674","level":"error","module":"Security","message":"2022-08-18 16:13:27.674 [error] [Security] Attempt to access restricted asset file mdbootstrap/js/mdb.min.js"},{"timestamp":"2022-08-18 16:13:46.931","level":"info","module":"Shutdown","message":"2022-08-18 16:13:46.931 [info] [Shutdown] Caught interrupt signal and shutting down gracefully"}]

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "opencountdown", "name": "opencountdown",
"version": "1.0.1", "version": "1.0.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "opencountdown", "name": "opencountdown",
"version": "1.0.1", "version": "1.0.2",
"license": "LGPL-3.0", "license": "LGPL-3.0",
"dependencies": { "dependencies": {
"body-parser": "^1.19.2", "body-parser": "^1.19.2",

View File

@ -1 +0,0 @@
../node_modules/bootstrap-duration-picker/dist/

View File

@ -1 +0,0 @@
../../node_modules/bootstrap/dist

View File

@ -1 +0,0 @@
../../node_modules/bootstrap-colorpicker/dist/css

View File

@ -1 +0,0 @@
../../node_modules/bootstrap-colorpicker/dist/js

View File

@ -1 +0,0 @@
../../node_modules/bootstrap-icons/font/bootstrap-icons.css

View File

@ -1 +0,0 @@
../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff

View File

@ -1 +0,0 @@
../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff2

1
static/favicon.svg Symbolic link
View File

@ -0,0 +1 @@
logo/faviconLogo.svg

View File

@ -1 +0,0 @@
../../node_modules/flatpickr/dist/

View File

@ -1 +0,0 @@
../../node_modules/js-cookie/dist/js.cookie.min.js

View File

@ -1 +0,0 @@
../../node_modules/darkreader/darkreader.js

View File

@ -1 +0,0 @@
../../node_modules/jquery/dist/jquery.min.js

View File

@ -1 +0,0 @@
../../node_modules/less/dist/less.min.js

4578
static/logo/faviconLogo.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 151 KiB

4631
static/logo/logoProposal.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 145 KiB

View File

@ -1 +0,0 @@
../../node_modules/mdbootstrap/css/

View File

@ -1 +0,0 @@
../../node_modules/mdbootstrap/js

View File

@ -10,26 +10,27 @@
<meta name="author" content="TheGreydiamond"> <meta name="author" content="TheGreydiamond">
<link rel="stylesheet" href="/css/bootstrap-icons.css"> <link rel="stylesheet" href="/assets/bootstrap-icons/font/bootstrap-icons.css">
<link rel="stylesheet" href="/mdbootstrap/css/style.css"> <link rel="stylesheet" href="/assets/mdbootstrap/css/style.css">
<script src="/bootstrap/dist/js/bootstrap.bundle.min.js"></script> <script src="/assets/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.min.js"></script> <script src="/assets/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="/mdbootstrap/js/mdb.min.js"></script> <script type="text/javascript" src="/mdbootstrap/js/mdb.min.js"></script>
<script type="text/javascript" src="/js/darkreader.js"></script> <script type="text/javascript" src="/js/darkreader.js"></script>
<script type="text/javascript" src="/js/cookie.js"></script> <script type="text/javascript" src="/assets/js-cookie/dist/js.cookie.min.js"></script>
<link href="/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/assets/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/mainStyle.css" rel="stylesheet"> <link href="/css/mainStyle.css" rel="stylesheet">
<link rel="stylesheet" href="/coloris/coloris.min.css" /> <link rel="stylesheet" href="/coloris/coloris.min.css" />
<link rel="stylesheet" href="/bootstrap-duration-picker/bootstrap-duration-picker.css" /> <link rel="stylesheet" href="/assets/bootstrap-duration-picker/dist/bootstrap-duration-picker.css" />
<link rel="stylesheet" href="/flatpickr/dist/flatpickr.min.css" /> <link rel="stylesheet" href="/assets/flatpickr/dist/flatpickr.min.css" />
<script src="/bootstrap-duration-picker/bootstrap-duration-picker-debug.js"></script> <script src="/assets/bootstrap-duration-picker/dist/bootstrap-duration-picker-debug.js"></script>
<script src="/coloris/coloris.min.js"></script> <script src="/coloris/coloris.min.js"></script>
<script type="text/javascript" src="/flatpickr/dist/flatpickr.js"> </script> <script type="text/javascript" src="/assets/flatpickr/dist/flatpickr.js"> </script>
<link rel="stylesheet" href="/css/bootstrap-icons.css">
<link rel="icon" href="/logo/favicon.svg" type="image/svg+xml">
</head> </head>
<body> <body>
@ -115,17 +116,9 @@
</page> </page>
</pages> </pages>
</main> </main>
<script type="text/javascript" src="js/jsonview.js"></script> <script type="text/javascript" src="/js/jsonview.js"></script>
<script type="text/javascript" src="/js/interface.js"> </script> <script type="text/javascript" src="/js/interface.js"> </script>
<script type="text/javascript"> <script type="text/javascript">
Coloris({
el: '.coloris',
alpha: false,
});
$(function () {
$('[data-toggle="tooltip"]').tooltip({ container: "body" })
})
$("#applyLang").on("click", function (event) { $("#applyLang").on("click", function (event) {
const lang = $("#lang").val() const lang = $("#lang").val()
saveOption("/api/ui/v1/lang/set?lang=" + lang, function handleLangSelect(event, xmlHttp) { saveOption("/api/ui/v1/lang/set?lang=" + lang, function handleLangSelect(event, xmlHttp) {

View File

@ -9,8 +9,8 @@
<meta name="description" content="openCountdown"> <meta name="description" content="openCountdown">
<meta name="author" content="TheGreydiamond"> <meta name="author" content="TheGreydiamond">
<script type="text/javascript" src="/js/cookie.js"></script> <script type="text/javascript" src="/assets/js-cookie/dist/js.cookie.min.js"></script>
<link rel="stylesheet" href="/assets/bootstrap-icons/font/bootstrap-icons.css">
<link rel="stylesheet/less" type="text/css" href="/css/errorPage/styles.less" /> <link rel="stylesheet/less" type="text/css" href="/css/errorPage/styles.less" />
@ -19,11 +19,9 @@
javascriptEnabled: true javascriptEnabled: true
}; };
</script> </script>
<script src="/js/less.min.js"></script> <script src="/assets/less/dist/less.min.js"></script>
<link rel="stylesheet" href="/css/errorPage/style.css"> <link rel="stylesheet" href="/css/errorPage/style.css">
<link rel="stylesheet" href="/css/bootstrap-icons.css">
</head> </head>
<body> <body>

View File

@ -10,26 +10,27 @@
<meta name="author" content="TheGreydiamond"> <meta name="author" content="TheGreydiamond">
<link rel="stylesheet" href="/css/bootstrap-icons.css"> <link rel="stylesheet" href="/assets/bootstrap-icons/font/bootstrap-icons.css">
<link rel="stylesheet" href="/mdbootstrap/css/style.css"> <link rel="stylesheet" href="/assets/mdbootstrap/css/style.css">
<script src="/bootstrap/dist/js/bootstrap.bundle.min.js"></script> <script src="/assets/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.min.js"></script> <script src="/assets/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="/mdbootstrap/js/mdb.min.js"></script> <script type="text/javascript" src="/assets/mdbootstrap/js/mdb.min.js"></script>
<script type="text/javascript" src="/js/darkreader.js"></script> <script type="text/javascript" src="/assets/darkreader/darkreader.js"></script>
<script type="text/javascript" src="/js/cookie.js"></script> <script type="text/javascript" src="/assets/js-cookie/dist/js.cookie.min.js"></script>
<link href="/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/assets/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/mainStyle.css" rel="stylesheet"> <link href="/css/mainStyle.css" rel="stylesheet">
<link rel="stylesheet" href="/coloris/coloris.min.css" /> <link rel="stylesheet" href="/coloris/coloris.min.css" />
<link rel="stylesheet" href="/bootstrap-duration-picker/bootstrap-duration-picker.css" /> <link rel="stylesheet" href="/assets/bootstrap-duration-picker/dist/bootstrap-duration-picker.css" />
<link rel="stylesheet" href="/flatpickr/dist/flatpickr.min.css" /> <link rel="stylesheet" href="/assets/flatpickr/dist/flatpickr.min.css" />
<script src="/bootstrap-duration-picker/bootstrap-duration-picker-debug.js"></script> <script src="/assets/bootstrap-duration-picker/dist/bootstrap-duration-picker-debug.js"></script>
<script src="/coloris/coloris.min.js"></script> <script src="/coloris/coloris.min.js"></script>
<script type="text/javascript" src="/flatpickr/dist/flatpickr.js"> </script> <script type="text/javascript" src="/assets/flatpickr/dist/flatpickr.js"> </script>
<link rel="stylesheet" href="/css/bootstrap-icons.css">
<link rel="icon" href="/logo/faviconLogo.svg" type="image/svg+xml">
</head> </head>
<body> <body>
@ -38,10 +39,12 @@
<div class="d-flex flex-column flex-shrink-0 p-3 text-white bg-dark trans" style="width: 250px;" <div class="d-flex flex-column flex-shrink-0 p-3 text-white bg-dark trans" style="width: 250px;"
id="navbarToggleExternalContent"> id="navbarToggleExternalContent">
<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none"> <a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
<svg class="bi me-2" width="40" height="32"> <center>
<use xlink:href="#bootstrap" /> <img class="bi me-2" width="200" height="128" src="/logo/logoProposal.svg">
</svg>
<span class="fs-4">Sidebar</span> </img >
</center>
</a> </a>
<hr> <hr>
<ul class="nav nav-pills flex-column mb-auto"> <ul class="nav nav-pills flex-column mb-auto">
@ -425,7 +428,7 @@
</page> </page>
</pages> </pages>
</main> </main>
<script type="text/javascript" src="js/jsonview.js"></script> <script type="text/javascript" src="/js/jsonview.js"></script>
<script type="text/javascript" src="/js/interface.js"> </script> <script type="text/javascript" src="/js/interface.js"> </script>
<script type="text/javascript"> <script type="text/javascript">