Skip to content

Commit

Permalink
Merge pull request #113 from vicwomg/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
vicwomg authored Feb 19, 2021
2 parents 14d0b19 + 5d3f762 commit 9b43e66
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 48 deletions.
20 changes: 9 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@ PiKaraoke is a "KTV"-style karaoke song search and queueing system. It connects
If you want to support this project with a little monetary tip, it's much appreciated: <br/>
<a href="https://www.buymeacoffee.com/vicwomg" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

## What's new (1.1.0)

Nice, big update full of great suggestions from supporters and kind patrons of this project.

- Singer names! Each new device is prompted for a name when first adding a song, so that singer name is shown in the queue, splash, and nowplaying. This value persists in a cookie for that device.
- Administrator mode! Every karaoke party has some drunken mischief, this keeps things from getting out of hand ;) Can be enabled with "--admin-password <password>" option. Log in via the info screen. Regular users can add songs, but cannot modify playback, queue order, or edit songs.
- VLC playback overlay can show the pikaraoke connection QR code with the "--show-overlay" option
- Advanced search option allows searching for non-karaoke results and downloading directly from a given Youtube URL.
- Expand the raspberry pi filesystem to fill the remainind SD card from the info screen.
- Loads of suggested UI improvements, polish, and optimizations.
- Bugfixes, refactoring
## What's new (1.1.1)

Primarily bugfixes for maintaining mega-libraries
- Fix slow loading of huge libraries
- Paging controls on browse screen for libraries > 500
- Fix issue with singer names with spaces and special characters not appearing #106
- Support scanning subdirectories #108 (thanks jramboz)
- Support more video formats and weird case sensitivity of mp3/cdg files #107 #95
- Singer names persist for 90 days #105

## Features

Expand Down
59 changes: 53 additions & 6 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import argparse
import datetime
import json
import logging
import os
Expand All @@ -11,8 +12,10 @@

import cherrypy
import psutil
from flask import (Flask, flash, make_response, redirect, render_template,
request, send_file, send_from_directory, url_for)
from flask import (Flask, flash, jsonify, make_response, redirect,
render_template, request, send_file, send_from_directory,
url_for)
from flask_paginate import Pagination, get_page_parameter

import karaoke
from constants import VERSION
Expand Down Expand Up @@ -73,7 +76,9 @@ def auth():
p = d["admin-password"]
if (p == admin_password):
resp = make_response(redirect('/'))
resp.set_cookie('admin', admin_password)
expire_date = datetime.datetime.now()
expire_date = expire_date + datetime.timedelta(days=90)
resp.set_cookie('admin', admin_password, expires=expire_date)
flash("Admin mode granted!", "is-success")
else:
resp = make_response(redirect(url_for('login')))
Expand Down Expand Up @@ -247,22 +252,64 @@ def search():
search_string=search_string,
)

@app.route("/autocomplete")
def autocomplete():
q = request.args.get('q').lower()
result = []
for each in k.available_songs:
if q in each.lower():
result.append({"path": each, "fileName": k.filename_from_path(each), "type": "autocomplete"})
response = app.response_class(
response=json.dumps(result),
mimetype='application/json'
)
return response

@app.route("/browse", methods=["GET"])
def browse():
search = False
q = request.args.get('q')
if q:
search = True
page = request.args.get(get_page_parameter(), type=int, default=1)

available_songs = k.available_songs

letter = request.args.get('letter')

if (letter):
result = []
if (letter == "numeric"):
for song in available_songs:
f = k.filename_from_path(song)[0]
if (f.isnumeric()):
result.append(song)
else:
for song in available_songs:
f = k.filename_from_path(song).lower()
if (f.startswith(letter.lower())):
result.append(song)
available_songs = result

if "sort" in request.args and request.args["sort"] == "date":
songs = sorted(k.available_songs, key=lambda x: os.path.getctime(x))
songs = sorted(available_songs, key=lambda x: os.path.getctime(x))
songs.reverse()
sort_order = "Date"
else:
songs = k.available_songs
songs = available_songs
sort_order = "Alphabetical"

results_per_page = 500
pagination = Pagination(css_framework='bulma', page=page, total=len(songs), search=search, record_name='songs', per_page=results_per_page)
start_index = (page - 1) * (results_per_page - 1)
return render_template(
"files.html",
pagination=pagination,
sort_order=sort_order,
site_title=site_name,
letter=letter,
title="Browse",
songs=songs,
songs=songs[start_index:start_index + results_per_page],
admin=is_admin()
)

Expand Down
2 changes: 1 addition & 1 deletion constants.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = "1.1.0"
VERSION = "1.1.1"
6 changes: 3 additions & 3 deletions karaoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,11 +446,11 @@ def download_video(self, video_url, enqueue=False, user="Pikaraoke"):

