.venv/
+critters.egg-info/
+build/
+__pycache__/
--- /dev/null
+#! .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/<int:track_id>")
+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/<int:track_id>.<string:feild>")
+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/<int:track_id>")
+@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/<int:track_id>")
+@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/<int:track_id>")
+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)
+++ /dev/null
-#! .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/<int:track_id>")
-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/<int:track_id>.<string:feild>")
-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/<int:track_id>")
-@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/<int:track_id>")
-@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/<int:track_id>")
-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)
--- /dev/null
+from distutils.core import setup
+setup(name='critters',
+ version='1.0',
+ py_modules=['critters'],
+ )
#! .venv/bin/python3
-from index import app
+from critters import app
application = app