webgui/server: upload dialog/status
This commit is contained in:
parent
9012b5240f
commit
0d2eee5f25
103
app.py
103
app.py
|
@ -99,7 +99,8 @@ cmd_server = [
|
||||||
]
|
]
|
||||||
|
|
||||||
current_upload = {
|
current_upload = {
|
||||||
# status : idle = 0, uploading = 1
|
# status : idle = 0, uploading = 1, done = -1
|
||||||
|
"host": -1,
|
||||||
"status": 0,
|
"status": 0,
|
||||||
"progress": -1,
|
"progress": -1,
|
||||||
"filename": -1,
|
"filename": -1,
|
||||||
|
@ -110,6 +111,8 @@ current_upload = {
|
||||||
"transferred_percent": 0
|
"transferred_percent": 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop_upload_flag = 0
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
debug = app.config['DEFAULT']['debug']
|
debug = app.config['DEFAULT']['debug']
|
||||||
pi_user = app.config['DEFAULT']['pi_user']
|
pi_user = app.config['DEFAULT']['pi_user']
|
||||||
|
@ -245,15 +248,49 @@ def list_media_files(folder):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def reset_current_upload():
|
||||||
|
global current_upload
|
||||||
|
current_upload = {
|
||||||
|
# status : idle = 0, uploading = 1, done = -1
|
||||||
|
"host": -1,
|
||||||
|
"status": 0,
|
||||||
|
"progress": -1,
|
||||||
|
"filename": -1,
|
||||||
|
"size": -1,
|
||||||
|
"total_size": -1,
|
||||||
|
"total_count": 0,
|
||||||
|
"transferred_size": 0,
|
||||||
|
"transferred_percent": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def stop_upload():
|
||||||
|
if sync_facility == "http":
|
||||||
|
# ~ global stop_upload_flag
|
||||||
|
global current_upload
|
||||||
|
current_upload["status"] = 0
|
||||||
|
# ~ stop_upload_flag = 1
|
||||||
|
reset_current_upload()
|
||||||
|
return current_upload
|
||||||
|
elif sync_facility == "rsync":
|
||||||
|
# TODO : This won't work in windows...
|
||||||
|
subprocess.run(["pkill", "rsync"])
|
||||||
|
else:
|
||||||
|
subprocess.run(["pkill", "scp"])
|
||||||
|
return _("Interrupting upload...")
|
||||||
|
|
||||||
|
|
||||||
def sync_media_folder(media_folder_local, media_folder_remote, host_local, port, sync_facility=sync_facility):
|
def sync_media_folder(media_folder_local, media_folder_remote, host_local, port, sync_facility=sync_facility):
|
||||||
'''
|
'''
|
||||||
Sync media_folder_local with media_folder_remote using sync_facility
|
Sync media_folder_local with media_folder_remote using sync_facility
|
||||||
'''
|
'''
|
||||||
# TODO : first send lift of files to check if they exist and if upload needed
|
# TODO : first send lift of files to check if they exist and if upload needed
|
||||||
global current_upload
|
global current_upload
|
||||||
|
global stop_upload_flag
|
||||||
total_size = 0
|
total_size = 0
|
||||||
# Using http_upload
|
# Using http_upload
|
||||||
if sync_facility == "http":
|
if sync_facility == "http":
|
||||||
|
current_upload["host"] = host_local
|
||||||
media_list = list_media_files(media_folder_local)
|
media_list = list_media_files(media_folder_local)
|
||||||
media_list = get_upload_candidate_list(host_local, port, media_list)
|
media_list = get_upload_candidate_list(host_local, port, media_list)
|
||||||
if debug:
|
if debug:
|
||||||
|
@ -266,19 +303,29 @@ def sync_media_folder(media_folder_local, media_folder_remote, host_local, port,
|
||||||
total_size += int(media["size"]) / 1024 / 1024
|
total_size += int(media["size"]) / 1024 / 1024
|
||||||
current_upload["total_size"] = round(total_size)
|
current_upload["total_size"] = round(total_size)
|
||||||
for media in media_list:
|
for media in media_list:
|
||||||
current_media_size = int(media["size"]) / 1024 / 1024
|
# ~ if not stop_upload_flag:
|
||||||
current_upload["filename"] = media["filename"].strip("/")
|
if current_upload["status"] > 0:
|
||||||
current_upload["progress"] = media_count
|
current_media_size = int(media["size"]) / 1024 / 1024
|
||||||
current_upload["size"] = round(current_media_size)
|
current_upload["filename"] = media["filename"].strip("/")
|
||||||
if debug:
|
current_upload["progress"] = media_count
|
||||||
print("Upload candidate : " + str(media))
|
current_upload["size"] = round(current_media_size)
|
||||||
if HTTP_upload(media, host_local, port):
|
|
||||||
if debug:
|
if debug:
|
||||||
print("File size: " + str(round(current_media_size)))
|
print("Upload candidate : " + str(media))
|
||||||
media_count += 1
|
if HTTP_upload(media, host_local, port):
|
||||||
current_upload["transferred_size"] += round(current_media_size)
|
if debug:
|
||||||
current_upload["transferred_percent"] += round((100 / total_size) * current_media_size)
|
print("File size: " + str(round(current_media_size)))
|
||||||
|
media_count += 1
|
||||||
|
current_upload["transferred_size"] += round(current_media_size)
|
||||||
|
current_upload["transferred_percent"] += round((100 / total_size) * current_media_size)
|
||||||
|
else:
|
||||||
|
# Upload interrupted
|
||||||
|
return _("Upload interrupted")
|
||||||
|
# ~ stop_upload_flag = 0
|
||||||
|
# ~ reset_current_upload() # host becomes -1
|
||||||
|
reset_current_upload()
|
||||||
|
current_upload["status"] = -1
|
||||||
# Using system cmd
|
# Using system cmd
|
||||||
|
# TODO : fill current_upload with some values from rsync/scp
|
||||||
elif which(sync_facility):
|
elif which(sync_facility):
|
||||||
# Build subprocess arg list accroding to sync_facility
|
# Build subprocess arg list accroding to sync_facility
|
||||||
# Using Rsync
|
# Using Rsync
|
||||||
|
@ -301,7 +348,7 @@ def sync_media_folder(media_folder_local, media_folder_remote, host_local, port,
|
||||||
total_size = str(sync_proc.stdout)[scrape_index:].split(" ")[0][:-1]
|
total_size = str(sync_proc.stdout)[scrape_index:].split(" ")[0][:-1]
|
||||||
if debug:
|
if debug:
|
||||||
print("Transferred size: " + str(round(total_size)))
|
print("Transferred size: " + str(round(total_size)))
|
||||||
return total_size
|
return current_upload
|
||||||
|
|
||||||
|
|
||||||
def get_meta_data(host, xml_data, request_="status", m3u_=0):
|
def get_meta_data(host, xml_data, request_="status", m3u_=0):
|
||||||
|
@ -417,6 +464,7 @@ def send_pilpil_command(host, arg0, arg1, arg2):
|
||||||
Builds a pilpil request according to args, send it and return parsed result.
|
Builds a pilpil request according to args, send it and return parsed result.
|
||||||
'''
|
'''
|
||||||
port_ = vlc_port
|
port_ = vlc_port
|
||||||
|
arg0_values = ["play", "delete", "sort", "move"]
|
||||||
# Build request
|
# Build request
|
||||||
#
|
#
|
||||||
# Default request
|
# Default request
|
||||||
|
@ -440,7 +488,8 @@ def send_pilpil_command(host, arg0, arg1, arg2):
|
||||||
# Build request for VLC command
|
# Build request for VLC command
|
||||||
HTTP_request = HTTP_request + "?command=" + cmd_player[arg0]
|
HTTP_request = HTTP_request + "?command=" + cmd_player[arg0]
|
||||||
if arg1 != "null":
|
if arg1 != "null":
|
||||||
if (arg0 == "play") or (arg0 == "delete") or (arg0 == "sort") or (arg0 == "move"):
|
# ~ if (arg0 == "play") or (arg0 == "delete") or (arg0 == "sort") or (arg0 == "move"):
|
||||||
|
if arg0 in arg0_values:
|
||||||
# Add 'id' url parameter
|
# Add 'id' url parameter
|
||||||
HTTP_request = HTTP_request + "&id=" + arg1
|
HTTP_request = HTTP_request + "&id=" + arg1
|
||||||
if (arg0 == "sort") or (arg0 == "move"):
|
if (arg0 == "sort") or (arg0 == "move"):
|
||||||
|
@ -543,18 +592,26 @@ def browse():
|
||||||
return list_local_media_files(media_folder_local)
|
return list_local_media_files(media_folder_local)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/sync/<host>")
|
@app.route("/sync/<host>/", defaults={"arg0": "null"})
|
||||||
def sync(host):
|
@app.route("/sync/<host>/<arg0>/")
|
||||||
# TODO: Add feedback for transfer in GUI
|
def sync(host, arg0):
|
||||||
size = 0
|
# TODO: move to action() with url /host/sync/...
|
||||||
if host == "status":
|
global current_upload
|
||||||
|
upload_ok = 0
|
||||||
|
if arg0 == "status":
|
||||||
return current_upload
|
return current_upload
|
||||||
|
if arg0 == "stop":
|
||||||
|
return stop_upload()
|
||||||
elif host == "all":
|
elif host == "all":
|
||||||
for hostl in hosts_available:
|
reset_current_upload()
|
||||||
size += sync_media_folder(media_folder_local, media_folder_remote_expanded, hostl, cmd_port)
|
return sync_media_folder(media_folder_local, media_folder_remote_expanded, host, cmd_port)
|
||||||
|
# TODO : figure it out for multiple hosts
|
||||||
|
# ~ for hostl in hosts_available:
|
||||||
|
# ~ sync_media_folder(media_folder_local, media_folder_remote_expanded, hostl, cmd_port)
|
||||||
else:
|
else:
|
||||||
size = sync_media_folder(media_folder_local, media_folder_remote_expanded, host, cmd_port)
|
reset_current_upload()
|
||||||
return str(size)
|
return sync_media_folder(media_folder_local, media_folder_remote_expanded, host, cmd_port)
|
||||||
|
return current_upload
|
||||||
|
|
||||||
|
|
||||||
@app.route("/<host>/<arg0>/", defaults={"arg1": "null", "arg2": "null"})
|
@app.route("/<host>/<arg0>/", defaults={"arg1": "null", "arg2": "null"})
|
||||||
|
|
|
@ -70,10 +70,14 @@ sha256 : 401359a84c6d60902c05602bd52fae70f0b2ecac36d550b52d14e1e3230854a6
|
||||||
|
|
||||||
|
|
||||||
# DOING NEXT :
|
# DOING NEXT :
|
||||||
* webgui: remove file from timeline (drag&drop to bin?)
|
|
||||||
|
* webgui/server : interrupt current download ?
|
||||||
|
|
||||||
# DONE :
|
# DONE :
|
||||||
|
|
||||||
|
* webgui: remove file from timeline (drag&drop to bin?) (check bugs)
|
||||||
|
* webgui: upload progress dialog
|
||||||
|
* server : file upload : only send new files, get upload status (/sync/status)
|
||||||
* webgui: l10n html + js
|
* webgui: l10n html + js
|
||||||
* webgui: Add remote file enqueuing
|
* webgui: Add remote file enqueuing
|
||||||
* webgui: Fix timeline UI
|
* webgui: Fix timeline UI
|
||||||
|
@ -84,8 +88,6 @@ sha256 : 401359a84c6d60902c05602bd52fae70f0b2ecac36d550b52d14e1e3230854a6
|
||||||
|
|
||||||
|
|
||||||
# TODO :
|
# TODO :
|
||||||
* webgui: remove file from timeline (drag&drop to bin?)
|
|
||||||
* webgui: file sync UI freeze/status/progress bar
|
|
||||||
* ~ Test with several rpis
|
* ~ Test with several rpis
|
||||||
* ? Scripts hotspot linux : nmcli
|
* ? Scripts hotspot linux : nmcli
|
||||||
win : https://github.com/JamesCullum/Windows-Hotspot
|
win : https://github.com/JamesCullum/Windows-Hotspot
|
||||||
|
|
172
static/script.js
172
static/script.js
|
@ -3,7 +3,7 @@ const DEBUG = 0;
|
||||||
const CMD_PORT = "8888";
|
const CMD_PORT = "8888";
|
||||||
const TIMELINE_COLOR_CURSOR = "#FF8839";
|
const TIMELINE_COLOR_CURSOR = "#FF8839";
|
||||||
const TIMELINE_COLOR_BG = "#2EB8E600";
|
const TIMELINE_COLOR_BG = "#2EB8E600";
|
||||||
const DEFAULT_LOCALE = "en"
|
const DEFAULT_LOCALE = "en";
|
||||||
// t9n
|
// t9n
|
||||||
let t9n =
|
let t9n =
|
||||||
{ fr : {
|
{ fr : {
|
||||||
|
@ -11,27 +11,37 @@ let t9n =
|
||||||
confirmMessage : "Êtes vous certain de vouloir effectuer cette action ?",
|
confirmMessage : "Êtes vous certain de vouloir effectuer cette action ?",
|
||||||
filename : "Nom",
|
filename : "Nom",
|
||||||
duration : "Durée",
|
duration : "Durée",
|
||||||
sync : "Transfert des fichiers..."
|
size : "Taille",
|
||||||
|
sync : "Transfert des fichiers..." ,
|
||||||
|
size_unit : " Mio",
|
||||||
|
of : " de ",
|
||||||
|
upload_sent_count_msg : " éléments envoyés",
|
||||||
},
|
},
|
||||||
en : {
|
en : {
|
||||||
statusDefault : "Searching network for live hosts...",
|
statusDefault : "Searching network for live hosts...",
|
||||||
confirmMessage : "Are you sure?",
|
confirmMessage : "Are you sure?",
|
||||||
filename : "Filename",
|
filename : "Filename",
|
||||||
duration : "Duration",
|
duration : "Duration",
|
||||||
sync : "Syncing files..."
|
size : "Size",
|
||||||
|
sync : "Syncing files...",
|
||||||
|
size_unit : " MB",
|
||||||
|
of : " of ",
|
||||||
|
upload_sent_count_msg : " elements transferred.",
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
// Timeline drag and drop elements default attributes
|
// Timeline drag and drop elements default attributes
|
||||||
const tl_cont_attr = {id:"tl_cont", ondrop: "drop(event, this)", ondragover:"allow_drop(event)"};
|
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)"};
|
const tl_drag_attr = {"id":"tl_drag", "draggable":"true", "ondragstart":"drag(event, this)"};
|
||||||
// Global object
|
// Global object
|
||||||
window.currentUser = {
|
window.currentUser = {
|
||||||
scan_interval : 3000,
|
scan_interval : 3000,
|
||||||
status_all : t9n[LOCALE].statusDefault,
|
status_all : t9n[LOCALE].statusDefault,
|
||||||
medias_status : {},
|
medias_status : {},
|
||||||
freeze_timeline_update : 0,
|
freeze_timeline_update : 0,
|
||||||
|
last_ul_host : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function sleep(ms) {
|
function sleep(ms) {
|
||||||
let delay = new Promise(function(resolve) {
|
let delay = new Promise(function(resolve) {
|
||||||
setTimeout(resolve, ms);
|
setTimeout(resolve, ms);
|
||||||
|
@ -59,6 +69,8 @@ async function update_sort_VLC_playlist(host) {
|
||||||
// Un-freeze timeline update flag
|
// Un-freeze timeline update flag
|
||||||
currentUser.freeze_timeline_update = 0;
|
currentUser.freeze_timeline_update = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function update_delete_VLC_playlist(host, delete_element_id) {
|
async function update_delete_VLC_playlist(host, delete_element_id) {
|
||||||
let delete_media = document.getElementById(delete_element_id);
|
let delete_media = document.getElementById(delete_element_id);
|
||||||
let delete_media_cont = delete_media.parentElement;
|
let delete_media_cont = delete_media.parentElement;
|
||||||
|
@ -67,7 +79,7 @@ async function update_delete_VLC_playlist(host, delete_element_id) {
|
||||||
send_ajax_cmd("/" + host + "/delete/" + delete_media_id);
|
send_ajax_cmd("/" + host + "/delete/" + delete_media_id);
|
||||||
await sleep(90);
|
await sleep(90);
|
||||||
adjust_timeline();
|
adjust_timeline();
|
||||||
currentUser.freeze_timeline_update = 0
|
currentUser.freeze_timeline_update = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_target_index(element, index) {
|
function find_target_index(element, index) {
|
||||||
|
@ -189,11 +201,11 @@ function add_HTML_attr(id, attribute, val , child=-1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function add_HTML_element(type, attribute, meta=0, uid=0){
|
function add_HTML_element(type, attribute, meta=0, uid=-1){
|
||||||
// Add HTML element with type 'type' and attributes 'attribute'.
|
// Add HTML element with type 'type' and attributes 'attribute'.
|
||||||
// 'attribute' should be a javascript object containing HTML attributes keys/values
|
// 'attribute' should be a javascript object containing HTML attributes keys/values to be applied to the new element
|
||||||
// 'meta' should be an array
|
// 'meta' should be an array
|
||||||
// 'uid' is used to make the HTML id attribute unique
|
// '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_element = document.createElement(type);
|
||||||
let HTML_attributes = Object.keys(attribute);
|
let HTML_attributes = Object.keys(attribute);
|
||||||
|
@ -201,7 +213,7 @@ function add_HTML_element(type, attribute, meta=0, uid=0){
|
||||||
let new_attribute = document.createAttribute(HTML_attributes[i]);
|
let new_attribute = document.createAttribute(HTML_attributes[i]);
|
||||||
if(HTML_attributes[i] == "id") {
|
if(HTML_attributes[i] == "id") {
|
||||||
// HTML id needs to be unique
|
// HTML id needs to be unique
|
||||||
new_attribute.value = Object.values(attribute)[i] + uid;
|
new_attribute.value = Object.values(attribute)[i] + (uid != -1 ? uid : i);
|
||||||
} else {
|
} else {
|
||||||
new_attribute.value = Object.values(attribute)[i];
|
new_attribute.value = Object.values(attribute)[i];
|
||||||
}
|
}
|
||||||
|
@ -212,9 +224,9 @@ function add_HTML_element(type, attribute, meta=0, uid=0){
|
||||||
let media_attribute = document.createAttribute("media_id");
|
let media_attribute = document.createAttribute("media_id");
|
||||||
media_attribute.value = meta[0];
|
media_attribute.value = meta[0];
|
||||||
HTML_element.setAttributeNode(media_attribute);
|
HTML_element.setAttributeNode(media_attribute);
|
||||||
|
// Set filename as inner text
|
||||||
|
HTML_element.innerText = meta[1];
|
||||||
}
|
}
|
||||||
// Set filename as inner text
|
|
||||||
HTML_element.innerText = meta[1];
|
|
||||||
return HTML_element;
|
return HTML_element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +260,7 @@ function update_status(infos_array_element) {
|
||||||
media_element.style.backgroundImage = media_cssgrad_rule;
|
media_element.style.backgroundImage = media_cssgrad_rule;
|
||||||
media_element.style.borderBottom = "4px solid " + TIMELINE_COLOR_CURSOR;
|
media_element.style.borderBottom = "4px solid " + TIMELINE_COLOR_CURSOR;
|
||||||
} else {
|
} else {
|
||||||
let media_url_str = "url(https://" + infos_array_element.host + ":" + CMD_PORT + "/thumb/" + media_element.innerText + ")"
|
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.backgroundImage = media_url_str;
|
||||||
media_element.style.borderBottom = "None";
|
media_element.style.borderBottom = "None";
|
||||||
}
|
}
|
||||||
|
@ -286,7 +298,7 @@ function update_list(infos_array_element){
|
||||||
}
|
}
|
||||||
document.getElementById(tl_cont_attr.id + j).replaceChildren(child_node);
|
document.getElementById(tl_cont_attr.id + j).replaceChildren(child_node);
|
||||||
let media_name = document.getElementById(tl_cont_attr.id + j).children[0].innerText;
|
let media_name = document.getElementById(tl_cont_attr.id + j).children[0].innerText;
|
||||||
let media_url_str = "url(https://" + host + ":" + CMD_PORT + "/thumb/" + media_name + ")"
|
let media_url_str = "url(https://" + host + ":" + CMD_PORT + "/thumb/" + media_name + ")";
|
||||||
document.getElementById(tl_cont_attr.id + j).children[0].style.backgroundImage = media_url_str;
|
document.getElementById(tl_cont_attr.id + j).children[0].style.backgroundImage = media_url_str;
|
||||||
// Adjust elements width
|
// Adjust elements width
|
||||||
adjust_timeline();
|
adjust_timeline();
|
||||||
|
@ -388,6 +400,92 @@ function update_host_list(infos_array){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function display_upload_status(command) {
|
||||||
|
// TODO : First this should set the HTMl with empty values, then call update_upload...
|
||||||
|
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() {
|
||||||
|
let container_element = document.getElementById(currentUser.last_ul_host);
|
||||||
|
let ul_cont_exists = document.getElementById("ul_dialog_cont_" + currentUser.last_ul_host);
|
||||||
|
if ( ul_cont_exists != undefined) {
|
||||||
|
container_element.removeChild(ul_cont_exists);
|
||||||
|
clearTimeout(currentUser["ul_timeout_" + currentUser.last_ul_host]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function update_upload_status(current_upload) {
|
||||||
|
console.log("Updating upload status...");
|
||||||
|
//~ console.log(current_upload);
|
||||||
|
if (current_upload.status == -1){
|
||||||
|
console.log("Destroying dialog..." + current_upload.host)
|
||||||
|
destroy_upload_status();
|
||||||
|
} else if (current_upload.status) {
|
||||||
|
console.log("Filling dialog...")
|
||||||
|
document.getElementById("ul_dialog_cont_" + current_upload.host).style.display = "block";
|
||||||
|
// Fill table
|
||||||
|
document.getElementById("ul_status_progress_cnt_" + current_upload.host).innerHTML = current_upload.progress + " / " + current_upload.total_count + t9n[LOCALE].upload_sent_count_msg;
|
||||||
|
document.getElementById("ul_status_progress_size_" + current_upload.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_" + current_upload.host).innerHTML = t9n[LOCALE].filename + ": " + current_upload.filename;
|
||||||
|
document.getElementById("ul_status_filesize_" + current_upload.host).innerHTML = t9n[LOCALE].size + ": " + current_upload.size + t9n[LOCALE].size_unit;
|
||||||
|
// Progress bar CSS
|
||||||
|
if (current_upload.transferred_percent) {
|
||||||
|
document.getElementById("ul_progress_" + current_upload.host).innerText = current_upload.transferred_percent + "%";
|
||||||
|
document.getElementById("ul_progress_" + current_upload.host).style.background = "linear-gradient(90deg, " + TIMELINE_COLOR_CURSOR + " " + current_upload.transferred_percent + "%, #fff " + current_upload.transferred_percent + "%)";
|
||||||
|
}
|
||||||
|
currentUser["ul_timeout_" + current_upload.host] = setTimeout(send_ajax_cmd, 3000, `/sync/${current_upload.host}/status`);
|
||||||
|
} else {
|
||||||
|
console.log("requesting status data");
|
||||||
|
currentUser.last_ul_host = current_upload.host;
|
||||||
|
send_ajax_cmd(`/sync/${current_upload.host}/status`);
|
||||||
|
await sleep(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <div id="ul_status_10.42.0.10" class="upload_status"></div>
|
||||||
// Metadata display
|
// Metadata display
|
||||||
function parse_result(command, infos_array) {
|
function parse_result(command, infos_array) {
|
||||||
if (command == "/all/status") {
|
if (command == "/all/status") {
|
||||||
|
@ -419,11 +517,22 @@ function parse_result(command, infos_array) {
|
||||||
// Display remote media files in a table
|
// Display remote media files in a table
|
||||||
infos_array.forEach(update_remote_filelist);
|
infos_array.forEach(update_remote_filelist);
|
||||||
|
|
||||||
} else if (command == "/sync/status") {
|
} else if (command.indexOf("/sync/") > -1) {
|
||||||
// TODO : File sync UI status
|
if (command.indexOf("/status") > -1 ) {
|
||||||
currentUser.status_all = infos_array;
|
console.log("updating infos...");
|
||||||
|
console.log(infos_array);
|
||||||
} else {
|
update_upload_status(infos_array);
|
||||||
|
} else if (command.indexOf("/stop") > -1 ) {
|
||||||
|
console.log("stopping upload...");
|
||||||
|
console.log(infos_array);
|
||||||
|
destroy_upload_status();
|
||||||
|
} else {
|
||||||
|
console.log("displaying status");
|
||||||
|
//~ console.log(infos_array);
|
||||||
|
//~ if (infos_array.total_count) {
|
||||||
|
//~ display_upload_status(infos_array)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
setTimeout(send_ajax_cmd, 80, "/all/list");
|
setTimeout(send_ajax_cmd, 80, "/all/list");
|
||||||
setTimeout(send_ajax_cmd, 120, "/all/status");
|
setTimeout(send_ajax_cmd, 120, "/all/status");
|
||||||
}
|
}
|
||||||
|
@ -437,14 +546,14 @@ function send_ajax_cmd(command) {
|
||||||
if (request.status === 200) {
|
if (request.status === 200) {
|
||||||
// responseText is a string, use parse to get an array.
|
// responseText is a string, use parse to get an array.
|
||||||
if (!currentUser.freeze_timeline_update) {
|
if (!currentUser.freeze_timeline_update) {
|
||||||
let infos_array = JSON.parse(request.responseText);
|
let infos_array = JSON.parse(request.responseText);
|
||||||
parse_result(command, infos_array);
|
parse_result(command, infos_array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
request.open("GET", command, true);
|
request.open("GET", command, true);
|
||||||
request.send();
|
request.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -453,6 +562,13 @@ function enqueue_file(evt) {
|
||||||
setTimeout(send_ajax_cmd, 40, "/" + evt.currentTarget.host + "/list");
|
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() {
|
function update_statusall_content() {
|
||||||
document.getElementById("status_all").innerHTML = currentUser.status_all;
|
document.getElementById("status_all").innerHTML = currentUser.status_all;
|
||||||
|
@ -463,7 +579,7 @@ function scan_hosts() {
|
||||||
send_ajax_cmd("/scan");
|
send_ajax_cmd("/scan");
|
||||||
update_statusall_content();
|
update_statusall_content();
|
||||||
setTimeout(scan_hosts, currentUser.scan_interval);
|
setTimeout(scan_hosts, currentUser.scan_interval);
|
||||||
};
|
}
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
addEventListener("DOMContentLoaded", function() {
|
addEventListener("DOMContentLoaded", function() {
|
||||||
|
@ -502,10 +618,14 @@ addEventListener("DOMContentLoaded", function() {
|
||||||
} else if ( command.indexOf("/clear") > -1 || command.indexOf("/sort") > -1) {
|
} else if ( command.indexOf("/clear") > -1 || command.indexOf("/sort") > -1) {
|
||||||
request.onload = send_ajax_cmd(command);
|
request.onload = send_ajax_cmd(command);
|
||||||
|
|
||||||
} else if ( command == "/sync/all" ) {
|
} else if ( command.indexOf("/sync/") > -1 ) {
|
||||||
|
console.log("Sync command detected")
|
||||||
currentUser.status_all = t9n[LOCALE].sync;
|
currentUser.status_all = t9n[LOCALE].sync;
|
||||||
request.onload = send_ajax_cmd("/sync/status");
|
// Display dialog
|
||||||
|
display_upload_status(command);
|
||||||
|
// Request values to fill dialog
|
||||||
|
//~ request.onload = send_ajax_cmd(command + "/status");
|
||||||
|
setTimeout(send_ajax_cmd, 1000, command + "/status");
|
||||||
}
|
}
|
||||||
else if ( command.indexOf("/browse") > -1 ) {
|
else if ( command.indexOf("/browse") > -1 ) {
|
||||||
request.onload = send_ajax_cmd("/all/browse");
|
request.onload = send_ajax_cmd("/all/browse");
|
||||||
|
|
|
@ -22,11 +22,61 @@ tr:nth-child(2n+1) {background-color: #888;}
|
||||||
border-bottom: #222 solid 1px;
|
border-bottom: #222 solid 1px;
|
||||||
display:none;
|
display:none;
|
||||||
background: linear-gradient(0deg, #999 10%, #666 80%);
|
background: linear-gradient(0deg, #999 10%, #666 80%);
|
||||||
|
position:relative;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
.client_container .left_col{border-right: #a8a8a8 2px solid;}
|
.client_container .left_col{border-right: #a8a8a8 2px solid;}
|
||||||
*/
|
*/
|
||||||
.client_container .button{}
|
.client_container .button{}
|
||||||
|
|
||||||
|
.client_container .upload_dialog_cont {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff8;
|
||||||
|
height: 100%;
|
||||||
|
padding: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client_container .upload_dialog {
|
||||||
|
width: 30%;
|
||||||
|
background-color: #cecece;
|
||||||
|
height: 100%;
|
||||||
|
margin: auto;
|
||||||
|
padding: 2em;
|
||||||
|
border: #00000047 2px solid;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #444;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client_container [id^="ul_dialog_cont_"] {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client_container .upload_dialog button {
|
||||||
|
background: #bbb;
|
||||||
|
color: #444;
|
||||||
|
width: 3em;
|
||||||
|
height: 3em;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client_container .upload_dialog .progress_bar {
|
||||||
|
background: #fff;
|
||||||
|
height: 1.4em;
|
||||||
|
border-radius: .7em;
|
||||||
|
border: #999 2px solid;
|
||||||
|
text-align: center;
|
||||||
|
transition: background 3s;
|
||||||
|
margin:.5em;
|
||||||
|
}
|
||||||
|
.client_container .upload_dialog .upload_status {}
|
||||||
|
.client_container .upload_dialog table {
|
||||||
|
margin: auto;
|
||||||
|
background: transparent;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.client_container .upload_dialog [id^="ul_status_"] {}
|
||||||
/*
|
/*
|
||||||
.timeline {height: 3em;background-color: #0f0;margin: 2em 0;}
|
.timeline {height: 3em;background-color: #0f0;margin: 2em 0;}
|
||||||
*/
|
*/
|
||||||
|
@ -133,23 +183,22 @@ tr:nth-child(2n+1) {background-color: #888;}
|
||||||
.col_1 {
|
.col_1 {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
float: left;
|
float: left;
|
||||||
padding: 3% 0 0 5%;
|
padding: 1% 0 0 2%;
|
||||||
}
|
}
|
||||||
.col_2 {
|
.col_2 {
|
||||||
width: 59%;
|
width: 59%;
|
||||||
display: inline-block;
|
|
||||||
clear: right;
|
|
||||||
max-height: 170px;
|
|
||||||
padding:.5em;
|
padding:.5em;
|
||||||
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
.col_2 div {
|
.col_2 div {
|
||||||
overflow-y: scroll;
|
|
||||||
max-height: 170px;
|
max-height: 170px;
|
||||||
}
|
}
|
||||||
.col_2 button {
|
.col_2 button {
|
||||||
margin:.3em !important;
|
|
||||||
background: #bbb;
|
background: #bbb;
|
||||||
color: #444;
|
color: #444;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
line-height: 1.1em;
|
||||||
}
|
}
|
||||||
.indicator {
|
.indicator {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
|
|
|
@ -30,11 +30,13 @@
|
||||||
{% for host in hosts %}
|
{% for host in hosts %}
|
||||||
<div class="client_container" id="{{ host }}">
|
<div class="client_container" id="{{ host }}">
|
||||||
<div class="left_col">
|
<div class="left_col">
|
||||||
<h2>{{host}}</h2>
|
|
||||||
<div class="col_1">
|
<div class="col_1">
|
||||||
|
<h2>{{host}}</h2>
|
||||||
<button value="/{{host}}/poweroff" class="command btn btn-block btn-lg btn-default" role="button">⏻<span class="btn_txt">{{gui_l10n['str_poweroff']}}</span></button>
|
<button value="/{{host}}/poweroff" class="command btn btn-block btn-lg btn-default" role="button">⏻<span class="btn_txt">{{gui_l10n['str_poweroff']}}</span></button>
|
||||||
<button value="/{{host}}/reboot" class="command btn btn-block btn-lg btn-default" role="button">↺<span class="btn_txt">{{gui_l10n['str_reboot']}}</span></button>
|
<button value="/{{host}}/reboot" class="command btn btn-block btn-lg btn-default" role="button">↺<span class="btn_txt">{{gui_l10n['str_reboot']}}</span></button>
|
||||||
<button value="/{{host}}/blink" class="command btn btn-block btn-lg btn-default" role="button">💡<span class="btn_txt">{{gui_l10n['str_blink']}}</span></button>
|
<button value="/{{host}}/blink" class="command btn btn-block btn-lg btn-default" role="button">💡<span class="btn_txt">{{gui_l10n['str_blink']}}</span></button>
|
||||||
|
<button value="/sync/{{host}}" class="command btn btn-block btn-lg btn-default" role="button">💡<span class="btn_txt">{{gui_l10n['str_sync']}}</span></button>
|
||||||
<p id="status_{{host}}">{{status_message}}</p>
|
<p id="status_{{host}}">{{status_message}}</p>
|
||||||
<p id="signal_{{host}}">
|
<p id="signal_{{host}}">
|
||||||
<span style="">{{gui_l10n['str_link']}}:</span>
|
<span style="">{{gui_l10n['str_link']}}:</span>
|
||||||
|
@ -48,6 +50,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col_2">
|
<div class="col_2">
|
||||||
<div>
|
<div>
|
||||||
|
<button value="/{{host}}/browse" class="command btn btn-block btn-lg btn-default" role="button">↺<span class="btn_txt">{{gui_l10n['str_refresh']}}</span></button>
|
||||||
<div id="playlist_{{host}}" class="table_cont">
|
<div id="playlist_{{host}}" class="table_cont">
|
||||||
<table id="file_sel_{{host}}">
|
<table id="file_sel_{{host}}">
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -55,7 +58,6 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<button value="/{{host}}/browse" class="command btn btn-block btn-lg btn-default" role="button">↺<span class="btn_txt">{{gui_l10n['str_refresh']}}</span></button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue