834 lines
31 KiB
JavaScript
834 lines
31 KiB
JavaScript
// Config
|
|
const DEBUG = 0;
|
|
const CMD_PORT = "8888";
|
|
const TIMELINE_COLOR_CURSOR = "#FF8839";
|
|
const TIMELINE_COLOR_BG = "#2EB8E600";
|
|
const DEFAULT_LOCALE = "en";
|
|
// t9n
|
|
let t9n =
|
|
{ fr : {
|
|
statusDefault : "Recherche des clients connectés...",
|
|
confirmMessage : "Êtes vous certain de vouloir effectuer cette action ?",
|
|
filename : "Nom",
|
|
duration : "Durée",
|
|
size : "Taille",
|
|
sync : "Transfert des fichiers..." ,
|
|
size_unit : " Mio",
|
|
of : " de ",
|
|
upload_sent_count_msg : " éléments envoyés",
|
|
item_queued : "Synchronisation en attente...",
|
|
},
|
|
en : {
|
|
statusDefault : "Searching network for live hosts...",
|
|
confirmMessage : "Are you sure?",
|
|
filename : "Filename",
|
|
duration : "Duration",
|
|
size : "Size",
|
|
sync : "Syncing files...",
|
|
size_unit : " MB",
|
|
of : " of ",
|
|
upload_sent_count_msg : " elements transferred.",
|
|
item_queued : "Queued for file synchronisation...",
|
|
}
|
|
};
|
|
// Timeline drag and drop elements default attributes
|
|
const tl_cont_attr = {"id":"tl_cont", "ondrop": "drop(event, this)", "ondragover":"allow_drop(event)"};
|
|
const tl_drag_attr = {"id":"tl_drag", "draggable":"true", "ondragstart":"drag(event, this)"};
|
|
// Global object
|
|
window.currentUser = {
|
|
scan_interval : 3000,
|
|
status_all : t9n[LOCALE].statusDefault,
|
|
medias_status : {},
|
|
freeze_timeline_update : 0,
|
|
freeze_ul : 0,
|
|
last_ul_host : 0,
|
|
ul_queue : [],
|
|
};
|
|
|
|
|
|
function sleep(ms) {
|
|
let delay = new Promise(function(resolve) {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
return delay ;
|
|
// arrow notation equivalent
|
|
// return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
|
|
async function update_sort_VLC_playlist(host) {
|
|
// Update host's VLC playlist according to web UI timeline
|
|
let media_count = document.getElementById(`timeline_${host}`).children.length;
|
|
// Reversed loop
|
|
for (let i=media_count, l=0; i>l; i--) {
|
|
// Find current's timeline element children's 'media_id' value
|
|
//~ console.log(document.getElementById(`timeline_${host}`).children[i-1].children[0])
|
|
let to_shift = document.getElementById(`timeline_${host}`).children[i-1].children[0].getAttribute("media_id");
|
|
//~ console.log(to_shift + " : " + document.getElementById(`timeline_${host}`).children[i-1].children[0].innerText);
|
|
// Move 'to_shift' after element with id '1' :
|
|
// In VLC's playlist XML representation, the playlist node always gets id '1', so moving to that id
|
|
// really means moving to the the very start of the playlist.
|
|
send_ajax_cmd("/" + host + "/move/" + to_shift + "/1");
|
|
await sleep(200);
|
|
}
|
|
// Un-freeze timeline update flag
|
|
currentUser.freeze_timeline_update = 0;
|
|
}
|
|
function get_child_by_id(id, parent_element, depth=0){
|
|
Array.from(parent_element.children).forEach(function(child){
|
|
if (depth){
|
|
if (child.children[0].id == id){
|
|
result = child.children[0];
|
|
}
|
|
} else if (child.id == id) {
|
|
result = child;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
async function update_delete_VLC_playlist(host, delete_element_id) {
|
|
// Delete item from timeline and send corresponding VLC command
|
|
let current_timeline = document.getElementById("timeline_" + host);
|
|
let delete_media = get_child_by_id(delete_element_id, current_timeline, 1);
|
|
let delete_media_cont = delete_media.parentElement;
|
|
let delete_media_id = delete_media.getAttribute("media_id");
|
|
|
|
current_timeline.removeChild(delete_media_cont);
|
|
send_ajax_cmd("/" + host + "/delete/" + delete_media_id);
|
|
await sleep(200);
|
|
adjust_timeline(host);
|
|
// Unfreeze timeline UI after delay
|
|
setTimeout(function(){
|
|
currentUser.freeze_timeline_update = 0;
|
|
}, 200);
|
|
}
|
|
|
|
function find_target_index(element, index) {
|
|
if (element == this) {
|
|
return index + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
function shift_elements(source_element, target_element) {
|
|
// Shift elements in the timeline UI
|
|
//
|
|
// Get a list of current element siblings
|
|
let siblings_list = Array.from(source_element.parentElement.children);
|
|
let siblings_list_slice;
|
|
// Find indexes of source and target elements in the timeline
|
|
let source_index = siblings_list.findIndex(find_target_index, source_element);
|
|
let target_index = siblings_list.findIndex(find_target_index, target_element);
|
|
let insert_at = 0;
|
|
// Target element is on the left of the source element
|
|
if (source_index < target_index){
|
|
siblings_list_slice = siblings_list.slice(source_index + 1, target_index + 1);
|
|
insert_at = source_index;
|
|
} else {
|
|
// Target element is on the right of the source element
|
|
siblings_list_slice = siblings_list.slice(target_index, source_index );
|
|
insert_at = target_index + 1;
|
|
}
|
|
// Shift elements according to insert_at
|
|
for (let i=0, l=siblings_list_slice.length; i<l;i++){
|
|
siblings_list[insert_at + i].appendChild(siblings_list_slice[i].children[0]);
|
|
}
|
|
return insert_at;
|
|
}
|
|
|
|
|
|
function allow_drop(event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
|
|
function drag_over_bin(event) {
|
|
event.preventDefault();
|
|
let dropped_id = event.dataTransfer.getData("target_id");
|
|
let source_id = event.dataTransfer.getData("parent_element_id");
|
|
let source_element = document.getElementById(source_id);
|
|
let cont_element = get_child_by_id(dropped_id, source_element, 1);
|
|
let current_host = source_id.split("_")[1];
|
|
cont_element.style.opacity = 0.5;
|
|
//~ document.getElement("delete_" + current_host).style.backgroundColor = "#f00";
|
|
//~ document.getElementById("delete_" + current_host).style.boxShadow = "0 0 10px #fff;";
|
|
document.getElementById("delete_btn").style.backgroundColor = "#f00";
|
|
document.getElementById("delete_btn").style.boxShadow = "0 0 10px #fff;";
|
|
}
|
|
|
|
|
|
function drag_leave_bin(event) {
|
|
event.preventDefault();
|
|
let dropped_id = event.dataTransfer.getData("target_id");
|
|
let source_id = event.dataTransfer.getData("parent_element_id");
|
|
let source_element = document.getElementById(source_id);
|
|
let cont_element = get_child_by_id(dropped_id, source_element, 1);
|
|
let current_host = source_id.split("_")[1];
|
|
cont_element.style.opacity = 1;
|
|
document.getElementById("delete_btn").style.backgroundColor = "#df7474";
|
|
}
|
|
|
|
|
|
function drag(event, source) {
|
|
// Freeze timeline update flag
|
|
currentUser.freeze_timeline_update = 1;
|
|
event.dataTransfer.setData("target_id", event.target.id);
|
|
event.dataTransfer.setData("parent_element_id", source.parentElement.parentElement.id);
|
|
}
|
|
|
|
|
|
function drop(event, target_element) {
|
|
// If the currently dragged element is dropped on another element,
|
|
// shift HTML elements in the timeline to the left or right from the target element.
|
|
event.preventDefault();
|
|
// Get dragged element id
|
|
let dropped_id = event.dataTransfer.getData("target_id");
|
|
let source_id = event.dataTransfer.getData("parent_element_id");
|
|
let source_element = document.getElementById(source_id);
|
|
let current_host = source_id.split("_")[1];
|
|
source_element.style.border = "none";
|
|
// Only shift if not dropping on self
|
|
if (source_element.id != target_element.id) {
|
|
//~ if ( target_element.id.indexOf("delete_") > -1 ) {
|
|
if ( target_element.id == "delete_btn") {
|
|
update_delete_VLC_playlist(current_host, dropped_id);
|
|
document.getElementById("delete_btn").style.backgroundColor = "#df7474";
|
|
} else {
|
|
dropped_element = get_child_by_id(dropped_id, source_element, 1);
|
|
let dropTarget = shift_elements(dropped_element.parentElement, target_element);
|
|
//~ console.log(target_element);
|
|
//~ if (dropTarget) {
|
|
// Append dropped element to drop target.
|
|
//~ target_element.appendChild(source_element);
|
|
target_element.appendChild(dropped_element);
|
|
update_sort_VLC_playlist(current_host);
|
|
//~ }
|
|
}
|
|
// Un-freeze timeline update flag
|
|
//~ currentUser.freeze_timeline_update = 0;
|
|
}
|
|
send_ajax_cmd("/" + current_host + "/list");
|
|
}
|
|
|
|
|
|
function adjust_timeline(host) {
|
|
// Adapt timeline's UI elements to fit the width of their parent container.
|
|
//~ let timeline_div = document.querySelector('[id^="timeline_"]').children;
|
|
let timeline_div = document.getElementById("timeline_" + host).children;
|
|
let div_width = 100 / timeline_div.length;
|
|
for (let i=0, l=timeline_div.length; i<l; i++) {
|
|
timeline_div[i].style.width= div_width + "%";
|
|
}
|
|
return timeline_div.length;
|
|
}
|
|
|
|
|
|
function add_HTML_attr(id, attribute, val , child=-1) {
|
|
// Add attribute 'attr' with value 'val' to the HTML element with id 'id'.
|
|
// If child is other than -1, the attribute is applied to the HTML element's child at position 'child'
|
|
let HTML_element = document.getElementById(id);
|
|
if (child > -1){
|
|
HTML_element = HTML_element.children[child];
|
|
}
|
|
let HTML_attr = document.createAttribute(attribute);
|
|
HTML_attr.value = val;
|
|
HTML_element.setAttributeNode(HTML_attr);
|
|
}
|
|
|
|
|
|
function add_HTML_element(type, attribute, meta=0, uid=-1){
|
|
// Add HTML element with type 'type' and attributes 'attribute'.
|
|
// 'attribute' should be a javascript object containing HTML attributes keys/values to be applied to the new element
|
|
// 'meta' should be an array
|
|
// 'uid' is used to make the HTML id attribute unique. If not set, this will use the loop's iteration count i
|
|
//
|
|
let HTML_element = document.createElement(type);
|
|
let HTML_attributes = Object.keys(attribute);
|
|
for (let i=0, l=HTML_attributes.length; i<l; i++) {
|
|
let new_attribute = document.createAttribute(HTML_attributes[i]);
|
|
if(HTML_attributes[i] == "id") {
|
|
// HTML id needs to be unique
|
|
new_attribute.value = Object.values(attribute)[i] + (uid != -1 ? uid : i);
|
|
} else {
|
|
new_attribute.value = Object.values(attribute)[i];
|
|
}
|
|
HTML_element.setAttributeNode(new_attribute);
|
|
}
|
|
// Set media_id attribute if metadata is provided
|
|
if (meta) {
|
|
let media_attribute = document.createAttribute("media_id");
|
|
media_attribute.value = meta[0];
|
|
HTML_element.setAttributeNode(media_attribute);
|
|
// Set filename as inner text
|
|
HTML_element.innerText = meta[1];
|
|
}
|
|
return HTML_element;
|
|
}
|
|
|
|
|
|
function toggle_indicator(infos_array_element, property) {
|
|
// Toggle element bg color
|
|
toggle_state = 0;
|
|
if (infos_array_element[property] == "true") {
|
|
document.getElementById(`${property}_ind_${infos_array_element.host}`).style.backgroundColor = "#78E738";
|
|
toggle_state = 1;
|
|
} else {
|
|
document.getElementById(`${property}_ind_${infos_array_element.host}`).style.backgroundColor = "#A42000";
|
|
}
|
|
return toggle_state;
|
|
}
|
|
|
|
|
|
function update_status(infos_array_element) {
|
|
if (infos_array_element.status) {
|
|
document.getElementById("status_" + infos_array_element.host).innerHTML = infos_array_element.file + " <br/> " + infos_array_element.time + " / " + infos_array_element.leng;
|
|
currentUser.medias_status[infos_array_element.id] = infos_array_element.pos;
|
|
// Highlight currently playing element
|
|
let current_timeline = document.getElementById("timeline_" + infos_array_element.host);
|
|
let timeline_medias_array = Array.from(current_timeline.querySelectorAll('[media_id]'));
|
|
timeline_medias_array.forEach(function(media_element){
|
|
if ( media_element.getAttribute("media_id") == infos_array_element.id ) {
|
|
let first_CSS_gradient_stop = infos_array_element.pos * 100;
|
|
let second_CSS_gradient_stop = first_CSS_gradient_stop - 1 + "%";
|
|
first_CSS_gradient_stop = first_CSS_gradient_stop + "%";
|
|
let media_url_str = "url(https://" + infos_array_element.host + ":" + CMD_PORT + "/thumb/" + infos_array_element.file + ")";
|
|
let media_cssgrad_rule = "linear-gradient(90deg," + TIMELINE_COLOR_BG + " " + second_CSS_gradient_stop + ", " + TIMELINE_COLOR_CURSOR + " " + first_CSS_gradient_stop + ", " + TIMELINE_COLOR_BG + " " + first_CSS_gradient_stop + ")," + media_url_str;
|
|
media_element.style.backgroundImage = media_cssgrad_rule;
|
|
media_element.style.borderBottom = "4px solid " + TIMELINE_COLOR_CURSOR;
|
|
} else {
|
|
let media_url_str = "url(https://" + infos_array_element.host + ":" + CMD_PORT + "/thumb/" + media_element.innerText + ")";
|
|
media_element.style.backgroundImage = media_url_str;
|
|
media_element.style.borderBottom = "None";
|
|
}
|
|
});
|
|
} else {
|
|
document.getElementById("status_" + infos_array_element.host).innerHTML = "<br><br>";
|
|
}
|
|
toggle_indicator(infos_array_element, "loop");
|
|
toggle_indicator(infos_array_element, "repeat");
|
|
return infos_array_element.status;
|
|
}
|
|
|
|
|
|
function update_list(infos_array_element){
|
|
// Playlist infos are displayed in a div ; number of items in list and total duration.
|
|
//~ document.getElementById("playlist_"+infos_array[i].host).innerHTML = infos_array[i].leng + " item(s) in playlist - " + infos_array[i].duration;
|
|
// Populate timeline according to the content of the playlist
|
|
// Get returned items as an array
|
|
let items_array = Array.from(infos_array_element.items);
|
|
let host = infos_array_element.host;
|
|
// If playlist is empty, remove all media divs in the timeline UI.
|
|
if (items_array.length == 0){
|
|
let child_list = Array.from(document.getElementById("timeline_" + host).children);
|
|
child_list.forEach(function(child){
|
|
document.getElementById("timeline_" + host).removeChild(child);
|
|
});
|
|
} else {
|
|
current_timeline = document.getElementById("timeline_" + host);
|
|
items_array.forEach(function(item, j){
|
|
item_meta = item.split(';');
|
|
let child_node = add_HTML_element("div", tl_drag_attr, item_meta, j);
|
|
let len = current_timeline.children.length;
|
|
add_HTML_attr("timeline_" + host, "length", len);
|
|
if ( len < items_array.length ) {
|
|
current_timeline.appendChild( add_HTML_element("div", tl_cont_attr, 0, len) );
|
|
}
|
|
//~ document.getElementById(tl_cont_attr.id + j).replaceChildren(child_node);
|
|
current_timeline_children = Array.from(current_timeline.children);
|
|
current_timeline_children[j].replaceChildren(child_node);
|
|
let media_name = current_timeline_children[j].children[0].innerText;
|
|
let media_url_str = "url(https://" + host + ":" + CMD_PORT + "/thumb/" + media_name + ")";
|
|
current_timeline_children[j].children[0].style.backgroundImage = media_url_str;
|
|
// Adjust elements width
|
|
adjust_timeline(host);
|
|
});
|
|
}
|
|
return items_array.length;
|
|
}
|
|
|
|
|
|
function populate_HTML_table(inner_text, host="all", CSS_class="file_selection") {
|
|
tr = document.createElement("tr");
|
|
td = document.createElement("td");
|
|
tr.appendChild(td);
|
|
tr.setAttribute("class", CSS_class);
|
|
tr.host = host;
|
|
td.innerText = inner_text;
|
|
// Add an event to the created element to send enqueue command when a file is clicked in the list
|
|
tr.addEventListener("click", enqueue_file, false);
|
|
document.getElementById("file_sel_" + host).appendChild(tr);
|
|
}
|
|
|
|
|
|
function empty_HTML_table(host="all", keep=1) {
|
|
|
|
let HTML_table_element = document.getElementById("file_sel_" + host);
|
|
let HTML_table_element_length = HTML_table_element.childElementCount;
|
|
for (let i=keep; i<HTML_table_element_length; HTML_table_element_length--) {
|
|
HTML_table_element.removeChild(HTML_table_element.children[i]);
|
|
}
|
|
}
|
|
|
|
|
|
function update_remote_filelist(infos_array_element) {
|
|
hosts = Object.keys(infos_array_element);
|
|
for (let j=0, m=hosts.length; j<m; j++) {
|
|
empty_HTML_table(hosts[j]);
|
|
let media_item = Object.keys(infos_array_element[hosts[j]]);
|
|
for (let k=0, n=media_item.length; k<n; k++) {
|
|
media_item_meta = infos_array_element[hosts[j]][media_item[k]];
|
|
populate_HTML_table(media_item_meta.name, hosts[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function update_rssi_indicator(infos_array_element){
|
|
let base_height = 0.5;
|
|
let signal_color = 40;
|
|
let best_rssi = 30;
|
|
let worst_rssi = 70;
|
|
let rssi_norm = Math.ceil( (worst_rssi - parseInt(infos_array_element.rssi) ) / ( worst_rssi - best_rssi ) * 4 );
|
|
signal_color = (rssi_norm-1) * signal_color;
|
|
// Reset to grey
|
|
for (let i=0, l=4; i<l; i++) {
|
|
document.getElementById("wl_" + infos_array_element.host + "_" +i).style.height = base_height + i * 0.15 + "em";
|
|
document.getElementById("wl_" + infos_array_element.host + "_" + i).style.backgroundColor = "hsl(0, 0%, 65%)";
|
|
}
|
|
// Color it
|
|
for (let i=0, l=rssi_norm > 4 ? 4 : rssi_norm; i<l; i++) {
|
|
document.getElementById("wl_" + infos_array_element.host + "_" +i).style.height = base_height + i * 0.15 + "em";
|
|
document.getElementById("wl_" + infos_array_element.host + "_" +i).style.backgroundColor = "hsl(" + signal_color + ", 100%, 50%)";
|
|
}
|
|
return rssi_norm;
|
|
}
|
|
|
|
|
|
//~ function update_local_filelist(infos_array) {
|
|
//~ let html_table = "<table>" +
|
|
//~ "<tr>" +
|
|
//~ "<th>" + t9n[LOCALE].filename + "</th>" +
|
|
//~ "<th>" + t9n[LOCALE].duration + "</th>" +
|
|
//~ "</tr>";
|
|
//~ infos_array.forEach(function(element){
|
|
//~ html_table += "<tr>" +
|
|
//~ "<td>" + element + "</td>" +
|
|
//~ "<td>" + "00:00" + "</td>" +
|
|
//~ "</tr>" ;
|
|
//~ });
|
|
//~ html_table += "</table>";
|
|
//~ return html_table;
|
|
//~ }
|
|
|
|
|
|
function update_host_list(infos_array){
|
|
let host_up = infos_array[0];
|
|
let host_down = infos_array[1];
|
|
if (host_up.length) {
|
|
host_up.forEach(function(host){
|
|
adjust_timeline(host);
|
|
document.getElementById(host).style.display = 'block';
|
|
send_ajax_cmd("/" + host + "/list");
|
|
send_ajax_cmd("/" + host + "/rssi");
|
|
});
|
|
currentUser.scan_interval = 10000;
|
|
}
|
|
host_down.forEach(function(element){
|
|
document.getElementById(element).style.display = 'none';
|
|
});
|
|
currentUser.hosts_up = host_up;
|
|
currentUser.hosts_down = host_down;
|
|
currentUser.status_all = host_up.length + " client(s).";
|
|
return host_up.length;
|
|
}
|
|
|
|
|
|
function freeze_ui_host(host, html_attributes, inner_html=0, inner_text=0){
|
|
// Add an overlay element to freeze part of the UI
|
|
// html_attributes, inner_html are objects with structure {"id":, 0 "class": 0, "attr" : "value", }
|
|
let container_element = document.getElementById(host);
|
|
let siblings = container_element.children;
|
|
// Upload dialog container / background
|
|
let upload_dialog_cont_element = add_HTML_element("div", html_attributes, 0, host);
|
|
container_element.insertBefore(upload_dialog_cont_element, siblings[0]);
|
|
if (inner_html){
|
|
let child_node = add_HTML_element("div", inner_html, 0, host);
|
|
let new_node = container_element.children.item(html_attributes.id + host).appendChild(child_node);
|
|
if (inner_text){
|
|
new_node.innerHTML = inner_text;
|
|
}
|
|
}
|
|
}
|
|
|
|
function freeze_queued_container(command){
|
|
freeze_attributes = {"id":"ul_queued_freeze_", "class": "ul_queued_freeze"};
|
|
inner_html = {"id":"ul_queued_msg_", "class": "ul_queued_msg"};
|
|
inner_text = t9n[LOCALE].item_queued;
|
|
let host = command.split("/")[2];
|
|
inner_text += '<buttton id="sync_unqueue_' + host + '" onclick="cancel_sync(this)" class="command btn btn-block btn-lg btn-default btn-unqueue" role="button">X</button';
|
|
freeze_ui_host(host, freeze_attributes, inner_html, inner_text);
|
|
}
|
|
|
|
function unfreeze_queued_container(host){
|
|
let container = document.getElementById(host);
|
|
let exists = container.querySelector("div.ul_queued_freeze");
|
|
if (exists){
|
|
exists.remove();
|
|
}
|
|
}
|
|
|
|
function unfreeze_all_containers(){
|
|
if (currentUser.hosts_up){
|
|
currentUser.hosts_up.forEach(function(host){
|
|
unfreeze_queued_container(host);
|
|
});
|
|
}
|
|
}
|
|
|
|
function exec_all_hosts(command){
|
|
let authorized_commands = ['reboot', 'poweroff'];
|
|
// Only send authorized commands
|
|
if (authorized_commands.indexOf(command) == -1 ){
|
|
return 0;
|
|
}
|
|
if ( confirm(t9n[LOCALE].confirmMessage) ) {
|
|
if (currentUser.hosts_up){
|
|
currentUser.hosts_up.forEach(function(host){
|
|
send_ajax_cmd("/" + host + "/" + command);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function display_upload_status(command) {
|
|
let host = command.split("/")[2];
|
|
let container_element = document.getElementById(host);
|
|
let siblings = container_element.children;
|
|
// Upload dialog container / background
|
|
let upload_dialog_cont_attributes = {"id":"ul_dialog_cont_", "class": "upload_dialog_cont"};
|
|
let upload_dialog_cont_element = add_HTML_element("div", upload_dialog_cont_attributes, 0, host);
|
|
let ul_cont_exists = document.getElementById(upload_dialog_cont_attributes.id + host);
|
|
// Upload dialog
|
|
//~ let upload_dialog_attributes = {"id":"ul_dialog_", "class": "upload_dialog"};
|
|
//~ let upload_dialog_element = add_HTML_element("div", upload_dialog_attributes, 0, host);
|
|
//~ let ul_dialog_exists = document.getElementById(upload_dialog_cont_attributes["id"] + host);
|
|
let upload_status_table = `
|
|
<table>
|
|
<tbody>
|
|
<tr>
|
|
<th colspan="2" id="ul_status_title_${host}">${t9n[LOCALE].sync}</th>
|
|
</tr>
|
|
<tr>
|
|
<td id="ul_status_progress_cnt_${host}"></td>
|
|
<td id="ul_status_progress_size_${host}"></td>
|
|
</tr>
|
|
<tr>
|
|
<td id="ul_status_filename_${host}"></td>
|
|
<td id="ul_status_filesize_${host}"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
let upload_dialog_HTML = `
|
|
<div id='ul_dialog_${host}' class='upload_dialog'>
|
|
<div id="ul_status_${host}" class="upload_status"></div>
|
|
<div id="ul_progress_${host}" class="progress_bar"></div>
|
|
<button id="ul_stop_btn_${host}" value="/sync/${host}/stop" class="command btn btn-block btn-lg btn-default" role="button">⏹<span class="btn_txt">Stop</span></button>
|
|
</div>
|
|
`;
|
|
if ( ul_cont_exists != undefined) {
|
|
container_element.removeChild(ul_cont_exists);
|
|
}
|
|
container_element.insertBefore(upload_dialog_cont_element, siblings[0]);
|
|
document.getElementById(upload_dialog_cont_attributes.id + host).innerHTML = upload_dialog_HTML;
|
|
document.getElementById("ul_stop_btn_" + host).addEventListener("click", send_btn_cmd, false);
|
|
document.getElementById("ul_status_" + host).innerHTML = upload_status_table;
|
|
}
|
|
|
|
|
|
function destroy_upload_status(host) {
|
|
let container_element = document.getElementById(host);
|
|
let ul_cont_exists = document.getElementById("ul_dialog_cont_" + host);
|
|
if ( ul_cont_exists != undefined) {
|
|
// Remove ul dialog
|
|
container_element.removeChild(ul_cont_exists);
|
|
// Clear update callback
|
|
clearTimeout(currentUser["ul_timeout_" + host]);
|
|
}
|
|
}
|
|
|
|
|
|
async function update_upload_status(current_upload) {
|
|
if (current_upload.status == -1){
|
|
// Upload finished
|
|
console.log("Upload finished - Destroying dialog for " + currentUser.last_ul_host);
|
|
destroy_upload_status(currentUser.last_ul_host);
|
|
|
|
// Remove first item from command queue
|
|
currentUser.ul_queue.shift();
|
|
// Upload done, un-freeze
|
|
currentUser.freeze_ul = 0;
|
|
// Call sync_host() again
|
|
setTimeout(sync_host, 1000);
|
|
|
|
} else if (current_upload.status) {
|
|
unfreeze_queued_container(currentUser.last_ul_host);
|
|
// Upload in progress
|
|
console.log("Updating dialog...");
|
|
//document.getElementById("ul_dialog_cont_" + current_upload.host).style.display = "block";
|
|
document.getElementById("ul_dialog_cont_" + currentUser.last_ul_host).style.display = "block";
|
|
// Fill table
|
|
document.getElementById("ul_status_progress_cnt_" + currentUser.last_ul_host).innerHTML = current_upload.progress + " / " + current_upload.total_count + t9n[LOCALE].upload_sent_count_msg;
|
|
document.getElementById("ul_status_progress_size_" + currentUser.last_ul_host).innerHTML = current_upload.transferred_size + t9n[LOCALE].size_unit + t9n[LOCALE].of + current_upload.total_size + t9n[LOCALE].size_unit;
|
|
document.getElementById("ul_status_filename_" + currentUser.last_ul_host).innerHTML = t9n[LOCALE].filename + ": " + current_upload.filename;
|
|
document.getElementById("ul_status_filesize_" + currentUser.last_ul_host).innerHTML = t9n[LOCALE].size + ": " + current_upload.size + t9n[LOCALE].size_unit;
|
|
// Progress bar CSS
|
|
// FIXME : cursor stops updating after upload ?
|
|
if (current_upload.transferred_percent) {
|
|
document.getElementById("ul_progress_" + currentUser.last_ul_host).innerText = current_upload.transferred_percent + "%";
|
|
document.getElementById("ul_progress_" + currentUser.last_ul_host).style.background = "linear-gradient(90deg, " + TIMELINE_COLOR_CURSOR + " " + current_upload.transferred_percent + "%, #fff " + current_upload.transferred_percent + "%)";
|
|
}
|
|
// Update status callback
|
|
currentUser["ul_timeout_" + currentUser.last_ul_host] = setTimeout(send_ajax_cmd, 1000, `/sync/${currentUser.last_ul_host}/status`);
|
|
} else {
|
|
// Upload is starting
|
|
console.log("Requesting data to update dialog for " + currentUser.last_ul_host);
|
|
// Freeze ul cmd
|
|
currentUser.freeze_ul = 1;
|
|
//~ currentUser.last_ul_host = current_upload.host;
|
|
// This will end up calling update_upload_status() again, expecting the ul status value to change from 0 to int
|
|
send_ajax_cmd(`/sync/${currentUser.last_ul_host}/status`);
|
|
//~ send_ajax_cmd(`/sync/${current_upload.host}/status`);
|
|
// Wait a bit for response
|
|
await sleep(200);
|
|
}
|
|
}
|
|
|
|
// <div id="ul_status_10.42.0.10" class="upload_status"></div>
|
|
// Metadata display
|
|
function parse_result(command, infos_array) {
|
|
if (command == "/all/status") {
|
|
// Requests current status of every instances, especially current media file's name, position and length.
|
|
// Also retrieves loop and repeat status.
|
|
infos_array.forEach(update_status);
|
|
|
|
} else if (command.indexOf("/list") > -1 ) {
|
|
// Requests playlist of every instances
|
|
if (!currentUser.freeze_timeline_update){
|
|
infos_array.forEach(update_list);
|
|
}
|
|
|
|
} else if (command == "/scan") {
|
|
// Scan for live hosts
|
|
update_host_list(infos_array);
|
|
|
|
} else if (command == "/browse_local") {
|
|
// Display local media files in a table
|
|
//~ document.getElementById("filelist").innerHTML = update_local_filelist(infos_array);
|
|
|
|
} else if (command == "/all/rssi") {
|
|
// RSSI strength indicator
|
|
infos_array.forEach(update_rssi_indicator);
|
|
|
|
//~ } else if ( command == "/all/browse") {
|
|
} else if (command.indexOf("/browse") > -1) {
|
|
// Display remote media files in a table
|
|
infos_array.forEach(update_remote_filelist);
|
|
|
|
} else if (command.indexOf("/sync/") > -1) {
|
|
if (command.indexOf("/status") > -1 ) {
|
|
//~ console.log("updating infos...");
|
|
//~ console.log(infos_array);
|
|
update_upload_status(infos_array);
|
|
} else if (command.indexOf("/stop") > -1 ) {
|
|
//~ console.log("stopping upload...");
|
|
//~ console.log(infos_array);
|
|
//~ destroy_upload_status();
|
|
}
|
|
} else {
|
|
setTimeout(send_ajax_cmd, 180, "/all/list");
|
|
setTimeout(send_ajax_cmd, 180, "/all/status");
|
|
}
|
|
}
|
|
|
|
|
|
function send_ajax_cmd(command) {
|
|
let request = new XMLHttpRequest();
|
|
request.onload = function() {
|
|
if (request.readyState === request.DONE) {
|
|
if (request.status === 200) {
|
|
// responseText is a string, use parse to get an array.
|
|
if (!currentUser.freeze_timeline_update) {
|
|
let infos_array = JSON.parse(request.responseText);
|
|
parse_result(command, infos_array);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
request.open("GET", command, true);
|
|
request.send();
|
|
}
|
|
|
|
|
|
function enqueue_file(evt) {
|
|
send_ajax_cmd("/" + evt.currentTarget.host + "/enqueue/" + evt.currentTarget.innerText);
|
|
// User can't be interacting with timeline when clicking on file so unfreeze it.
|
|
currentUser.freeze_timeline_update = 0;
|
|
setTimeout(send_ajax_cmd, 40, "/" + evt.currentTarget.host + "/list");
|
|
}
|
|
|
|
function send_btn_cmd(evt) {
|
|
let clickedButton = event.currentTarget;
|
|
let command = clickedButton.value;
|
|
send_ajax_cmd(command);
|
|
//~ setTimeout(send_ajax_cmd, 40, "/" + evt.currentTarget.host + "/list");
|
|
}
|
|
|
|
|
|
function update_statusall_content() {
|
|
document.getElementById("status_all").innerHTML = currentUser.status_all;
|
|
}
|
|
|
|
|
|
function scan_hosts() {
|
|
send_ajax_cmd("/scan");
|
|
update_statusall_content();
|
|
setTimeout(scan_hosts, currentUser.scan_interval);
|
|
}
|
|
|
|
|
|
function sync_host() {
|
|
// If ul is not in progress
|
|
if (!currentUser.freeze_ul){
|
|
// If there's something in the queue
|
|
if (currentUser.ul_queue.length){
|
|
// Send first command in queue.
|
|
let command_q = currentUser.ul_queue[0];
|
|
console.log("Sending command " + command_q);
|
|
let host = command_q.split("/")[2];
|
|
// Send ul command
|
|
send_ajax_cmd(command_q);
|
|
// Update status
|
|
currentUser.status_all = t9n[LOCALE].sync;
|
|
// Create dialog
|
|
display_upload_status(command_q);
|
|
// Set current host
|
|
currentUser.last_ul_host = host;
|
|
// Send command to update dialog according to upload status
|
|
// This ends up calling update_upload_status()
|
|
setTimeout(send_ajax_cmd, 200, command_q + "/status");
|
|
} else {
|
|
console.log("Nothing else in the queue !");
|
|
// Make sure sane values are set back
|
|
unfreeze_all_containers();
|
|
currentUser.last_ul_host = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
console.log("UL freezed, waiting a bit...");
|
|
return 0;
|
|
}
|
|
|
|
|
|
function cancel_sync(host_btn_id){
|
|
let host = host_btn_id.id.split("_")[2];
|
|
let command = "/sync/" + host;
|
|
if (currentUser.ul_queue){
|
|
let item_index = currentUser.ul_queue.indexOf(command);
|
|
// Skip [0]
|
|
if (item_index > 0){
|
|
console.log(host + " unqueuing");
|
|
currentUser.ul_queue.splice(item_index, 1);
|
|
unfreeze_queued_container(host);
|
|
}
|
|
}
|
|
}
|
|
|
|
// UI
|
|
addEventListener("DOMContentLoaded", function() {
|
|
//~ adjust_timeline();
|
|
let commandButtons = document.querySelectorAll(".command");
|
|
for (let i=0, l=commandButtons.length; i<l; i++) {
|
|
let button = commandButtons[i];
|
|
button.addEventListener("click", function(event) {
|
|
event.preventDefault();
|
|
let clickedButton = event.currentTarget;
|
|
let command = clickedButton.value;
|
|
|
|
if ( command.indexOf("/reboot" ) > -1 || command.indexOf("/poweroff") > -1 ) {
|
|
if (command.indexOf("/all" ) == -1){
|
|
if ( !confirm(t9n[LOCALE].confirmMessage) ) {
|
|
return 0;
|
|
}
|
|
}
|
|
} else if ( command == "/scan" ) {
|
|
document.getElementById("status_all").innerHTML = currentUser.status_all;
|
|
|
|
} else if ( command.indexOf("/sort") > -1 ){
|
|
if (command.indexOf('/1/') > -1 ) {
|
|
clickedButton.value = clickedButton.value.replace('/1/','/0/');
|
|
|
|
} else {
|
|
clickedButton.value = clickedButton.value.replace('/0/','/1/');
|
|
}
|
|
}
|
|
// AJAX request
|
|
let request = new XMLHttpRequest();
|
|
if ( command == "/scan") {
|
|
request.onload = send_ajax_cmd(command);
|
|
|
|
} else if ( command.indexOf("/clear") > -1 || command.indexOf("/sort") > -1) {
|
|
request.onload = send_ajax_cmd(command);
|
|
|
|
} else if ( command.indexOf("/sync/") > -1 ) {
|
|
if ( command.indexOf("/all") > -1 ) {
|
|
console.log("Sync all request");
|
|
// If command is /sync/all, add live hosts to sync queue
|
|
if (currentUser.hosts_up){
|
|
currentUser.hosts_up.forEach(function(host){
|
|
let command = "/sync/" + host;
|
|
if (currentUser.ul_queue.indexOf(command) == -1){
|
|
console.log("Adding " + host + " to sync queue...");
|
|
currentUser.ul_queue.push(command);
|
|
freeze_queued_container(command);
|
|
}
|
|
});
|
|
}
|
|
if (currentUser.ul_queue.length > 1){
|
|
sync_host();
|
|
}
|
|
// Prevent request
|
|
return 0;
|
|
}
|
|
// If command not already in queue, add it
|
|
if (!currentUser.ul_queue.includes(command)){
|
|
currentUser.ul_queue.push(command);
|
|
freeze_queued_container(command);
|
|
} else {
|
|
console.log("Command already in queue...");
|
|
return 0;
|
|
}
|
|
sync_host();
|
|
// Prevent request
|
|
return 1;
|
|
}
|
|
else if ( command.indexOf("/browse") > -1 ) {
|
|
request.onload = send_ajax_cmd("/all/browse");
|
|
}
|
|
request.open("GET", command, true);
|
|
request.send();
|
|
});
|
|
}
|
|
}, true);
|
|
send_ajax_cmd("/scan");
|
|
send_ajax_cmd("/browse_local");
|
|
setInterval(send_ajax_cmd, 500, "/all/status");
|
|
setTimeout(send_ajax_cmd, 1000, "/all/list");
|
|
setTimeout(send_ajax_cmd, 3000, "/all/browse");
|
|
setInterval(send_ajax_cmd, 20000, "/all/rssi");
|
|
setTimeout(scan_hosts, currentUser.scan_interval);
|
|
|
|
|