diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app.py b/app.py index 74f4eca..2602271 100755 --- a/app.py +++ b/app.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -import sys, os +import sys, os, base64, toml import http.client import xml.etree.ElementTree as ET from flask import Flask, render_template, request, make_response, jsonify @@ -9,21 +9,17 @@ from waitress import serve app = Flask(__name__) -DEBUG = 0 -video_folder = "/home/pi" -media_ext = [ "mp4", "avi", "mkv" ] -# ~ video_folder = "/media/" -## base64 encoded ":secret"" -# import base64 -# passwd = "foo" -# passswd64 = str(base64.b64encode(passwd.encode('utf-8')), 'utf-8') -auth = "OnNlY3JldA==" -cmd_auth = "OnNlY3JldA==" -hosts = [ "10.42.0.135", "10.42.0.156" ] -# VLC http LUA port -port = 8080 -# Clients cmd port -cmd_port = 5000 +# Load config defaults, then look for other config files +app.config.from_file("defaults.toml", load=toml.load) +config_locations = ["./", "~/.", "~/.config/"] +for location in config_locations: + # Optional config files, ~ is expanded to $HOME on *nix, %USERPROFILE% on windows + # ~ app.config.from_file("videopi.toml", load=toml.load, silent=True) + if app.config.from_file(os.path.expanduser( location + "videopi.toml"), load=toml.load, silent=True): + print("Found configuration file in " + os.path.expanduser( location )) + # ~ app.config.from_file(os.path.expanduser("~/.config/videopi.toml"), load=toml.load, silent=True) + +### hosts_available, hosts_unavailable = [],[] @@ -64,6 +60,18 @@ cmd = { } +# Set configuration + +DEBUG = app.config['DEFAULT']['DEBUG'] +media_folder_remote = app.config['DEFAULT']['media_folder_remote'] +media_folder_local = app.config['DEFAULT']['media_folder_local'] +media_ext = app.config['DEFAULT']['media_ext'] +auth = str(base64.b64encode(str(":" + app.config['DEFAULT']['auth']).encode('utf-8')), 'utf-8') +cmd_auth = str(base64.b64encode(str(":" + app.config['DEFAULT']['cmd_auth']).encode('utf-8')), 'utf-8') +hosts = app.config['DEFAULT']['hosts'] +port = app.config['DEFAULT']['port'] +cmd_port = app.config['DEFAULT']['cmd_port'] + # Network/link utilities # https://www.metageek.com/training/resources/understanding-rssi/ @@ -153,7 +161,7 @@ def sendCommand(host, arg0, arg1, arg2): elif arg0 == "seek" : req = req + "&val=" + arg1 elif (arg0 == "enqueue") or (arg0 == "add") : - req = req + "&input=file://" + video_folder + "/" + arg1 + req = req + "&input=file://" + media_folder_remote + "/" + arg1 # Send request conn = http.client.HTTPConnection( host + ":" + str(portl), timeout=3 ) try: @@ -187,14 +195,22 @@ def sendCommand(host, arg0, arg1, arg2): cur_time = int(xml.find('time').text) cur_length_fmtd = sec2min(cur_length) cur_time_fmtd = sec2min(cur_time) + cur_id = int(xml.find('currentplid').text) + cur_pos = xml.find('position').text + cur_loop = xml.find('loop').text + cur_repeat = xml.find('repeat').text response_dict = { 'host': host, 'file': filename, 'time': cur_time_fmtd, 'leng': cur_length_fmtd, - 'pos': xml.find('position').text, - 'loop': xml.find('loop').text, - 'repeat': xml.find('repeat').text, + 'pos': cur_pos, + 'loop': cur_loop, + 'repeat': cur_repeat, + # ~ 'pos': xml.find('position').text, + # ~ 'loop': xml.find('loop').text, + # ~ 'repeat': xml.find('repeat').text, + 'id': cur_id, } return response_dict @@ -248,7 +264,7 @@ def scan(): @app.route("/browse") def browse(): - files = listMediaFiles("../"); + files = listMediaFiles(media_folder_local); return files; diff --git a/defaults.toml b/defaults.toml new file mode 100644 index 0000000..1316eb4 --- /dev/null +++ b/defaults.toml @@ -0,0 +1,12 @@ +[DEFAULT] +DEBUG = 0 +media_folder_local = "~/Videos" +media_folder_remote = "~/Videos" +media_ext = [] +auth = "" +cmd_auth = "" +hosts = [] +# VLC http LUA port +port = 0 +# Clients cmd port +cmd_port = 0 \ No newline at end of file diff --git a/static/script.js b/static/script.js index 4b84966..f96ba56 100644 --- a/static/script.js +++ b/static/script.js @@ -2,7 +2,12 @@ const tl_cont_attr = {id:"tl_cont", ondrop: "drop(event, this)", ondragover:"allowDrop(event)"}; const tl_drag_attr = {id:"tl_drag", draggable:"true", ondragstart:"drag(event, this)"}; +// Config +var timeline_color_cursor = "#FF8839"; +var timeline_color_bg = "#2EB8E6"; + var src_id = ""; +var medias_status = {}; function updatePlaylist(){ var new_list = []; @@ -72,7 +77,17 @@ function adjustTl() { } }; -function addElement(type, attr, meta = [], j = 0){ +function addAttr(id, attr, val , child=-1) { + var elem = document.getElementById(id); + if (child>-1){ + elem = elem.children[child]; + } + var att = document.createAttribute(attr); + att.value = val; + elem.setAttributeNode(att); +}; + +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 " + 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 .btn, .btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} -#master_remote {background-color:#222;min-height: 20em;} +#master_remote { + background: linear-gradient(0deg, #222 10%, #444 80%); + min-height: 20em; +} #master_remote .right_col {background-color:transparent;} -.client_container {border-bottom: #bbb solid 4px;display:none;} +.client_container { + border-bottom: #222 solid 1px; + display:none; + background: linear-gradient(0deg, #999 10%, #666 80%); + } .client_container .button{} /* .timeline {height: 3em;background-color: #0f0;margin: 2em 0;} */ #timeline { - background-color:#ddd; height: 75px; - width:100% + width:100%; + margin-top:1em; } [id^="tl_cont"] { float: left; @@ -32,25 +46,12 @@ tr:nth-child(2n+1) {background-color: #888;} height:75px; line-height: 75px; width:100%; - background-color:#999; + background-color:#1F7B99; } [id^="tl_cont"]:nth-child(2n+1) [id^="tl_drag"] { - background-color:#777; + background-color:#255E70; } -/* -#tl_drag1 {background-color:#486;} -#tl_drag2 {background-color:#a9e;} -#tl_drag3 {background-color:#d53;} -#tl_drag4 {background-color:#ea5;} -#tl_drag5 {background-color:#964;} -#tl_drag6 {background-color:#135;} -#tl_drag7 {background-color:#973;} -#tl_drag8 {background-color:#b26;} -#tl_drag9 {background-color:#fe9;} -#tl_drag10 {background-color:#fe5;} -*/ -.right_col {width: 78%;display: inline-block;background-color:#888;} .client_container:nth-child(2n+1) {background-color:#444;} .command {margin: 0 !important;} .buttons {width:75%;margin:auto;text-align: center;padding: 2em;} @@ -59,7 +60,7 @@ tr:nth-child(2n+1) {background-color: #888;} width:3em; height: 4em; display:inline-block; - padding: 6px 12px; + padding: 0; font-weight: 400; line-height: 1.42857143; text-align: center; @@ -72,15 +73,13 @@ tr:nth-child(2n+1) {background-color: #888;} -moz-user-select: none; -ms-user-select: none; user-select: none; - background-image: none; border: 1px solid transparent; - border-top-color: transparent; - border-right-color: transparent; - border-bottom-color: transparent; - border-left-color: transparent; border-radius: 4px; + background: linear-gradient(0deg, #b9b9b9 10%, #f9f9f9 80%); } .btn_txt {display: block;font-size: small;} +/*Right column*/ +.right_col {width: 79.9%;display: inline-block;} /*Left column*/ .left_col {width: 20%;display: inline-block;float: left;clear: left;} .left_col button { @@ -89,18 +88,36 @@ tr:nth-child(2n+1) {background-color: #888;} padding: 0; line-height: 2em; } -.left_col button .btn_txt {display:none;position: absolute;left: 5%;color:#fff;font-weight:bold;font-size: medium;} +.left_col button .btn_txt { + display:none; + position: relative; + left: 40%; + top:80%; + color:#fff; + font-weight:bold; + font-size: medium; + background-color: #ff3030; + border: 1px solid #fff; + padding: 0 .5%; +} .left_col button:hover .btn_txt {display:initial;} .col_1 { - width: 50%; + width: 40%; float: left; + padding: 3% 0 0 5%; +} } .col_2 { - width: 50%; + width: 60%; display: inline-block; clear: right; } -.indicator {display:inline-block;background-color: #f00;} +.indicator { + display:inline-block; + background-color: #f00; + margin: 0 0 0 5%; + padding: 0.3em; + } .wl_indicator { display: inline-block; background-color: #bbb; @@ -108,9 +125,24 @@ tr:nth-child(2n+1) {background-color: #888;} margin: 0 1px; padding: 0; height: .5em; - width: 1em; + width: 5%; } #wl_0 {height:.5em;} #wl_1 {height:.65em;} #wl_2 {height:.80em;} -#wl_3 {height:.95em;} \ No newline at end of file +#wl_3 {height:.95em;} + + +@media screen and (max-width: 800px) { + table {margin:0} + td {padding:0;} + .btn-group-lg > .btn, .btn-lg { + font-size:14px; + } + .left_col {width: 30%;} + .right_col {width: 69.9%;} + .col_2 { + overflow: scroll; + font-size: .9em; + } +} \ No newline at end of file diff --git a/templates/main.html b/templates/main.html index eb76904..d645720 100644 --- a/templates/main.html +++ b/templates/main.html @@ -1,7 +1,9 @@ RPi Web Server + @@ -28,6 +30,7 @@ +

@@ -35,13 +38,13 @@ {% for host in hosts %}
+

{{ host }}

-

{{ host }}

{{status_message}}

- Signal: + Link: @@ -56,18 +59,6 @@

- diff --git a/videopi.toml b/videopi.toml new file mode 100644 index 0000000..7d0a85a --- /dev/null +++ b/videopi.toml @@ -0,0 +1,12 @@ +[DEFAULT] +DEBUG = 0 +media_folder_local = "../medias" +media_folder_remote = "/home/pi" +media_ext = ["mp4", "avi", "mkv"] +auth = "secret" +cmd_auth = "secret" +hosts = ["10.42.0.135", "10.42.0.156"] +# VLC http LUA port +port = 8080 +# Clients cmd port +cmd_port = 5000 \ No newline at end of file