Add nice frontend, Add song search, add enqueueing

This commit is contained in:
Phillip Kühne 2019-05-22 03:04:54 +02:00
parent 65287d299b
commit ab1db95d06
8 changed files with 260 additions and 39 deletions

2
.vscode/launch.json vendored
View File

@ -4,7 +4,9 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{"name":"Python: Flask","type":"python","request":"launch","module":"flask","env":{"FLASK_APP":"main.py","FLASK_ENV":"development","FLASK_DEBUG":"1"},"args":["run","--no-debugger","--no-reload"],"jinja":true}, {"name":"Python: Flask","type":"python","request":"launch","module":"flask","env":{"FLASK_APP":"main.py","FLASK_ENV":"development","FLASK_DEBUG":"1"},"args":["run","--no-debugger","--no-reload"],"jinja":true},
{"name":"Python: Flask (with reload)","type":"python","request":"launch","module":"flask","env":{"FLASK_APP":"main.py","FLASK_ENV":"development","FLASK_DEBUG":"1"},"args":["run","--no-debugger"],"jinja":true},
{ {
"name": "Python: Current File (Integrated Terminal)", "name": "Python: Current File (Integrated Terminal)",
"type": "python", "type": "python",

View File

@ -23,6 +23,7 @@ def create_entry_table():
t = (entry_table,) t = (entry_table,)
conn.execute('CREATE TABLE IF NOT EXISTS '+entry_table + conn.execute('CREATE TABLE IF NOT EXISTS '+entry_table +
' (ID INTEGER PRIMARY KEY NOT NULL, Song_Id INTEGER NOT NULL, Name VARCHAR(255))') ' (ID INTEGER PRIMARY KEY NOT NULL, Song_Id INTEGER NOT NULL, Name VARCHAR(255))')
conn.close()
def create_list_view(): def create_list_view():
conn = open_db() conn = open_db()
@ -30,6 +31,7 @@ def create_list_view():
SELECT Name, Title, Artist SELECT Name, Title, Artist
FROM entries, songs FROM entries, songs
WHERE entries.Song_Id=songs.Id""") WHERE entries.Song_Id=songs.Id""")
conn.close()
def get_list(): def get_list():
conn = open_db() conn = open_db()
@ -37,3 +39,23 @@ def get_list():
cur.execute("SELECT * FROM Liste") cur.execute("SELECT * FROM Liste")
return cur.fetchall() return cur.fetchall()
def get_song_list():
conn =open_db()
cur = conn.cursor()
cur.execute("SELECT Title || \" - \" || Artist AS Song, Id FROM songs")
return cur.fetchall()
def get_song_completions(input_string):
conn = open_db()
cur = conn.cursor()
cur.execute("SELECT Title || \" - \" || Artist AS Song, Id FROM songs WHERE Song LIKE '%"+input_string+"%'")
return cur.fetchall()
def add_entry(name,song_id):
conn = open_db()
cur = conn.cursor()
cur.execute(
"INSERT INTO entries (Song_Id,Name) VALUES(?,?);", (song_id,name))
conn.commit()
conn.close()
return

37
main.py
View File

@ -1,18 +1,37 @@
from flask import Flask, render_template from flask import Flask, render_template, Response, abort, request
import helpers import helpers
import database import database
import os, errno import os, errno
app = Flask(__name__) import json
app = Flask(__name__, static_url_path='/static')
@app.route("/") @app.route("/")
def home(): def home():
return render_template('index.html', list=database.get_list()) return render_template('main.html', list=database.get_list())
@app.route('/api/enqueue', methods=['POST'])
def enqueue():
if not request.json:
print(request.data)
abort(400)
name = request.json['name']
song_id = request.json['id']
database.add_entry(name,song_id)
return "OK"
@app.route("/list") @app.route("/list")
def index(): def songlist():
list = database.get_list() return render_template('songlist.html', list=database.get_song_list())
for entry in list:
print(entry[0]) @app.route("/api/songs")
return str(database.get_list()) def songs():
list = database.get_song_list()
return Response(json.dumps(list, ensure_ascii=False).encode('utf-8'), mimetype='text/json')
@app.route("/api/songs/compl/<input_string>")
def get_song_completions(input_string):
list = database.get_song_completions(input_string=input_string)
return Response(json.dumps(list, ensure_ascii=False).encode('utf-8'), mimetype='text/json')
if __name__ == "__main__": if __name__ == "__main__":
"""try: """try:
@ -24,4 +43,4 @@ if __name__ == "__main__":
database.create_entry_table() database.create_entry_table()
database.create_list_view() database.create_list_view()
database.import_songs(helpers.get_songs(helpers.get_catalog_url())) database.import_songs(helpers.get_songs(helpers.get_catalog_url()))
app.run(debug=True) app.run(debug=True, host='0.0.0.0')

3
static/css/style.css Normal file
View File

@ -0,0 +1,3 @@
body {
padding-top: 5rem;
}

76
templates/base.html Normal file
View File

@ -0,0 +1,76 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="favicon.ico">
<title>{% block title %}{% endblock %} - KaraQueue</title>
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<!-- Custom styles for this template -->
<link href="static/css/style.css" rel="stylesheet">
<!-- Material Icons-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="/">KaraQueue</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault"
aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/list">Songsuche</a>
</li>
</ul>
<!--<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>-->
</div>
</nav>
<main role="main" class="container">
{% block content %}{% endblock %}
</main><!-- /.container -->
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f" crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous">
</script>
{% block extrajs %}{% endblock %}
<script>
$(document).ready(function () {
// get current URL path and assign 'active' class
var pathname = window.location.pathname;
$('.navbar-nav > li > a[href="' + pathname + '"]').parent().addClass('active');
})
</script>
</body>
</html>

View File

@ -1,30 +0,0 @@
<!doctype html>
<html>
<body>
<h1>Hello!</h1>
<table>
<tr>
<th scope="col">Name</th>
<th scope="col">Song</th>
<th scope="col">Künstler</th>
</tr>
{% for entry in list: %}
<tr>
<td>
{{ entry[0] }}
</td>
<td>
{{ entry[1] }}
</td>
<td>
{{ entry[2] }}
</td>
</tr>
{% endfor %}
</table>
</body>
</html>

26
templates/main.html Normal file
View File

@ -0,0 +1,26 @@
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
<table class="table">
<tr>
<th scope="col">Name</th>
<th scope="col">Song</th>
<th scope="col">Künstler</th>
</tr>
{% for entry in list: %}
<tr>
<td>
{{ entry[0] }}
</td>
<td>
{{ entry[1] }}
</td>
<td>
{{ entry[2] }}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}

