Add video thumbnail serving
This commit is contained in:
parent
4b95a8130e
commit
4af1885757
49
app.py
49
app.py
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# pilpil-client 0.1
|
# pilpil-client 0.1
|
||||||
# abelliqueux <contact@arthus.net>
|
# abelliqueux <contact@arthus.net>
|
||||||
from flask import Flask, flash, request, redirect, url_for
|
from flask import Flask, flash, request, redirect, url_for, send_file
|
||||||
from flask_httpauth import HTTPBasicAuth
|
from flask_httpauth import HTTPBasicAuth
|
||||||
import gettext
|
import gettext
|
||||||
import os
|
import os
|
||||||
|
@ -23,8 +23,8 @@ app.config.from_file("defaults.toml", load=toml.load)
|
||||||
config_locations = ["./", "~/.", "~/.config/"]
|
config_locations = ["./", "~/.", "~/.config/"]
|
||||||
for location in config_locations:
|
for location in config_locations:
|
||||||
# Optional config files, ~ is expanded to $HOME on *nix, %USERPROFILE% on windows
|
# Optional config files, ~ is expanded to $HOME on *nix, %USERPROFILE% on windows
|
||||||
if app.config.from_file(os.path.expanduser( location + "pilpil-client.toml"), load=toml.load, silent=True):
|
if app.config.from_file(os.path.expanduser(location + "pilpil-client.toml"), load=toml.load, silent=True):
|
||||||
print(_("Found configuration file in {}").format( os.path.expanduser(location)))
|
print(_("Found configuration file in {}").format(os.path.expanduser(location)))
|
||||||
|
|
||||||
upload_folder = os.path.expanduser(app.config['DEFAULT']['media_folder_local'])
|
upload_folder = os.path.expanduser(app.config['DEFAULT']['media_folder_local'])
|
||||||
media_exts = app.config['DEFAULT']['media_exts']
|
media_exts = app.config['DEFAULT']['media_exts']
|
||||||
|
@ -32,6 +32,7 @@ HTTP_secret = str(app.config['DEFAULT']['auth'])
|
||||||
debug = app.config['DEFAULT']['debug']
|
debug = app.config['DEFAULT']['debug']
|
||||||
useSSL = app.config['DEFAULT']['useSSL']
|
useSSL = app.config['DEFAULT']['useSSL']
|
||||||
rssi_signal = 0
|
rssi_signal = 0
|
||||||
|
thumbnails_folder = "thumb"
|
||||||
|
|
||||||
# HTTP upload settings
|
# HTTP upload settings
|
||||||
app.config['UPLOAD_FOLDER'] = upload_folder
|
app.config['UPLOAD_FOLDER'] = upload_folder
|
||||||
|
@ -51,6 +52,7 @@ if useSSL:
|
||||||
if debug:
|
if debug:
|
||||||
print(HTTP_url_scheme)
|
print(HTTP_url_scheme)
|
||||||
|
|
||||||
|
|
||||||
@auth.verify_password
|
@auth.verify_password
|
||||||
def verify_password(username, password):
|
def verify_password(username, password):
|
||||||
'''
|
'''
|
||||||
|
@ -59,6 +61,7 @@ def verify_password(username, password):
|
||||||
if username in users and check_password_hash(users.get(username), password):
|
if username in users and check_password_hash(users.get(username), password):
|
||||||
return username
|
return username
|
||||||
|
|
||||||
|
|
||||||
def allowed_ext(filename):
|
def allowed_ext(filename):
|
||||||
'''
|
'''
|
||||||
Check if filename has an allowed extension.
|
Check if filename has an allowed extension.
|
||||||
|
@ -66,9 +69,10 @@ def allowed_ext(filename):
|
||||||
# Check for dot in filename
|
# Check for dot in filename
|
||||||
if "." in filename:
|
if "." in filename:
|
||||||
# Split from right at first dot to find ext and allow files with "." in name
|
# Split from right at first dot to find ext and allow files with "." in name
|
||||||
if filename.rsplit(".",1)[-1] in media_exts:
|
if filename.rsplit(".", 1)[-1] in media_exts:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def XMLify(string, child_node_name="child"):
|
def XMLify(string, child_node_name="child"):
|
||||||
'''
|
'''
|
||||||
'''
|
'''
|
||||||
|
@ -76,7 +80,8 @@ def XMLify(string, child_node_name="child"):
|
||||||
if debug:
|
if debug:
|
||||||
print("<{0}><{1}>{2}</{1}></{0}>".format(root_element, child_node_name, string))
|
print("<{0}><{1}>{2}</{1}></{0}>".format(root_element, child_node_name, string))
|
||||||
return "<{0}><{1}>{2}</{1}></{0}>".format(root_element, child_node_name, string)
|
return "<{0}><{1}>{2}</{1}></{0}>".format(root_element, child_node_name, string)
|
||||||
|
|
||||||
|
|
||||||
def get_RSSI():
|
def get_RSSI():
|
||||||
'''
|
'''
|
||||||
Get wireless signal level to AP
|
Get wireless signal level to AP
|
||||||
|
@ -90,13 +95,15 @@ def get_RSSI():
|
||||||
print(rssi_signal)
|
print(rssi_signal)
|
||||||
return XMLify(rssi_signal, child_node_name="rssi")
|
return XMLify(rssi_signal, child_node_name="rssi")
|
||||||
|
|
||||||
|
|
||||||
def running_on_rpi():
|
def running_on_rpi():
|
||||||
with open("/proc/cpuinfo", "r") as wl:
|
with open("/proc/cpuinfo", "r") as wl:
|
||||||
for line in wl:
|
for line in wl:
|
||||||
if line.lower().find("raspberry") > 0 :
|
if line.lower().find("raspberry") > 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def led_init():
|
def led_init():
|
||||||
'''
|
'''
|
||||||
Set ACT and PWR leds trigger and turn them off
|
Set ACT and PWR leds trigger and turn them off
|
||||||
|
@ -106,6 +113,7 @@ def led_init():
|
||||||
led_set(0, 0)
|
led_set(0, 0)
|
||||||
led_set(1, 0)
|
led_set(1, 0)
|
||||||
|
|
||||||
|
|
||||||
def led_set(led_id, state):
|
def led_set(led_id, state):
|
||||||
'''
|
'''
|
||||||
Set led with id led_id to state.
|
Set led with id led_id to state.
|
||||||
|
@ -114,6 +122,7 @@ def led_set(led_id, state):
|
||||||
# state : 0 = off, 1 = on
|
# state : 0 = off, 1 = on
|
||||||
os.system("echo {} | sudo tee /sys/class/leds/led{}/brightness".format(str(state), str(led_id)))
|
os.system("echo {} | sudo tee /sys/class/leds/led{}/brightness".format(str(state), str(led_id)))
|
||||||
|
|
||||||
|
|
||||||
def blink_pi(n):
|
def blink_pi(n):
|
||||||
'''
|
'''
|
||||||
Blink ACT and PWR leds altenatively n times to allow physical identification.
|
Blink ACT and PWR leds altenatively n times to allow physical identification.
|
||||||
|
@ -130,6 +139,7 @@ def blink_pi(n):
|
||||||
led_set(1, 0)
|
led_set(1, 0)
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|
||||||
|
|
||||||
def thread_blink():
|
def thread_blink():
|
||||||
'''
|
'''
|
||||||
Blink leds as a thread to avoid blocking.
|
Blink leds as a thread to avoid blocking.
|
||||||
|
@ -137,12 +147,13 @@ def thread_blink():
|
||||||
th = threading.Thread(target=blink_pi, args=(16,))
|
th = threading.Thread(target=blink_pi, args=(16,))
|
||||||
th.start()
|
th.start()
|
||||||
|
|
||||||
|
|
||||||
def list_media_files(folder):
|
def list_media_files(folder):
|
||||||
'''
|
'''
|
||||||
List files in folder which extension is allowed (exists in media_exts).
|
List files in folder which extension is allowed (exists in media_exts).
|
||||||
'''
|
'''
|
||||||
if os.path.exists(folder):
|
if os.path.exists(folder):
|
||||||
files = os.listdir(folder);
|
files = os.listdir(folder)
|
||||||
medias = []
|
medias = []
|
||||||
for fd in files:
|
for fd in files:
|
||||||
if len(fd.split('.')) > 1:
|
if len(fd.split('.')) > 1:
|
||||||
|
@ -152,16 +163,25 @@ def list_media_files(folder):
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def generate_thumbnails():
|
||||||
|
media_files = list_media_files(upload_folder)
|
||||||
|
for media in media_files:
|
||||||
|
subprocess.call(['ffmpeg', '-i', upload_folder + "/" + media, '-q:v', '30', '-s' , '160x120' , '-vf' , 'boxblur=2' , '-ss', '00:00:01.000', '-vframes', '1', thumbnails_folder + "/" + media + ".jpg", "-y"])
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def main():
|
def main():
|
||||||
return _("Nothing to see here !")
|
return _("Nothing to see here !")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/rssi")
|
@app.route("/rssi")
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def rssi():
|
def rssi():
|
||||||
return get_RSSI()
|
return get_RSSI()
|
||||||
|
|
||||||
|
|
||||||
@app.route("/blink")
|
@app.route("/blink")
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def blink():
|
def blink():
|
||||||
|
@ -169,6 +189,7 @@ def blink():
|
||||||
thread_blink()
|
thread_blink()
|
||||||
return _("Blinkin")
|
return _("Blinkin")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/reboot")
|
@app.route("/reboot")
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def reboot():
|
def reboot():
|
||||||
|
@ -176,6 +197,7 @@ def reboot():
|
||||||
print(stdout)
|
print(stdout)
|
||||||
return _("Rebooting...")
|
return _("Rebooting...")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/poweroff")
|
@app.route("/poweroff")
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def shutdown():
|
def shutdown():
|
||||||
|
@ -185,6 +207,7 @@ def shutdown():
|
||||||
|
|
||||||
# File upload
|
# File upload
|
||||||
|
|
||||||
|
|
||||||
@app.route('/upload', methods=['GET', 'POST'])
|
@app.route('/upload', methods=['GET', 'POST'])
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def upload_file(over_write=1):
|
def upload_file(over_write=1):
|
||||||
|
@ -211,7 +234,17 @@ def upload_file(over_write=1):
|
||||||
return "File exists, skipping..."
|
return "File exists, skipping..."
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/thumb/<media>")
|
||||||
|
@auth.login_required
|
||||||
|
def get_thumbnail(media):
|
||||||
|
if media:
|
||||||
|
return send_file( thumbnails_folder + os.sep + media + ".jpg", mimetype='image/jpg')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
generate_thumbnails()
|
||||||
# Turn ACT and POW leds off on start
|
# Turn ACT and POW leds off on start
|
||||||
if running_on_rpi():
|
if running_on_rpi():
|
||||||
led_init()
|
led_init()
|
||||||
|
|
Loading…
Reference in New Issue