Compare commits

...

53 Commits

Author SHA1 Message Date
d8899267c3 Merge pull request #76 from PhoenixTwoFive/PhoenixTwoFive-patch-1
Update devcontainer.json
2023-10-04 15:19:02 +02:00
dd83d6c9c4 Update devcontainer.json 2023-10-04 15:18:54 +02:00
14630b97be Move mariabd install to postCreate to fix github codespaces 2023-10-04 13:11:43 +00:00
7f4625a062 Fix CSS quirks 2023-10-04 12:49:06 +00:00
e7d9816010 Add song year to detail view 2023-10-04 12:48:50 +00:00
37990e596c Add python extensions to devcontainer.json 2023-10-04 12:48:28 +00:00
00e090ec48 Remove faulty postAttachCommand from devcontainer.json 2023-10-04 10:45:36 +00:00
e7b0f5f2dc make requirements.txt useful 2023-10-04 01:33:35 +00:00
c32ed395d8 Improve construction tape gimmick 2023-10-04 01:23:21 +00:00
95be876a19 Change terminology 2023-10-04 01:06:16 +00:00
0f9ad4f91a Fix trailing whitespace 2023-10-04 01:02:30 +00:00
ac940ded8c Add debouncing for the search 2023-10-04 00:53:03 +00:00
c8b65e4433 Ensure Index exists after Song import 2023-10-04 00:33:15 +00:00
c50f00c1d3 Fix env var version 2023-10-04 00:24:26 +00:00
3b4152f89f Fix build script 2023-10-04 00:19:14 +00:00
4561f5f376 Merge branch 'legacy' of github.com:PhoenixTwoFive/karaoqueue into legacy 2023-10-04 00:18:33 +00:00
3728e282e3 Fix container build script 2023-10-04 00:18:29 +00:00
6d3ca87869 Merge pull request #75 from PhoenixTwoFive/59-dark-theme-toast-notifications
Dark theme Toast notifications
2023-10-04 02:15:48 +02:00
e443cdb35a Dark theme Toast notifications
Fixes #59
2023-10-04 00:11:42 +00:00
8c98edb604 Fix depenndencies 2023-10-03 23:48:59 +00:00
9d1bab6a07 Less dodgy debug/version handling 2023-10-03 23:48:52 +00:00
c87abb506d Add docker build and push script 2023-10-03 23:47:57 +00:00
c03f632ea0 Add useful VScode Extensions to devcontainer.json 2023-10-03 23:01:12 +00:00
ab0aca9f90 Add song info and remove string bodging 2023-10-03 22:57:37 +00:00
e3f8839c07 Fix queue modal header border 2023-10-03 22:57:03 +00:00
81267a4484 Update devcontainer.json 2023-10-03 22:56:40 +00:00
a1a041c5ce Add detailed song info view on song select 2023-10-03 19:23:09 +00:00
c3603a13dd Merge pull request #74 from PhoenixTwoFive/73-fix-code-scanning-alert-flask-app-is-run-in-debug-mode
Remove standalone run stub
2023-10-03 20:22:20 +02:00
c9613dfbd9 Remove standalone run stub 2023-10-03 18:17:36 +00:00
a1c8181779 Merge pull request #72 from PhoenixTwoFive/71-fix-code-scanning-alert-clear-text-logging-of-sensitive-information
Remove Logging
2023-10-03 19:51:06 +02:00
1ef4830588 Fix formatting issues 2023-10-03 17:46:52 +00:00
5a8b2fe66c Remove Logging 2023-10-03 17:42:21 +00:00
0db1ef1fc4 Apply Flask deprecation fixes 2023-10-03 17:36:10 +00:00
dcc79aed1b Improve search
(cherry picked from commit 85497a1569)
2023-10-03 17:25:39 +00:00
3d8cf665db Update devcontainer.json 2023-10-03 17:23:54 +00:00
8f926621c1 Merge pull request #62 from PhoenixTwoFive/dependabot/pip/backend/flask-2.3.2
Bump flask from 2.2.3 to 2.3.2 in /backend
2023-09-29 23:33:02 +02:00
a8e1a8f647 Merge pull request #67 from PhoenixTwoFive/dependabot/pip/backend/requests-2.31.0
Bump requests from 2.28.2 to 2.31.0 in /backend
2023-09-29 23:32:42 +02:00
e8e0bca648 Update devcontainer.json 2023-09-22 16:55:05 +00:00
5efa21924b Update dockerfile to adapt to new debian version 2023-06-30 15:59:04 +02:00
4c806c3550 update docker-compose container version 2023-06-30 15:58:34 +02:00
c21e6300e9 Merge pull request #70 from PhoenixTwoFive/64-defaults-for-entry-limitation-too-high
lowered maxqueue to 10 and participant quota to 2
2023-06-30 15:34:56 +02:00
7525708dce lowered maxqueue to 10 and participant quota to 2 2023-06-30 15:32:13 +02:00
37d95f61b2 Merge pull request #69 from PhoenixTwoFive/63-input-sanitization
63 input sanitization
2023-06-30 15:29:46 +02:00
a54953ff0d fix copy functionality
Fixed copy functionality by no longer rendering the data into the
function call as string literal, but instead accessing it from the DOM
in the function call.
2023-06-30 15:28:46 +02:00
349eff9a09 strip whitespace from participant name in enqueue endpoint 2023-06-30 14:50:32 +02:00
b7a79462dc Add pipfile 2023-06-30 00:17:44 +02:00
0a038029f7 Merge pull request #68 from PhoenixTwoFive/61-properly-set-focus-on-opening-enqueue-modal
Set focus on singer name input when modal is shown
2023-06-30 00:16:09 +02:00
93e6606d6d Set focus on singer name input when modal is shown 2023-06-30 00:13:48 +02:00
bd3bec8c4f Bump requests from 2.28.2 to 2.31.0 in /backend
Bumps [requests](https://github.com/psf/requests) from 2.28.2 to 2.31.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.28.2...v2.31.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-23 06:41:06 +00:00
9cb93d2d49 Bump flask from 2.2.3 to 2.3.2 in /backend
Bumps [flask](https://github.com/pallets/flask) from 2.2.3 to 2.3.2.
- [Release notes](https://github.com/pallets/flask/releases)
- [Changelog](https://github.com/pallets/flask/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/flask/compare/2.2.3...2.3.2)

---
updated-dependencies:
- dependency-name: flask
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-02 00:33:58 +00:00
1faa2614fa Merge branch 'legacy' of github.com:PhoenixTwoFive/karaoqueue into legacy 2023-04-28 13:41:51 +02:00
93c8a2cb7b Update Version 2023-04-28 13:41:39 +02:00
ddb1e0d2a0 Merge pull request #58 from PhoenixTwoFive:fix/legacy/fix-no-owned-entry
Fix error on no owned entries
2023-04-28 13:40:28 +02:00
15 changed files with 598 additions and 226 deletions

View File

@ -4,11 +4,8 @@
"cpus": 4 "cpus": 4
}, },
"waitFor": "onCreateCommand", "waitFor": "onCreateCommand",
"updateContentCommand": "pip install -r requirements.txt", "onCreateCommand": "curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash && sudo apt install -y libmariadb3 libmariadb-dev",
"postCreateCommand": "", "updateContentCommand": "pip install -r backend/requirements.txt",
"postAttachCommand": {
"server": "flask --debug run"
},
"portsAttributes": { "portsAttributes": {
"5000": { "5000": {
"label": "Application", "label": "Application",
@ -23,10 +20,21 @@
}, },
"vscode": { "vscode": {
"extensions": [ "extensions": [
"ms-python.python" "ms-python.python",
"batisteo.vscode-django",
"ms-python.flake8",
"ms-python.isort",
"ms-python.vscode-pylance",
"redhat.vscode-yaml",
"ms-azuretools.vscode-docker",
"donjayamanne.python-extension-pack"
] ]
} }
}, },
"forwardPorts": [5000] "forwardPorts": [
5000
],
"features": {
"ghcr.io/devcontainers-contrib/features/angular-cli:2": {}
}
} }

