mirror of
https://github.com/PhoenixTwoFive/karaoqueue.git
synced 2025-05-21 12:01:49 +02:00
Add list of played songs
This commit is contained in:
parent
438bcffd0b
commit
5f551ac092
3
.gitignore
vendored
3
.gitignore
vendored
@ -130,5 +130,4 @@ dmypy.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Test data
|
||||
test.db
|
||||
config.json
|
||||
data/
|
||||
|
@ -7,6 +7,7 @@ from io import StringIO
|
||||
song_table = "songs"
|
||||
entry_table = "entries"
|
||||
index_label = "Id"
|
||||
done_table = "done_songs"
|
||||
|
||||
def open_db():
|
||||
conn = sqlite3.connect("data/test.db")
|
||||
@ -28,14 +29,19 @@ def import_songs(song_csv):
|
||||
|
||||
def create_entry_table():
|
||||
conn = open_db()
|
||||
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_done_song_table():
|
||||
conn = open_db()
|
||||
conn.execute('CREATE TABLE IF NOT EXISTS '+done_table +
|
||||
' (Song_Id INTEGER PRIMARY KEY NOT NULL, Plays INTEGER)')
|
||||
conn.close()
|
||||
|
||||
def create_song_table():
|
||||
conn = open_db()
|
||||
t = (entry_table,)
|
||||
conn.execute("CREATE TABLE IF NOT EXISTS \""+song_table+"""\" (
|
||||
"Id" INTEGER,
|
||||
"Title" TEXT,
|
||||
@ -52,21 +58,37 @@ def create_song_table():
|
||||
def create_list_view():
|
||||
conn = open_db()
|
||||
conn.execute("""CREATE VIEW IF NOT EXISTS [Liste] AS
|
||||
SELECT Name, Title, Artist, entries.Id
|
||||
SELECT Name, Title, Artist, entries.Id, songs.Id
|
||||
FROM entries, songs
|
||||
WHERE entries.Song_Id=songs.Id""")
|
||||
conn.close()
|
||||
|
||||
|
||||
def create_done_song_view():
|
||||
conn = open_db()
|
||||
conn.execute("""CREATE VIEW IF NOT EXISTS [Abspielliste] AS
|
||||
SELECT Artist || \" - \" || Title AS Song, Plays AS Wiedergaben
|
||||
FROM songs, done_songs
|
||||
WHERE done_songs.Song_Id=songs.Id""")
|
||||
conn.close()
|
||||
|
||||
def get_list():
|
||||
conn = open_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT * FROM Liste")
|
||||
return cur.fetchall()
|
||||
|
||||
|
||||
def get_played_list():
|
||||
conn = open_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT * FROM Abspielliste")
|
||||
return cur.fetchall()
|
||||
|
||||
def get_song_list():
|
||||
conn =open_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT Title || \" - \" || Artist AS Song, Id FROM songs")
|
||||
cur.execute("SELECT Artist || \" - \" || Title AS Song, Id FROM songs")
|
||||
return cur.fetchall()
|
||||
|
||||
def get_song_completions(input_string):
|
||||
@ -86,6 +108,30 @@ def add_entry(name,song_id):
|
||||
conn.close()
|
||||
return
|
||||
|
||||
def add_sung_song(entry_id):
|
||||
conn = open_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""SELECT Song_Id FROM entries WHERE Id=?""",(entry_id,))
|
||||
song_id = cur.fetchone()[0]
|
||||
cur.execute("""INSERT OR REPLACE INTO done_songs (Song_Id, Plays)
|
||||
VALUES("""+str(song_id)+""",
|
||||
COALESCE(
|
||||
(SELECT Plays FROM done_songs
|
||||
WHERE Song_Id="""+str(song_id)+"), 0) + 1)"
|
||||
)
|
||||
conn.commit()
|
||||
delete_entry(entry_id)
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
def clear_played_songs():
|
||||
conn = open_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("DELETE FROM done_songs")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
def delete_entry(id):
|
||||
conn = open_db()
|
||||
cur = conn.cursor()
|
||||
|
24
app/main.py
24
app/main.py
@ -29,6 +29,11 @@ def enqueue():
|
||||
def songlist():
|
||||
return render_template('songlist.html', list=database.get_song_list(), auth=basic_auth.authenticate())
|
||||
|
||||
@app.route("/plays")
|
||||
@basic_auth.required
|
||||
def played_list():
|
||||
return render_template('played_list.html', list=database.get_played_list(), auth=basic_auth.authenticate())
|
||||
|
||||
@app.route("/api/songs")
|
||||
def songs():
|
||||
list = database.get_song_list()
|
||||
@ -63,6 +68,23 @@ def delete_entry(entry_id):
|
||||
else:
|
||||
return Response('{"status": "FAIL"}', mimetype='text/json')
|
||||
|
||||
|
||||
@app.route("/api/entries/mark_sung/<entry_id>")
|
||||
@basic_auth.required
|
||||
def mark_sung(entry_id):
|
||||
if database.add_sung_song(entry_id):
|
||||
return Response('{"status": "OK"}', mimetype='text/json')
|
||||
else:
|
||||
return Response('{"status": "FAIL"}', mimetype='text/json')
|
||||
|
||||
@app.route("/api/played/clear")
|
||||
@basic_auth.required
|
||||
def clear_played_songs():
|
||||
if database.clear_played_songs():
|
||||
return Response('{"status": "OK"}', mimetype='text/json')
|
||||
else:
|
||||
return Response('{"status": "FAIL"}', mimetype='text/json')
|
||||
|
||||
@app.route("/api/entries/delete_all")
|
||||
@basic_auth.required
|
||||
def delete_all_entries():
|
||||
@ -81,7 +103,9 @@ def activate_job():
|
||||
helpers.create_data_directory()
|
||||
database.create_entry_table()
|
||||
database.create_song_table()
|
||||
database.create_done_song_table()
|
||||
database.create_list_view()
|
||||
database.create_done_song_view()
|
||||
helpers.setup_config(app)
|
||||
|
||||
|
||||
|
@ -38,3 +38,16 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.admincontrols {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -39,6 +39,11 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/list">Songsuche</a>
|
||||
</li>
|
||||
{% if auth %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/plays">Abspielliste</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<!--<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
@ -79,6 +84,9 @@
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
|
||||
integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"
|
||||
integrity="sha256-4F7e4JsAJyLUdpP7Q8Sah866jCOhv72zU5E8lIRER4w=" crossorigin="anonymous">
|
||||
</script>
|
||||
{% block extrajs %}{% endblock %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
@ -21,7 +21,7 @@
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Song</th>
|
||||
<th scope="col">Künstler</th>
|
||||
<th scope="col">Löschen</th>
|
||||
<th scope="col">Aktionen</th>
|
||||
</tr>
|
||||
{% for entry in list: %}
|
||||
<tr>
|
||||
@ -35,7 +35,12 @@
|
||||
{{ entry[2] }}
|
||||
</td>
|
||||
<td>
|
||||
<button type='button' class='btn btn-danger justify-content-center align-content-between'
|
||||
<button type='button' class='btn btn-success'
|
||||
data-toggle="tooltip" data-placement="top" title="Als gesungen markieren"
|
||||
onclick='markEntryAsSung({{ entry[3] }})'><i
|
||||
class="fas fa-check"></i></button>
|
||||
<button type='button' class='btn btn-danger'
|
||||
data-toggle="tooltip" data-placement="top" title="Eintrag löschen"
|
||||
onclick='confirmDeleteEntry("{{ entry[0] }}",{{ entry[3] }})'><i
|
||||
class="fas fa-trash"></i></button>
|
||||
</td>
|
||||
@ -47,9 +52,10 @@
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extrajs %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"
|
||||
integrity="sha256-4F7e4JsAJyLUdpP7Q8Sah866jCOhv72zU5E8lIRER4w=" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
function confirmDeleteEntry(name, entry_id) {
|
||||
bootbox.confirm("Wirklich den Eintrag von "+name+" löschen?", function(result){
|
||||
if (result) {
|
||||
@ -107,7 +113,18 @@
|
||||
type: 'GET',
|
||||
url: '/api/entries/delete/'+entry_id,
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
dataType: 'json',
|
||||
async: false
|
||||
});
|
||||
location.reload();
|
||||
}
|
||||
function markEntryAsSung(entry_id) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/api/entries/mark_sung/'+entry_id,
|
||||
contentType: "application/json",
|
||||
dataType: 'json',
|
||||
async: false
|
||||
});
|
||||
location.reload();
|
||||
}
|
||||
@ -116,7 +133,8 @@
|
||||
type: 'GET',
|
||||
url: '/api/entries/delete_all',
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
dataType: 'json',
|
||||
async: false
|
||||
});
|
||||
location.reload();
|
||||
}
|
||||
|
61
app/templates/played_list.html
Normal file
61
app/templates/played_list.html
Normal file
@ -0,0 +1,61 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Songsuche{% endblock %}
|
||||
{% block content %}
|
||||
<div class="card admincontrols" style="width: 100%">
|
||||
<div class="card-body">
|
||||
<button type="button" class="topbutton btn btn-danger" onclick="confirmDeleteAllEntries()"><i
|
||||
class="fas fa-trash mr-2"></i>Abspielliste löschen</button>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th scope="col">Song</th>
|
||||
<th scope="col">Wiedergaben</th>
|
||||
</tr>
|
||||
{% for entry in list: %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ entry[0] }}
|
||||
</td>
|
||||
<td>
|
||||
{{ entry[1] }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% block extrajs %}
|
||||
<script>
|
||||
function confirmDeleteAllEntries() {
|
||||
bootbox.confirm({
|
||||
message: "Wirklich Abspielliste löschen?",
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: 'Ja',
|
||||
className: 'btn btn-danger'
|
||||
},
|
||||
cancel: {
|
||||
label: 'Nein',
|
||||
className: 'btn btn-secondary'
|
||||
}
|
||||
},
|
||||
callback: function(result){
|
||||
if (result) {
|
||||
deleteAllEntries()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
function deleteAllEntries() {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/api/played/clear',
|
||||
contentType: "application/json",
|
||||
dataType: 'json',
|
||||
async: false
|
||||
});
|
||||
location.reload();
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user