def get_available_songs(self):
logging.debug("Fetching available songs in: " + self.download_path)
types = ('*.mp4', '*.mp3', '*.zip')
types = ('*.mp4', '*.MP4', '*.mp3', '*.MP3', '*.Mp3', '*.zip', '*.ZIP', '*.mkv', '*.MKV', '*.avi', '*.AVI', '*.webm', '*.WEBM', '*.mov', '*.MOV')
files_grabbed = []
for files in types:
files_grabbed.extend(glob.glob(u"%s/%s" % (self.download_path, files)))
self.available_songs = sorted(files_grabbed)
files_grabbed.extend(glob.glob(u"%s/**/%s" % (self.download_path, files), recursive=True))
self.available_songs = sorted(files_grabbed, key=lambda f: str.lower(os.path.basename(f)))

def delete(self, song_path):
logging.info("Deleting song: " + song_path)
Expand Down
8 changes: 5 additions & 3 deletions lib/vlcclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,10 @@ def handle_zipped_cdg(self, file_path):
cdg_file = None
files = os.listdir(extracted_dir)
for file in files:
if os.path.splitext(file)[1] == ".mp3":
ext = os.path.splitext(file)[1]
if ext == ".mp3" or ext == ".Mp3" or ext == ".MP3":
mp3_file = file
elif os.path.splitext(file)[1] == ".cdg":
elif ext == ".cdg" or ext == ".Cdg" or ext == ".CDG":
cdg_file = file

if (mp3_file is not None) and (cdg_file is not None):
Expand All @@ -121,7 +122,8 @@ def handle_zipped_cdg(self, file_path):
raise Exception("No .mp3 or .cdg was found in the zip file: " + file_path)

def handle_mp3_cdg(self, file_path):
if (os.path.isfile(os.path.splitext(file_path)[0] + ".cdg")):
f = os.path.splitext(file_path)[0]
if (os.path.isfile(f + ".cdg") or os.path.isfile(f + ".Cdg") or os.path.isfile(f + ".CDG")):
return file_path
else:
raise Exception("No matching .cdg file found for: " + file_path)
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ futures
psutil
unidecode
requests
flask-paginate
35 changes: 35 additions & 0 deletions static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,38 @@
.control-box a:hover {
color: #74ccb3;
}

.pagination {
margin-bottom: 7px;
}
.pagination-page-info {
padding: 0;
width: 100%;
margin: .5em;
margin-left: 0;
font-size: 12px;
}
.pagination-page-info b {
color: black;
background: #6aa6ed;
padding-right: 5px;
font-size: 150%;
}
.pagination-list {
list-style: none !important;
margin-top: 0px !important;
margin-left: 0px !important;
margin-bottom: 0px !important;
}
.pagination-list li {
margin-top: 0px !important;
}
.pagination-previous, .pagination-next {
margin-top: 0px !important;
margin-bottom: 0px !important;
}
.pagination-page-info b {
color: white;
background-color: transparent;
font-size: 100%
}
2 changes: 1 addition & 1 deletion templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"Do you want to change the name of the person using this device? This will show up on queued songs. Current: " + currentUser
);
if (name) {
Cookies.set("user", name)
Cookies.set("user", name, { expires: 3650 })
}
location.reload();
});
Expand Down
30 changes: 21 additions & 9 deletions templates/files.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,26 @@

$('a.add-song-link').click(function(e) {
e.preventDefault();
if (!Cookies.get("user")) {
var user = Cookies.get("user")
if (!user) {
let name = window.prompt(
"Please enter your name. This will show up next to the songs you queue up from this device."
);
if (name) {
Cookies.set("user", name)
Cookies.set("user", name, { expires: 3650 })
user = Cookies.get("user")
}
}
$.get(this.href + Cookies.get("user"), function (data) {
$.get(this.href + encodeURIComponent(user), function (data) {
var obj = JSON.parse(data);

if (obj.success) {
showNotification("Song added to the queue: " + obj.song, "is-success")
}
else {
showNotification("Song already the queue: " + obj.song, "is-danger")
}
})

// location.href = this.href + Cookies.get("user");
})
});
Expand All @@ -48,7 +49,14 @@
{% endblock %}

{% block header %}
<h1>{% block title %}{{ title }}{% endblock %}</h1>
<h1>{% block title %}
{% if letter %}
{{title}}: "{{ letter.upper() }}"
{% else %}
{{title}}
{% endif %}
{% endblock %}
</h1>
<style>
#alpha-bar {
padding: 5px 10px;
Expand All @@ -58,6 +66,7 @@ <h1>{% block title %}{{ title }}{% endblock %}</h1>
display: flex;
justify-content: space-between;
top: 3px;
z-index: 20;
}
@media screen and (max-width: 500px) {
#alpha-bar {
Expand Down Expand Up @@ -91,16 +100,18 @@ <h1>{% block title %}{{ title }}{% endblock %}</h1>
</p>

<div id="alpha-bar" class="has-background-dark mobile-hide" >
<a href="#">#</a>
<a href="{{ url_for('browse') }}?letter=numeric">#</a>
{% for letter in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] %}
<a href="#{{letter}}">{{letter.upper()}}</a>
<a href="{{ url_for('browse') }}?letter={{letter}}">{{letter.upper()}}</a>
{% endfor %}
</div>