2
.gitignore vendored
View File

@ -87,7 +87,7 @@ ipython_config.py
# However, in case of collaboration, if having platform-specific dependencies or dependencies # However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not # having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies. # install all needed dependencies.
#Pipfile.lock Pipfile.lock
# celery beat schedule file # celery beat schedule file
celerybeat-schedule celerybeat-schedule

View File

@ -1,16 +1,23 @@
FROM tiangolo/meinheld-gunicorn-flask:python3.9 FROM tiangolo/meinheld-gunicorn-flask:python3.9
RUN apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db # Currently unusable, mariadb is not available through installer for debian 12
RUN curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash # RUN apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db
# RUN curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash
RUN apt-get update RUN apt-get update
RUN apt-get upgrade -y RUN apt-get upgrade -y
RUN apt-get dist-upgrade RUN apt-get dist-upgrade
# In the meantime, acquire the mariadb packages through apt
RUN apt-get install -y libmariadb3 libmariadb-dev
COPY ./backend/requirements.txt /app/requirements.txt COPY ./backend/requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
RUN pip install --no-cache-dir -U meinheld RUN pip install --no-cache-dir -U meinheld
ARG SOURCE_VERSION
ENV SOURCE_VERSION ${SOURCE_VERSION:-unknown}
COPY ./backend /app COPY ./backend /app

48
backend/Pipfile Normal file
View File

@ -0,0 +1,48 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
autopep8 = "==2.0.2"
beautifulsoup4 = "==4.12.0"
bs4 = "==0.0.1"
certifi = "==2022.12.7"
charset-normalizer = "==3.1.0"
click = "==8.1.3"
flake8 = "==6.0.0"
flask = "==2.2.3"
flask-basicauth = "==0.2.0"
greenlet = "==2.0.2"
gunicorn = "==20.1.0"
idna = "==3.4"
itsdangerous = "==2.1.2"
jinja2 = "==3.1.2"
mariadb = "==1.1.6"
markupsafe = "==2.1.2"
mccabe = "==0.7.0"
mysql = "==0.0.3"
mysqlclient = "==2.1.1"
numpy = "==1.24.2"
packaging = "==23.0"
pandas = "==1.5.3"
pycodestyle = "==2.10.0"
pyflakes = "==3.0.1"
pymysql = "==1.0.3"
python-dateutil = "==2.8.2"
pytz = "==2023.3"
requests = "==2.28.2"
six = "==1.16.0"
soupsieve = "==2.4"
sqlalchemy = "==2.0.7"
toml = "==0.10.2"
tomli = "==2.0.1"
typing-extensions = "==4.5.0"
urllib3 = "==1.26.15"
werkzeug = "==2.2.3"
[dev-packages]
[requires]
python_version = "3.9"
python_full_version = "3.9.17"

View File

