From: Max Value Date: Mon, 9 Dec 2024 06:31:49 +0000 (+0000) Subject: Added setup to make module X-Git-Url: https://git.ozva.co.uk/?a=commitdiff_plain;h=73754f5e5923aa5dbd92069553d740f8b21f7954;p=critters-api Added setup to make module --- diff --git a/.gitignore b/.gitignore index 21d0b89..37c69db 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ .venv/ +critters.egg-info/ +build/ +__pycache__/ diff --git a/critters.py b/critters.py new file mode 100755 index 0000000..f842953 --- /dev/null +++ b/critters.py @@ -0,0 +1,312 @@ +#! .venv/bin/python3 + +from flask import Flask, Response, request, render_template, redirect, send_from_directory, url_for +from flask_httpauth import HTTPBasicAuth +from werkzeug.security import generate_password_hash, check_password_hash +from werkzeug.middleware.proxy_fix import ProxyFix +from multiprocessing import Value +from os import listdir +import sqlite3 +import random +import json +import os.path + +app = Flask(__name__) +app.wsgi_app = ProxyFix( + app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1 +) +auth = HTTPBasicAuth() +db_keys = ["title", "album", "artist", "year", "link", "info", "category", "playing", "intime", "outtime"] +allowed_audio = ["mp3", "wav", "ogg", "flac"] +allowed_image = ["png", "jpg", "jpeg"] + +current_track_id = Value("I") # This is the global track ID +with current_track_id.get_lock(): + current_track_id.value = 1 + +audio_path = "../audio/" +cover_path = "../cover/" +icon_path = "../icon/" +upload_path = "../upload/" + +def check_files(track_id): + return { + "track_path": url_for("get_audio", track_id=track_id), + "track_exists": os.path.isfile(f"{audio_path}{track_id}.mp3"), + "front_anno_path": url_for("get_audio", track_id=track_id, position="front"), + "front_anno_exists": os.path.isfile(f"{audio_path}{track_id}-front.mp3"), + "back_anno_path": url_for("get_audio", track_id=track_id, position="back"), + "back_anno_exists": os.path.isfile(f"{audio_path}{track_id}-back.mp3"), + "cover_path": url_for("get_cover", track_id=track_id), + "cover_exists": os.path.isfile(f"{cover_path}{track_id}.png"), + "icon_path": url_for("get_icon", track_id=track_id) + } + +with open("../secrets.json", "r") as f: + users = json.loads(f.read()) +users = {k: generate_password_hash(v) for (k, v) in users.items()} + +@auth.verify_password +def verify_password(username, password): + if username in users and \ + check_password_hash(users.get(username), password): + return username + +# Homepage +@app.route("/") +def homepage(): + page = render_template("home.html") + return Response(page, mimetype="text/html") + +# Admin pannel +@app.route("/admin", methods=['POST', 'GET']) +@auth.login_required +def admin(): + if request.method == "POST": + con = sqlite3.connect("../../metadata.db") + cur = con.cursor() + + try: commit_id = int(request.form["id"]) + except: commit_id = 0 + + if "playing" in request.form: + playing = "true" + else: + playing = "false" + + print(playing) + + # Get the new track id if neccicary + if commit_id == 0: + tracks = cur.execute(f"SELECT id FROM critters").fetchall() + tracks = [track_id[0] for track_id in tracks] + commit_id = 1 + while commit_id in tracks: + commit_id += 1 + + cur.execute(f""" + INSERT INTO critters + (id, title, album, artist, year, link, info, category, playing, intime, outtime) + VALUES ( + {commit_id}, + '{request.form["title"]}', + '{request.form["album"]}', + '{request.form["artist"]}', + '{request.form["year"]}', + '{request.form["link"]}', + '{request.form["info"]}', + '{request.form["category"]}', + '{playing}', + '{request.form["intime"]}', + '{request.form["outtime"]}' + ); + """) + con.commit() + + else: + if "delete" in request.form: + cur.execute(f"DELETE FROM critters WHERE id={request.form["id"]};") + con.commit() + + con.close() + return "" + + else: + cur.execute(f""" + UPDATE critters SET + title = '{request.form["title"]}', + album = '{request.form["album"]}', + artist = '{request.form["artist"]}', + year = '{request.form["year"]}', + link = '{request.form["link"]}', + info = '{request.form["info"]}', + category = '{request.form["category"]}', + playing = '{playing}', + intime = '{request.form["intime"]}', + outtime = '{request.form["outtime"]}' + WHERE id = {commit_id}; + """) + con.commit() + + if "audio" in request.files: + upload = request.files["audio"] + if upload.filename != "": + extention = upload.filename.rsplit('.', 1)[1].lower() + if extention in allowed_audio: + file_path = f"{upload_path}{commit_id}.{extention}" + upload.save(file_path) + os.system(f"sox {file_path} -r 22050 {audio_path}{commit_id}.mp3 &") + + if "front" in request.files: + upload = request.files["front"] + if upload.filename != "": + extention = upload.filename.rsplit('.', 1)[1].lower() + if extention in allowed_audio: + file_path = f"{upload_path}{commit_id}-front.{extention}" + upload.save(file_path) + os.system(f"sox {file_path} -r 22050 {audio_path}{commit_id}-front.mp3 &") + + if "back" in request.files: + upload = request.files["back"] + if upload.filename != "": + extention = upload.filename.rsplit('.', 1)[1].lower() + if extention in allowed_audio: + file_path = f"{upload_path}{commit_id}-back.{extention}" + upload.save(file_path) + os.system(f"sox {file_path} -r 22050 {audio_path}{commit_id}-back.mp3 &") + + if "cover" in request.files: + upload = request.files["cover"] + if upload.filename != "": + extention = upload.filename.rsplit('.')[-1].lower() + if extention in allowed_image: + file_path = f"{upload_path}{commit_id}.{extention}" + upload.save(file_path) + os.system(f"convert {file_path} -scale 32x32! {icon_path}{commit_id}.png &") + os.system(f"convert {file_path} -scale 600x600! {cover_path}{commit_id}.png &") + + page = render_template("admin.html", user = auth.current_user()) + return Response(page, mimetype="text/html") + +# Get the next track +@app.route("/api/next") +@auth.login_required +def set_current_id(): + server_data = { # The value for each of the keys is the position in the database columns that peice of data can be found + "id": 0, # (Note 1) + "title": 1, + "artist": 3, + "intime": 9, + "outtime": 10 + } + + with current_track_id.get_lock(): # Lock for entire function + track_id = current_track_id.value + + current_album = "" + current_artist = "" + + con = sqlite3.connect("../../metadata.db") + cur = con.cursor() + track = cur.execute(f"SELECT album, artist FROM critters WHERE id={track_id}").fetchone() + + if track is not None: + current_album, current_artist = track + + category_secifier = "" + if "c" in request.args: + category = request.args.get("c") + category_secifier = f" AND category = '{category}'" + + tracks = cur.execute(f""" + SELECT * FROM critters WHERE + playing = 'true' AND + id != {track_id} AND + album != '{current_album}' AND + artist != '{current_artist}'{category_secifier} + """).fetchall() + + if tracks is not None: + target_index = random.randint(0, len(tracks)-1) + + current_track_id.value = tracks[target_index][0] + + for key, i in server_data.items(): + server_data[key] = tracks[target_index][i] # See note 1 + + return Response(json.dumps(server_data), mimetype="text/json") + +@app.route("/api/get", methods=['GET']) +def get_tracks(): + track_data = { + "id": 0, + "title": "Unknown", + "album": "Unknown", + "artist": "Unknown", + "year": "Unknown", + "link": "https://treecritters.bandcamp.com", + "info": "No info", + "category":"None", + "playing":"false" + } + responce_data = [track_data] + + con = sqlite3.connect("../../metadata.db") + cur = con.cursor() + tracks = cur.execute(f"SELECT * FROM critters").fetchall() + if tracks is not None: + responce_data = [{key: track[i] for (i, key) in enumerate(track_data)} | check_files(track[0]) for track in tracks] + + return Response(json.dumps(responce_data), mimetype="text/json") + +# Call for getting single track details with all feilds in JSON +@app.route("/api/") +def get_single_track(track_id): + if track_id == 0: + with current_track_id.get_lock(): + track_id = current_track_id.value + con = sqlite3.connect("../../metadata.db") + cur = con.cursor() + track = cur.execute(f"SELECT * FROM critters WHERE id={track_id}").fetchone() + track_data = { + "id": 0, + "title": "Unknown", + "album": "Unknown", + "artist": "Unknown", + "year": "Unknown", + "link": "https://treecritters.bandcamp.com", + "info": "No info", + "category": "None", + "playing": "false", + } + cover_path = {"cover_path": url_for("get_cover", track_id=track_id)} + if track is not None: + for (i, key) in enumerate(track_data): + track_data[key] = track[i] + return Response(json.dumps(track_data | cover_path), mimetype="text/json") + +# Call for getting single track details with a single feild +@app.route("/api/.") +def get_single_field(track_id, feild): + if track_id == 0: + with current_track_id.get_lock(): + track_id = current_track_id.value + result = "Unknown" + if feild in db_keys: + con = sqlite3.connect("../../metadata.db") + cur = con.cursor() + track = cur.execute(f"SELECT {feild} FROM critters WHERE id={track_id}").fetchone() + if track is not None: + result = track[0] + if feild == "cover_path": + result = url_for("get_cover", track_id=track_id) + + return Response(result, mimetype="text/plaintext") + +@app.route("/api/audio/") +@auth.login_required +def get_audio(track_id): + if "position" in request.args: + position = request.args.get('position') + if position in ["front", "back"]: + return send_from_directory(audio_path, f"{track_id}-{position}.mp3") + + return send_from_directory(audio_path, f"{track_id}.mp3") + +@app.route("/api/icon/") +@auth.login_required +def get_icon(track_id): + if os.path.isfile(f"{icon_path}{track_id}.png"): + return send_from_directory(icon_path, f"{track_id}.png") + else: + return send_from_directory(icon_path, "default.png") + +@app.route("/api/cover/") +def get_cover(track_id): + if os.path.isfile(f"{cover_path}{track_id}.png"): + return send_from_directory(cover_path, f"{track_id}.png") + else: + return send_from_directory(cover_path, "default.png") + +if __name__ == "__main__": + app.run(host='127.0.0.1', port=5000, debug=True) diff --git a/index.py b/index.py deleted file mode 100755 index f842953..0000000 --- a/index.py +++ /dev/null @@ -1,312 +0,0 @@ -#! .venv/bin/python3 - -from flask import Flask, Response, request, render_template, redirect, send_from_directory, url_for -from flask_httpauth import HTTPBasicAuth -from werkzeug.security import generate_password_hash, check_password_hash -from werkzeug.middleware.proxy_fix import ProxyFix -from multiprocessing import Value -from os import listdir -import sqlite3 -import random -import json -import os.path - -app = Flask(__name__) -app.wsgi_app = ProxyFix( - app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1 -) -auth = HTTPBasicAuth() -db_keys = ["title", "album", "artist", "year", "link", "info", "category", "playing", "intime", "outtime"] -allowed_audio = ["mp3", "wav", "ogg", "flac"] -allowed_image = ["png", "jpg", "jpeg"] - -current_track_id = Value("I") # This is the global track ID -with current_track_id.get_lock(): - current_track_id.value = 1 - -audio_path = "../audio/" -cover_path = "../cover/" -icon_path = "../icon/" -upload_path = "../upload/" - -def check_files(track_id): - return { - "track_path": url_for("get_audio", track_id=track_id), - "track_exists": os.path.isfile(f"{audio_path}{track_id}.mp3"), - "front_anno_path": url_for("get_audio", track_id=track_id, position="front"), - "front_anno_exists": os.path.isfile(f"{audio_path}{track_id}-front.mp3"), - "back_anno_path": url_for("get_audio", track_id=track_id, position="back"), - "back_anno_exists": os.path.isfile(f"{audio_path}{track_id}-back.mp3"), - "cover_path": url_for("get_cover", track_id=track_id), - "cover_exists": os.path.isfile(f"{cover_path}{track_id}.png"), - "icon_path": url_for("get_icon", track_id=track_id) - } - -with open("../secrets.json", "r") as f: - users = json.loads(f.read()) -users = {k: generate_password_hash(v) for (k, v) in users.items()} - -@auth.verify_password -def verify_password(username, password): - if username in users and \ - check_password_hash(users.get(username), password): - return username - -# Homepage -@app.route("/") -def homepage(): - page = render_template("home.html") - return Response(page, mimetype="text/html") - -# Admin pannel -@app.route("/admin", methods=['POST', 'GET']) -@auth.login_required -def admin(): - if request.method == "POST": - con = sqlite3.connect("../../metadata.db") - cur = con.cursor() - - try: commit_id = int(request.form["id"]) - except: commit_id = 0 - - if "playing" in request.form: - playing = "true" - else: - playing = "false" - - print(playing) - - # Get the new track id if neccicary - if commit_id == 0: - tracks = cur.execute(f"SELECT id FROM critters").fetchall() - tracks = [track_id[0] for track_id in tracks] - commit_id = 1 - while commit_id in tracks: - commit_id += 1 - - cur.execute(f""" - INSERT INTO critters - (id, title, album, artist, year, link, info, category, playing, intime, outtime) - VALUES ( - {commit_id}, - '{request.form["title"]}', - '{request.form["album"]}', - '{request.form["artist"]}', - '{request.form["year"]}', - '{request.form["link"]}', - '{request.form["info"]}', - '{request.form["category"]}', - '{playing}', - '{request.form["intime"]}', - '{request.form["outtime"]}' - ); - """) - con.commit() - - else: - if "delete" in request.form: - cur.execute(f"DELETE FROM critters WHERE id={request.form["id"]};") - con.commit() - - con.close() - return "" - - else: - cur.execute(f""" - UPDATE critters SET - title = '{request.form["title"]}', - album = '{request.form["album"]}', - artist = '{request.form["artist"]}', - year = '{request.form["year"]}', - link = '{request.form["link"]}', - info = '{request.form["info"]}', - category = '{request.form["category"]}', - playing = '{playing}', - intime = '{request.form["intime"]}', - outtime = '{request.form["outtime"]}' - WHERE id = {commit_id}; - """) - con.commit() - - if "audio" in request.files: - upload = request.files["audio"] - if upload.filename != "": - extention = upload.filename.rsplit('.', 1)[1].lower() - if extention in allowed_audio: - file_path = f"{upload_path}{commit_id}.{extention}" - upload.save(file_path) - os.system(f"sox {file_path} -r 22050 {audio_path}{commit_id}.mp3 &") - - if "front" in request.files: - upload = request.files["front"] - if upload.filename != "": - extention = upload.filename.rsplit('.', 1)[1].lower() - if extention in allowed_audio: - file_path = f"{upload_path}{commit_id}-front.{extention}" - upload.save(file_path) - os.system(f"sox {file_path} -r 22050 {audio_path}{commit_id}-front.mp3 &") - - if "back" in request.files: - upload = request.files["back"] - if upload.filename != "": - extention = upload.filename.rsplit('.', 1)[1].lower() - if extention in allowed_audio: - file_path = f"{upload_path}{commit_id}-back.{extention}" - upload.save(file_path) - os.system(f"sox {file_path} -r 22050 {audio_path}{commit_id}-back.mp3 &") - - if "cover" in request.files: - upload = request.files["cover"] - if upload.filename != "": - extention = upload.filename.rsplit('.')[-1].lower() - if extention in allowed_image: - file_path = f"{upload_path}{commit_id}.{extention}" - upload.save(file_path) - os.system(f"convert {file_path} -scale 32x32! {icon_path}{commit_id}.png &") - os.system(f"convert {file_path} -scale 600x600! {cover_path}{commit_id}.png &") - - page = render_template("admin.html", user = auth.current_user()) - return Response(page, mimetype="text/html") - -# Get the next track -@app.route("/api/next") -@auth.login_required -def set_current_id(): - server_data = { # The value for each of the keys is the position in the database columns that peice of data can be found - "id": 0, # (Note 1) - "title": 1, - "artist": 3, - "intime": 9, - "outtime": 10 - } - - with current_track_id.get_lock(): # Lock for entire function - track_id = current_track_id.value - - current_album = "" - current_artist = "" - - con = sqlite3.connect("../../metadata.db") - cur = con.cursor() - track = cur.execute(f"SELECT album, artist FROM critters WHERE id={track_id}").fetchone() - - if track is not None: - current_album, current_artist = track - - category_secifier = "" - if "c" in request.args: - category = request.args.get("c") - category_secifier = f" AND category = '{category}'" - - tracks = cur.execute(f""" - SELECT * FROM critters WHERE - playing = 'true' AND - id != {track_id} AND - album != '{current_album}' AND - artist != '{current_artist}'{category_secifier} - """).fetchall() - - if tracks is not None: - target_index = random.randint(0, len(tracks)-1) - - current_track_id.value = tracks[target_index][0] - - for key, i in server_data.items(): - server_data[key] = tracks[target_index][i] # See note 1 - - return Response(json.dumps(server_data), mimetype="text/json") - -@app.route("/api/get", methods=['GET']) -def get_tracks(): - track_data = { - "id": 0, - "title": "Unknown", - "album": "Unknown", - "artist": "Unknown", - "year": "Unknown", - "link": "https://treecritters.bandcamp.com", - "info": "No info", - "category":"None", - "playing":"false" - } - responce_data = [track_data] - - con = sqlite3.connect("../../metadata.db") - cur = con.cursor() - tracks = cur.execute(f"SELECT * FROM critters").fetchall() - if tracks is not None: - responce_data = [{key: track[i] for (i, key) in enumerate(track_data)} | check_files(track[0]) for track in tracks] - - return Response(json.dumps(responce_data), mimetype="text/json") - -# Call for getting single track details with all feilds in JSON -@app.route("/api/") -def get_single_track(track_id): - if track_id == 0: - with current_track_id.get_lock(): - track_id = current_track_id.value - con = sqlite3.connect("../../metadata.db") - cur = con.cursor() - track = cur.execute(f"SELECT * FROM critters WHERE id={track_id}").fetchone() - track_data = { - "id": 0, - "title": "Unknown", - "album": "Unknown", - "artist": "Unknown", - "year": "Unknown", - "link": "https://treecritters.bandcamp.com", - "info": "No info", - "category": "None", - "playing": "false", - } - cover_path = {"cover_path": url_for("get_cover", track_id=track_id)} - if track is not None: - for (i, key) in enumerate(track_data): - track_data[key] = track[i] - return Response(json.dumps(track_data | cover_path), mimetype="text/json") - -# Call for getting single track details with a single feild -@app.route("/api/.") -def get_single_field(track_id, feild): - if track_id == 0: - with current_track_id.get_lock(): - track_id = current_track_id.value - result = "Unknown" - if feild in db_keys: - con = sqlite3.connect("../../metadata.db") - cur = con.cursor() - track = cur.execute(f"SELECT {feild} FROM critters WHERE id={track_id}").fetchone() - if track is not None: - result = track[0] - if feild == "cover_path": - result = url_for("get_cover", track_id=track_id) - - return Response(result, mimetype="text/plaintext") - -@app.route("/api/audio/") -@auth.login_required -def get_audio(track_id): - if "position" in request.args: - position = request.args.get('position') - if position in ["front", "back"]: - return send_from_directory(audio_path, f"{track_id}-{position}.mp3") - - return send_from_directory(audio_path, f"{track_id}.mp3") - -@app.route("/api/icon/") -@auth.login_required -def get_icon(track_id): - if os.path.isfile(f"{icon_path}{track_id}.png"): - return send_from_directory(icon_path, f"{track_id}.png") - else: - return send_from_directory(icon_path, "default.png") - -@app.route("/api/cover/") -def get_cover(track_id): - if os.path.isfile(f"{cover_path}{track_id}.png"): - return send_from_directory(cover_path, f"{track_id}.png") - else: - return send_from_directory(cover_path, "default.png") - -if __name__ == "__main__": - app.run(host='127.0.0.1', port=5000, debug=True) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0356f21 --- /dev/null +++ b/setup.py @@ -0,0 +1,5 @@ +from distutils.core import setup +setup(name='critters', + version='1.0', + py_modules=['critters'], + ) diff --git a/wsgi.py b/wsgi.py index d659370..11f8531 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,5 +1,5 @@ #! .venv/bin/python3 -from index import app +from critters import app application = app