103
templates/songlist.html Normal file
View File

@ -0,0 +1,103 @@
{% extends 'base.html' %}
{% block title %}Songliste{% endblock %}
{% block content %}
<input class="form-control" id="filter" type="text" placeholder="Suchen...">
<table class="table">
<tbody id="songtable">
<!--{% for entry in (): %}
<tr>
<td>
{{ entry[0] }}
</td>
<td>
<button type="button" class="btn btn-primary"><i class="material-icons">queue_music</i></button>
</td>
</tr>
{% endfor %}-->
</tbody>
</table>
<div class="modal fade" id="enqueueModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Auf Liste setzen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="form-group">
<form id="nameForm">
<div class="modal-body">
<label for="singerNameInput">Sängername</label>
<input type="text" class="form-control" id="singerNameInput" placeholder="Max Mustermann"
required>
<input id="selectedId" name="selectedId" type="hidden" value="">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" id="submitSongButton">Anmelden</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extrajs %}
<script>
$(document).ready(function () {
$("#filter").keyup( function () {
var value = $(this).val().toLowerCase();
//alert(value);
if(value.length >= 3) {
$.getJSON("/api/songs/compl/" + value, function (data) {
var items = [];
$.each(data, function (key, val) {
items.push("<tr><td>"+val[0]+`</td>
<td><button type='button' class='btn btn-primary' data-toggle='modal'
data-target='#enqueueModal' onclick='setSelectedId(`+val[1]+`)'><i
class='material-icons'>queue_music</i></button></td>
</tr>`)
});
$("#songtable").html("")
$(items.join("")).appendTo("#songtable");
});
}
});
$("#nameForm").submit( function (e) {
e.preventDefault();
submitModal();
});
});
function enqueue(id,name) {
var data = {
"name": name,
"id": id
}
$.ajax({
type: 'POST',
url: '/api/enqueue',
data: JSON.stringify(data), // or JSON.stringify ({name: 'jonas'}),
contentType: "application/json",
dataType: 'json'
});
}
function setSelectedId(id) {
$("#selectedId").attr("value",id);
}
function submitModal() {
var name = $("#singerNameInput").val();
var id = $("#selectedId").attr("value");
enqueue(id,name);
$("#enqueueModal").modal('hide');
}
</script>
{% endblock %}