@ -16,9 +16,9 @@ accept_entries = True
@app.route("/") @app.route("/")
def home(): def home():
if basic_auth.authenticate(): if basic_auth.authenticate():
return render_template('main_admin.html', list=database.get_list(), auth=basic_auth.authenticate()) return render_template('main_admin.html', list=database.get_list(), auth=basic_auth.authenticate(), debug=app.config['DEBUG'])
else: else:
return render_template('main.html', list=database.get_list(), auth=basic_auth.authenticate()) return render_template('main.html', list=database.get_list(), auth=basic_auth.authenticate(), debug=app.config['DEBUG'])
@app.route("/favicon.ico") @app.route("/favicon.ico")
@ -37,7 +37,7 @@ def enqueue():
if not helpers.is_valid_uuid(client_id): if not helpers.is_valid_uuid(client_id):
print(request.data) print(request.data)
abort(400) abort(400)
name = request.json['name'] name = request.json['name'].strip()
song_id = request.json['id'] song_id = request.json['id']
if request.authorization: if request.authorization:
entry_id = database.add_entry(name, song_id, client_id) entry_id = database.add_entry(name, song_id, client_id)
@ -67,14 +67,14 @@ def enqueue():
@app.route("/list") @app.route("/list")
def songlist(): def songlist():
return render_template('songlist.html', list=database.get_song_list(), auth=basic_auth.authenticate()) return render_template('songlist.html', list=database.get_song_list(), auth=basic_auth.authenticate(), debug=app.config['DEBUG'])
@app.route("/settings") @app.route("/settings")
@nocache @nocache
@basic_auth.required @basic_auth.required
def settings(): def settings():
return render_template('settings.html', app=app, auth=basic_auth.authenticate(), themes=helpers.get_themes()) return render_template('settings.html', app=app, auth=basic_auth.authenticate(), themes=helpers.get_themes(), debug=app.config['DEBUG'])
@app.route("/settings", methods=['POST']) @app.route("/settings", methods=['POST'])
@ -109,7 +109,7 @@ def settings_post():
if changed_credentials: if changed_credentials:
return redirect("/") return redirect("/")
else: else:
return render_template('settings.html', app=app, auth=basic_auth.authenticate(), themes=helpers.get_themes()) return render_template('settings.html', app=app, auth=basic_auth.authenticate(), themes=helpers.get_themes(), debug=app.config['DEBUG'])
@app.route("/api/queue") @app.route("/api/queue")
@ -123,7 +123,7 @@ def queue_json():
@nocache @nocache
@basic_auth.required @basic_auth.required
def played_list(): def played_list():
return render_template('played_list.html', list=database.get_played_list(), auth=basic_auth.authenticate()) return render_template('played_list.html', list=database.get_played_list(), auth=basic_auth.authenticate(), debug=app.config['DEBUG'])
@app.route("/api/songs") @app.route("/api/songs")
@ -157,6 +157,28 @@ def get_song_completions(input_string=""):
return 400 return 400
@app.route("/api/songs/search")
@nocache
def query_songs_with_details(input_string=""):
input_string = request.args.get("q", input_string)
if input_string == "":
return Response(status=400)
result = []
for x in database.get_songs_with_details(input_string):
# Turn row into dict. Add field labels.
result.append(dict(zip(['karafun_id', 'title', 'artist', 'year', 'duo', 'explicit', 'styles', 'languages'], x)))
return jsonify(result)
@app.route("/api/songs/details/<song_id>")
def get_song_details(song_id):
result = database.get_song_details(song_id)
if result is None:
abort(404)
else:
return jsonify(dict(zip(['karafun_id', 'title', 'artist', 'year', 'duo', 'explicit', 'styles', 'languages'], result[0])))
@app.route("/api/entries/delete/<entry_id>", methods=['GET']) @app.route("/api/entries/delete/<entry_id>", methods=['GET'])
@nocache @nocache
@basic_auth.required @basic_auth.required
@ -272,8 +294,8 @@ def get_current_event():
return Response('{"status": "OK", "event": "' + helpers.get_current_event_id(app) + '"}', mimetype='text/json') return Response('{"status": "OK", "event": "' + helpers.get_current_event_id(app) + '"}', mimetype='text/json')
@app.before_first_request
def activate_job(): def activate_job():
with app.app_context():
helpers.load_dbconfig(app) helpers.load_dbconfig(app)
helpers.load_version(app) helpers.load_version(app)
database.create_entry_table() database.create_entry_table()
@ -301,5 +323,5 @@ def inject_version():
return dict(karaoqueue_version=app.config['VERSION']) return dict(karaoqueue_version=app.config['VERSION'])
if __name__ == "__main__": # Perform setup here so it will be executed when the module is imported by the WSGI server.
app.run(host='127.0.0.1', port=8080, debug=True) activate_job()

View File

