mirror of
https://github.com/PhoenixTwoFive/karaoqueue.git
synced 2025-05-19 11:01:47 +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
|
||||
"version": "0.2.0",
|
||||
"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 (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)",
|
||||
"type": "python",
|
||||
|
22
database.py
22
database.py
@ -23,6 +23,7 @@ def create_entry_table():
|
||||
t = (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))')
|
||||
conn.close()
|
||||
|
||||
def create_list_view():
|
||||
conn = open_db()
|
||||
@ -30,6 +31,7 @@ def create_list_view():
|
||||
SELECT Name, Title, Artist
|
||||
FROM entries, songs
|
||||
WHERE entries.Song_Id=songs.Id""")
|
||||
conn.close()
|
||||
|
||||
def get_list():
|
||||
conn = open_db()
|
||||
@ -37,3 +39,23 @@ def get_list():
|
||||
cur.execute("SELECT * FROM Liste")
|
||||
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 database
|
||||
import os, errno
|
||||
app = Flask(__name__)
|
||||
import json
|
||||
app = Flask(__name__, static_url_path='/static')
|
||||
@app.route("/")
|
||||
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")
|
||||
def index():
|
||||
list = database.get_list()
|
||||
for entry in list:
|
||||
print(entry[0])
|
||||
return str(database.get_list())
|
||||
def songlist():
|
||||
return render_template('songlist.html', list=database.get_song_list())
|
||||
|
||||
@app.route("/api/songs")
|
||||
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__":
|
||||
"""try:
|
||||
@ -24,4 +43,4 @@ if __name__ == "__main__":
|
||||
database.create_entry_table()
|
||||
database.create_list_view()
|
||||
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