{{ pagination.links }}
{{ pagination.info }}
<table>
{% for song in songs %}
<tr value='{{ song }}'>
<td width="20px" style="padding: 5px 0px">{{loop.index}}</td>
<td width="20px" style="padding: 5px 0px">{{loop.index + pagination.skip}}</td>
<td id={{filename_from_path(song)[0].lower()}} width="20px" style="padding: 5px 0px">
<a class='add-song-link has-text-weight-bold has-text-success' title="Add '{{filename_from_path(song)}}' to queue"
href="{{url_for('enqueue')}}?song={{url_escape(song.encode('utf-8'))}}&user="><i class="icon icon-list-add"></i> </a>
Expand All @@ -116,6 +127,7 @@ <h1>{% block title %}{{ title }}{% endblock %}</h1>
{% endif %}
{% endfor %}
</table>
{{ pagination.links }}


{% endblock %}
39 changes: 25 additions & 14 deletions templates/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@
$("#add-queue-link").hide();
$("#add-queue-link").attr("disabled", "true");
$("#search-link").attr("disabled", "true");
var $select = $('.search-selectize').selectize({
var $select = $('#song-to-add').selectize({
valueField: 'path',
labelField: 'fileName',
searchField: ['fileName'],
optgroupField: "type",
optgroups: [
{value: 'autocomplete', label: 'Available songs in local library'},
],
createOnBlur: true,
openOnFocus: false,
createFilter: function (input) { return input.length >= 2; },
Expand Down Expand Up @@ -129,13 +136,23 @@
option: function (item, escape) {
return '<div class="row">'
+ '<div class="col-icon"><i class="icon icon-music has-text-info"></i></div>'
+ '<div class="col-text">' + item.text + '</div>'
+ '<div class="col-text">' + escape(item.fileName) + '</div>'
+ '</div>';
},
optgroup_header: function (data, escape) {
return '<div class="optgroup-header has-text-info">' + escape(data.label) + '</div>';
optgroup_header: function(data, escape) {
return '<div class="optgroup-header">' + escape(data.label) + '</div>';
}
},
load: function(query, callback) {
if (query.length < 2) return callback;
$.ajax({
url: "{{ url_for('autocomplete') }}" + "?q=" + query,
type: 'get',
success: function(data){
callback(data)
}
});
}
});

$('#search-link').on('click', function (e) {
Expand Down Expand Up @@ -185,7 +202,6 @@
i = -1;
changeImage();


$(document).on('change', '#search_result_selector', function () {
var url = $('#search_result_selector').val();
$('#youtube-link').attr('href', url);
Expand Down Expand Up @@ -228,7 +244,7 @@
"Please enter your name. This will show up next to the songs you queue up from this device."
);
if (name) {
Cookies.set("user", name)
Cookies.set("user", name , { expires: 3650 })
}
location.reload()
}
Expand All @@ -237,7 +253,7 @@
$("#search-user").val(user)

});

function isYoutubeURL(s) {
if (s.includes("http")) {
return s.includes("youtube.com/watch?v=") || s.includes("youtube.com/v/") || s.includes("youtu.be/")
Expand Down Expand Up @@ -268,13 +284,8 @@ <h1>{% block title %}Search / Add New{% endblock %}</h1>
<form id="queue-form" >
<div id="search-field" class="field has-addons" style="margin-bottom: 5px">
<div class="control" style="width:100%">
<select class="search-selectize is-size-7" name="song-to-add">
<option value=''></option>
<optgroup label="Available Songs" id="available-songs">
{% for file in songs %}
<option value='{{file}}'>{{ filename_from_path(file) }}</option>
{% endfor %}
</optgroup>
<select id="song-to-add" class="search-selectize is-size-7" name="song-to-add">
<optgroup label="Available Songs" id="available-songs"></optgroup>
</select>
</div>
<div class="control">
Expand Down

0 comments on commit 9b43e66

Please sign in to comment.