Media enqueuing UI
This commit is contained in:
parent
9bcb04890b
commit
82a67286ea
103
app.py
103
app.py
|
@ -7,15 +7,18 @@ from flask import Flask, render_template, request, make_response, jsonify
|
|||
import gettext
|
||||
import http.client
|
||||
import os
|
||||
import socket
|
||||
# ~ import requests
|
||||
# ~ import socket
|
||||
import ssl
|
||||
import subprocess
|
||||
import requests
|
||||
from shutil import which
|
||||
import sys
|
||||
# ~ import threading
|
||||
import toml
|
||||
from urllib.parse import quote, unquote
|
||||
import xml.etree.ElementTree as ET
|
||||
from waitress import serve
|
||||
|
||||
|
||||
# l10n
|
||||
LOCALE = os.getenv('LANG', 'en')
|
||||
|
@ -30,8 +33,6 @@ for location in config_locations:
|
|||
if app.config.from_file(os.path.expanduser( location + "pilpil-server.toml"), load=toml.load, silent=True):
|
||||
print( _("Found configuration file in {}").format( os.path.expanduser(location) ) )
|
||||
|
||||
###
|
||||
|
||||
hosts_available, hosts_unavailable = [],[]
|
||||
queue_msgs = [
|
||||
_("No items"),
|
||||
|
@ -57,7 +58,6 @@ cmd_player = {
|
|||
"move" : "pl_move",
|
||||
"sort" : "pl_sort",
|
||||
"seek" : "seek",
|
||||
"sync" : "sync",
|
||||
"status" : "status.xml",
|
||||
"list" : "playlist.xml",
|
||||
#"volume" : "volume",
|
||||
|
@ -65,19 +65,20 @@ cmd_player = {
|
|||
#"dir" : "?dir=<uri>",
|
||||
#"command" : "?command=<cmd>",
|
||||
#"key" : "key=",
|
||||
#"browse" : "browse.xml?uri=file://~"
|
||||
"browse" : "browse.xml?uri=file://~"
|
||||
}
|
||||
cmd_server = [
|
||||
# Map pilpil-client http url parameters to pilpil-server urls
|
||||
"blink",
|
||||
"reboot",
|
||||
"poweroff",
|
||||
"rssi"
|
||||
"rssi",
|
||||
"sync"
|
||||
]
|
||||
|
||||
# Configuration
|
||||
debug = app.config['DEFAULT']['debug']
|
||||
media_folder_remote = app.config['DEFAULT']['media_folder_remote']
|
||||
media_folder_remote = os.path.expanduser(app.config['DEFAULT']['media_folder_remote'])
|
||||
media_folder_local = os.path.expanduser(app.config['DEFAULT']['media_folder_local'])
|
||||
media_exts = app.config['DEFAULT']['media_exts']
|
||||
auth = str(base64.b64encode(str(":" + app.config['DEFAULT']['vlc_auth']).encode('utf-8')), 'utf-8')
|
||||
|
@ -98,6 +99,7 @@ else:
|
|||
sslcontext.check_hostname = False
|
||||
sslcontext.verify_mode = ssl.CERT_NONE
|
||||
|
||||
current_upload = 0
|
||||
|
||||
class PilpilClient:
|
||||
def __init__(self):
|
||||
|
@ -190,6 +192,8 @@ def sync_media_folder(media_folder_local, media_folder_remote, host_local, port,
|
|||
'''
|
||||
Sync media_folder_local with media_folder_remote using sync_facility
|
||||
'''
|
||||
total_size = 0
|
||||
transfer_ok = 0
|
||||
trailing_slash = 1
|
||||
# Check for trailing / and add it if missing
|
||||
if media_folder_local[-1:] != "/":
|
||||
|
@ -200,10 +204,18 @@ def sync_media_folder(media_folder_local, media_folder_remote, host_local, port,
|
|||
#Using http_upload
|
||||
if sync_facility == "http":
|
||||
media_list = list_media_files(media_folder_local)
|
||||
transfer_ok = 0
|
||||
for media in media_list:
|
||||
transfer_ok += HTTP_upload(media, host_local, port, trailing_slash)
|
||||
return _("{} files uploaded.").format(str(transfer_ok))
|
||||
current_upload = media.strip("/")
|
||||
if debug:
|
||||
print("Uploading " + str(media))
|
||||
if HTTP_upload(media, host_local, port, trailing_slash):
|
||||
if debug:
|
||||
print("File size : " + str(os.stat(media_folder_local + media).st_size))
|
||||
total_size += os.stat(media_folder_local + media).st_size
|
||||
transfer_ok += 1
|
||||
# ~ return _("{} files uploaded.").format(str(transfer_ok))
|
||||
# ~ return _("{} files uploaded.").format(str(transfer_ok))
|
||||
# Using system cmd
|
||||
elif which(sync_facility):
|
||||
# Build subprocess arg list accroding to sync_facility
|
||||
# Using Rsync
|
||||
|
@ -224,9 +236,9 @@ def sync_media_folder(media_folder_local, media_folder_remote, host_local, port,
|
|||
if len(sync_proc.stdout):
|
||||
scrape_index = str(sync_proc.stdout).index(scrape_str)+len(scrape_str)
|
||||
total_size = str(sync_proc.stdout)[ scrape_index: ].split(" ")[0][:-1]
|
||||
else:
|
||||
total_size = "N/A";
|
||||
return total_size
|
||||
if debug:
|
||||
print("Transferred size : " + str(total_size))
|
||||
return total_size
|
||||
|
||||
def get_meta_data(host, xml_data, request_="status", m3u_=0):
|
||||
'''
|
||||
|
@ -239,7 +251,7 @@ def get_meta_data(host, xml_data, request_="status", m3u_=0):
|
|||
}
|
||||
if request_ == "list":
|
||||
# Return current instance's playlist
|
||||
return get_playlist(host, xml_data, m3u_)
|
||||
return get_playlist(host, xml_data, m3u_)
|
||||
elif request_ == "status":
|
||||
# Return current instance's status ( currently playing, state, time length, etc. )
|
||||
if xml_data.findall("./information/category/"):
|
||||
|
@ -267,22 +279,37 @@ def get_meta_data(host, xml_data, request_="status", m3u_=0):
|
|||
'id': cur_id,
|
||||
})
|
||||
elif request_ == "rssi":
|
||||
# # Return current instance's wifi signal quality
|
||||
print(xml_data)
|
||||
# Return current instance's wifi signal quality
|
||||
if debug:
|
||||
print(xml_data)
|
||||
if xml_data.findall("rssi"):
|
||||
media_infos.update({
|
||||
'status': 1,
|
||||
'rssi' : xml_data.find('rssi').text
|
||||
})
|
||||
|
||||
elif request_ == "browse":
|
||||
host_medias = {}
|
||||
for media in xml_data:
|
||||
media_name = media.attrib["name"]
|
||||
if len(media_name.split('.')) > 1:
|
||||
if media_name.split('.')[1] in media_exts:
|
||||
host_medias[media_name] = {
|
||||
"name": media_name,
|
||||
"uri": media.attrib["uri"],
|
||||
"size": round(int(media.attrib["size"])/1000000, 2)}
|
||||
media_infos = {host : host_medias}
|
||||
if debug:
|
||||
print(media_infos)
|
||||
|
||||
return media_infos
|
||||
|
||||
def get_playlist(host, xml_data, m3u=0):
|
||||
playlist = []
|
||||
item_list = []
|
||||
playlist_duration = 0
|
||||
|
||||
if xml_data.find("./node") and xml_data.find("./node").get('name') == "Playlist":
|
||||
|
||||
if xml_data.find("./node") and xml_data.find("./node").get('name') == _("Playlist"):
|
||||
print("HAHAHAH")
|
||||
playlist = xml_data.findall("./node/leaf")
|
||||
|
||||
content_format = "{};{};{};"
|
||||
|
@ -329,14 +356,22 @@ def send_pilpil_command(host, arg0, arg1, arg2):
|
|||
#
|
||||
# Default request
|
||||
HTTP_request = "/requests/status.xml"
|
||||
if arg0 == "list" :
|
||||
if arg0 == "list":
|
||||
# Get playlist
|
||||
HTTP_request = "/requests/playlist.xml"
|
||||
elif arg0 == "browse":
|
||||
if debug:
|
||||
print("Brosing {}".format(media_folder_remote))
|
||||
# Browse remote media folder
|
||||
media_folder_remote_URL = quote(media_folder_remote)
|
||||
HTTP_request = "/requests/browse.xml?uri=file://{}".format(media_folder_remote_URL)
|
||||
if debug:
|
||||
print("requesting url {} to {}:{}".format(HTTP_request, host, port_))
|
||||
elif arg0 in cmd_server:
|
||||
# Switching to cmd server
|
||||
HTTP_request = "/" + str(arg0)
|
||||
port_ = cmd_port
|
||||
elif arg0 != "status" :
|
||||
elif arg0 != "status":
|
||||
# Build request for VLC command
|
||||
HTTP_request = HTTP_request + "?command=" + cmd_player[arg0]
|
||||
if arg1 != "null" :
|
||||
|
@ -352,7 +387,7 @@ def send_pilpil_command(host, arg0, arg1, arg2):
|
|||
HTTP_request = HTTP_request + "&val=" + arg1
|
||||
elif (arg0 == "enqueue") or (arg0 == "add") :
|
||||
# Add 'input' url parameter
|
||||
HTTP_request = HTTP_request + "&input=file://" + media_folder_remote + "/" + arg1
|
||||
HTTP_request = HTTP_request + "&input=file://" + quote(media_folder_remote) + "/" + arg1
|
||||
|
||||
# Send request and get data response
|
||||
data = send_HTTP_request(host, port_, time_out=3, request_=HTTP_request)
|
||||
|
@ -371,7 +406,7 @@ def send_pilpil_command(host, arg0, arg1, arg2):
|
|||
return metadata
|
||||
|
||||
# Utilities
|
||||
def list_media_files(folder):
|
||||
def list_local_media_files(folder):
|
||||
'''
|
||||
List files in folder which extension is allowed (exists in media_exts).
|
||||
'''
|
||||
|
@ -426,20 +461,24 @@ def scan():
|
|||
hosts_available, hosts_unavailable = check_hosts(hosts)
|
||||
return [hosts_available, hosts_unavailable]
|
||||
|
||||
@app.route("/browse")
|
||||
@app.route("/browse_local")
|
||||
def browse():
|
||||
return list_media_files(media_folder_local)
|
||||
|
||||
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 == "all":
|
||||
if host == "status":
|
||||
return str(current_upload)
|
||||
elif host == "all":
|
||||
for hostl in hosts_available:
|
||||
size += sync_media_folder(media_folder_local, media_folder_remote, hostl, cmd_port)
|
||||
# ~ th = threading.Thread(target=blink_pi, args=(16,))
|
||||
# ~ th.start()
|
||||
else:
|
||||
size = sync_media_folder(media_folder_local, media_folder_remote, host, cmd_port)
|
||||
return size;
|
||||
return str(size)
|
||||
|
||||
@app.route("/<host>/<arg0>/", defaults = { "arg1": "null", "arg2": "null" })
|
||||
@app.route("/<host>/<arg0>/<arg1>/", defaults = { "arg2": "null" })
|
||||
|
@ -453,10 +492,10 @@ def action(host, arg0, arg1, arg2):
|
|||
|
||||
if host == "all":
|
||||
# Send request to all available hosts
|
||||
resp = []
|
||||
responses = []
|
||||
for hostl in hosts_available:
|
||||
resp.append(send_pilpil_command(hostl, arg0, arg1, arg2))
|
||||
status_message = resp
|
||||
responses.append(send_pilpil_command(hostl, arg0, arg1, arg2))
|
||||
status_message = responses
|
||||
elif host not in hosts_available:
|
||||
status_message = "<p>{}</p>".format("Host is not reachable")
|
||||
else:
|
||||
|
|
|
@ -32,7 +32,7 @@ sha256 : 0fe3fe76d0e56e445124fa20646fa8b3d8c59568786b3ebc8a96d83d92f203e3
|
|||
md5 : dee7af70135994169cab4f073ee51905
|
||||
sha256 : ec3e17fc9b41f8c5181484e9866be2d1d92cab8403210e3d22f4f689edd4cfde
|
||||
|
||||
* Switch to rpi os Bullseye
|
||||
* Switch to rpi os Bullseye arm64
|
||||
* Switch to user 'pil', pw 'pilpoil'
|
||||
* client config file parsing ( look for 'pilpil-client.toml' in ./, ~/., ~/.config/)
|
||||
* Add media folder sync (scp, rsync, http upload)
|
||||
|
@ -70,6 +70,7 @@ sha256 :
|
|||
* setup : Generate/install http auth secret at setup
|
||||
* setup : Add dry, help flags
|
||||
* FR localisation for server, client and install script
|
||||
* pep8ification
|
||||
|
||||
|
||||
# OTHER:
|
||||
|
@ -77,7 +78,7 @@ sha256 :
|
|||
|
||||
# TODO :
|
||||
|
||||
* ? python sanitization
|
||||
* ~ python sanitization
|
||||
* ~ Test with several rpis
|
||||
* ? Scripts hotspot linux/win/mac
|
||||
* ? Config sync
|
||||
|
|
Binary file not shown.
|
@ -54,6 +54,10 @@ msgstr "Erreur pendant la connexion à {}:{}"
|
|||
msgid "{} reachable on {}"
|
||||
msgstr "{} accessible sur {}"
|
||||
|
||||
#: app.py:311
|
||||
msgid "Playlist"
|
||||
msgstr "Liste de lecture"
|
||||
|
||||
#: app.py:331
|
||||
msgid "Idle"
|
||||
msgstr "Innocupé"
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
[DEFAULT]
|
||||
debug = 1
|
||||
useSSL = true
|
||||
useSSL = false
|
||||
CAfile = "selfCA.crt"
|
||||
# scp, rsync, http
|
||||
sync_facility = "http"
|
||||
media_folder_local = "../medias"
|
||||
media_folder_remote = "/home/pil/Videos"
|
||||
media_folder_remote = "~/Vidéos"
|
||||
media_exts = ["mp4", "avi", "mkv"]
|
||||
vlc_auth = "secret"
|
||||
# OnNlY3JldA==
|
||||
cmd_auth = "secret"
|
||||
hosts = ["10.42.0.10", "10.42.0.11"]
|
||||
#hosts = ["10.42.0.10", "10.42.0.11"]
|
||||
hosts = ["127.0.0.1"]
|
||||
# VLC http LUA port
|
||||
vlc_port = 8887
|
||||
# Clients cmd port
|
||||
|
|
203
static/script.js
203
static/script.js
|
@ -5,15 +5,17 @@ const tl_drag_attr = {id:"tl_drag", draggable:"true", ondragstart:"drag(event, t
|
|||
// Config
|
||||
var timeline_color_cursor = "#FF8839";
|
||||
var timeline_color_bg = "#2EB8E6";
|
||||
|
||||
var scanInterval = 3000;
|
||||
var status_all = "Searching network for live hosts..."
|
||||
// Global vars
|
||||
var src_id = "";
|
||||
var medias_status = {};
|
||||
var fileButtons = [];
|
||||
|
||||
function updatePlaylist(){
|
||||
var new_list = [];
|
||||
var media_count = document.getElementById("timeline").children.length;
|
||||
for (i=media_count,l=0;i>l;i--) {
|
||||
//~ new_list.push(document.getElementById("timeline").children[i].children[0].getAttribute("media_id"));
|
||||
toMove = document.getElementById("timeline").children[i-1].children[0].getAttribute("media_id");
|
||||
console.log(toMove);
|
||||
sendCmd("/all/move/" + toMove + "/1");
|
||||
|
@ -21,10 +23,10 @@ function updatePlaylist(){
|
|||
}
|
||||
|
||||
function findTargetIndex(element, index, array, thisArg){
|
||||
if (element == this) {
|
||||
return index+1;
|
||||
}
|
||||
return 0;
|
||||
if (element == this) {
|
||||
return index+1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
function moveElements(target) {
|
||||
|
@ -47,26 +49,25 @@ function moveElements(target) {
|
|||
};
|
||||
|
||||
function allowDrop(ev) {
|
||||
ev.preventDefault();
|
||||
drop_id = ev.dataTransfer.getData("text");
|
||||
ev.preventDefault();
|
||||
drop_id = ev.dataTransfer.getData("text");
|
||||
};
|
||||
|
||||
function drag(ev, source) {
|
||||
src_id = ev.target.parentElement;
|
||||
ev.dataTransfer.setData("text", ev.target.id);
|
||||
src_id = ev.target.parentElement;
|
||||
ev.dataTransfer.setData("text", ev.target.id);
|
||||
};
|
||||
|
||||
function drop(ev, target) {
|
||||
ev.preventDefault();
|
||||
var data = ev.dataTransfer.getData("text");
|
||||
if (src_id.id != target.id) {
|
||||
ev.preventDefault();
|
||||
var data = ev.dataTransfer.getData("text");
|
||||
if (src_id.id != target.id) {
|
||||
dropTarget = moveElements(target);
|
||||
if (dropTarget) {
|
||||
dropTarget.appendChild(document.getElementById(data));
|
||||
updatePlaylist();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function adjustTl() {
|
||||
|
@ -88,36 +89,45 @@ function addAttr(id, attr, val , child=-1) {
|
|||
};
|
||||
|
||||
function addElement(type, attr, meta = 0, j = 0){
|
||||
var elem = document.createElement(type);
|
||||
var keys_array = Object.keys(attr);
|
||||
for (i=0, l=keys_array.length;i<l;i++) {
|
||||
var att = document.createAttribute(keys_array[i]);
|
||||
if(!i){
|
||||
att.value = Object.values(attr)[i]+j;
|
||||
} else {
|
||||
att.value = Object.values(attr)[i];
|
||||
var elem = document.createElement(type);
|
||||
var keys_array = Object.keys(attr);
|
||||
for (i=0, l=keys_array.length;i<l;i++) {
|
||||
var att = document.createAttribute(keys_array[i]);
|
||||
if(!i){
|
||||
att.value = Object.values(attr)[i]+j;
|
||||
} else {
|
||||
att.value = Object.values(attr)[i];
|
||||
}
|
||||
elem.setAttributeNode(att);
|
||||
}
|
||||
// Set playlist id attribute
|
||||
if (meta) {
|
||||
att = document.createAttribute("media_id");
|
||||
att.value = meta[0];
|
||||
elem.setAttributeNode(att);
|
||||
}
|
||||
elem.setAttributeNode(att);
|
||||
}
|
||||
// Set playlist id attribute
|
||||
if (meta) {
|
||||
att = document.createAttribute("media_id");
|
||||
att.value = meta[0];
|
||||
elem.setAttributeNode(att);
|
||||
}
|
||||
// Get filename
|
||||
elem.innerText = meta[1];
|
||||
return elem;
|
||||
// Get filename
|
||||
elem.innerText = meta[1];
|
||||
return elem;
|
||||
};
|
||||
|
||||
var scanInterval = 3000;
|
||||
// Bouttons de commande
|
||||
addEventListener("DOMContentLoaded", function() {
|
||||
sendCmd("/scan");
|
||||
sendCmd("/browse");
|
||||
sendCmd("/browse_local");
|
||||
sendCmd("/all/rssi");
|
||||
sendCmd("/all/list");
|
||||
sendCmd("/all/browse");
|
||||
adjustTl();
|
||||
|
||||
// Get filename when selected in table
|
||||
//~ for (var i=0, l=fileButtons.length; i<l; i++) {
|
||||
//~ var selected_file = fileButtons[i];
|
||||
//~ // Sur un click
|
||||
//~ selected_file.addEventListener("click", function(event) {
|
||||
//~ // On intercepte le signal
|
||||
//~ event.preventDefault();
|
||||
//~ }
|
||||
//~ }
|
||||
// Tous les elements avec la classe ".command"
|
||||
var commandButtons = document.querySelectorAll(".command");
|
||||
for (var i=0, l=commandButtons.length; i<l; i++) {
|
||||
|
@ -133,14 +143,17 @@ addEventListener("DOMContentLoaded", function() {
|
|||
if ( !confirm("Êtes vous certain de vouloir effectuer cette action ?") ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if ( command == "/scan" ) {
|
||||
document.getElementById("status_all").innerHTML = "Searching network for live hosts...";
|
||||
document.getElementById("status_all").innerHTML = 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/')
|
||||
}
|
||||
|
||||
} else if ( command.indexOf("/move") > -1 ) {
|
||||
const test_array = [21,19,20];
|
||||
for (i=test_array.length, l=0;i>l;i--){
|
||||
|
@ -155,7 +168,11 @@ addEventListener("DOMContentLoaded", function() {
|
|||
var request = new XMLHttpRequest();
|
||||
if ( command == "/scan" ) {
|
||||
request.onload = sendCmd(command);
|
||||
}
|
||||
} else if ( command == "/sync/all" ) {
|
||||
status_all = "Syncing files..."
|
||||
request.onload = sendCmd("/sync/status");
|
||||
};
|
||||
|
||||
// On construit la commande
|
||||
request.open("GET", command, true);
|
||||
// et on l'envoie
|
||||
|
@ -175,15 +192,6 @@ function parseResult(command, infos_array) {
|
|||
document.getElementById("status_"+infos_array[i].host).innerHTML = infos_array[i].file + " <br/> " + infos_array[i].time + " / " + infos_array[i].leng;
|
||||
medias_status[infos_array[i].id] = infos_array[i].pos;
|
||||
}
|
||||
// Find currently playing element
|
||||
//~ var pl_length = document.getElementById("timeline").getAttribute("length");
|
||||
//~ for (j=0,k=pl_length;j<k;j++){
|
||||
//~ if (document.getElementById("timeline").children[j].children[0].getAttribute('media_id') == infos_array[i].id ) {
|
||||
//~ addAttr(document.getElementById("timeline").children[j].children[0].id, "pos", infos_array[i].pos);
|
||||
//~ }
|
||||
//~ };
|
||||
//~ document.getElementById("timeline").children[0].children[0].hasAttribute('media_id')
|
||||
// Toggle loop indicator
|
||||
if (infos_array[i].loop == "true") {
|
||||
document.getElementById("loop_ind_" + infos_array[i].host).style.backgroundColor = "#78E738"
|
||||
} else {
|
||||
|
@ -201,7 +209,7 @@ function parseResult(command, infos_array) {
|
|||
|
||||
for (var i = 0, l=infos_array.length; i<l; i++) {
|
||||
// Fill Playlist infos
|
||||
document.getElementById("playlist_"+infos_array[i].host).innerHTML = infos_array[i].leng + " item(s) in playlist - " + infos_array[i].duration;
|
||||
//~ document.getElementById("playlist_"+infos_array[i].host).innerHTML = infos_array[i].leng + " item(s) in playlist - " + infos_array[i].duration;
|
||||
// Build html table and timeline
|
||||
var items_array = Array.from(infos_array[i].items);
|
||||
//console.log(items_array.length);
|
||||
|
@ -212,20 +220,20 @@ function parseResult(command, infos_array) {
|
|||
};
|
||||
break;
|
||||
}
|
||||
var html_table = "<table>" +
|
||||
"<tr>" +
|
||||
"<th>Id</th>" +
|
||||
"<th>Filename</th>" +
|
||||
"<th>Duration</th>" +
|
||||
"</tr>";
|
||||
//~ var html_table = "<table>" +
|
||||
//~ "<tr>" +
|
||||
//~ "<th>Id</th>" +
|
||||
//~ "<th>Filename</th>" +
|
||||
//~ "<th>Duration</th>" +
|
||||
//~ "</tr>";
|
||||
for (var j = 0, k=items_array.length; j<k; j++) {
|
||||
// Table
|
||||
item_meta = items_array[j].split(';');
|
||||
html_table += "<tr>" +
|
||||
"<td>" + item_meta[0] + "</td>" +
|
||||
"<td>" + item_meta[1] + "</td>" +
|
||||
"<td>" + item_meta[2] + "</td>" +
|
||||
"</tr>" ;
|
||||
//~ html_table += "<tr>" +
|
||||
//~ "<td>" + item_meta[0] + "</td>" +
|
||||
//~ "<td>" + item_meta[1] + "</td>" +
|
||||
//~ "<td>" + item_meta[2] + "</td>" +
|
||||
//~ "</tr>" ;
|
||||
// Timeline
|
||||
var child_node = addElement("div", tl_drag_attr, item_meta, j);
|
||||
var len = document.getElementById("timeline").children.length;
|
||||
|
@ -248,8 +256,8 @@ function parseResult(command, infos_array) {
|
|||
document.getElementById(tl_cont_attr.id + j).children[0].style.background = "linear-gradient(90deg," + timeline_color_bg + " " + pos1 + ", " + timeline_color_cursor + " " + pos + ", " + timeline_color_bg + " " + pos + ")";
|
||||
}
|
||||
}
|
||||
html_table += "</table>";
|
||||
document.getElementById("playlist_"+infos_array[i].host).innerHTML += html_table;
|
||||
//~ html_table += "</table>";
|
||||
//~ document.getElementById("playlist_"+infos_array[i].host).innerHTML += html_table;
|
||||
};
|
||||
break;
|
||||
case "/scan":
|
||||
|
@ -263,11 +271,13 @@ function parseResult(command, infos_array) {
|
|||
}
|
||||
if (host_up.length) {
|
||||
scanInterval = 10000;
|
||||
document.getElementById("status_all").innerHTML = "Scan intarvel set to " + scanInterval;
|
||||
//~ document.getElementById("status_all").innerHTML = "Scan interval set to " + scanInterval;
|
||||
status_all = "Scan interval set to " + scanInterval;
|
||||
}
|
||||
document.getElementById("status_all").innerHTML = host_up.length + " client(s).";
|
||||
//~ document.getElementById("status_all").innerHTML = host_up.length + " client(s).";
|
||||
status_all = host_up.length + " client(s).";
|
||||
break;
|
||||
case "/browse":
|
||||
case "/browse_local":
|
||||
var html_table = "<table>" +
|
||||
"<tr>" +
|
||||
"<th>Filename</th>" +
|
||||
|
@ -299,6 +309,47 @@ function parseResult(command, infos_array) {
|
|||
};
|
||||
};
|
||||
break;
|
||||
case "/all/browse":
|
||||
for (var i=0, l=infos_array.length; i<l; i++) {
|
||||
hosts = Object.keys(infos_array[i]);
|
||||
//~ console.log(keys);
|
||||
//~ var html_table = "<table id='file_sel_" + hosts + "'>" +
|
||||
//~ "<tr>" +
|
||||
//~ "<th>Filename</th>" +
|
||||
//"<th>Size</th>" +
|
||||
//~ "</tr>";
|
||||
for ( var j=0, k=hosts.length;j<k;j++ ) {
|
||||
keys_ = Object.keys(infos_array[i][hosts[j]]);
|
||||
//~ console.log(infos_array[i][hosts[j]]);
|
||||
for ( var m=0, n=keys_.length;m<n;m++ ) {
|
||||
item_meta = infos_array[i][hosts[j]][keys_[m]];
|
||||
//~ console.log(item_meta);
|
||||
//~ html_table += "<tr>" +
|
||||
//~ "<td class='.file_selection'>" + item_meta["name"] + "</td>" +
|
||||
//"<td>" + item_meta["size"] + "</td>" +
|
||||
//~ "</tr>" ;
|
||||
tr = document.createElement("tr");
|
||||
td = document.createElement("td");
|
||||
tr.appendChild(td);
|
||||
tr.setAttribute("class", "file_selection");
|
||||
tr.host = hosts[j];
|
||||
td.innerText = item_meta["name"];
|
||||
tr.addEventListener("click", enqueueFile, false)
|
||||
document.getElementById("file_sel_"+hosts).appendChild(tr);
|
||||
};
|
||||
}
|
||||
//~ html_table += "</table>";
|
||||
//~ document.getElementById("playlist_"+hosts).innerHTML += html_table;
|
||||
//~ fileButtons = document.querySelectorAll('.file_selection');
|
||||
//~ console.log(fileButtons);
|
||||
//~ for (var i=fileButtons.length; i>0; i--) {
|
||||
//~ fileButtons[i].addEventListener('click', selectFile, false);
|
||||
//~ }
|
||||
}
|
||||
break;
|
||||
case "/sync/status":
|
||||
status_all = infos_array;
|
||||
break;
|
||||
}; // End switch case
|
||||
};
|
||||
|
||||
|
@ -321,8 +372,20 @@ function sendCmd(command) {
|
|||
request.send();
|
||||
};
|
||||
|
||||
setInterval( sendCmd, 500, "/all/status");
|
||||
setInterval( sendCmd, 1000, "/all/list");
|
||||
setInterval( sendCmd, scanInterval, "/scan");
|
||||
setInterval( sendCmd, 20000, "/all/rssi");
|
||||
function enqueueFile(evt) {
|
||||
//console.log(evt.currentTarget.innerText + evt.currentTarget.host);
|
||||
sendCmd("/" + evt.currentTarget.host + "/enqueue/" + evt.currentTarget.innerText);
|
||||
};
|
||||
|
||||
function updateStatusAll() {
|
||||
document.getElementById("status_all").innerHTML = status_all;
|
||||
};
|
||||
|
||||
setInterval(sendCmd, 500, "/all/status");
|
||||
setInterval(sendCmd, 1000, "/all/list");
|
||||
//~ setInterval(sendCmd, 3000, "/all/browse");
|
||||
setInterval(sendCmd, scanInterval, "/scan");
|
||||
setInterval(sendCmd, 20000, "/all/rssi");
|
||||
setInterval(updateStatusAll, 1000);
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
body {color:#fff;background-color:#666;margin:0;}
|
||||
div {box-sizing: border-box;}
|
||||
h2 {margin:0;}
|
||||
table {background-color: #555;margin:.5em;max-width:100%;font-size:.9em}
|
||||
table {background-color: #555;margin-left:.5em;max-width:100%;font-size:.9em}
|
||||
td {padding: 0;}
|
||||
th {background-color: #aaa;}
|
||||
tr:nth-child(2n+1) {background-color: #888;}
|
||||
|
@ -87,9 +87,9 @@ tr:nth-child(2n+1) {background-color: #888;}
|
|||
}
|
||||
.btn_txt {display: block;font-size: small;}
|
||||
/*Right column*/
|
||||
.right_col {width: 79.9%;display: inline-block;}
|
||||
.right_col {width: 71%;display: inline-block;}
|
||||
/*Left column*/
|
||||
.left_col {width: 20%;display: inline-block;float: left;clear: left;}
|
||||
.left_col {width: 28%;display: inline-block;float: left;clear: left;}
|
||||
.left_col button {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
|
@ -109,30 +109,38 @@ tr:nth-child(2n+1) {background-color: #888;}
|
|||
}
|
||||
.left_col button:hover .btn_txt {display:block;}
|
||||
.col_1 {
|
||||
width: 40%;
|
||||
float: left;
|
||||
padding: 3% 0 0 5%;
|
||||
}
|
||||
width: 40%;
|
||||
float: left;
|
||||
padding: 3% 0 0 5%;
|
||||
}
|
||||
.col_2 {
|
||||
width: 60%;
|
||||
display: inline-block;
|
||||
clear: right;
|
||||
width: 59%;
|
||||
display: inline-block;
|
||||
clear: right;
|
||||
height: 170px;
|
||||
}
|
||||
.col_2 div {
|
||||
overflow-y: scroll;
|
||||
height: 170px;
|
||||
}
|
||||
.indicator {
|
||||
display:inline-block;
|
||||
background-color: #C32600;
|
||||
margin: 0 0 0 5%;
|
||||
padding: 0.3em;
|
||||
display:inline-block;
|
||||
background-color: #C32600;
|
||||
margin: 0 0 0 5%;
|
||||
padding: 0.3em;
|
||||
}
|
||||
.file_sel {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.wl_indicator {
|
||||
display: inline-block;
|
||||
background-color: #bbb;
|
||||
vertical-align: bottom;
|
||||
margin: 0 1px;
|
||||
padding: 0;
|
||||
height: .5em;
|
||||
width: 5%;
|
||||
display: inline-block;
|
||||
background-color: #bbb;
|
||||
vertical-align: bottom;
|
||||
margin: 0 1px;
|
||||
padding: 0;
|
||||
height: .5em;
|
||||
width: 5%;
|
||||
}
|
||||
#wl_0 {height:.5em;}
|
||||
#wl_1 {height:.65em;}
|
||||
|
|
|
@ -56,7 +56,15 @@
|
|||
<p id="repeat_ind_{{ host }}" class="indicator">Repeat</p>
|
||||
</div>
|
||||
<div class="col_2">
|
||||
<p id="playlist_{{ host }}">{{queue_msgs[1]}}</p>
|
||||
<div>{{queue_msgs[1]}}
|
||||
<div id="playlist_{{ host }}" class="table_cont">
|
||||
<table id="file_sel_{{ host }}">
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right_col">
|
||||
|
|
Loading…
Reference in New Issue