Replace ajax calls with fetch
This commit is contained in:
parent
a9fa16051e
commit
23cf5e127a
|
@ -47,7 +47,7 @@
|
||||||
<body id="page-top">
|
<body id="page-top">
|
||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar navbar-expand-lg bg-secondary fixed-top text-uppercase" id="mainNav" style="padding-bottom: 3rem">
|
<nav class="navbar navbar-expand-lg bg-secondary fixed-top text-uppercase" id="mainNav" style="padding-bottom: 0rem">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand js-scroll-trigger" href="@{/docs/index.md}"><img src="@{/static/icon64.png}" alt="Logo"/>CTB Recorder</a>
|
<a class="navbar-brand js-scroll-trigger" href="@{/docs/index.md}"><img src="@{/static/icon64.png}" alt="Logo"/>CTB Recorder</a>
|
||||||
<button class="navbar-toggler navbar-toggler-right text-uppercase bg-primary text-white rounded" type="button" data-toggle="collapse"
|
<button class="navbar-toggler navbar-toggler-right text-uppercase bg-primary text-white rounded" type="button" data-toggle="collapse"
|
||||||
|
|
|
@ -1,68 +1,97 @@
|
||||||
function loadConfig() {
|
function loadConfig() {
|
||||||
try {
|
try {
|
||||||
$.ajax({
|
const headers = {};
|
||||||
type : 'GET',
|
if (hmac && hmac.length > 0) {
|
||||||
url : '../config',
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256('', hmac).toString(CryptoJS.enc.Base64);
|
||||||
dataType : 'json',
|
|
||||||
async : true,
|
|
||||||
timeout : 60000,
|
|
||||||
headers : {
|
|
||||||
'CTBREC-HMAC' : CryptoJS.HmacSHA256('', hmac)
|
|
||||||
}
|
|
||||||
}).done(function(data, textStatus, jqXHR) {
|
|
||||||
if (textStatus === 'success') {
|
|
||||||
while (observableSettingsArray().length > 0) {
|
|
||||||
observableSettingsArray.pop();
|
|
||||||
}
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
let param = data[i];
|
|
||||||
param.ko_value = ko.observable(param.value);
|
|
||||||
observableSettingsArray.push(param);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (console)
|
|
||||||
console.log('request failed', data);
|
|
||||||
}
|
|
||||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
|
||||||
if (console)
|
|
||||||
console.log(jqXHR, textStatus, errorThrown);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if (console)
|
|
||||||
console.log('Unexpected error', e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetch('../config', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: headers,
|
||||||
|
cache: 'no-cache'
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
while (observableSettingsArray().length > 0) {
|
||||||
|
observableSettingsArray.pop();
|
||||||
|
}
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
let param = data[i];
|
||||||
|
param.ko_value = ko.observable(param.value);
|
||||||
|
observableSettingsArray.push(param);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to load config:', error);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveConfig() {
|
function saveConfig() {
|
||||||
try {
|
try {
|
||||||
let msg = JSON.stringify(observableSettingsArray());
|
// Create new array with updated values
|
||||||
$.ajax({
|
let settings = observableSettingsArray().map(param => ({
|
||||||
type : 'POST',
|
key: param.key,
|
||||||
url : '../config',
|
type: param.type,
|
||||||
dataType : 'json',
|
value: param.ko_value() // Use observable value
|
||||||
async : true,
|
}));
|
||||||
timeout : 60000,
|
let msg = JSON.stringify(settings);
|
||||||
headers : {
|
console.log('Saving config JSON:', msg);
|
||||||
'CTBREC-HMAC' : CryptoJS.HmacSHA256(msg, hmac)
|
|
||||||
},
|
const abortController = new AbortController();
|
||||||
data : msg
|
const timeoutId = setTimeout(() => abortController.abort(), 60000); // 60 seconds timeout
|
||||||
}).done(function(data, textStatus, jqXHR) {
|
|
||||||
if (textStatus === 'success') {
|
fetch('../config', {
|
||||||
loadConfig();
|
method: 'POST',
|
||||||
$.notify('Configuration saved. You might have to restart the server.', 'info');
|
headers: {
|
||||||
} else {
|
'Content-Type': 'application/json',
|
||||||
if (console)
|
'CTBREC-HMAC': CryptoJS.HmacSHA256(msg, hmac)
|
||||||
console.log('request failed', data);
|
},
|
||||||
$.notify('Error: ' + jqXHR.responseText, 'error');
|
body: msg,
|
||||||
}
|
signal: abortController.signal
|
||||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
})
|
||||||
if (console)
|
.then(response => {
|
||||||
console.log(jqXHR, textStatus, errorThrown);
|
clearTimeout(timeoutId); // Clear timeout on success
|
||||||
$.notify(errorThrown + ': ' + jqXHR.responseText, 'error');
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
// Update param.value to reflect saved values
|
||||||
|
observableSettingsArray().forEach(param => {
|
||||||
|
param.value = param.ko_value();
|
||||||
});
|
});
|
||||||
} catch (e) {
|
loadConfig();
|
||||||
if (console)
|
$.notify('Configuration saved. You might have to restart the server.', 'info');
|
||||||
console.log('Unexpected error', e);
|
})
|
||||||
$.notify(errorThrown + ': ' + jqXHR.responseText, 'error');
|
.catch(error => {
|
||||||
}
|
clearTimeout(timeoutId); // Clear timeout on error
|
||||||
|
if (console) console.log('Request failed:', error);
|
||||||
|
$.notify(error.message || 'Unknown error: ' + (error.responseText || 'No response'), 'error');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
$.notify('Unexpected error: ' + e.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function notify(msg, type = 'info') {
|
||||||
|
const toastEl = document.getElementById('toast');
|
||||||
|
toastEl.querySelector('.toast-body').textContent = msg;
|
||||||
|
toastEl.classList.remove('bg-success', 'bg-danger', 'bg-info');
|
||||||
|
toastEl.classList.add(type === 'error' ? 'bg-danger' : type === 'info' ? 'bg-info' : 'bg-success', 'text-white');
|
||||||
|
const toast = new bootstrap.Toast(toastEl, {
|
||||||
|
autohide: true,
|
||||||
|
delay: 5000
|
||||||
|
});
|
||||||
|
toast.show();
|
||||||
|
document.getElementById('alert-container').appendChild(toastEl.parentElement);
|
||||||
}
|
}
|
|
@ -1 +1,61 @@
|
||||||
!function(o){"use strict";o('a.js-scroll-trigger[href*="#"]:not([href="#"])').click(function(){if(location.pathname.replace(/^\//,"")==this.pathname.replace(/^\//,"")&&location.hostname==this.hostname){var t=o(this.hash);if((t=t.length?t:o("[name="+this.hash.slice(1)+"]")).length)return o("html, body").animate({scrollTop:t.offset().top-70},1e3,"easeInOutExpo"),!1}}),o(document).scroll(function(){o(this).scrollTop()>100?o(".scroll-to-top").fadeIn():o(".scroll-to-top").fadeOut()}),o(".js-scroll-trigger").click(function(){o(".navbar-collapse").collapse("hide")}),o("body").scrollspy({target:"#mainNav",offset:80});var t=function(){o("#mainNav").offset().top>100?o("#mainNav").addClass("navbar-shrink"):o("#mainNav").removeClass("navbar-shrink")};t(),o(window).scroll(t),o(".portfolio-item").magnificPopup({type:"inline",preloader:!1,focus:"#username",modal:!0}),o(document).on("click",".portfolio-modal-dismiss",function(t){t.preventDefault(),o.magnificPopup.close()}),o(function(){o("body").on("input propertychange",".floating-label-form-group",function(t){o(this).toggleClass("floating-label-form-group-with-value",!!o(t.target).val())}).on("focus",".floating-label-form-group",function(){o(this).addClass("floating-label-form-group-with-focus")}).on("blur",".floating-label-form-group",function(){o(this).removeClass("floating-label-form-group-with-focus")})})}(jQuery);
|
!(function (o) {
|
||||||
|
"use strict";
|
||||||
|
o('a.js-scroll-trigger[href*="#"]:not([href="#"])').click(function () {
|
||||||
|
if (
|
||||||
|
location.pathname.replace(/^\//, "") ==
|
||||||
|
this.pathname.replace(/^\//, "") &&
|
||||||
|
location.hostname == this.hostname
|
||||||
|
) {
|
||||||
|
var t = o(this.hash);
|
||||||
|
if ((t = t.length ? t : o("[name=" + this.hash.slice(1) + "]")).length)
|
||||||
|
return (
|
||||||
|
o("html, body").animate(
|
||||||
|
{ scrollTop: t.offset().top - 70 },
|
||||||
|
1e3,
|
||||||
|
"easeInOutExpo",
|
||||||
|
),
|
||||||
|
!1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
o(document).scroll(function () {
|
||||||
|
o(this).scrollTop() > 100
|
||||||
|
? o(".scroll-to-top").fadeIn()
|
||||||
|
: o(".scroll-to-top").fadeOut();
|
||||||
|
}),
|
||||||
|
o(".js-scroll-trigger").click(function () {
|
||||||
|
o(".navbar-collapse").collapse("hide");
|
||||||
|
}),
|
||||||
|
o("body").scrollspy({ target: "#mainNav", offset: 80 });
|
||||||
|
var t = function () {
|
||||||
|
o("#mainNav").offset().top > 100
|
||||||
|
? o("#mainNav").addClass("navbar-shrink")
|
||||||
|
: o("#mainNav").removeClass("navbar-shrink");
|
||||||
|
};
|
||||||
|
t(),
|
||||||
|
o(window).scroll(t),
|
||||||
|
o(".portfolio-item").magnificPopup({
|
||||||
|
type: "inline",
|
||||||
|
preloader: !1,
|
||||||
|
focus: "#username",
|
||||||
|
modal: !0,
|
||||||
|
}),
|
||||||
|
o(document).on("click", ".portfolio-modal-dismiss", function (t) {
|
||||||
|
t.preventDefault(), o.magnificPopup.close();
|
||||||
|
}),
|
||||||
|
o(function () {
|
||||||
|
o("body")
|
||||||
|
.on("input propertychange", ".floating-label-form-group", function (t) {
|
||||||
|
o(this).toggleClass(
|
||||||
|
"floating-label-form-group-with-value",
|
||||||
|
!!o(t.target).val(),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.on("focus", ".floating-label-form-group", function () {
|
||||||
|
o(this).addClass("floating-label-form-group-with-focus");
|
||||||
|
})
|
||||||
|
.on("blur", ".floating-label-form-group", function () {
|
||||||
|
o(this).removeClass("floating-label-form-group-with-focus");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})(jQuery);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,141 +1,317 @@
|
||||||
function updateOnlineModels() {
|
function add(input, duration, onsuccess) {
|
||||||
try {
|
try {
|
||||||
let action = '{"action": "listOnline"}';
|
let model = {
|
||||||
$.ajax({
|
type: null,
|
||||||
type : 'POST',
|
name: '',
|
||||||
url : '../rec',
|
url: input
|
||||||
dataType : 'json',
|
};
|
||||||
async : true,
|
if (console) console.log(model);
|
||||||
timeout : 60000,
|
let action = input.startsWith('http') ? 'startByUrl' : 'startByName';
|
||||||
headers : {
|
const msg = JSON.stringify({ action: action, model: model });
|
||||||
'CTBREC-HMAC' : CryptoJS.HmacSHA256(action, hmac)
|
const headers = {
|
||||||
},
|
'Content-Type': 'application/json'
|
||||||
data : action
|
};
|
||||||
}).done(function(data, textStatus, jqXHR) {
|
if (hmac && hmac.length > 0) {
|
||||||
if (data.status === 'success') {
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(msg, hmac).toString(CryptoJS.enc.Base64);
|
||||||
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);
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: msg
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return response.text().then(text => {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (console) console.log(data);
|
||||||
|
if (data.status === 'success') {
|
||||||
|
if (onsuccess) {
|
||||||
|
onsuccess.call(data);
|
||||||
|
}
|
||||||
|
$.notify('Model added', 'info');
|
||||||
|
} else {
|
||||||
|
$.notify('Adding model failed', 'error');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to add model:', error);
|
||||||
|
$.notify('Adding model failed: ' + error.message, 'error');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function resume(model) {
|
||||||
|
try {
|
||||||
|
const action = JSON.stringify({ action: "resume", model: model });
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
if (hmac && hmac.length > 0) {
|
||||||
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
|
}
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return response.text().then(text => {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
$.notify('Recording of ' + model.name + ' resumed', 'info');
|
||||||
|
} else {
|
||||||
|
$.notify('Resuming recording of model ' + model.name + ' failed', 'error');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to resume recording:', error);
|
||||||
|
$.notify('Resuming recording of model ' + model.name + ' failed: ' + error.message, 'error');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function suspend(model) {
|
||||||
|
try {
|
||||||
|
const action = JSON.stringify({ action: "suspend", model: model });
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
if (hmac && hmac.length > 0) {
|
||||||
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
|
}
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return response.text().then(text => {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
$.notify('Recording of ' + model.name + ' suspended', 'info');
|
||||||
|
} else {
|
||||||
|
$.notify('Suspending recording of model ' + model.name + ' failed', 'error');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to suspend recording:', error);
|
||||||
|
$.notify('Suspending recording of model ' + model.name + ' failed: ' + error.message, 'error');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop(model) {
|
||||||
|
try {
|
||||||
|
const action = JSON.stringify({ action: "stop", model: model });
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
if (hmac && hmac.length > 0) {
|
||||||
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
|
}
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return response.text().then(text => {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
$.notify('Removed ' + model.name, 'info');
|
||||||
|
observableModelsArray.remove(model);
|
||||||
|
} else {
|
||||||
|
$.notify('Removing model ' + model.name + ' failed', 'error');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to remove model:', error);
|
||||||
|
$.notify('Removing model ' + model.name + ' failed: ' + error.message, 'error');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateOnlineModels() {
|
||||||
|
try {
|
||||||
|
const action = '{"action": "listOnline"}';
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
if (hmac && hmac.length > 0) {
|
||||||
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
onlineModels = data.models;
|
||||||
|
} else {
|
||||||
|
if (console) console.log('Request failed:', data);
|
||||||
|
}
|
||||||
|
updateModels();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to fetch online models:', error);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
|
setTimeout(updateOnlineModels, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isModelInArray(array, model) {
|
function isModelInArray(array, model) {
|
||||||
for ( let idx in array) {
|
for (let idx in array) {
|
||||||
let m = array[idx];
|
let m = array[idx];
|
||||||
if (m.url === model.url) {
|
if (m.url === model.url) {
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronizes models from the server with the displayed knockout model table
|
* Synchronizes models from the server with the displayed knockout model table
|
||||||
*/
|
*/
|
||||||
function syncModels(models) {
|
function syncModels(models) {
|
||||||
// remove models from the observable array, which are not in the updated list
|
// remove models from the observable array, which are not in the updated list
|
||||||
var newModelsMap = new Map(models.map(m => [m.url, m]));
|
var newModelsMap = new Map(models.map(m => [m.url, m]));
|
||||||
observableModelsArray.remove(m => !newModelsMap.get(m.ko_url()));
|
observableModelsArray.remove(m => !newModelsMap.get(m.ko_url()));
|
||||||
|
|
||||||
var modelsMap = new Map(observableModelsArray().map(m => [m.ko_url(), m]));
|
|
||||||
|
|
||||||
for (let model of models) {
|
|
||||||
const m = modelsMap.get(model.url);
|
|
||||||
|
|
||||||
if (!m) {
|
|
||||||
// add models to the observable array, which are new in the updated list
|
|
||||||
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_recording_class = ko.observable( (model.online && !model.suspended) ? 'fa fa-circle red' : '' );
|
|
||||||
model.ko_suspended = ko.observable(model.suspended);
|
|
||||||
model.ko_recordUntil = ko.observable(model.recordUntil);
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
// update existing models
|
|
||||||
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.ko_recording_class( (model.online && !model.suspended) ? 'fa fa-circle red' : '');
|
|
||||||
m.swallowEvents = true;
|
|
||||||
m.ko_suspended(model.suspended);
|
|
||||||
m.swallowEvents = false;
|
|
||||||
m.ko_recording(m.ko_online() && !m.ko_suspended());
|
|
||||||
|
|
||||||
// Update the recordUntil property to ensure clock icon refreshes
|
var modelsMap = new Map(observableModelsArray().map(m => [m.ko_url(), m]));
|
||||||
if (m.ko_recordUntil && typeof m.ko_recordUntil === 'function') {
|
|
||||||
m.ko_recordUntil(model.recordUntil);
|
for (let model of models) {
|
||||||
} else {
|
const m = modelsMap.get(model.url);
|
||||||
m.ko_recordUntil = ko.observable(model.recordUntil);
|
|
||||||
}
|
if (!m) {
|
||||||
|
// add models to the observable array, which are new in the updated list
|
||||||
|
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.ko_recordUntil = ko.observable(model.recordUntil);
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
// update existing models
|
||||||
|
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());
|
||||||
|
|
||||||
|
// Update the recordUntil property to ensure clock icon refreshes
|
||||||
|
if (m.ko_recordUntil && typeof m.ko_recordUntil === 'function') {
|
||||||
|
m.ko_recordUntil(model.recordUntil);
|
||||||
|
} else {
|
||||||
|
m.ko_recordUntil = ko.observable(model.recordUntil);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateModels() {
|
function updateModels() {
|
||||||
try {
|
try {
|
||||||
let action = '{"action": "list"}';
|
const action = '{"action": "list"}';
|
||||||
$.ajax({
|
const headers = {
|
||||||
type : 'POST',
|
'Content-Type': 'application/json'
|
||||||
url : '../rec',
|
};
|
||||||
dataType : 'json',
|
if (hmac && hmac.length > 0) {
|
||||||
async : true,
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
syncModels(data.models);
|
||||||
|
} else {
|
||||||
|
if (console) console.log('Request failed:', data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to fetch models:', error);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -47,6 +47,42 @@ function play(recording) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function show(recording) {
|
||||||
|
if (console) console.log("Show: " + recording.ko_contactSheet());
|
||||||
|
let localFilePath = recording.ko_contactSheet();
|
||||||
|
let src = getImageUrl(localFilePath);
|
||||||
|
|
||||||
|
if (src) {
|
||||||
|
let localFilePath = recording.ko_contactSheet();
|
||||||
|
let src = getImageUrl(recording.ko_contactSheet());
|
||||||
|
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("Final image URL: " + src);
|
||||||
|
let modalImage = document.getElementById('imageModalImage');
|
||||||
|
modalImage.src = src;
|
||||||
|
|
||||||
|
let fileName = localFilePath.split('\\').pop().split('/').pop();
|
||||||
|
|
||||||
|
let modalTitle = document.getElementById('contactsheetModalLabel');
|
||||||
|
modalTitle.innerText = fileName + " - " + recording.ko_selectedResolution() + "p";
|
||||||
|
|
||||||
|
$('#contactsheetModal').modal('show');
|
||||||
|
|
||||||
|
document.getElementById('deleteRecordingBtn').onclick = function() {
|
||||||
|
$('#contactsheetModal').modal('hide');
|
||||||
|
deleteRecording(recording);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
console.log('No contact sheet available');
|
||||||
|
$.notify('No contact sheet available', 'error');
|
||||||
|
}
|
||||||
|
document.activeElement.blur();
|
||||||
|
}
|
||||||
|
|
||||||
function download(recording) {
|
function download(recording) {
|
||||||
let src = recording.singleFile ? '/hls/' + recording.id : recording.playlist;
|
let src = recording.singleFile ? '/hls/' + recording.id : recording.playlist;
|
||||||
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
|
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
|
||||||
|
@ -59,51 +95,81 @@ function download(recording) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function rerunProcessing(recording) {
|
function rerunProcessing(recording) {
|
||||||
let name = recording.model.name + ' ' + recording.ko_date();
|
let name = recording.model.name + ' ' + recording.ko_date();
|
||||||
try {
|
try {
|
||||||
let action = '{"action": "rerunPostProcessing", "recording": ' + JSON.stringify(recording) + '}';
|
const action = JSON.stringify({ action: "rerunPostProcessing", recording: recording });
|
||||||
$.ajax({
|
const headers = {
|
||||||
type: 'POST',
|
'Content-Type': 'application/json'
|
||||||
url: '../rec',
|
};
|
||||||
dataType: 'json',
|
if (hmac && hmac.length > 0) {
|
||||||
async: true,
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
timeout: 60000,
|
|
||||||
headers: {'CTBREC-HMAC': CryptoJS.HmacSHA256(action, hmac)},
|
|
||||||
data: action
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if (console) console.log('Unexpected error', e);
|
|
||||||
}
|
}
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return response.text().then(text => {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status !== 'success') {
|
||||||
|
if (console) console.log('Request failed:', data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to rerun post-processing:', error);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteRecording(recording) {
|
function deleteRecording(recording) {
|
||||||
let name = recording.model.name + ' ' + recording.ko_date();
|
let name = recording.model.name + ' ' + recording.ko_date();
|
||||||
try {
|
try {
|
||||||
let action = '{"action": "delete", "recording": ' + JSON.stringify(recording) + '}';
|
const action = JSON.stringify({ action: "delete", recording: recording });
|
||||||
$.ajax({
|
const headers = {
|
||||||
type: 'POST',
|
'Content-Type': 'application/json'
|
||||||
url: '../rec',
|
};
|
||||||
dataType: 'json',
|
if (hmac && hmac.length > 0) {
|
||||||
async: true,
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
timeout: 60000,
|
|
||||||
headers: {'CTBREC-HMAC': CryptoJS.HmacSHA256(action, hmac)},
|
|
||||||
data: action
|
|
||||||
})
|
|
||||||
.done(function(data) {
|
|
||||||
if (data.status === 'success') {
|
|
||||||
$.notify('Removed recording ' + name, 'info');
|
|
||||||
observableRecordingsArray.remove(recording);
|
|
||||||
} else {
|
|
||||||
$.notify('Removing recording ' + name + ' failed', 'error');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
|
||||||
if (console) console.log(textStatus, errorThrown);
|
|
||||||
$.notify('Removing recording ' + name + ' failed', 'error');
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if (console) console.log('Unexpected error', e);
|
|
||||||
}
|
}
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return response.text().then(text => {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
$.notify('Removed recording ' + name, 'info');
|
||||||
|
observableRecordingsArray.remove(recording);
|
||||||
|
} else {
|
||||||
|
if (console) console.log('Request failed:', data);
|
||||||
|
$.notify('Removing recording ' + name + ' failed', 'error');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to delete recording:', error);
|
||||||
|
$.notify(`Removing recording ${name} failed: ${error.message}`, 'error');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
$.notify(`Removing recording ${name} failed: ${e.message}`, 'error');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateSize(sizeInByte) {
|
function calculateSize(sizeInByte) {
|
||||||
|
@ -132,32 +198,6 @@ function isRecordingInArray(array, recording) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function show(recording) {
|
|
||||||
if (console) console.log("Show: " + recording.ko_contactSheet());
|
|
||||||
let localFilePath = recording.ko_contactSheet();
|
|
||||||
let src = getImageUrl(recording.ko_contactSheet());
|
|
||||||
if (console) console.log("Show: " + src);
|
|
||||||
if (src) {
|
|
||||||
if (console) console.log("Image: " + src);
|
|
||||||
// Update the modal's image source and display the modal
|
|
||||||
let modalImage = document.getElementById('imageModalImage');
|
|
||||||
modalImage.src = src;
|
|
||||||
let fileName = localFilePath.split('\\').pop().split('/').pop();
|
|
||||||
let modalTitle = document.getElementById('contactsheetModalLabel');
|
|
||||||
modalTitle.innerText = fileName; // Set the title to the file name
|
|
||||||
// Show the modal (assuming you are using Bootstrap's modal)
|
|
||||||
$('#contactsheetModal').modal('show');
|
|
||||||
// Update the delete button to use this recording
|
|
||||||
document.getElementById('deleteRecordingBtn').onclick = function() {
|
|
||||||
$('#contactsheetModal').modal('hide');
|
|
||||||
deleteRecording(recording);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
console.log('No contact sheet available');
|
|
||||||
}
|
|
||||||
document.activeElement.blur();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronizes recordings from the server with the displayed knockout recordings table
|
* Synchronizes recordings from the server with the displayed knockout recordings table
|
||||||
*/
|
*/
|
||||||
|
@ -188,6 +228,8 @@ function syncRecordings(recordings) {
|
||||||
});
|
});
|
||||||
recording.ko_size = ko.observable(calculateSize(recording.sizeInByte));
|
recording.ko_size = ko.observable(calculateSize(recording.sizeInByte));
|
||||||
recording.ko_status = ko.observable(recording.status);
|
recording.ko_status = ko.observable(recording.status);
|
||||||
|
recording.ko_singleFile = ko.observable(recording.singleFile);
|
||||||
|
recording.ko_selectedResolution = ko.observable(recording.selectedResolution);
|
||||||
recording.ko_contactSheet = ko.observable(
|
recording.ko_contactSheet = ko.observable(
|
||||||
recording.associatedFiles?.find(file => file.endsWith('.jpg') || file.endsWith('.png')) || null
|
recording.associatedFiles?.find(file => file.endsWith('.jpg') || file.endsWith('.png')) || null
|
||||||
);
|
);
|
||||||
|
@ -209,7 +251,9 @@ function syncRecordings(recordings) {
|
||||||
r.progress = recording.progress;
|
r.progress = recording.progress;
|
||||||
r.sizeInByte = recording.sizeInByte;
|
r.sizeInByte = recording.sizeInByte;
|
||||||
r.status = recording.status;
|
r.status = recording.status;
|
||||||
|
r.selectedResolution = recording.selectedResolution;
|
||||||
r.startDate = recording.startDate;
|
r.startDate = recording.startDate;
|
||||||
|
r.singleFile = recording.singleFile;
|
||||||
r.ko_size(calculateSize(recording.sizeInByte));
|
r.ko_size(calculateSize(recording.sizeInByte));
|
||||||
r.ko_status(recording.status);
|
r.ko_status(recording.status);
|
||||||
r.ko_contactSheet(
|
r.ko_contactSheet(
|
||||||
|
@ -223,67 +267,88 @@ function syncRecordings(recordings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateRecordings() {
|
function updateRecordings() {
|
||||||
try {
|
try {
|
||||||
let action = '{"action": "recordings"}';
|
const action = '{"action": "recordings"}';
|
||||||
$.ajax({
|
const headers = {
|
||||||
type : 'POST',
|
'Content-Type': 'application/json'
|
||||||
url : '../rec',
|
};
|
||||||
dataType : 'json',
|
if (hmac && hmac.length > 0) {
|
||||||
async : true,
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
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);
|
|
||||||
|
fetch('../rec', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: action
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return response.text().then(text => {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
syncRecordings(data.recordings);
|
||||||
|
updateDiskSpace();
|
||||||
|
} else {
|
||||||
|
if (console) console.log('Request failed:', data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to fetch recordings:', error);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
|
setTimeout(updateRecordings, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDiskSpace() {
|
function updateDiskSpace() {
|
||||||
let action = '{"action": "space"}';
|
try {
|
||||||
$.ajax({
|
const action = '{"action": "space"}';
|
||||||
type : 'POST',
|
const headers = {
|
||||||
url : '../rec',
|
'Content-Type': 'application/json'
|
||||||
dataType : 'json',
|
};
|
||||||
async : true,
|
if (hmac && hmac.length > 0) {
|
||||||
timeout : 60000,
|
headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256(action, hmac).toString(CryptoJS.enc.Base64);
|
||||||
headers : {
|
}
|
||||||
'CTBREC-HMAC' : CryptoJS.HmacSHA256(action, hmac)
|
|
||||||
},
|
fetch('../rec', {
|
||||||
data : action
|
method: 'POST',
|
||||||
}).done(function(data) {
|
headers: headers,
|
||||||
if (data.status === 'success') {
|
body: action
|
||||||
space.total(data.spaceTotal);
|
})
|
||||||
space.free(data.spaceFree);
|
.then(response => {
|
||||||
space.percent((data.spaceFree / data.spaceTotal * 100).toFixed(2));
|
if (!response.ok) {
|
||||||
space.text(calculateSize(data.spaceFree) + ' / ' + calculateSize(data.spaceTotal));
|
return response.text().then(text => {
|
||||||
throughput.bytes(data.throughput);
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||||
throughput.timeframe(data.throughputTimeframe);
|
});
|
||||||
let bytesPerSecond = data.throughput / data.throughputTimeframe * 1000;
|
}
|
||||||
throughput.text(calculateSize(bytesPerSecond) + '/s');
|
return response.json();
|
||||||
} else {
|
})
|
||||||
if (console)
|
.then(data => {
|
||||||
console.log('request failed', data);
|
if (data.status === 'success') {
|
||||||
}
|
space.total(data.spaceTotal);
|
||||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
space.free(data.spaceFree);
|
||||||
if (console)
|
space.percent((data.spaceFree / data.spaceTotal * 100).toFixed(2));
|
||||||
console.log(textStatus, errorThrown);
|
space.text(calculateSize(data.spaceFree) + ' / ' + calculateSize(data.spaceTotal));
|
||||||
|
throughput.bytes(data.throughput);
|
||||||
|
throughput.timeframe(data.throughputTimeframe);
|
||||||
|
let bytesPerSecond = data.throughput / data.throughputTimeframe * 1000;
|
||||||
|
throughput.text(calculateSize(bytesPerSecond) + '/s');
|
||||||
|
} else {
|
||||||
|
if (console) console.log('Request failed:', data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (console) console.log('Failed to fetch disk space:', error);
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (console) console.log('Unexpected error:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImageUrl(localFilePath) {
|
function getImageUrl(localFilePath) {
|
||||||
|
@ -292,18 +357,17 @@ function getImageUrl(localFilePath) {
|
||||||
let recordingsDirEntry = ko.utils.arrayFirst(observableSettingsArray(), item => item.key === 'recordingsDir');
|
let recordingsDirEntry = ko.utils.arrayFirst(observableSettingsArray(), item => item.key === 'recordingsDir');
|
||||||
if (!recordingsDirEntry) return null; // Can be removed since it has to exist in the config
|
if (!recordingsDirEntry) return null; // Can be removed since it has to exist in the config
|
||||||
let recordingsDir = recordingsDirEntry.ko_value();
|
let recordingsDir = recordingsDirEntry.ko_value();
|
||||||
// Normalize paths to use forward slashes
|
// Normalize paths to use forward slashes and convert to lowercase for comparison
|
||||||
const normalizedLocalPath = localFilePath.replace(/\\/g, '/');
|
const normalizedLocalPath = localFilePath.replace(/\\/g, '/').toLowerCase();
|
||||||
const normalizedRecordingsDir = recordingsDir.replace(/\\/g, '/');
|
const normalizedRecordingsDir = recordingsDir.replace(/\\/g, '/').toLowerCase();
|
||||||
const basePath = normalizedRecordingsDir.endsWith('/') ?
|
const basePath = normalizedRecordingsDir.endsWith('/') ?
|
||||||
normalizedRecordingsDir :
|
normalizedRecordingsDir :
|
||||||
normalizedRecordingsDir + '/';
|
normalizedRecordingsDir + '/';
|
||||||
if (console) console.log("normalizedLocalPath: " + normalizedLocalPath);
|
|
||||||
if (console) console.log("normalizedRecordingsDir: " + normalizedRecordingsDir);
|
|
||||||
if (console) console.log("basePath: " + basePath);
|
|
||||||
// Check if localFilePath starts with recordingsDir and replace it
|
// Check if localFilePath starts with recordingsDir and replace it
|
||||||
if (normalizedLocalPath.startsWith(basePath)) {
|
if (normalizedLocalPath.startsWith(basePath)) {
|
||||||
return "/image/recording/" + normalizedLocalPath.substring(basePath.length);
|
// Use original path case for URL
|
||||||
|
const originalNormalizedLocalPath = localFilePath.replace(/\\/g, '/');
|
||||||
|
return "/image/recording/" + originalNormalizedLocalPath.substring(basePath.length);
|
||||||
}
|
}
|
||||||
return null; // Return null if the path doesn't match - in theory shouldn't happen
|
return null; // Return null if the path doesn't match
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue