From df10e08a8f45fa432d9a758b2e75f5bc21ea2c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 12:51:33 +0200 Subject: [PATCH 01/23] Add initial SQL schema for creating SQLite DB --- schema.sql | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 schema.sql diff --git a/schema.sql b/schema.sql new file mode 100644 index 0000000..56c6cd4 --- /dev/null +++ b/schema.sql @@ -0,0 +1,17 @@ +CREATE TABLE IF NOT EXISTS tag ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); + +CREATE TABLE IF NOT EXISTS button ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file TEXT, + checksum TEXT +); + +CREATE TABLE IF NOT EXISTS button_tags ( + fk_tag INTEGER, + fk_button INTEGER, + FOREIGN KEY(fk_tag) REFERENCES tag(id), + FOREIGN KEY(fk_button) REFERENCES button(id) +); From fdcaf3edf7ae6f3426303f75f86b3472789056a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 12:51:58 +0200 Subject: [PATCH 02/23] Ignore SQLite database files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bea195b..7a3ba1a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ # Project specific files config.py +metadata.sqlite* From 1e40ad66619eb5de48dc26b6bad8003ab94ef18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 13:23:02 +0200 Subject: [PATCH 03/23] Implement edit mode --- soundboard.py | 8 +++++++- static/main.css | 22 +++++++++++++++++++++- static/main.js | 2 +- templates/index.html | 7 ++++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/soundboard.py b/soundboard.py index beb27be..81465de 100644 --- a/soundboard.py +++ b/soundboard.py @@ -12,6 +12,7 @@ app.jinja_env.lstrip_blocks = True processlist = [] @app.route("/") +@app.route("/edit") @app.route("/play/") @app.route("/say/", methods=["POST"]) @app.route("/say/") @@ -48,4 +49,9 @@ def index(sound=None, text=None, video=None): if killvideo is not None and killvideo in ["1", "true", "yes"]: subprocess.Popen(["pkill", "-f", "omxplayer"]) - return render_template("index.html", sounds=sounds) + if request.path == "/edit": + edit = True + else: + edit = False + + return render_template("index.html", sounds=sounds, edit=edit) diff --git a/static/main.css b/static/main.css index 5dd5835..6cc1904 100644 --- a/static/main.css +++ b/static/main.css @@ -43,7 +43,7 @@ nav { margin: 1em; } -nav a { +nav > a { background-color: #eee; border: 1px solid #000; border-radius: 5px; @@ -74,6 +74,22 @@ section { cursor: pointer; } +nav .extra { + position: absolute; + padding: 1em; + top: 1em; + right: 1em; +} + +nav .extra > a { + background-color: #2ecc40; + border: 1px solid #000; + border-radius: 5px; + color: #333; + display: inline-block; + padding: 1em; +} + .sound { display: inline-block; } @@ -99,3 +115,7 @@ section { background-color: #ff4136; box-shadow: inset 5px 5px 5px rgba(0, 0, 0, 0.6); } + +.edit { + border: 1px dashed #eee; +} diff --git a/static/main.js b/static/main.js index e2af0a3..ecf48b6 100644 --- a/static/main.js +++ b/static/main.js @@ -10,7 +10,7 @@ ready(function() { hideSections(); var sections = document.querySelectorAll("section"); - var nav = document.querySelectorAll("nav a"); + var nav = document.querySelectorAll("nav > a"); sections[0].style.display = "block"; diff --git a/templates/index.html b/templates/index.html index 9e7b804..5aa2897 100644 --- a/templates/index.html +++ b/templates/index.html @@ -11,12 +11,17 @@ Sounds YouTube Voice + {% if not edit %} + + {% else %} + + {% endif %}
{% for sound in sounds %} - + {% endfor %}
From e2687550f58f41dcb565e46f7a3b94625750ae06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 13:41:34 +0200 Subject: [PATCH 04/23] Split templates for edit page --- soundboard.py | 8 +++++++ templates/base.html | 56 ++++++++++++++++++++++++++++++++++++++++++++ templates/edit.html | 9 +++++++ templates/index.html | 27 +++------------------ 4 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 templates/base.html create mode 100644 templates/edit.html diff --git a/soundboard.py b/soundboard.py index 81465de..aa8704a 100644 --- a/soundboard.py +++ b/soundboard.py @@ -55,3 +55,11 @@ def index(sound=None, text=None, video=None): edit = False return render_template("index.html", sounds=sounds, edit=edit) + +@app.route("/edit/", methods=["GET", "POST"]) +def edit(sound): + if request.method == "POST": + # TODO: Store changes + return redirect("/edit") + + return render_template("edit.html") diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..b7914d8 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,56 @@ + + + + + + WIAI Soundboard + + + + {% block navigation %} + + {% endblock %} + + {% block content %} +
+
+ {% for sound in sounds %} + + {% endfor %} +
+
+
+ + + +
+
+ + +
+
+
+
+ + + + + + + +
+
+ {% endblock %} +
+ + + diff --git a/templates/edit.html b/templates/edit.html new file mode 100644 index 0000000..040b78a --- /dev/null +++ b/templates/edit.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% block navigation %} +{% endblock %} +{% block content %} +
+ + +
+{% endblock %} diff --git a/templates/index.html b/templates/index.html index 5aa2897..4484fd0 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,23 +1,5 @@ - - - - - - WIAI Soundboard - - - - - +{% extends "base.html" %} +{% block content %}
{% for sound in sounds %} @@ -46,7 +28,4 @@
-
- - - +{% endblock %} From ab381d27299734894f11d7f0b4c9fc18252e2b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 16:51:50 +0200 Subject: [PATCH 05/23] Nicer forms --- static/main.css | 24 +++++++++++++++++++++--- templates/edit.html | 25 +++++++++++++++++++++---- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/static/main.css b/static/main.css index 6cc1904..94a6e5c 100644 --- a/static/main.css +++ b/static/main.css @@ -21,7 +21,6 @@ h1 { form { padding: 5px; - text-align: center; } input { @@ -30,11 +29,21 @@ input { border-radius: 5px; color: #eee; margin: 0; - padding: 5px; + padding: 1em; vertical-align: middle; } -label { +.editform { + display: table; + margin-left: auto; + margin-right: auto; +} + +.editform input { + margin: 0.5em; +} + +.youtube label { vertical-align: middle; } @@ -119,3 +128,12 @@ nav .extra > a { .edit { border: 1px dashed #eee; } + +.table-row { + display: table-row; +} + +.table-cell { + display: table-cell; +} + diff --git a/templates/edit.html b/templates/edit.html index 040b78a..39343c4 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -2,8 +2,25 @@ {% block navigation %} {% endblock %} {% block content %} -
- - -
+
+

Filename

+
+
+
+ +
+
+ +
+
+
+
+
+
+ + +
+
+
+
{% endblock %} From 102dd681a082cd766e65e14aff72111f2844922e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 19:13:56 +0200 Subject: [PATCH 06/23] Design nice tag input field --- static/main.css | 35 ++++++++++++++++++++++++++++++----- templates/edit.html | 5 ++++- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/static/main.css b/static/main.css index 94a6e5c..37f47bf 100644 --- a/static/main.css +++ b/static/main.css @@ -29,7 +29,7 @@ input { border-radius: 5px; color: #eee; margin: 0; - padding: 1em; + padding: 5px; vertical-align: middle; } @@ -39,8 +39,34 @@ input { margin-right: auto; } -.editform input { - margin: 0.5em; +.editform input, .tagcontainer { + margin: 5px; +} + +.tagcontainer { + background-color: #666; + border: 1px solid #999; + border-radius: 5px; +} + +.tags span { + background-color: #333; + border-radius: 2px; + font-size: 0.9em; + margin: 5px; + padding: 2px 5px 2px 5px; +} + +.tags, .taginput { + display: inline-block; +} + +.taginput { + background: none; + border: none; + border-radius: 0; + margin: 0 !important; + padding: 5px 5px 5px 0px; } .youtube label { @@ -48,8 +74,8 @@ input { } nav { - text-align: center; margin: 1em; + text-align: center; } nav > a { @@ -136,4 +162,3 @@ nav .extra > a { .table-cell { display: table-cell; } - diff --git a/templates/edit.html b/templates/edit.html index 39343c4..c8f5f88 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -10,7 +10,10 @@
- +
+
Test
+ +
From e9f4f29a87d0acf9aa9ef052400d6ae079107a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 20:37:52 +0200 Subject: [PATCH 07/23] Simplify tag form --- static/main.css | 26 +++--------------- static/main.js | 64 +++++++++++++++++++++++++++++--------------- templates/edit.html | 8 +++--- templates/index.html | 2 +- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/static/main.css b/static/main.css index 37f47bf..5266282 100644 --- a/static/main.css +++ b/static/main.css @@ -39,17 +39,11 @@ input { margin-right: auto; } -.editform input, .tagcontainer { +.editform input { margin: 5px; } -.tagcontainer { - background-color: #666; - border: 1px solid #999; - border-radius: 5px; -} - -.tags span { +.tags li { background-color: #333; border-radius: 2px; font-size: 0.9em; @@ -57,18 +51,6 @@ input { padding: 2px 5px 2px 5px; } -.tags, .taginput { - display: inline-block; -} - -.taginput { - background: none; - border: none; - border-radius: 0; - margin: 0 !important; - padding: 5px 5px 5px 0px; -} - .youtube label { vertical-align: middle; } @@ -100,12 +82,12 @@ section { width: 100%; } -#reset { +.reset { font-size: 2em; padding-left: 5px; } -#reset:hover { +.reset:hover { cursor: pointer; } diff --git a/static/main.js b/static/main.js index ecf48b6..3542316 100644 --- a/static/main.js +++ b/static/main.js @@ -12,7 +12,8 @@ ready(function() { var sections = document.querySelectorAll("section"); var nav = document.querySelectorAll("nav > a"); - sections[0].style.display = "block"; + if (sections.length > 0) + sections[0].style.display = "block"; nav.forEach(function(item) { item.onclick = function(e) { @@ -29,35 +30,54 @@ ready(function() { var searchfield = document.querySelector("#search"); - searchfield.addEventListener("keyup", function() { - console.log("Search!"); + if (searchfield !== null) { + searchfield.addEventListener("keyup", function() { + console.log("Search!"); - var buttons = document.querySelectorAll(".sound"); + var buttons = document.querySelectorAll(".sound"); - buttons.forEach(function(item) { - item.style.display = "inline-block"; + buttons.forEach(function(item) { + item.style.display = "inline-block"; + }); + + buttons.forEach(function(item) { + var name = item.firstChild.innerHTML; + + if (name.toLowerCase().indexOf(searchfield.value.toLowerCase()) === -1) { + item.style.display = "none"; + } + }); }); + } - buttons.forEach(function(item) { - var name = item.firstChild.innerHTML; - - if (name.toLowerCase().indexOf(searchfield.value.toLowerCase()) === -1) { - item.style.display = "none"; - } + var reset = document.querySelector("#sounds .reset"); + + if (reset !== null) { + reset.addEventListener("click", function() { + var buttons = document.querySelectorAll(".sound"); + + buttons.forEach(function(item) { + item.style.display = "inline-block"; + }); + + searchfield.value = ""; }); - }); + } - var reset = document.querySelector("#reset"); + var taginputs = document.querySelectorAll(".taginput"); - reset.addEventListener("click", function() { - var buttons = document.querySelectorAll(".sound"); - - buttons.forEach(function(item) { - item.style.display = "inline-block"; + if (taginputs.length > 0) { + taginputs.forEach(function(taginput) { + taginput.addEventListener("keydown", function(e) { + if (e.target == taginput && (e.which == 13 || e.keyCode == 13)) { + e.preventDefault(); + } else if (e.which == 32 || e.keyCode == 13) { + console.log("Space"); + addTag(e.target); + } + }); }); - - searchfield.value = ""; - }); + } }); function hideSections() { diff --git a/templates/edit.html b/templates/edit.html index c8f5f88..e59ec17 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -10,12 +10,12 @@
-
-
Test
- -
+
+
    +
  • Test
  • +
diff --git a/templates/index.html b/templates/index.html index 4484fd0..84fb9ed 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% block content %}
-
+
{% for sound in sounds %} {% endfor %} From 0026d9cce32d8904379126af2984f28ec4981b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 20:47:59 +0200 Subject: [PATCH 08/23] Fix tag form layout --- templates/edit.html | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/templates/edit.html b/templates/edit.html index e59ec17..f8ac239 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -13,9 +13,14 @@
-
    -
  • Test
  • -
+
+
+
+
    +
  • Test
  • +
+
+
From 600a1875f6f60d2c1872f44932485a77ecfc066f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 21:11:04 +0200 Subject: [PATCH 09/23] Switch from spaces to tabs for indentation --- soundboard.py | 56 +++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/soundboard.py b/soundboard.py index aa8704a..efa7f7f 100644 --- a/soundboard.py +++ b/soundboard.py @@ -17,44 +17,44 @@ processlist = [] @app.route("/say/", methods=["POST"]) @app.route("/say/") def index(sound=None, text=None, video=None): - sounds = [os.fsencode(file).decode() for file in os.listdir(config.path)] - sounds = sorted(sounds) + sounds = [os.fsencode(file).decode() for file in os.listdir(config.path)] + sounds = sorted(sounds) - if sound is not None and sound in sounds: - subprocess.Popen(["omxplayer", os.path.join(config.path, sound).encode("utf-8")], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + if sound is not None and sound in sounds: + subprocess.Popen(["omxplayer", os.path.join(config.path, sound).encode("utf-8")], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - if text is None: - text = request.form.get("text") + if text is None: + text = request.form.get("text") - if text is not None: - voice = request.form.get("voice", default="") - voice = voice if voice.strip() != "" else "DE" - speed = request.form.get("speed", default="") - speed = speed if speed.strip() != "" else "160" - pitch = request.form.get("pitch", default="") - pitch = pitch if pitch.strip() != "" else "50" + if text is not None: + voice = request.form.get("voice", default="") + voice = voice if voice.strip() != "" else "DE" + speed = request.form.get("speed", default="") + speed = speed if speed.strip() != "" else "160" + pitch = request.form.get("pitch", default="") + pitch = pitch if pitch.strip() != "" else "50" - subprocess.Popen(["espeak", "-v", voice, "-s", speed, "-p", pitch, text], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - return redirect("/") + subprocess.Popen(["espeak", "-v", voice, "-s", speed, "-p", pitch, text], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + return redirect("/") - video = request.args.get("video") + video = request.args.get("video") - if video is not None: - url = subprocess.check_output(["youtube-dl", "-g", "-f", "mp4", video]).decode() - subprocess.Popen(["omxplayer", url.split("\n")[1]]) - subprocess.Popen(["omxplayer", "-b", url.split("\n")[0]]) + if video is not None: + url = subprocess.check_output(["youtube-dl", "-g", "-f", "mp4", video]).decode() + subprocess.Popen(["omxplayer", url.split("\n")[1]]) + subprocess.Popen(["omxplayer", "-b", url.split("\n")[0]]) - killvideo = request.args.get("killvideo") + killvideo = request.args.get("killvideo") - if killvideo is not None and killvideo in ["1", "true", "yes"]: - subprocess.Popen(["pkill", "-f", "omxplayer"]) + if killvideo is not None and killvideo in ["1", "true", "yes"]: + subprocess.Popen(["pkill", "-f", "omxplayer"]) - if request.path == "/edit": - edit = True - else: - edit = False + if request.path == "/edit": + edit = True + else: + edit = False - return render_template("index.html", sounds=sounds, edit=edit) + return render_template("index.html", sounds=sounds, edit=edit) @app.route("/edit/", methods=["GET", "POST"]) def edit(sound): From 5535add0797385b73f5fd71a8375890b37a90719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 21:56:46 +0200 Subject: [PATCH 10/23] Add SQLite query for tags with simple view --- config.py.example | 1 + soundboard.py | 32 +++++++++++++++++++++++++++++--- templates/index.html | 5 +++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/config.py.example b/config.py.example index 841b7df..63b42bd 100644 --- a/config.py.example +++ b/config.py.example @@ -1 +1,2 @@ path = "/home/pi/sounds" +db = "metadata.sqlite" diff --git a/soundboard.py b/soundboard.py index efa7f7f..69a470a 100644 --- a/soundboard.py +++ b/soundboard.py @@ -1,7 +1,8 @@ import os import subprocess +import sqlite3 -from flask import Flask, render_template, request, redirect, url_for +from flask import Flask, render_template, request, redirect, url_for, g import config @@ -9,7 +10,30 @@ app = Flask(__name__) app.jinja_env.trim_blocks = True app.jinja_env.lstrip_blocks = True -processlist = [] +# Credits: http://flask.pocoo.org/docs/0.12/patterns/sqlite3/ +def getDB(): + db = getattr(g, "_database", None) + + if db is None: + db = g._database = sqlite3.connect(config.db) + db.row_factory = sqlite3.Row + + return db + +@app.teardown_appcontext +def closeDBConnection(exception): + db = getattr(g, "_database", None) + + if db is not None: + db.close() + +def queryDB(query, args=(), one=False): + cur = getDB().execute(query, args) + result = cur.fetchall() + + cur.close() + + return (result[0] if result else None) if one else result @app.route("/") @app.route("/edit") @@ -20,6 +44,8 @@ def index(sound=None, text=None, video=None): sounds = [os.fsencode(file).decode() for file in os.listdir(config.path)] sounds = sorted(sounds) + tags = queryDB("SELECT name FROM tag") + if sound is not None and sound in sounds: subprocess.Popen(["omxplayer", os.path.join(config.path, sound).encode("utf-8")], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -54,7 +80,7 @@ def index(sound=None, text=None, video=None): else: edit = False - return render_template("index.html", sounds=sounds, edit=edit) + return render_template("index.html", sounds=sounds, tags=tags, edit=edit) @app.route("/edit/", methods=["GET", "POST"]) def edit(sound): diff --git a/templates/index.html b/templates/index.html index 84fb9ed..affb5d2 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2,6 +2,11 @@ {% block content %}
+
    + {% for tag in tags %} +
  • {{ tag.name }}
  • + {% endfor %} +
{% for sound in sounds %} {% endfor %} From cc7ed0daf12129c60d78f662a3290a7db5601123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 22:03:50 +0200 Subject: [PATCH 11/23] Remove debug print in search --- static/main.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/main.js b/static/main.js index 3542316..198de5a 100644 --- a/static/main.js +++ b/static/main.js @@ -32,8 +32,6 @@ ready(function() { if (searchfield !== null) { searchfield.addEventListener("keyup", function() { - console.log("Search!"); - var buttons = document.querySelectorAll(".sound"); buttons.forEach(function(item) { From 35e6337d2005a69db2a6f4eb2c8f8161aec86872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Tue, 18 Jul 2017 22:12:00 +0200 Subject: [PATCH 12/23] Style tag list for button view --- static/main.css | 12 ++++++++++++ templates/index.html | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/static/main.css b/static/main.css index 5266282..4f61fcb 100644 --- a/static/main.css +++ b/static/main.css @@ -44,13 +44,25 @@ input { } .tags li { + display: inline-block; + list-style-type: none; +} + +.tags li a { background-color: #333; + border: 1px solid #999; border-radius: 2px; + color: #999; font-size: 0.9em; margin: 5px; padding: 2px 5px 2px 5px; } +.tags li a:hover { + background-color: #eee; + color: #333; +} + .youtube label { vertical-align: middle; } diff --git a/templates/index.html b/templates/index.html index affb5d2..d418a40 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2,9 +2,9 @@ {% block content %}
-
    +
      {% for tag in tags %} -
    • {{ tag.name }}
    • +
    • {{ tag.name }}
    • {% endfor %}
    {% for sound in sounds %} From eb549417db14d52994724073f74fc188e21ff38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Wed, 19 Jul 2017 11:33:12 +0200 Subject: [PATCH 13/23] Sort tags alphabetically --- soundboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soundboard.py b/soundboard.py index 69a470a..f6e1226 100644 --- a/soundboard.py +++ b/soundboard.py @@ -44,7 +44,7 @@ def index(sound=None, text=None, video=None): sounds = [os.fsencode(file).decode() for file in os.listdir(config.path)] sounds = sorted(sounds) - tags = queryDB("SELECT name FROM tag") + tags = queryDB("SELECT name FROM tag ORDER BY name COLLATE NOCASE") if sound is not None and sound in sounds: subprocess.Popen(["omxplayer", os.path.join(config.path, sound).encode("utf-8")], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) From ce7f55771caf66c25833ccc2a915b7b65203d388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Thu, 27 Jul 2017 17:17:13 +0200 Subject: [PATCH 14/23] Ensure relative paths to DB are inside project --- soundboard.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soundboard.py b/soundboard.py index f6e1226..f3a9f9d 100644 --- a/soundboard.py +++ b/soundboard.py @@ -1,4 +1,5 @@ import os +import sys import subprocess import sqlite3 @@ -15,7 +16,12 @@ def getDB(): db = getattr(g, "_database", None) if db is None: - db = g._database = sqlite3.connect(config.db) + if os.path.isabs(config.db): + dbPath = config.db + else: + dbPath = os.path.join(sys.path[0], config.db) + + db = g._database = sqlite3.connect(dbPath) db.row_factory = sqlite3.Row return db From 80e0ba439bf3b2039a85334a2d38944a40ba293a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Fri, 3 Nov 2017 16:17:10 +0100 Subject: [PATCH 15/23] Rework edit form w/ checkboxes, filter and DB tags --- soundboard.py | 4 +++- static/main.css | 29 +++++++++++++++++++++++++++++ static/main.js | 40 +++++++++++++++++++++++----------------- templates/edit.html | 34 +++++++++------------------------- 4 files changed, 64 insertions(+), 43 deletions(-) diff --git a/soundboard.py b/soundboard.py index f3a9f9d..cc0da8a 100644 --- a/soundboard.py +++ b/soundboard.py @@ -94,4 +94,6 @@ def edit(sound): # TODO: Store changes return redirect("/edit") - return render_template("edit.html") + tags = queryDB("SELECT name FROM tag ORDER BY name COLLATE NOCASE") + + return render_template("edit.html", sound=sound, tags=tags) diff --git a/static/main.css b/static/main.css index 4f61fcb..a70b8f7 100644 --- a/static/main.css +++ b/static/main.css @@ -43,6 +43,35 @@ input { margin: 5px; } +.editform input[type="text"] { + display: block; +} + +.editform input[type="checkbox"] { + display: block; + float: left; + height: 15px; + margin: 5px; + width: 15px; +} + +.editform .tags li { + clear: left; + display: block; + line-height: 20px; + vertical-align: middle; +} + +.editform .tags li span { + display: inline-block; + line-height: 20px; + vertical-align: middle; +} + +.tags { + padding-left: 0; +} + .tags li { display: inline-block; list-style-type: none; diff --git a/static/main.js b/static/main.js index 198de5a..b0fa63e 100644 --- a/static/main.js +++ b/static/main.js @@ -30,23 +30,8 @@ ready(function() { var searchfield = document.querySelector("#search"); - if (searchfield !== null) { - searchfield.addEventListener("keyup", function() { - var buttons = document.querySelectorAll(".sound"); - - buttons.forEach(function(item) { - item.style.display = "inline-block"; - }); - - buttons.forEach(function(item) { - var name = item.firstChild.innerHTML; - - if (name.toLowerCase().indexOf(searchfield.value.toLowerCase()) === -1) { - item.style.display = "none"; - } - }); - }); - } + filter(searchfield, ".sound", "inline-block"); + filter(searchfield, ".tag", "block"); var reset = document.querySelector("#sounds .reset"); @@ -78,6 +63,27 @@ ready(function() { } }); +function filter(searchfield, itemSelector, unHideStyle) { + if (searchfield !== null) { + searchfield.addEventListener("keyup", function() { + var items = document.querySelectorAll(itemSelector); + + items.forEach(function(item) { + item.style.display = unHideStyle; + }); + + items.forEach(function(item) { + var name = item.firstChild.innerHTML; + console.log(name); + + if (name.toLowerCase().indexOf(searchfield.value.toLowerCase()) === -1) { + item.style.display = "none"; + } + }); + }); + } +} + function hideSections() { var sections = document.querySelectorAll("section"); diff --git a/templates/edit.html b/templates/edit.html index f8ac239..d9182ad 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -3,32 +3,16 @@ {% endblock %} {% block content %}
    -

    Filename

    +

    Edit {{ sound }}

    -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
      -
    • Test
    • -
    -
    -
    -
    -
    -
    -
    - - -
    -
    + +
      + {% for tag in tags %} +
    • {{ tag.name }}
    • + {% endfor %} +
    + +
    {% endblock %} From 03be396c873eac1a0fd035e765f350f2b10e161e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Fri, 3 Nov 2017 17:38:48 +0100 Subject: [PATCH 16/23] Change SQL query to get already set tags --- soundboard.py | 20 +++++++++++++++++++- templates/edit.html | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/soundboard.py b/soundboard.py index cc0da8a..f104b1b 100644 --- a/soundboard.py +++ b/soundboard.py @@ -94,6 +94,24 @@ def edit(sound): # TODO: Store changes return redirect("/edit") - tags = queryDB("SELECT name FROM tag ORDER BY name COLLATE NOCASE") + tags = queryDB("""\ +SELECT + tag.name, + checked.id IS NOT NULL AS checked +FROM + tag +LEFT OUTER JOIN ( + SELECT + tag.id + FROM + tag + JOIN + button_tags + ON + fk_tag = tag.id + WHERE fk_button = 1 +) AS checked +ON tag.id = checked.id""") + print(tags) return render_template("edit.html", sound=sound, tags=tags) diff --git a/templates/edit.html b/templates/edit.html index d9182ad..2c4ceb7 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -8,7 +8,7 @@
      {% for tag in tags %} -
    • {{ tag.name }}
    • +
    • {{ tag.name }}
    • {% endfor %}
    From d52dede612fdda408cc0ab525cc623ca2661c2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Fri, 3 Nov 2017 17:55:11 +0100 Subject: [PATCH 17/23] Fix SQL query for tag to include button name --- soundboard.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/soundboard.py b/soundboard.py index f104b1b..8e365b8 100644 --- a/soundboard.py +++ b/soundboard.py @@ -109,9 +109,16 @@ LEFT OUTER JOIN ( button_tags ON fk_tag = tag.id - WHERE fk_button = 1 + WHERE fk_button = ( + SELECT + button.id + FROM + button + WHERE + button.file = ? + ) ) AS checked -ON tag.id = checked.id""") +ON tag.id = checked.id""", (sound,)) print(tags) return render_template("edit.html", sound=sound, tags=tags) From 99bb026a569eeb1fb638a80643d993eafa200430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Sat, 4 Nov 2017 11:47:16 +0100 Subject: [PATCH 18/23] Fix alignment of checkboxes for edit form --- static/main.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/static/main.css b/static/main.css index a70b8f7..4d209c9 100644 --- a/static/main.css +++ b/static/main.css @@ -63,9 +63,7 @@ input { } .editform .tags li span { - display: inline-block; - line-height: 20px; - vertical-align: middle; + line-height: 25px; } .tags { From a6a1b04a8ed727bc5c075cfdb9fd8c0c2e7699d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Sat, 4 Nov 2017 11:58:11 +0100 Subject: [PATCH 19/23] Fix button spacing and adjust it to edit mode --- static/main.css | 4 ++++ templates/index.html | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/static/main.css b/static/main.css index 4d209c9..40aa431 100644 --- a/static/main.css +++ b/static/main.css @@ -148,6 +148,8 @@ nav .extra > a { .sound { display: inline-block; + border: 1px solid transparent; + margin: 5px; } .sound a { @@ -174,6 +176,8 @@ nav .extra > a { .edit { border: 1px dashed #eee; + box-sizing: border-box; + margin: 5px; } .table-row { diff --git a/templates/index.html b/templates/index.html index d418a40..3676f82 100644 --- a/templates/index.html +++ b/templates/index.html @@ -7,9 +7,9 @@
  • {{ tag.name }}
  • {% endfor %}
- {% for sound in sounds %} - - {% endfor %} + {% for sound in sounds %}{% endfor %}
From 50684883869cc64559ad2ff2154e5cc99230454c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Sat, 4 Nov 2017 12:01:51 +0100 Subject: [PATCH 20/23] Disable button hover effect when in edit mode --- static/main.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/main.css b/static/main.css index 40aa431..af3478c 100644 --- a/static/main.css +++ b/static/main.css @@ -180,6 +180,10 @@ nav .extra > a { margin: 5px; } +.sound.edit a:hover { + box-shadow: inset -5px -5px 5px rgba(0, 0, 0, 0.6); +} + .table-row { display: table-row; } From b4e795417bed19e0627f39db41ef57d9858fd5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Sat, 4 Nov 2017 12:03:12 +0100 Subject: [PATCH 21/23] Remove print statement used for debugging --- soundboard.py | 1 - 1 file changed, 1 deletion(-) diff --git a/soundboard.py b/soundboard.py index 8e365b8..31c1d0f 100644 --- a/soundboard.py +++ b/soundboard.py @@ -119,6 +119,5 @@ LEFT OUTER JOIN ( ) ) AS checked ON tag.id = checked.id""", (sound,)) - print(tags) return render_template("edit.html", sound=sound, tags=tags) From 92f869ce6b5cd9b432307a7795ec8367548592dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Sat, 4 Nov 2017 16:57:05 +0100 Subject: [PATCH 22/23] Store changes to tags in metadata DB --- schema.sql | 3 ++- soundboard.py | 27 +++++++++++++++++++++++---- templates/edit.html | 6 +++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/schema.sql b/schema.sql index 56c6cd4..92f2c6c 100644 --- a/schema.sql +++ b/schema.sql @@ -13,5 +13,6 @@ CREATE TABLE IF NOT EXISTS button_tags ( fk_tag INTEGER, fk_button INTEGER, FOREIGN KEY(fk_tag) REFERENCES tag(id), - FOREIGN KEY(fk_button) REFERENCES button(id) + FOREIGN KEY(fk_button) REFERENCES button(id), + PRIMARY KEY(fk_tag, fk_button) ); diff --git a/soundboard.py b/soundboard.py index 31c1d0f..83ed7d5 100644 --- a/soundboard.py +++ b/soundboard.py @@ -90,12 +90,9 @@ def index(sound=None, text=None, video=None): @app.route("/edit/", methods=["GET", "POST"]) def edit(sound): - if request.method == "POST": - # TODO: Store changes - return redirect("/edit") - tags = queryDB("""\ SELECT + tag.id, tag.name, checked.id IS NOT NULL AS checked FROM @@ -120,4 +117,26 @@ LEFT OUTER JOIN ( ) AS checked ON tag.id = checked.id""", (sound,)) + if request.method == "POST": + if not request.form.get("cancel"): + buttonId = queryDB("SELECT id FROM button WHERE file = ?", (sound,), True) + + if buttonId is None: + queryDB("INSERT INTO button (file) VALUES (?)", (sound,)) + getDB().commit() + + buttonId = queryDB("SELECT id FROM button WHERE file = ?", (sound,), True) + + for tag in tags: + checkbox = 1 if request.form.get("cb-{}".format(tag["name"])) else 0 + + if tag["checked"] < checkbox: + queryDB("INSERT OR REPLACE INTO button_tags (fk_button, fk_tag) VALUES (?, ?)", (buttonId[0], tag["id"])) + getDB().commit() + elif tag["checked"] > checkbox: + queryDB("DELETE FROM button_tags WHERE fk_button = ? AND fk_tag = ?", (buttonId[0], tag["id"])) + getDB().commit() + + return redirect("/edit") + return render_template("edit.html", sound=sound, tags=tags) diff --git a/templates/edit.html b/templates/edit.html index 2c4ceb7..62f4a45 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -8,11 +8,11 @@
    {% for tag in tags %} -
  • {{ tag.name }}
  • +
  • {{ tag.name }}
  • {% endfor %}
- - + +
{% endblock %} From fad8a1b1f8564df1b10066a3039ba3fd3734c251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCller?= Date: Sat, 4 Nov 2017 17:06:02 +0100 Subject: [PATCH 23/23] Rename filter function to searchFilter --- static/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/static/main.js b/static/main.js index b0fa63e..d162601 100644 --- a/static/main.js +++ b/static/main.js @@ -30,8 +30,8 @@ ready(function() { var searchfield = document.querySelector("#search"); - filter(searchfield, ".sound", "inline-block"); - filter(searchfield, ".tag", "block"); + searchFilter(searchfield, ".sound", "inline-block"); + searchFilter(searchfield, ".tag", "block"); var reset = document.querySelector("#sounds .reset"); @@ -63,7 +63,7 @@ ready(function() { } }); -function filter(searchfield, itemSelector, unHideStyle) { +function searchFilter(searchfield, itemSelector, unHideStyle) { if (searchfield !== null) { searchfield.addEventListener("keyup", function() { var items = document.querySelectorAll(itemSelector);