@ -28,6 +28,11 @@ def import_songs(song_csv):
with get_db_engine().connect() as conn: with get_db_engine().connect() as conn:
df.to_sql(song_table, conn, if_exists='replace', df.to_sql(song_table, conn, if_exists='replace',
index=False) index=False)
try:
cur = conn.execute(text("ALTER TABLE songs ADD FULLTEXT(Title,Artist)"))
conn.commit()
except Exception:
pass
cur = conn.execute(text("SELECT Count(Id) FROM songs")) cur = conn.execute(text("SELECT Count(Id) FROM songs"))
num_songs = cur.fetchone()[0] # type: ignore num_songs = cur.fetchone()[0] # type: ignore
conn.commit() conn.commit()
@ -62,7 +67,9 @@ def create_song_table():
`Explicit` INTEGER, `Explicit` INTEGER,
`Date Added` TIMESTAMP, `Date Added` TIMESTAMP,
`Styles` TEXT, `Styles` TEXT,
`Languages` TEXT `Languages` TEXT,
PRIMARY KEY (`Id`),
FULLTEXT KEY (`Title`,`Artist`)
)""") )""")
conn.execute(stmt) conn.execute(stmt)
conn.commit() conn.commit()
@ -123,11 +130,46 @@ def get_song_list():
def get_song_completions(input_string): def get_song_completions(input_string):
with get_db_engine().connect() as conn: with get_db_engine().connect() as conn:
prepared_string = f"%{input_string.upper()}%" prepared_string = f"{input_string}"
prepared_string_with_wildcard = f"%{input_string}%"
stmt = text( stmt = text(
"SELECT CONCAT(Artist, ' - ', Title) AS Song, Id FROM songs WHERE CONCAT(Artist, ' - ', Title) LIKE :prepared_string LIMIT 20;") """
SELECT CONCAT(Artist, ' - ', Title) AS Song, Id FROM songs
WHERE MATCH(Artist, Title)
AGAINST (:prepared_string IN NATURAL LANGUAGE MODE)
LIMIT 20;
""")
cur = conn.execute( cur = conn.execute(
stmt, {"prepared_string": prepared_string}) # type: ignore stmt, {"prepared_string": prepared_string, "prepared_string_with_wildcard": prepared_string_with_wildcard}) # type: ignore
return cur.fetchall()
def get_songs_with_details(input_string: str):
with get_db_engine().connect() as conn:
prepared_string = f"%{input_string}"
stmt = text(
"""
SELECT Id, Title, Artist, Year, Duo, Explicit, Styles, Languages FROM songs
WHERE MATCH(Artist, Title)
AGAINST (:prepared_string IN NATURAL LANGUAGE MODE)
LIMIT 20;
"""
)
cur = conn.execute(
stmt, {"prepared_string": prepared_string})
return cur.fetchall()
def get_song_details(song_id: int):
with get_db_engine().connect() as conn:
stmt = text(
"""
SELECT Id, Title, Artist, Year, Duo, Explicit, Styles, Languages FROM songs
WHERE Id = :song_id;
"""
)
cur = conn.execute(
stmt, {"song_id": song_id})
return cur.fetchall() return cur.fetchall()
@ -250,7 +292,6 @@ def get_config(key: str) -> str:
def set_config(key: str, value: str) -> bool: def set_config(key: str, value: str) -> bool:
print(f"Setting config {key} to {value}")
with get_db_engine().connect() as conn: with get_db_engine().connect() as conn:
conn.execute(text( conn.execute(text(
"INSERT INTO config (`Key`, `Value`) VALUES ( :par_key , :par_value) ON DUPLICATE KEY UPDATE `Value`= :par_value"), "INSERT INTO config (`Key`, `Value`) VALUES ( :par_key , :par_value) ON DUPLICATE KEY UPDATE `Value`= :par_value"),

View File

@ -1,5 +1,6 @@
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import subprocess
import os import os
import uuid import uuid
from flask import make_response, Flask from flask import make_response, Flask
@ -34,17 +35,14 @@ def check_config_exists():
def load_version(app: Flask): def load_version(app: Flask):
if app.config['DEBUG'] is True:
app.config['VERSION'] = subprocess.Popen("echo \"$(git rev-parse --abbrev-ref HEAD)-$(git describe)\"", shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8').strip() + " (debug)" # noqa: E501 # type: ignore
return
if os.environ.get("SOURCE_VERSION"): if os.environ.get("SOURCE_VERSION"):
app.config['VERSION'] = os.environ.get("SOURCE_VERSION")[0:7] # type: ignore # noqa: E501 app.config['VERSION'] = os.environ.get("SOURCE_VERSION") # type: ignore # noqa: E501
elif os.path.isfile(".version"): return
with open('.version', 'r') as file:
data = file.read().replace('\n', '')
if data:
app.config['VERSION'] = data
else: else:
app.config['VERSION'] = "" app.config['VERSION'] = "Unknown"
else:
app.config['VERSION'] = ""
def load_dbconfig(app: Flask): def load_dbconfig(app: Flask):
@ -91,8 +89,8 @@ def setup_config(app: Flask):
exit() exit()
default_config = {'username': initial_username, default_config = {'username': initial_username,
'password': initial_password, 'password': initial_password,
'entryquota': 3, 'entryquota': 2,
'maxqueue': 20, 'maxqueue': 10,
'entries_allowed': 1, 'entries_allowed': 1,
'theme': 'default.css'} 'theme': 'default.css'}
for key, value in default_config.items(): for key, value in default_config.items():

View File

@ -1,36 +1,36 @@
autopep8==2.0.2 autopep8~=2.0.2
beautifulsoup4==4.12.0 beautifulsoup4~=4.12.0
bs4==0.0.1 bs4~=0.0.1
certifi==2022.12.7 certifi~=2022.12.7
charset-normalizer==3.1.0 charset-normalizer~=3.1.0
click==8.1.3 click~=8.1.3
flake8==6.0.0 flake8~=6.0.0
Flask==2.2.3 Flask~=2.3.2
Flask-BasicAuth==0.2.0 Flask-BasicAuth~=0.2.0
greenlet==2.0.2 greenlet~=2.0.2
gunicorn==20.1.0 gunicorn~=20.1.0
idna==3.4 idna~=3.4
itsdangerous==2.1.2 itsdangerous~=2.1.2
Jinja2==3.1.2 Jinja2~=3.1.2
mariadb==1.1.6 mariadb~=1.1.6
MarkupSafe==2.1.2 MarkupSafe~=2.1.2
mccabe==0.7.0 mccabe~=0.7.0
mysql==0.0.3 mysql~=0.0.3
mysqlclient==2.1.1 mysqlclient~=2.1.1
numpy==1.24.2 numpy~=1.24.2
packaging==23.0 packaging~=23.0
pandas==1.5.3 pandas~=1.5.3
pycodestyle==2.10.0 pycodestyle~=2.10.0
pyflakes==3.0.1 pyflakes~=3.0.1
PyMySQL==1.0.3 PyMySQL~=1.0.3
python-dateutil==2.8.2 python-dateutil~=2.8.2
pytz==2023.3 pytz~=2023.3
requests==2.28.2 requests~=2.31.0
six==1.16.0 six~=1.16.0
soupsieve==2.4 soupsieve~=2.4
SQLAlchemy==2.0.7 SQLAlchemy~=2.0.7
toml==0.10.2 toml~=0.10.2
tomli==2.0.1 tomli~=2.0.1
typing_extensions==4.5.0 typing_extensions~=4.5.0
urllib3==1.26.15 urllib3~=1.26.15
Werkzeug==2.2.3 Werkzeug~=3.0.0

View File

@ -4,12 +4,14 @@
--navbar-text-color: rgba(255, 255, 255, .5); --navbar-text-color: rgba(255, 255, 255, .5);
--navbar-text-color-hover: rgba(255, 255, 255, .75); --navbar-text-color-hover: rgba(255, 255, 255, .75);
--navbar-text-color-active: rgba(255, 255, 255, 1); --navbar-text-color-active: rgba(255, 255, 255, 1);
--navbar-padding: 4.5rem;
/* Common */ /* Common */
--background-color: #ffffff; --background-color: #ffffff;
--background-color-var: #f5f5f5; --background-color-var: #f5f5f5;
--text-color: #212529; --text-color: #212529;
--text-color-var: #343a40; --text-color-var: #343a40;
--text-color-light: #6c757d;
/* Modals */ /* Modals */
--modal-background-color: #ffffff; --modal-background-color: #ffffff;
@ -24,11 +26,18 @@
/* Misc */ /* Misc */
--copy-highlight-color: rgba(251, 255, 0, 0.6); --copy-highlight-color: rgba(251, 255, 0, 0.6);
/* Toasts */
--toast-background-color: #ffffff;
--toast-text-color: #212529;
/* Footer */
--footer-height: 80px;
} }
body { body {
padding-top: 5rem; padding-top: var(--navbar-padding);
background-color: var(--background-color); background-color: var(--background-color);
} }
@ -38,21 +47,15 @@ body {
} }
.site { .site {
height: auto; min-height: calc(100vh - var(--navbar-padding) - var(--footer-height));
min-height: 100%; margin-bottom: -var(--footer-height);
}
main {
padding-bottom: 60px;
/* Höhe des Footers */
} }
.footer { .footer {
margin-top: -60px; /*margin-top: var(--footer-height);*/
width: 100%; width: 100%;
height: 60px; height: var(--footer-height);
/* Set the fixed height of the footer here */
/*line-height: 60px; /* Vertically center the text there */
background-color: var(--background-color-var); background-color: var(--background-color-var);
} }
@ -129,13 +132,13 @@ body {
.modal-header { .modal-header {
background-color: var(--background-color); background-color: var(--background-color);
color: var(--text-color-var); color: var(--text-color-var);
border-color: var(var(--modal-separator-color)); border-color: var(--modal-separator-color);
} }
.modal-footer { .modal-footer {
background-color: var(--background-color); background-color: var(--background-color);
color: var(--text-color-var); color: var(--text-color-var);
border-color: var(var(--modal-separator-color)); border-color: var(--modal-separator-color);
} }
.form-control { .form-control {
@ -173,6 +176,35 @@ pre {
background-color: var(--copy-highlight-color); background-color: var(--copy-highlight-color);
} }
.list-indicator {
width: 1.5rem;
height: 1.5rem;
}
#songYear {
font-size: small;
font-weight: 400;
color: var(--text-color-light);
}
.construction_bg {
background: repeating-linear-gradient(45deg,
#222200,
#222200 10px,
#000000 10px,
#000000 20px) !important;
}
.toast {
background-color: var(--toast-background-color);
color: var(--toast-text-color);
}
.toast-header {
background-color: var(--toast-background-color);
color: var(--toast-text-color);
}
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
/* Navbar */ /* Navbar */
@ -186,6 +218,7 @@ pre {
--background-color-var: #232323; --background-color-var: #232323;
--text-color: #f5f5f5; --text-color: #f5f5f5;
--text-color-var: #a2a2a2; --text-color-var: #a2a2a2;
--text-color-light: #6c757d;
/* Modals */ /* Modals */
--modal-background-color: #121212; --modal-background-color: #121212;
@ -197,5 +230,9 @@ pre {
/* Input */ /* Input */
--input-background-color: #343434; --input-background-color: #343434;
/* Toasts */
--toast-background-color: #232323;
--toast-text-color: #f5f5f5;
} }
} }

View File

@ -16,11 +16,14 @@
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.21.2/dist/bootstrap-table.min.css"> <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.21.2/dist/bootstrap-table.min.css">
<!-- Bootstrap-Toaster--> <!-- Bootstrap-Toaster-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-toaster/4.1.2/css/bootstrap-toaster.min.css" <link rel="stylesheet"
integrity="sha512-kYPLvO+Bu+xttOhbQvxs9nx7XSdxrb2JexRxQ3CpJQ7EtmlkBsWyOjlinLgiLWeLxuupFYB4cPqLOo0gnBnzeQ==" crossorigin="anonymous" referrerpolicy="no-referrer" /> href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-toaster/4.1.2/css/bootstrap-toaster.min.css"
integrity="sha512-kYPLvO+Bu+xttOhbQvxs9nx7XSdxrb2JexRxQ3CpJQ7EtmlkBsWyOjlinLgiLWeLxuupFYB4cPqLOo0gnBnzeQ=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Bootstrap core CSS --> <!-- Bootstrap core CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/css/bootstrap.min.css"
integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<!-- Custom styles for this template --> <!-- Custom styles for this template -->
<link href="static/css/style.css" rel="stylesheet"> <link href="static/css/style.css" rel="stylesheet">
@ -76,13 +79,13 @@
</main><!-- /.container --> </main><!-- /.container -->
</div> </div>
<!-- Footer --> <!-- Footer -->
<footer class="footer"> <footer class="footer {% if debug %} construction_bg {% endif %}">
<div class="container text-center py-3"> <div class="container text-center py-3">
{% if not auth %} {% if not auth %}
<a href="/login" class="ml-1 mr-1"><i class="fas fa-sign-in-alt mr-1"></i><span>Login</span></a> <a href="/login" class="ml-1 mr-1"><i class="fas fa-sign-in-alt mr-1"></i><span>Login</span></a>
{% endif %} {% endif %}
<a href="https://github.com/PhoenixTwoFive/karaoqueue" <a href="https://github.com/PhoenixTwoFive/karaoqueue" class="ml-1 mr-1"><i
class="ml-1 mr-1"><i class="fab fa-github mr-1"></i><span>Github</span></a> class="fab fa-github mr-1"></i><span>Github</span></a>
<span class="text-muted"> {{karaoqueue_version}} -&nbsp;2019-23 - Phillip <span class="text-muted"> {{karaoqueue_version}} -&nbsp;2019-23 - Phillip
Kühne</span> Kühne</span>
</div> </div>
@ -95,8 +98,12 @@
integrity="sha512-pumBsjNRGGqkPzKHndZMaAG+bir374sORyzM3uulLV14lN5LyykqNk8eEeUlUkB3U0M4FApyaHraT65ihJhDpQ==" integrity="sha512-pumBsjNRGGqkPzKHndZMaAG+bir374sORyzM3uulLV14lN5LyykqNk8eEeUlUkB3U0M4FApyaHraT65ihJhDpQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script> crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js"
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js"
integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"
integrity="sha256-4F7e4JsAJyLUdpP7Q8Sah866jCOhv72zU5E8lIRER4w=" crossorigin="anonymous"> integrity="sha256-4F7e4JsAJyLUdpP7Q8Sah866jCOhv72zU5E8lIRER4w=" crossorigin="anonymous">
</script> </script>
@ -106,7 +113,8 @@
<script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script> <script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-toaster/4.1.2/js/bootstrap-toaster.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-toaster/4.1.2/js/bootstrap-toaster.min.js"
integrity="sha512-Ur6jgeoP3jnn38C7oBzDqMLRb+wxG2PXLKqgx2vgQ1ePFvbJ28f9iQSJplHD0APFHELOeS/df+RPNeENFtLrYw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> integrity="sha512-Ur6jgeoP3jnn38C7oBzDqMLRb+wxG2PXLKqgx2vgQ1ePFvbJ28f9iQSJplHD0APFHELOeS/df+RPNeENFtLrYw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
{% block extrajs %}{% endblock %} {% block extrajs %}{% endblock %}
<script> <script>
$(document).ready(function () { $(document).ready(function () {

View File

@ -1,5 +1,3 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block title %}Warteliste{% endblock %} {% block title %}Warteliste{% endblock %}
{% block content %} {% block content %}

View File

@ -187,15 +187,16 @@
function TableActions(value, row, index) { function TableActions(value, row, index) {
let outerHTML = "" let outerHTML = ""
if (row.Transferred == 1) { if (row.Transferred == 1) {
outerHTML = "<button type=\"button\" class=\"btn btn-default\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Markierung zurückziehen\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsTransferred(" + row.entry_ID + ")\"><i class=\"fas fa-backward\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Als gesungen markieren\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsSung(" + row.entry_ID + ")\"><i class=\"fas fa-check\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Eintrag löschen\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');confirmDeleteEntry('" + row.Name + "'," + row.entry_ID + ")\"><i class=\"fas fa-trash\"></i></button>"; outerHTML = "<button type=\"button\" class=\"btn btn-default\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Markierung zurückziehen\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsTransferred(" + row.entry_ID + ")\"><i class=\"fas fa-backward\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Als gesungen markieren\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsSung(" + row.entry_ID + ")\"><i class=\"fas fa-check\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Eintrag löschen\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');confirmDeleteEntry(this.parentElement.parentElement.children[1].innerText," + row.entry_ID + ")\"><i class=\"fas fa-trash\"></i></button>";
} else { } else {
outerHTML = "<button type=\"button\" class=\"btn btn-info\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Als übertragen markieren\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsTransferred(" + row.entry_ID + ")\"><i class=\"fas fa-exchange-alt\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Als gesungen markieren\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsSung(" + row.entry_ID + ")\"><i class=\"fas fa-check\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Eintrag löschen\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');confirmDeleteEntry('" + row.Name + "'," + row.entry_ID + ")\"><i class=\"fas fa-trash\"></i></button>"; outerHTML = "<button type=\"button\" class=\"btn btn-info\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Als übertragen markieren\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsTransferred(" + row.entry_ID + ")\"><i class=\"fas fa-exchange-alt\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Als gesungen markieren\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');markEntryAsSung(" + row.entry_ID + ")\"><i class=\"fas fa-check\"></i></button>&nbsp;<button type=\"button\" class=\"btn btn-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Eintrag löschen\" onclick=\"event.stopPropagation();$(this).tooltip('dispose');confirmDeleteEntry(this.parentElement.parentElement.children[1].innerText," + row.entry_ID + ")\"><i class=\"fas fa-trash\"></i></button>";
} }
return outerHTML; return outerHTML;
} }
function CopyFormatter(value, row, index) { function CopyFormatter(value, row, index) {
return "<span onclick='copyAndNotify(\""+value+"\")'>"+value+"</span>"; let escapedString = value.replace("\"", "\\\"").replace("\'", "\\\'")
return "<span onclick='copyAndNotify(this.innerText)'>" + value + "</span>";
} }
function getIdSelections() { function getIdSelections() {

View File

@ -11,21 +11,52 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Auf Liste setzen</h5> <h5 class="modal-title" id="exampleModalLabel">Auf die Liste setzen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<div class="songinfo container">
<div class="row">
<div class="col">
<h5 id="songTitle"></h5>
<p><span id="songArtist"></span>&nbsp;<span id="songYear"></span></p>
</div>
</div>
<div class="row">
<div class="col-1">
<p><i class="fas fa-info"></i></p>
</div>
<div class="col" id="indicators">
</div>
</div>
<div class="row">
<div class="col-1">
<p><i class="fas fa-file-audio"></i></p>
</div>
<div class="col">
<p id="songGenres"></p>
</div>
</div>
<div class="row">
<div class="col-1">
<p><i class="fas fa-language"></i></p>
</div>
<div class="col">
<p id="songLanguages"></p>
</div>
</div>
</div>
<div class="form-group"> <div class="form-group">
<form id="nameForm"> <form id="nameForm">
<div class="modal-body"> <div class="modal-body">
<label for="singerNameInput">Sängername</label> <label for="singerNameInput">Dein Name:</label>
<input type="text" class="form-control" id="singerNameInput" placeholder="Max Mustermann" <input type="text" class="form-control" id="singerNameInput" placeholder="Max Mustermann"
required> required>
<input id="selectedId" name="selectedId" type="hidden" value=""> <input id="selectedId" name="selectedId" type="hidden" value="">
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Schließen</button>
<button type="submit" class="btn btn-primary" id="submitSongButton">Anmelden</button> <button type="submit" class="btn btn-primary" id="submitSongButton">Anmelden</button>
</div> </div>
</form> </form>
@ -38,35 +69,15 @@
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$("#filter").focus(); $("#filter").focus();
$("#filter").keyup(function () { $("#filter").keyup(debounce(() => songSearch()));
var value = $(this).val().toLowerCase();
//alert(value);
if (value.length >= 1) {
$.getJSON("/api/songs/compl", { search: value }, function (data) {
var items = [];
$.each(data, function (key, val) {
items.push("<tr><td>" + val[0] + `</td>
<td class='buttoncell'><button type='button'
class='btn btn-primary justify-content-center align-content-between enqueueButton'
data-toggle='modal'
data-target='#enqueueModal' onclick='setSelectedId(`+ val[1] + `)'><i
class="fas fa-plus"></i></button></td>
</tr>`)
});
$("#songtable").html("")
$(items.join("")).appendTo("#songtable");
entriesAccepted()
});
} else {
$("#songtable").html("")
}
});
$("#nameForm").submit(function (e) { $("#nameForm").submit(function (e) {
e.preventDefault(); e.preventDefault();
submitModal(); submitModal();
}); });
$('#enqueueModal').on('shown.bs.modal', function (e) {
$("#singerNameInput").focus();
})
}); });
@ -90,7 +101,90 @@
} }
function setSelectedId(id) { function setSelectedId(id) {
$("#songArtist").html("");
$("#songTitle").html("");
$("#songYear").html("");
$("#indicators")[0].innerHTML = "";
$("#selectedId").attr("value", id); $("#selectedId").attr("value", id);
$.getJSON("/api/songs/details/" + id, function (data) {
console.log(data);
$("#songTitle").html(data["title"]);
$("#songArtist").html(data["artist"]);
$("#songYear").html(data["year"]);
$("#indicators")[0].innerHTML = "";
let duoindicator_badge = document.createElement("span");
duoindicator_badge.classList.add("badge");
duoindicator_badge.classList.add("badge-secondary");
duoindicator_badge.classList.add("badge-pill");
duoindicator_badge.classList.add("mx-1");
duoindicator_badge.classList.add("p-2");
if (data["duo"] == 0) {
duoindicator_badge.innerHTML = "Solo";
let duoindicator = document.createElement("i");
duoindicator.classList.add("fas");
duoindicator.classList.add("fa-user");
duoindicator.classList.add("ml-1");
duoindicator_badge.appendChild(duoindicator);
$("#indicators")[0].appendChild(duoindicator_badge)
}
if (data["duo"] == 1) {
duoindicator_badge.innerHTML = "Duo";
let duoindicator = document.createElement("i");
duoindicator.classList.add("fas");
duoindicator.classList.add("fa-user-friends");
duoindicator.classList.add("ml-1");
duoindicator_badge.appendChild(duoindicator);
$("#indicators")[0].appendChild(duoindicator_badge)
}
if (data["explicit"] == 1) {
let explicitindicator_badge = document.createElement("span");
explicitindicator_badge.classList.add("badge");
explicitindicator_badge.classList.add("badge-secondary");
explicitindicator_badge.classList.add("badge-pill");
explicitindicator_badge.classList.add("mx-1");
explicitindicator_badge.classList.add("p-2");
explicitindicator_badge.innerHTML = "Explicit";
let explicitindicator = document.createElement("i");
explicitindicator.classList.add("fas");
explicitindicator.classList.add("fa-e");
explicitindicator.classList.add("ml-1");
explicitindicator_badge.appendChild(explicitindicator);
$("#indicators")[0].appendChild(explicitindicator_badge)
}
let styles = data["styles"].split(",");
let languages = data["languages"].split(",");
$("#songGenres").html("");
$("#songLanguages").html("");
for (let i = 0; i < styles.length; i++) {
let badge = document.createElement("span");
badge.classList.add("badge");
badge.classList.add("badge-secondary");
badge.classList.add("badge-pill");
badge.classList.add("mx-1");
badge.classList.add("p-2");
badge.innerHTML = styles[i];
$("#songGenres")[0].appendChild(badge);
}
for (let i = 0; i < languages.length; i++) {
let badge = document.createElement("span");
badge.classList.add("badge");
badge.classList.add("badge-secondary");
badge.classList.add("badge-pill");
badge.classList.add("mx-1");
badge.classList.add("p-2");
badge.innerHTML = languages[i];
$("#songLanguages")[0].appendChild(badge);
}
});
} }
function submitModal() { function submitModal() {
@ -122,6 +216,76 @@
} }
function songSearch() {
let value = $("#filter").val()
if (value.length >= 1) {
$.getJSON("/api/songs/search", { q: value }, function (data) {
var items = [];
$("#songtable").html("")
$.each(data, function (key, val) {
let itemRow = document.createElement("tr")
let itemCell = document.createElement("td")
itemCell.innerHTML = val["artist"] + ` - ` + val["title"]
itemRow.appendChild(itemCell)
let infoCell = document.createElement("td")
let duoindicator = document.createElement("i")
duoindicator.classList.add("fas")
if (val["duo"] == 0) {
duoindicator.classList.add("fa-user")
}
if (val["duo"] == 1) {
duoindicator.classList.add("fa-user-friends")
}
duoindicator.classList.add("ml-1")
duoindicator.classList.add("list-indicator")
infoCell.appendChild(duoindicator)
if (val["explicit"] == 1) {
let explicitindicator = document.createElement("i")
explicitindicator.classList.add("fas")
explicitindicator.classList.add("fa-e")
explicitindicator.classList.add("ml-1")
infoCell.appendChild(explicitindicator)
}
itemRow.appendChild(infoCell)
let buttonCell = document.createElement("td")
let button = document.createElement("button")
button.classList.add("btn")
button.classList.add("btn-primary")
button.classList.add("justify-content-center")
button.classList.add("align-content-between")
button.classList.add("enqueueButton")
button.setAttribute("type", "button")
button.setAttribute("data-toggle", "modal")
button.setAttribute("data-target", "#enqueueModal")
button.setAttribute("onclick", "setSelectedId(" + val["karafun_id"] + ")")
let buttonIcon = document.createElement("i")
buttonIcon.classList.add("fas")
buttonIcon.classList.add("fa-plus")
button.appendChild(buttonIcon)
buttonCell.appendChild(button)
itemRow.appendChild(buttonCell)
$("#songtable").append(itemRow)
});
$(items.join("")).appendTo("#songtable");
entriesAccepted()
});
} else {
$("#songtable").html("")
}
}
function debounce(func, timeout = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
}
{% if not auth %} {% if not auth %}
function entriesAccepted() { function entriesAccepted() {
$.getJSON("/api/entries/accept", (data, out) => { $.getJSON("/api/entries/accept", (data, out) => {
@ -133,6 +297,7 @@
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()
} else { } else {
$(".enqueueButton").prop("disabled", false) $(".enqueueButton").prop("disabled", false)
} }
}) })

