mirror of
https://github.com/PhoenixTwoFive/karaoqueue.git
synced 2025-05-19 19:11:49 +02:00
Add nice frontend, Add song search, add enqueueing
This commit is contained in:
parent
65287d299b
commit
ab1db95d06
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -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",
|
||||||
|
22
database.py
22
database.py
@ -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
37
main.py
@ -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
3
static/css/style.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
body {
|
||||||
|
padding-top: 5rem;
|
||||||
|
}
|
76
templates/base.html
Normal file
76
templates/base.html
Normal 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>
|
@ -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
26
templates/main.html
Normal 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
103
templates/songlist.html
Normal 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">×</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 %}
|
Loading…
x
Reference in New Issue
Block a user