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 = {
|
||||
# status : idle = 0, uploading = 1
|
||||
# status : idle = 0, uploading = 1, done = -1
|
||||
"host": -1,
|
||||
"status": 0,
|
||||
"progress": -1,
|
||||
"filename": -1,
|
||||
|
@ -110,6 +111,8 @@ current_upload = {
|
|||
"transferred_percent": 0
|
||||
}
|
||||
|
||||
stop_upload_flag = 0
|
||||
|
||||
# Configuration
|
||||
debug = app.config['DEFAULT']['debug']
|
||||
pi_user = app.config['DEFAULT']['pi_user']
|
||||
|
@ -245,15 +248,49 @@ def list_media_files(folder):
|
|||
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):
|
||||
'''
|
||||
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
|
||||
global current_upload
|
||||
global stop_upload_flag
|
||||
total_size = 0
|
||||
# Using http_upload
|
||||
if sync_facility == "http":
|
||||
current_upload["host"] = host_local
|
||||
media_list = list_media_files(media_folder_local)
|
||||
media_list = get_upload_candidate_list(host_local, port, media_list)
|
||||
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
|
||||
current_upload["total_size"] = round(total_size)
|
||||
for media in media_list:
|
||||
current_media_size = int(media["size"]) / 1024 / 1024
|
||||
current_upload["filename"] = media["filename"].strip("/")
|
||||
current_upload["progress"] = media_count
|
||||
current_upload["size"] = round(current_media_size)
|
||||
if debug:
|
||||
print("Upload candidate : " + str(media))
|
||||
if HTTP_upload(media, host_local, port):
|
||||
# ~ if not stop_upload_flag:
|
||||
if current_upload["status"] > 0:
|
||||
current_media_size = int(media["size"]) / 1024 / 1024
|
||||
current_upload["filename"] = media["filename"].strip("/")
|
||||
current_upload["progress"] = media_count
|
||||
current_upload["size"] = round(current_media_size)
|
||||
if debug:
|
||||
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)
|
||||
print("Upload candidate : " + str(media))
|
||||
if HTTP_upload(media, host_local, port):
|
||||
if debug:
|
||||
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
|
||||
# TODO : fill current_upload with some values from rsync/scp
|
||||
elif which(sync_facility):
|
||||
# Build subprocess arg list accroding to sync_facility
|
||||
# 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]
|
||||
if debug:
|
||||
print("Transferred size: " + str(round(total_size)))
|
||||
return total_size
|
||||
return current_upload
|
||||
|
||||
|
||||
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.
|
||||
'''
|
||||
port_ = vlc_port
|
||||
arg0_values = ["play", "delete", "sort", "move"]
|
||||
# Build request
|
||||
#
|
||||
# Default request
|
||||
|
@ -440,7 +488,8 @@ def send_pilpil_command(host, arg0, arg1, arg2):
|
|||
# Build request for VLC command
|
||||
HTTP_request = HTTP_request + "?command=" + cmd_player[arg0]
|
||||
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
|
||||
HTTP_request = HTTP_request + "&id=" + arg1
|
||||
if (arg0 == "sort") or (arg0 == "move"):
|
||||
|
@ -543,18 +592,26 @@ def browse():
|
|||
return list_local_media_files(media_folder_local)
|
||||
|
||||
|
||||
@app.route("/sync/<host>")
|
||||
def sync(host):
|
||||
# TODO: Add feedback for transfer in GUI
|
||||
size = 0
|
||||
if host == "status":
|
||||
@app.route("/sync/<host>/", defaults={"arg0": "null"})
|
||||
@app.route("/sync/<host>/<arg0>/")
|
||||
def sync(host, arg0):
|
||||
# TODO: move to action() with url /host/sync/...
|
||||
global current_upload
|
||||
upload_ok = 0
|
||||
if arg0 == "status":
|
||||
return current_upload
|
||||
if arg0 == "stop":
|
||||
return stop_upload()
|
||||
elif host == "all":
|
||||
for hostl in hosts_available:
|
||||
size += sync_media_folder(media_folder_local, media_folder_remote_expanded, hostl, cmd_port)
|
||||
reset_current_upload()
|
||||
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:
|
||||
size = sync_media_folder(media_folder_local, media_folder_remote_expanded, host, cmd_port)
|
||||
return str(size)
|
||||
reset_current_upload()
|
||||
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"})
|
||||
|
|
|
@ -70,10 +70,14 @@ sha256 : 401359a84c6d60902c05602bd52fae70f0b2ecac36d550b52d14e1e3230854a6
|
|||
|
||||
|
||||
# DOING NEXT :
|
||||
* webgui: remove file from timeline (drag&drop to bin?)
|
||||
|
||||
* webgui/server : interrupt current download ?
|
||||
|
||||
# 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: Add remote file enqueuing
|
||||
* webgui: Fix timeline UI
|
||||
|
@ -84,8 +88,6 @@ sha256 : 401359a84c6d60902c05602bd52fae70f0b2ecac36d550b52d14e1e3230854a6
|
|||
|
||||
|
||||
# TODO :
|
||||
* webgui: remove file from timeline (drag&drop to bin?)
|
||||
* webgui: file sync UI freeze/status/progress bar
|
||||
* ~ Test with several rpis
|
||||
* ? Scripts hotspot linux : nmcli
|
||||
win : https://github.com/JamesCullum/Windows-Hotspot
|
||||
|
|
168
static/script.js
168
static/script.js
|
@ -3,7 +3,7 @@ const DEBUG = 0;
|
|||
const CMD_PORT = "8888";
|
||||
const TIMELINE_COLOR_CURSOR = "#FF8839";
|
||||
const TIMELINE_COLOR_BG = "#2EB8E600";
|
||||
const DEFAULT_LOCALE = "en"
|
||||
const DEFAULT_LOCALE = "en";
|
||||
// t9n
|
||||
let t9n =
|
||||
{ fr : {
|
||||
|
@ -11,27 +11,37 @@ let t9n =
|
|||
confirmMessage : "Êtes vous certain de vouloir effectuer cette action ?",
|
||||
filename : "Nom",
|
||||
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 : {
|
||||
statusDefault : "Searching network for live hosts...",
|
||||
confirmMessage : "Are you sure?",
|
||||
filename : "Filename",
|
||||
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
|
||||
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_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,
|
||||
last_ul_host : 0,
|
||||
};
|
||||
|
||||
|
||||
function sleep(ms) {
|
||||
let delay = new Promise(function(resolve) {
|
||||
setTimeout(resolve, ms);
|
||||
|
@ -59,6 +69,8 @@ async function update_sort_VLC_playlist(host) {
|
|||
// Un-freeze timeline update flag
|
||||
currentUser.freeze_timeline_update = 0;
|
||||
}
|
||||
|
||||
|
||||
async function update_delete_VLC_playlist(host, delete_element_id) {
|
||||
let delete_media = document.getElementById(delete_element_id);
|
||||
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);
|
||||
await sleep(90);
|
||||
adjust_timeline();
|
||||
currentUser.freeze_timeline_update = 0
|
||||
currentUser.freeze_timeline_update = 0;
|
||||
}
|
||||
|
||||
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'.
|
||||
// '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
|
||||
// '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_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]);
|
||||
if(HTML_attributes[i] == "id") {
|
||||
// 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 {
|
||||
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");
|
||||
media_attribute.value = meta[0];
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -248,7 +260,7 @@ function update_status(infos_array_element) {
|
|||
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 + ")"
|
||||
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";
|
||||
}
|
||||
|
@ -286,7 +298,7 @@ function update_list(infos_array_element){
|
|||
}
|
||||
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_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;
|
||||
// Adjust elements width
|
||||
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
|
||||
function parse_result(command, infos_array) {
|
||||
if (command == "/all/status") {
|
||||
|
@ -419,11 +517,22 @@ function parse_result(command, infos_array) {
|
|||
// Display remote media files in a table
|
||||
infos_array.forEach(update_remote_filelist);
|
||||
|
||||
} else if (command == "/sync/status") {
|
||||
// TODO : File sync UI status
|
||||
currentUser.status_all = infos_array;
|
||||
|
||||
} else {
|
||||
} 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 {
|
||||
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, 120, "/all/status");
|
||||
}
|
||||
|
@ -453,6 +562,13 @@ function enqueue_file(evt) {
|
|||
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;
|
||||
|
@ -463,7 +579,7 @@ function scan_hosts() {
|
|||
send_ajax_cmd("/scan");
|
||||
update_statusall_content();
|
||||
setTimeout(scan_hosts, currentUser.scan_interval);
|
||||
};
|
||||
}
|
||||
|
||||
// UI
|
||||
addEventListener("DOMContentLoaded", function() {
|
||||
|
@ -502,10 +618,14 @@ addEventListener("DOMContentLoaded", function() {
|
|||
} else if ( command.indexOf("/clear") > -1 || command.indexOf("/sort") > -1) {
|
||||
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;
|
||||
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 ) {
|
||||
request.onload = send_ajax_cmd("/all/browse");
|
||||
|
|
|
@ -22,11 +22,61 @@ tr:nth-child(2n+1) {background-color: #888;}
|
|||
border-bottom: #222 solid 1px;
|
||||
display:none;
|
||||
background: linear-gradient(0deg, #999 10%, #666 80%);
|
||||
position:relative;
|
||||
}
|
||||
/*
|
||||
.client_container .left_col{border-right: #a8a8a8 2px solid;}
|
||||
*/
|
||||
.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;}
|
||||
*/
|
||||
|
@ -133,23 +183,22 @@ tr:nth-child(2n+1) {background-color: #888;}
|
|||
.col_1 {
|
||||
width: 40%;
|
||||
float: left;
|
||||
padding: 3% 0 0 5%;
|
||||
padding: 1% 0 0 2%;
|
||||
}
|
||||
.col_2 {
|
||||
width: 59%;
|
||||
display: inline-block;
|
||||
clear: right;
|
||||
max-height: 170px;
|
||||
padding:.5em;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.col_2 div {
|
||||
overflow-y: scroll;
|
||||
max-height: 170px;
|
||||
}
|
||||
.col_2 button {
|
||||
margin:.3em !important;
|
||||
background: #bbb;
|
||||
color: #444;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
line-height: 1.1em;
|
||||
}
|
||||
.indicator {
|
||||
display:inline-block;
|
||||
|
|
|
@ -30,11 +30,13 @@
|
|||
{% for host in hosts %}
|
||||
<div class="client_container" id="{{ host }}">
|
||||
<div class="left_col">
|
||||
<h2>{{host}}</h2>
|
||||
|
||||
<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}}/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="/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="signal_{{host}}">
|
||||
<span style="">{{gui_l10n['str_link']}}:</span>
|
||||
|
@ -48,6 +50,7 @@
|
|||
</div>
|
||||
<div class="col_2">
|
||||
<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">
|
||||
<table id="file_sel_{{host}}">
|
||||
<tr>
|
||||
|
@ -55,7 +58,6 @@
|
|||
</tr>
|
||||
</table>
|
||||
</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>
|
||||
|
|
Loading…
Reference in New Issue