39
build_container.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/bash
# Get username from command line
if [ $# -eq 0 ]; then
echo "No username supplied. Please supply a github username as the first argument."
exit 1
fi
# Store username in variable
USERNAME=$1
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
echo "You have uncommitted changes. Please commit or stash them and try again."
exit 1
fi
# Get the appropriate version of the container using git
VERSION=$(git rev-parse --abbrev-ref HEAD)-$(git describe)
# Build the container. Add the version as a tag and as ENV variable SOURCE_VERSION
docker build -t ghcr.io/$USERNAME/karaoqueue:$VERSION --build-arg SOURCE_VERSION=$VERSION .
# Ask the user if they want to push the container. Confirm Version.
read -p "Push container to ghcr.io/$USERNAME/karaoqueue:$VERSION? [y/n] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
docker push ghcr.io/$USERNAME/karaoqueue:$VERSION
fi
# Ask the user if they want to push the container as latest
read -p "Push container to ghcr.io/$USERNAME/karaoqueue:latest? [y/n] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
docker tag ghcr.io/$USERNAME/karaoqueue:$VERSION ghcr.io/$USERNAME/karaoqueue:latest
docker push ghcr.io/$USERNAME/karaoqueue:latest
fi

View File

@ -6,7 +6,7 @@ secrets:
services: services:
karaoqueue: karaoqueue:
image: "ghcr.io/phoenixtwofive/karaoqueue:v2023.04" image: "ghcr.io/phoenixtwofive/karaoqueue:v2023.06"
build: . build: .
restart: always restart: always
ports: ports: