mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-10 18:03:47 +00:00
folder restructure
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import { Server } from 'node-osc';
|
||||
|
||||
export const initiateOSC = (config) => {
|
||||
const oscServer = new Server(config.port, '0.0.0.0', () => {
|
||||
console.log(`OSC Server is listening on port ${config.port}`);
|
||||
});
|
||||
|
||||
oscServer.on('message', function (msg) {
|
||||
// message should look like /ontime/{path}/{args} where
|
||||
// ontime: fixed message for app
|
||||
// path: command to be called
|
||||
// args: extra data, only used on some of the API entries (delay, goto)
|
||||
console.log('OSC received', msg);
|
||||
|
||||
// split message
|
||||
const [, address, path] = msg[0].split('/');
|
||||
const args = msg[1];
|
||||
|
||||
// get first part before (ontime)
|
||||
if (address !== 'ontime') return;
|
||||
|
||||
// get second part (command)
|
||||
switch (path.toLocaleLowerCase()) {
|
||||
case 'start':
|
||||
case 'play':
|
||||
console.log('calling play');
|
||||
global.timer.start();
|
||||
break;
|
||||
case 'pause':
|
||||
console.log('calling pause');
|
||||
global.timer.pause();
|
||||
break;
|
||||
case 'prev':
|
||||
console.log('calling prev');
|
||||
global.timer.previous();
|
||||
break;
|
||||
case 'next':
|
||||
console.log('calling next');
|
||||
global.timer.next();
|
||||
break;
|
||||
case 'unload':
|
||||
console.log('calling unload');
|
||||
global.timer.unload();
|
||||
break;
|
||||
case 'reload':
|
||||
console.log('calling reload');
|
||||
global.timer.reload();
|
||||
break;
|
||||
case 'roll':
|
||||
console.log('calling roll');
|
||||
break;
|
||||
case 'delay':
|
||||
console.log('calling delay with', args);
|
||||
try {
|
||||
let t = parseInt(args);
|
||||
if (!isNaN(t)) global.timer.increment(t * 1000 * 60);
|
||||
} catch (error) {
|
||||
console.log('error parsing: ', error);
|
||||
}
|
||||
break;
|
||||
case 'goto':
|
||||
console.log('calling goto with', args);
|
||||
try {
|
||||
let eventIndex = parseInt(args);
|
||||
if (isNaN(eventIndex) || eventIndex <= 0) return;
|
||||
global.timer.loadEvent(eventIndex - 1, undefined, true);
|
||||
} catch (error) {
|
||||
console.log('error calling goto: ', error);
|
||||
}
|
||||
break;
|
||||
case 'gotoid':
|
||||
console.log('calling gotoid with', args);
|
||||
try {
|
||||
global.timer.loadEventById(args.toLowerCase());
|
||||
} catch (error) {
|
||||
console.log('error calling goto: ', error);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('Error: not recognised');
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
// get database
|
||||
import { db, data } from '../app.js';
|
||||
|
||||
// Create controller for GET request to 'event'
|
||||
// Returns ACK message
|
||||
export const getEvent = async (req, res) => {
|
||||
res.json(data.event);
|
||||
};
|
||||
|
||||
// Create controller for POST request to 'event'
|
||||
// Returns ACK message
|
||||
export const postEvent = async (req, res) => {
|
||||
if (!req.body) {
|
||||
res.status(400).send('No object found in request');
|
||||
return;
|
||||
}
|
||||
// TODO: validate data
|
||||
try {
|
||||
data.event = { ...data.event, ...req.body };
|
||||
await db.write();
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
res.status(400).send(error);
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,329 @@
|
||||
// get database
|
||||
import { db, data } from '../app.js';
|
||||
|
||||
// utils
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('1234567890abcdef', 4);
|
||||
import {
|
||||
event as eventDef,
|
||||
delay as delayDef,
|
||||
block as blockDef,
|
||||
} from '../data/eventsDefinition.js';
|
||||
|
||||
function _getEventsCount() {
|
||||
return Array.from(data.events).length;
|
||||
}
|
||||
|
||||
function _pushNew(entry) {
|
||||
return data.events.push(entry).write();
|
||||
}
|
||||
|
||||
async function _insertAt(entry, index) {
|
||||
// get events
|
||||
let events = data.events;
|
||||
let count = events.length;
|
||||
let order = entry.order;
|
||||
|
||||
// Remove order field from object
|
||||
delete entry.order;
|
||||
|
||||
// Insert at beggining
|
||||
if (order === 0) {
|
||||
events.unshift(entry);
|
||||
}
|
||||
|
||||
// insert at end
|
||||
else if (order >= count) {
|
||||
events.push(entry);
|
||||
}
|
||||
|
||||
// insert in the middle
|
||||
else {
|
||||
events.splice(index, 0, entry);
|
||||
}
|
||||
|
||||
// save events
|
||||
data.events = events;
|
||||
await db.write();
|
||||
}
|
||||
|
||||
async function _removeById(eventId) {
|
||||
data.events = Array.from(data.events).filter((e) => e.id != eventId);
|
||||
await db.write();
|
||||
}
|
||||
|
||||
function getEventEvents() {
|
||||
// return data.events.filter((e) => e.type === 'event');
|
||||
return Array.from(data.events).filter((e) => e.type === 'event');
|
||||
}
|
||||
|
||||
// Updates timer object
|
||||
function _updateTimers() {
|
||||
const results = getEventEvents();
|
||||
global.timer.updateEventList(results);
|
||||
}
|
||||
|
||||
// Updates timer object single event
|
||||
function _updateTimersSingle(id, entry) {
|
||||
global.timer.updateSingleEvent(id, entry);
|
||||
}
|
||||
|
||||
// Delete a single entry in timer object
|
||||
function _deleteTimerId(entryId) {
|
||||
global.timer.deleteId(entryId);
|
||||
}
|
||||
|
||||
// Create controller for GET request to '/events'
|
||||
// Returns -
|
||||
export const eventsGetAll = async (req, res) => {
|
||||
res.json(data.events);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/events/:eventId'
|
||||
// Returns -
|
||||
export const eventsGetById = async (req, res) => {
|
||||
const e = data.events.find({ id: req.params.eventId }).value();
|
||||
console.log('event by id', e);
|
||||
res.json(e);
|
||||
};
|
||||
|
||||
// Create controller for POST request to '/events/'
|
||||
// Returns -
|
||||
export const eventsPost = async (req, res) => {
|
||||
// TODO: Validate event
|
||||
if (!req.body) {
|
||||
res.status(400).send(`No object found in request`);
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure structure
|
||||
let newEvent = {};
|
||||
req.body.id = nanoid();
|
||||
|
||||
switch (req.body.type) {
|
||||
case 'event':
|
||||
newEvent = { ...eventDef, ...req.body };
|
||||
break;
|
||||
case 'delay':
|
||||
newEvent = { ...delayDef, ...req.body };
|
||||
break;
|
||||
case 'block':
|
||||
newEvent = { ...blockDef, ...req.body };
|
||||
break;
|
||||
|
||||
default:
|
||||
res
|
||||
.status(400)
|
||||
.send(`Object type missing or unrecognised: ${req.body.type}`);
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
// get place where event should be
|
||||
const index = newEvent.order || 0;
|
||||
|
||||
// add new event in place
|
||||
_insertAt(newEvent, index);
|
||||
|
||||
// update timers
|
||||
_updateTimers();
|
||||
|
||||
// reply OK
|
||||
res.sendStatus(201);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(400).send(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Create controller for PUT request to '/events/'
|
||||
// Returns -
|
||||
export const eventsPut = async (req, res) => {
|
||||
// no valid params
|
||||
if (!req.body) {
|
||||
res.status(400).send(`No object found`);
|
||||
return;
|
||||
}
|
||||
|
||||
let eventId = req.body.id;
|
||||
if (!eventId) {
|
||||
res.status(400).send(`Object malformed: id missing`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const eventIndex = data.events.findIndex((e) => e.id === req.body.id);
|
||||
if (eventIndex === -1) {
|
||||
res.status(400).send(`No Id found found`);
|
||||
return;
|
||||
}
|
||||
|
||||
const e = data.events[eventIndex];
|
||||
data.events[eventIndex] = { ...e, ...req.body };
|
||||
data.events[eventIndex].revision++;
|
||||
db.write();
|
||||
|
||||
// update timer
|
||||
_updateTimersSingle(req.body.id, req.body);
|
||||
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(400).send(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Create controller for PATCH request to '/events/'
|
||||
// Returns -
|
||||
export const eventsPatch = async (req, res) => {
|
||||
// Code is the same as put, call that
|
||||
eventsPut(req, res);
|
||||
};
|
||||
|
||||
export const eventsReorder = async (req, res) => {
|
||||
// TODO: Validate event
|
||||
if (!req.body) {
|
||||
res.status(400).send(`No object found in request`);
|
||||
return;
|
||||
}
|
||||
|
||||
const { index, from, to } = req.body;
|
||||
|
||||
// get events
|
||||
let events = data.events;
|
||||
let idx = events.findIndex((e) => e.id === index, from);
|
||||
|
||||
// Check if item is at given index
|
||||
if (idx !== from) {
|
||||
res.status(400).send(`Id not found at index`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// remove item at from
|
||||
const [reorderedItem] = events.splice(from, 1);
|
||||
|
||||
// reinsert item at to
|
||||
events.splice(to, 0, reorderedItem);
|
||||
|
||||
// save events
|
||||
data.events = events;
|
||||
db.write();
|
||||
|
||||
// TODO: would it be more efficient to reorder at timer?
|
||||
// update timer
|
||||
_updateTimers();
|
||||
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(400).send(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Create controller for PATCH request to '/events/applydelay/:eventId'
|
||||
// Returns -
|
||||
export const eventsApplyDelay = async (req, res) => {
|
||||
// no valid params
|
||||
if (!req.params.eventId) {
|
||||
res.status(400).send(`No id found in request`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// get events
|
||||
let events = data.events;
|
||||
|
||||
// AUX
|
||||
let delayIndex = null;
|
||||
let blockIndex = null;
|
||||
let delayValue = 0;
|
||||
|
||||
for (const [index, e] of events.entries()) {
|
||||
if (delayIndex == null) {
|
||||
// look for delay
|
||||
if (e.id === req.params.eventId && e.type === 'delay') {
|
||||
delayValue = e.duration;
|
||||
delayIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
// apply delay value to all items until block or end
|
||||
else {
|
||||
if (e.type === 'event') {
|
||||
// update times
|
||||
e.timeStart += delayValue;
|
||||
e.timeEnd += delayValue;
|
||||
|
||||
// increment revision
|
||||
e.revision += 1;
|
||||
} else if (e.type === 'block') {
|
||||
// save id and stop
|
||||
blockIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete delay
|
||||
events.splice(delayIndex, 1);
|
||||
|
||||
// delete block
|
||||
// index would have moved down since we deleted delay
|
||||
if (blockIndex) events.splice(blockIndex - 1, 1);
|
||||
|
||||
// update events
|
||||
data.events = events;
|
||||
db.write();
|
||||
|
||||
// update timer
|
||||
_updateTimers();
|
||||
|
||||
res.sendStatus(201);
|
||||
} catch (error) {
|
||||
console.log('debug:', error);
|
||||
|
||||
res.status(400).send(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Create controller for DELETE request to '/events/:eventId'
|
||||
// Returns -
|
||||
export const eventsDelete = async (req, res) => {
|
||||
// no valid params
|
||||
if (!req.params.eventId) {
|
||||
res.status(400).send(`No id found in request`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// remove new event
|
||||
_removeById(req.params.eventId);
|
||||
|
||||
// update timer
|
||||
_deleteTimerId(req.params.eventId);
|
||||
|
||||
res.sendStatus(201);
|
||||
} catch (error) {
|
||||
console.log('debug:', error);
|
||||
|
||||
res.status(400).send(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Create controller for DELETE request to '/events/:eventId'
|
||||
// Returns -
|
||||
export const eventsDeleteAll = async (req, res) => {
|
||||
try {
|
||||
// set with nothing
|
||||
data.events = [];
|
||||
db.write();
|
||||
|
||||
// update timer object
|
||||
_updateTimersSingle();
|
||||
|
||||
res.sendStatus(201);
|
||||
} catch (error) {
|
||||
res.status(400).send(error);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
// get database
|
||||
import { db, data } from '../app.js';
|
||||
import fs from 'fs';
|
||||
import {
|
||||
event as eventDef,
|
||||
delay as delayDef,
|
||||
block as blockDef,
|
||||
} from '../data/eventsDefinition.js';
|
||||
import { dbModel } from '../data/dataModel.js';
|
||||
|
||||
function getEventTitle() {
|
||||
return data.event.title;
|
||||
}
|
||||
|
||||
async function deleteFile(file) {
|
||||
// delete a file
|
||||
fs.unlink(file, (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// parses version 1 of the data system
|
||||
async function parsev1(jsonData) {
|
||||
if ('events' in jsonData) {
|
||||
let events = [];
|
||||
let ids = [];
|
||||
for (const e of jsonData.events) {
|
||||
if (e.type === 'event') {
|
||||
// doublecheck unique ids
|
||||
if (e.id == null || ids.indexOf(e.id) !== -1) continue;
|
||||
ids.push(e.id);
|
||||
|
||||
// make sure all properties exits
|
||||
// dont load any extra properties than the ones known
|
||||
events.push({
|
||||
...eventDef,
|
||||
title: e.title,
|
||||
subtitle: e.subtitle,
|
||||
presenter: e.presenter,
|
||||
note: e.note,
|
||||
timeStart: e.timeStart,
|
||||
timeEnd: e.timeEnd,
|
||||
isPublic: e.isPublic,
|
||||
id: e.id,
|
||||
});
|
||||
} else if (e.type === 'delay') {
|
||||
events.push({ ...delayDef, duration: e.duration });
|
||||
} else if (e.type === 'block') {
|
||||
events.push({ ...blockDef });
|
||||
}
|
||||
}
|
||||
// write to db
|
||||
db.data.events = events;
|
||||
db.write();
|
||||
}
|
||||
|
||||
if ('event' in jsonData) {
|
||||
const e = jsonData.event;
|
||||
// filter known properties
|
||||
const event = {
|
||||
...dbModel.event,
|
||||
title: e.title,
|
||||
url: e.url,
|
||||
publicInfo: e.publicInfo,
|
||||
backstageInfo: e.backstageInfo,
|
||||
};
|
||||
|
||||
// write to db
|
||||
db.data.event = event;
|
||||
db.write();
|
||||
}
|
||||
|
||||
// Not handling settings yet
|
||||
// let settings = {};
|
||||
// if ('settings' in jsonData) {
|
||||
// }
|
||||
}
|
||||
|
||||
// Create controller for GET request to '/ontime/db'
|
||||
// Returns -
|
||||
export const dbDownload = async (req, res) => {
|
||||
const fileTitle = getEventTitle() || 'ontime events';
|
||||
res.download('db.json', `${fileTitle}.json`, (err) => {
|
||||
if (err) {
|
||||
res.status(500).send({
|
||||
message: 'Could not download the file. ' + err,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Create controller for POST request to '/ontime/db'
|
||||
// Returns -
|
||||
export const dbUpload = async (req, res) => {
|
||||
if (!req.file) {
|
||||
res.status(400).send({ message: 'File not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
const file = req.file.path;
|
||||
if (!fs.existsSync(file)) {
|
||||
res.status(500).send({ message: 'Upload failed' });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// get file
|
||||
let rawdata = fs.readFileSync(file);
|
||||
let uploadedJson = JSON.parse(rawdata);
|
||||
|
||||
// delete file
|
||||
deleteFile(file);
|
||||
|
||||
// check version
|
||||
if (uploadedJson.settings.version === 1) parsev1(uploadedJson);
|
||||
else {
|
||||
res.status(400).send({ message: 'Error parsing file, version unknown' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.log('Error parsing file', error);
|
||||
res.status(400).send({ message: error });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
// Create controller for GET request to '/playback'
|
||||
// Returns ACK message
|
||||
export const pbGet = async (req, res) => {
|
||||
res.send(global.timer.playState);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/start'
|
||||
// Starts timer object
|
||||
export const pbStart = async (req, res) => {
|
||||
global.timer.start();
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/pause'
|
||||
// Pauses timer object
|
||||
export const pbPause = async (req, res) => {
|
||||
global.timer.pause();
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/stop'
|
||||
// Stops timer object
|
||||
export const pbStop = async (req, res) => {
|
||||
global.timer.stop();
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/roll'
|
||||
// Sets timer object to roll mode
|
||||
export const pbRoll = async (req, res) => {
|
||||
global.timer.roll();
|
||||
res.sendStatus(501);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/previous'
|
||||
// Sets timer object to roll mode
|
||||
export const pbPrevious = async (req, res) => {
|
||||
global.timer.previous();
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/next'
|
||||
// Sets timer object to roll mode
|
||||
export const pbNext = async (req, res) => {
|
||||
global.timer.next();
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/unload'
|
||||
// Unloads any events
|
||||
export const pbUnload = async (req, res) => {
|
||||
global.timer.unload();
|
||||
console.log('debug: unload called');
|
||||
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
// Create controller for GET request to '/playback/reload'
|
||||
// Reloads current event
|
||||
export const pbReload = async (req, res) => {
|
||||
global.timer.reload();
|
||||
console.log('debug: reload called');
|
||||
res.sendStatus(200);
|
||||
};
|
||||
Reference in New Issue
Block a user