Add first implementation of a config servlet
This commit is contained in:
parent
0ed6d93d30
commit
e1fb29b7c8
|
@ -0,0 +1,64 @@
|
||||||
|
package ctbrec.recorder.server;
|
||||||
|
|
||||||
|
import static javax.servlet.http.HttpServletResponse.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ctbrec.Config;
|
||||||
|
import ctbrec.Settings;
|
||||||
|
|
||||||
|
public class ConfigServlet extends AbstractCtbrecServlet {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ConfigServlet.class);
|
||||||
|
private Config config;
|
||||||
|
private Settings settings;
|
||||||
|
|
||||||
|
public enum DataType {
|
||||||
|
STRING,
|
||||||
|
BOOLEAN,
|
||||||
|
INTEGER,
|
||||||
|
DOUBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigServlet(Config config) {
|
||||||
|
this.config = config;
|
||||||
|
this.settings = config.getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
resp.setStatus(SC_OK);
|
||||||
|
resp.setContentType("application/json");
|
||||||
|
|
||||||
|
JSONArray json = new JSONArray();
|
||||||
|
addParameter("httpPort", "HTTP port", DataType.INTEGER, settings.httpPort, json);
|
||||||
|
|
||||||
|
resp.getWriter().print(json.toString(2));
|
||||||
|
LOG.debug("GET {} {}", req.getRequestURI(), req.getRequestURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addParameter(String key, String name, DataType type, Object value, JSONArray json) {
|
||||||
|
JSONObject param = new JSONObject();
|
||||||
|
param.put("key", key);
|
||||||
|
param.put("name", name);
|
||||||
|
param.put("type", type);
|
||||||
|
param.put("value", value);
|
||||||
|
json.put(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
resp.setStatus(SC_OK);
|
||||||
|
resp.setContentType("application/json");
|
||||||
|
LOG.debug("POST");
|
||||||
|
}
|
||||||
|
}
|
|
@ -207,6 +207,10 @@ public class HttpServer {
|
||||||
ServletHolder holder = new ServletHolder(recorderServlet);
|
ServletHolder holder = new ServletHolder(recorderServlet);
|
||||||
defaultContext.addServlet(holder, "/rec");
|
defaultContext.addServlet(holder, "/rec");
|
||||||
|
|
||||||
|
ConfigServlet configServlet = new ConfigServlet(config);
|
||||||
|
holder = new ServletHolder(configServlet);
|
||||||
|
defaultContext.addServlet(holder, "/config");
|
||||||
|
|
||||||
HlsServlet hlsServlet = new HlsServlet(this.config);
|
HlsServlet hlsServlet = new HlsServlet(this.config);
|
||||||
holder = new ServletHolder(hlsServlet);
|
holder = new ServletHolder(hlsServlet);
|
||||||
defaultContext.addServlet(holder, "/hls/*");
|
defaultContext.addServlet(holder, "/hls/*");
|
||||||
|
|
|
@ -197,7 +197,6 @@
|
||||||
<script src="vendor/knockout/knockout-3.5.0.js"></script>
|
<script src="vendor/knockout/knockout-3.5.0.js"></script>
|
||||||
<script src="vendor/knockout-orderable/knockout.bindings.orderable.js"></script>
|
<script src="vendor/knockout-orderable/knockout.bindings.orderable.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom scripts for this template -->
|
<!-- Custom scripts for this template -->
|
||||||
<script src="freelancer.min.js"></script>
|
<script src="freelancer.min.js"></script>
|
||||||
|
|
||||||
|
@ -209,12 +208,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- HLS MediaSource support -->
|
<!-- Video Player -->
|
||||||
<script src="vendor/hls.js/hls.js"></script>
|
<script src="vendor/hls.js/hls.js"></script>
|
||||||
|
<script src="modal.js"></script>
|
||||||
|
|
||||||
<!-- CryptoJS for HMAc authentication -->
|
<!-- CryptoJS for HMAc authentication -->
|
||||||
<script src="vendor/CryptoJS/hmac-sha256.js"></script>
|
<script src="vendor/CryptoJS/hmac-sha256.js"></script>
|
||||||
|
|
||||||
|
<!-- ctbrec stuff -->
|
||||||
|
<script src="recordings.js"></script>
|
||||||
|
<script src="models.js"></script>
|
||||||
<script>
|
<script>
|
||||||
let onlineModels = [];
|
let onlineModels = [];
|
||||||
let observableModelsArray = ko.observableArray();
|
let observableModelsArray = ko.observableArray();
|
||||||
|
@ -389,82 +392,6 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function play(recording) {
|
|
||||||
let src = recording.singleFile ? '/hls' + recording.path : recording.playlist;
|
|
||||||
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
|
|
||||||
src = '..' + src;
|
|
||||||
if(console) console.log("Path", src, "HMAC", hmacOfPath);
|
|
||||||
if (hmac.length > 0) {
|
|
||||||
src += "?hmac=" + hmacOfPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(console) console.log('Playing video from', src);
|
|
||||||
|
|
||||||
if(recording.singleFile) {
|
|
||||||
var video = document.getElementById('player');
|
|
||||||
video.src = src;
|
|
||||||
video.load();
|
|
||||||
console.log(video);
|
|
||||||
video.oncanplay = function() {
|
|
||||||
video.height = window.innerHeight * 0.85;
|
|
||||||
$('#player-window').css('display', 'block');
|
|
||||||
video.play();
|
|
||||||
};
|
|
||||||
video.onerror = function() {
|
|
||||||
$.notify(video.error.message, 'error');
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if (Hls.isSupported()) {
|
|
||||||
var video = document.getElementById('player');
|
|
||||||
var hls = new Hls();
|
|
||||||
hls.attachMedia(video);
|
|
||||||
hls.on(Hls.Events.MEDIA_ATTACHED, function () {
|
|
||||||
if(console) console.log(src);
|
|
||||||
hls.loadSource(src);
|
|
||||||
hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
|
|
||||||
if(console) {
|
|
||||||
console.log(data);
|
|
||||||
console.log("manifest loaded, found " + data.levels.length + " quality level");
|
|
||||||
}
|
|
||||||
$('#player-window').css('display', 'block');
|
|
||||||
video.play();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$.notify('Loading HLS video streaming support failed', 'error');
|
|
||||||
if(console) console.log('HLS is not supported');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function download(recording) {
|
|
||||||
let src = recording.singleFile ? '/hls' + recording.path : recording.playlist;
|
|
||||||
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
|
|
||||||
src = '..' + src;
|
|
||||||
if(console) console.log("Path", src, "HMAC", hmacOfPath);
|
|
||||||
if (hmac.length > 0) {
|
|
||||||
src += "?hmac=" + hmacOfPath;
|
|
||||||
}
|
|
||||||
location.href = src;
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateSize(sizeInByte) {
|
|
||||||
let size = sizeInByte;
|
|
||||||
let unit = "Bytes";
|
|
||||||
if(size > 1024.0 * 1024 * 1024) {
|
|
||||||
size = size / 1024.0 / 1024 / 1024;
|
|
||||||
unit = "GiB";
|
|
||||||
} else if(size > 1024.0 * 1024) {
|
|
||||||
size = size / 1024.0 / 1024;
|
|
||||||
unit = "MiB";
|
|
||||||
} else if(size > 1024.0) {
|
|
||||||
size = size / 1024.0;
|
|
||||||
unit = "KiB";
|
|
||||||
}
|
|
||||||
return size.toFixed(2) + ' ' + unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
if (localStorage !== undefined && localStorage.hmac !== undefined) {
|
if (localStorage !== undefined && localStorage.hmac !== undefined) {
|
||||||
if(console) console.log('using hmac from local storage');
|
if(console) console.log('using hmac from local storage');
|
||||||
|
@ -508,273 +435,11 @@
|
||||||
space
|
space
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateOnlineModels() {
|
|
||||||
try {
|
|
||||||
let action = '{"action": "listOnline"}';
|
|
||||||
$.ajax({
|
|
||||||
type : 'POST',
|
|
||||||
url : '../rec',
|
|
||||||
dataType : 'json',
|
|
||||||
async : true,
|
|
||||||
timeout : 60000,
|
|
||||||
headers : {'CTBREC-HMAC': CryptoJS.HmacSHA256(action, hmac)},
|
|
||||||
data : action
|
|
||||||
})
|
|
||||||
.done(function(data, textStatus, jqXHR) {
|
|
||||||
if (data.status === 'success') {
|
|
||||||
onlineModels = data.models;
|
|
||||||
} else {
|
|
||||||
if(console) console.log('request failed', data);
|
|
||||||
}
|
|
||||||
updateModels();
|
|
||||||
})
|
|
||||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
|
||||||
if(console) console.log(jqXHR, textStatus, errorThrown);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if(console) console.log('Unexpected error', e);
|
|
||||||
}
|
|
||||||
setTimeout(updateOnlineModels, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isModelInArray(array, model) {
|
|
||||||
for (let idx in array) {
|
|
||||||
let m = array[idx];
|
|
||||||
if(m.url === model.url) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronizes models from the server with the displayed
|
|
||||||
* knockout model table
|
|
||||||
*/
|
|
||||||
function syncModels(models) {
|
|
||||||
// remove models from the observable array, which are not in the
|
|
||||||
// updated list
|
|
||||||
for (let idx in observableModelsArray()) {
|
|
||||||
let model = observableModelsArray()[idx];
|
|
||||||
if(!isModelInArray(models, model)) {
|
|
||||||
observableModelsArray.remove(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add models to the observable array, which are new in the
|
|
||||||
// updated list
|
|
||||||
for (let idx in models) {
|
|
||||||
let model = models[idx];
|
|
||||||
if (!isModelInArray(observableModelsArray(), model)) {
|
|
||||||
model.ko_name = ko.observable(model.name);
|
|
||||||
model.ko_url = ko.observable(model.url);
|
|
||||||
model.ko_online = ko.observable(false);
|
|
||||||
for ( let i in onlineModels) {
|
|
||||||
let onlineModel = onlineModels[i];
|
|
||||||
if (onlineModel.url === model.url) {
|
|
||||||
model.ko_online(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
model.ko_recording = ko.observable(model.online && !model.suspended);
|
|
||||||
model.ko_suspended = ko.observable(model.suspended);
|
|
||||||
model.swallowEvents = false;
|
|
||||||
model.ko_suspended.subscribe(function(checked) {
|
|
||||||
if (model.swallowEvents) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!checked) {
|
|
||||||
ctbrec.resume(model);
|
|
||||||
} else {
|
|
||||||
ctbrec.suspend(model);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
observableModelsArray.push(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update existing models
|
|
||||||
for (let i in models) {
|
|
||||||
let model = models[i];
|
|
||||||
for (let j in observableModelsArray()) {
|
|
||||||
let m = observableModelsArray()[j];
|
|
||||||
if(model.url === m.ko_url()) {
|
|
||||||
m.ko_name(model.name);
|
|
||||||
m.ko_url(model.url);
|
|
||||||
let onlineState = false;
|
|
||||||
for ( let i in onlineModels) {
|
|
||||||
let onlineModel = onlineModels[i];
|
|
||||||
if (onlineModel.url === model.url) {
|
|
||||||
onlineState = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.ko_online(onlineState);
|
|
||||||
m.swallowEvents = true;
|
|
||||||
m.ko_suspended(model.suspended);
|
|
||||||
m.swallowEvents = false;
|
|
||||||
m.ko_recording(m.ko_online() && !m.ko_suspended());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateModels() {
|
|
||||||
try {
|
|
||||||
let action = '{"action": "list"}';
|
|
||||||
$.ajax({
|
|
||||||
type : 'POST',
|
|
||||||
url : '../rec',
|
|
||||||
dataType : 'json',
|
|
||||||
async : true,
|
|
||||||
timeout : 60000,
|
|
||||||
headers : {'CTBREC-HMAC': CryptoJS.HmacSHA256(action, hmac)},
|
|
||||||
data : action
|
|
||||||
})
|
|
||||||
.done(function(data) {
|
|
||||||
if (data.status === 'success') {
|
|
||||||
syncModels(data.models);
|
|
||||||
} else {
|
|
||||||
if(console) console.log('request failed', data);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
|
||||||
if(console) console.log(textStatus, errorThrown);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if(console) console.log('Unexpected error', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRecordingInArray(array, recording) {
|
|
||||||
for (let idx in array) {
|
|
||||||
let r = array[idx];
|
|
||||||
if(r.path === recording.path) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronizes recordings from the server with the displayed
|
|
||||||
* knockout recordings table
|
|
||||||
*/
|
|
||||||
function syncRecordings(recordings) {
|
|
||||||
// remove recordings from the observable array, which are not in the
|
|
||||||
// updated list
|
|
||||||
for (let idx in observableRecordingsArray()) {
|
|
||||||
let recording = observableRecordingsArray()[idx];
|
|
||||||
if(!isRecordingInArray(recordings, recording)) {
|
|
||||||
observableRecordingsArray.remove(recording);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add recordings to the observable array, which are new in the
|
|
||||||
// updated list
|
|
||||||
for (let idx in recordings) {
|
|
||||||
let recording = recordings[idx];
|
|
||||||
if (!isRecordingInArray(observableRecordingsArray(), recording)) {
|
|
||||||
recording.ko_date = ko.computed(function() {
|
|
||||||
return new Date(recording.startDate).toLocaleString('default', {
|
|
||||||
'day': '2-digit',
|
|
||||||
'month': '2-digit',
|
|
||||||
'year': 'numeric',
|
|
||||||
'hour': '2-digit',
|
|
||||||
'minute': '2-digit',
|
|
||||||
'second': '2-digit'
|
|
||||||
})
|
|
||||||
});
|
|
||||||
recording.ko_progressString = ko.observable(recording.progress === -1 ? '' : recording.progress);
|
|
||||||
recording.ko_size = ko.observable(calculateSize(recording.sizeInByte));
|
|
||||||
recording.ko_status = ko.observable(recording.status);
|
|
||||||
if (recording.path.endsWith('.mp4')) {
|
|
||||||
recording.playlist = '/hls' + recording.path;
|
|
||||||
} else {
|
|
||||||
recording.playlist = '/hls' + recording.path + '/playlist.m3u8';
|
|
||||||
}
|
|
||||||
observableRecordingsArray.push(recording);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update existing recordings
|
|
||||||
for (let i in recordings) {
|
|
||||||
let recording = recordings[i];
|
|
||||||
for (let j in observableRecordingsArray()) {
|
|
||||||
let r = observableRecordingsArray()[j];
|
|
||||||
if(recording.path === r.path) {
|
|
||||||
r.progress = recording.progress;
|
|
||||||
r.sizeInByte = recording.sizeInByte;
|
|
||||||
r.status = recording.status;
|
|
||||||
r.startDate = recording.startDate;
|
|
||||||
r.ko_progressString(recording.progress === -1 ? '' : (recording.progress + '%'));
|
|
||||||
r.ko_size(calculateSize(recording.sizeInByte));
|
|
||||||
r.ko_status(recording.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateRecordings() {
|
|
||||||
try {
|
|
||||||
let action = '{"action": "recordings"}';
|
|
||||||
$.ajax({
|
|
||||||
type : 'POST',
|
|
||||||
url : '../rec',
|
|
||||||
dataType : 'json',
|
|
||||||
async : true,
|
|
||||||
timeout : 60000,
|
|
||||||
headers : {'CTBREC-HMAC': CryptoJS.HmacSHA256(action, hmac)},
|
|
||||||
data : action
|
|
||||||
})
|
|
||||||
.done(function(data) {
|
|
||||||
if (data.status === 'success') {
|
|
||||||
syncRecordings(data.recordings);
|
|
||||||
updateDiskSpace();
|
|
||||||
} else {
|
|
||||||
if(console) console.log('request failed', data);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
|
||||||
if(console) console.log(textStatus, errorThrown);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if(console) console.log('Unexpected error', e);
|
|
||||||
}
|
|
||||||
setTimeout(updateRecordings, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateDiskSpace() {
|
|
||||||
let action = '{"action": "space"}';
|
|
||||||
$.ajax({
|
|
||||||
type : 'POST',
|
|
||||||
url : '../rec',
|
|
||||||
dataType : 'json',
|
|
||||||
async : true,
|
|
||||||
timeout : 60000,
|
|
||||||
headers : {'CTBREC-HMAC': CryptoJS.HmacSHA256(action, hmac)},
|
|
||||||
data : action
|
|
||||||
})
|
|
||||||
.done(function(data) {
|
|
||||||
if (data.status === 'success') {
|
|
||||||
space.total(data.spaceTotal);
|
|
||||||
space.free(data.spaceFree);
|
|
||||||
space.percent( (data.spaceFree/data.spaceTotal*100).toFixed(2) );
|
|
||||||
space.text(calculateSize(data.spaceFree) + ' / ' + calculateSize(data.spaceTotal));
|
|
||||||
} else {
|
|
||||||
if(console) console.log('request failed', data);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
|
||||||
if(console) console.log(textStatus, errorThrown);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateOnlineModels();
|
updateOnlineModels();
|
||||||
updateRecordings();
|
updateRecordings();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script src="modal.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
function updateOnlineModels() {
|
||||||
|
try {
|
||||||
|
let action = '{"action": "listOnline"}';
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '../rec',
|
||||||
|
dataType : 'json',
|
||||||
|
async : true,
|
||||||
|
timeout : 60000,
|
||||||
|
headers : {
|
||||||
|
'CTBREC-HMAC' : CryptoJS.HmacSHA256(action, hmac)
|
||||||
|
},
|
||||||
|
data : action
|
||||||
|
}).done(function(data, textStatus, jqXHR) {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
onlineModels = data.models;
|
||||||
|
} else {
|
||||||
|
if (console)
|
||||||
|
console.log('request failed', data);
|
||||||
|
}
|
||||||
|
updateModels();
|
||||||
|
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||||
|
if (console)
|
||||||
|
console.log(jqXHR, textStatus, errorThrown);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console)
|
||||||
|
console.log('Unexpected error', e);
|
||||||
|
}
|
||||||
|
setTimeout(updateOnlineModels, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isModelInArray(array, model) {
|
||||||
|
for ( let idx in array) {
|
||||||
|
let m = array[idx];
|
||||||
|
if (m.url === model.url) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronizes models from the server with the displayed knockout model table
|
||||||
|
*/
|
||||||
|
function syncModels(models) {
|
||||||
|
// remove models from the observable array, which are not in the
|
||||||
|
// updated list
|
||||||
|
for ( let idx in observableModelsArray()) {
|
||||||
|
let model = observableModelsArray()[idx];
|
||||||
|
if (!isModelInArray(models, model)) {
|
||||||
|
observableModelsArray.remove(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add models to the observable array, which are new in the
|
||||||
|
// updated list
|
||||||
|
for ( let idx in models) {
|
||||||
|
let model = models[idx];
|
||||||
|
if (!isModelInArray(observableModelsArray(), model)) {
|
||||||
|
model.ko_name = ko.observable(model.name);
|
||||||
|
model.ko_url = ko.observable(model.url);
|
||||||
|
model.ko_online = ko.observable(false);
|
||||||
|
for ( let i in onlineModels) {
|
||||||
|
let onlineModel = onlineModels[i];
|
||||||
|
if (onlineModel.url === model.url) {
|
||||||
|
model.ko_online(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model.ko_recording = ko.observable(model.online && !model.suspended);
|
||||||
|
model.ko_suspended = ko.observable(model.suspended);
|
||||||
|
model.swallowEvents = false;
|
||||||
|
model.ko_suspended.subscribe(function(checked) {
|
||||||
|
if (model.swallowEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!checked) {
|
||||||
|
ctbrec.resume(model);
|
||||||
|
} else {
|
||||||
|
ctbrec.suspend(model);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observableModelsArray.push(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update existing models
|
||||||
|
for ( let i in models) {
|
||||||
|
let model = models[i];
|
||||||
|
for ( let j in observableModelsArray()) {
|
||||||
|
let m = observableModelsArray()[j];
|
||||||
|
if (model.url === m.ko_url()) {
|
||||||
|
m.ko_name(model.name);
|
||||||
|
m.ko_url(model.url);
|
||||||
|
let onlineState = false;
|
||||||
|
for ( let i in onlineModels) {
|
||||||
|
let onlineModel = onlineModels[i];
|
||||||
|
if (onlineModel.url === model.url) {
|
||||||
|
onlineState = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.ko_online(onlineState);
|
||||||
|
m.swallowEvents = true;
|
||||||
|
m.ko_suspended(model.suspended);
|
||||||
|
m.swallowEvents = false;
|
||||||
|
m.ko_recording(m.ko_online() && !m.ko_suspended());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateModels() {
|
||||||
|
try {
|
||||||
|
let action = '{"action": "list"}';
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '../rec',
|
||||||
|
dataType : 'json',
|
||||||
|
async : true,
|
||||||
|
timeout : 60000,
|
||||||
|
headers : {
|
||||||
|
'CTBREC-HMAC' : CryptoJS.HmacSHA256(action, hmac)
|
||||||
|
},
|
||||||
|
data : action
|
||||||
|
}).done(function(data) {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
syncModels(data.models);
|
||||||
|
} else {
|
||||||
|
if (console)
|
||||||
|
console.log('request failed', data);
|
||||||
|
}
|
||||||
|
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||||
|
if (console)
|
||||||
|
console.log(textStatus, errorThrown);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console)
|
||||||
|
console.log('Unexpected error', e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
function play(recording) {
|
||||||
|
let src = recording.singleFile ? '/hls' + recording.path : recording.playlist;
|
||||||
|
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
|
||||||
|
src = '..' + src;
|
||||||
|
if(console) console.log("Path", src, "HMAC", hmacOfPath);
|
||||||
|
if (hmac.length > 0) {
|
||||||
|
src += "?hmac=" + hmacOfPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(console) console.log('Playing video from', src);
|
||||||
|
|
||||||
|
if(recording.singleFile) {
|
||||||
|
var video = document.getElementById('player');
|
||||||
|
video.src = src;
|
||||||
|
video.load();
|
||||||
|
console.log(video);
|
||||||
|
video.oncanplay = function() {
|
||||||
|
video.height = window.innerHeight * 0.85;
|
||||||
|
$('#player-window').css('display', 'block');
|
||||||
|
video.play();
|
||||||
|
};
|
||||||
|
video.onerror = function() {
|
||||||
|
$.notify(video.error.message, 'error');
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
if (Hls.isSupported()) {
|
||||||
|
var video = document.getElementById('player');
|
||||||
|
var hls = new Hls();
|
||||||
|
hls.attachMedia(video);
|
||||||
|
hls.on(Hls.Events.MEDIA_ATTACHED, function () {
|
||||||
|
if(console) console.log(src);
|
||||||
|
hls.loadSource(src);
|
||||||
|
hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
|
||||||
|
if(console) {
|
||||||
|
console.log(data);
|
||||||
|
console.log("manifest loaded, found " + data.levels.length + " quality level");
|
||||||
|
}
|
||||||
|
$('#player-window').css('display', 'block');
|
||||||
|
video.play();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$.notify('Loading HLS video streaming support failed', 'error');
|
||||||
|
if(console) console.log('HLS is not supported');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(recording) {
|
||||||
|
let src = recording.singleFile ? '/hls' + recording.path : recording.playlist;
|
||||||
|
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
|
||||||
|
src = '..' + src;
|
||||||
|
if(console) console.log("Path", src, "HMAC", hmacOfPath);
|
||||||
|
if (hmac.length > 0) {
|
||||||
|
src += "?hmac=" + hmacOfPath;
|
||||||
|
}
|
||||||
|
location.href = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateSize(sizeInByte) {
|
||||||
|
let size = sizeInByte;
|
||||||
|
let unit = "Bytes";
|
||||||
|
if(size > 1024.0 * 1024 * 1024) {
|
||||||
|
size = size / 1024.0 / 1024 / 1024;
|
||||||
|
unit = "GiB";
|
||||||
|
} else if(size > 1024.0 * 1024) {
|
||||||
|
size = size / 1024.0 / 1024;
|
||||||
|
unit = "MiB";
|
||||||
|
} else if(size > 1024.0) {
|
||||||
|
size = size / 1024.0;
|
||||||
|
unit = "KiB";
|
||||||
|
}
|
||||||
|
return size.toFixed(2) + ' ' + unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRecordingInArray(array, recording) {
|
||||||
|
for ( let idx in array) {
|
||||||
|
let r = array[idx];
|
||||||
|
if (r.path === recording.path) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronizes recordings from the server with the displayed knockout recordings table
|
||||||
|
*/
|
||||||
|
function syncRecordings(recordings) {
|
||||||
|
// remove recordings from the observable array, which are not in the
|
||||||
|
// updated list
|
||||||
|
for ( let idx in observableRecordingsArray()) {
|
||||||
|
let recording = observableRecordingsArray()[idx];
|
||||||
|
if (!isRecordingInArray(recordings, recording)) {
|
||||||
|
observableRecordingsArray.remove(recording);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add recordings to the observable array, which are new in the
|
||||||
|
// updated list
|
||||||
|
for ( let idx in recordings) {
|
||||||
|
let recording = recordings[idx];
|
||||||
|
if (!isRecordingInArray(observableRecordingsArray(), recording)) {
|
||||||
|
recording.ko_date = ko.computed(function() {
|
||||||
|
return new Date(recording.startDate).toLocaleString('default', {
|
||||||
|
'day' : '2-digit',
|
||||||
|
'month' : '2-digit',
|
||||||
|
'year' : 'numeric',
|
||||||
|
'hour' : '2-digit',
|
||||||
|
'minute' : '2-digit',
|
||||||
|
'second' : '2-digit'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
recording.ko_progressString = ko.observable(recording.progress === -1 ? '' : recording.progress);
|
||||||
|
recording.ko_size = ko.observable(calculateSize(recording.sizeInByte));
|
||||||
|
recording.ko_status = ko.observable(recording.status);
|
||||||
|
if (recording.path.endsWith('.mp4')) {
|
||||||
|
recording.playlist = '/hls' + recording.path;
|
||||||
|
} else {
|
||||||
|
recording.playlist = '/hls' + recording.path + '/playlist.m3u8';
|
||||||
|
}
|
||||||
|
observableRecordingsArray.push(recording);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update existing recordings
|
||||||
|
for ( let i in recordings) {
|
||||||
|
let recording = recordings[i];
|
||||||
|
for ( let j in observableRecordingsArray()) {
|
||||||
|
let r = observableRecordingsArray()[j];
|
||||||
|
if (recording.path === r.path) {
|
||||||
|
r.progress = recording.progress;
|
||||||
|
r.sizeInByte = recording.sizeInByte;
|
||||||
|
r.status = recording.status;
|
||||||
|
r.startDate = recording.startDate;
|
||||||
|
r.ko_progressString(recording.progress === -1 ? '' : (recording.progress + '%'));
|
||||||
|
r.ko_size(calculateSize(recording.sizeInByte));
|
||||||
|
r.ko_status(recording.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRecordings() {
|
||||||
|
try {
|
||||||
|
let action = '{"action": "recordings"}';
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '../rec',
|
||||||
|
dataType : 'json',
|
||||||
|
async : true,
|
||||||
|
timeout : 60000,
|
||||||
|
headers : {
|
||||||
|
'CTBREC-HMAC' : CryptoJS.HmacSHA256(action, hmac)
|
||||||
|
},
|
||||||
|
data : action
|
||||||
|
}).done(function(data) {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
syncRecordings(data.recordings);
|
||||||
|
updateDiskSpace();
|
||||||
|
} else {
|
||||||
|
if (console)
|
||||||
|
console.log('request failed', data);
|
||||||
|
}
|
||||||
|
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||||
|
if (console)
|
||||||
|
console.log(textStatus, errorThrown);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console)
|
||||||
|
console.log('Unexpected error', e);
|
||||||
|
}
|
||||||
|
setTimeout(updateRecordings, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDiskSpace() {
|
||||||
|
let action = '{"action": "space"}';
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '../rec',
|
||||||
|
dataType : 'json',
|
||||||
|
async : true,
|
||||||
|
timeout : 60000,
|
||||||
|
headers : {
|
||||||
|
'CTBREC-HMAC' : CryptoJS.HmacSHA256(action, hmac)
|
||||||
|
},
|
||||||
|
data : action
|
||||||
|
}).done(function(data) {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
space.total(data.spaceTotal);
|
||||||
|
space.free(data.spaceFree);
|
||||||
|
space.percent((data.spaceFree / data.spaceTotal * 100).toFixed(2));
|
||||||
|
space.text(calculateSize(data.spaceFree) + ' / ' + calculateSize(data.spaceTotal));
|
||||||
|
} else {
|
||||||
|
if (console)
|
||||||
|
console.log('request failed', data);
|
||||||
|
}
|
||||||
|
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||||
|
if (console)
|
||||||
|
console.log(textStatus, errorThrown);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue