]> OzVa Git service - critters-api/commitdiff
Did a lot :3
authorMax Value <greenwoodw50@gmail.com>
Mon, 9 Dec 2024 05:08:12 +0000 (05:08 +0000)
committerMax Value <greenwoodw50@gmail.com>
Mon, 9 Dec 2024 05:08:12 +0000 (05:08 +0000)
.gitignore [new file with mode: 0644]
index.py [new file with mode: 0755]
schema [new file with mode: 0644]
static/admin.js [new file with mode: 0644]
static/pause.svg [new file with mode: 0644]
static/play.svg [new file with mode: 0644]
static/player.html [new file with mode: 0644]
static/style.css [new file with mode: 0644]
templates/admin.html [new file with mode: 0644]
templates/home.html [new file with mode: 0644]
test.txt [deleted file]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..21d0b89
--- /dev/null
@@ -0,0 +1 @@
+.venv/
diff --git a/index.py b/index.py
new file mode 100755 (executable)
index 0000000..9e46087
--- /dev/null
+++ b/index.py
@@ -0,0 +1,308 @@
+#! .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 multiprocessing import Value
+from os import listdir
+import sqlite3
+import random
+import json
+import os.path
+
+app = Flask(__name__)
+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}
+
+@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)
diff --git a/schema b/schema
new file mode 100644 (file)
index 0000000..e9b93f8
--- /dev/null
+++ b/schema
@@ -0,0 +1,13 @@
+CREATE TABLE critters (
+       id INTEGER PRIMARY KEY,
+       title TEXT,
+       album TEXT,
+       artist TEXT,
+       year TEXT,
+       link TEXT,
+       info TEXT,
+       category TEXT,
+       playing TEXT,
+       intime TEXT,
+       outtime TEXT
+);
diff --git a/static/admin.js b/static/admin.js
new file mode 100644 (file)
index 0000000..7693cf3
--- /dev/null
@@ -0,0 +1,122 @@
+const goodSymbol = "&#10004;";
+const badSymbol = "&#10008;";
+
+function getTrackList () {
+    fetch("/api/get")
+        .then(data => data.text())
+        .then(data => JSON.parse(data))
+        .then(data => {
+            var html = `
+                <tr>
+                    <th></th>
+                    <th>#</th>
+                    <th>Title</th>
+                    <th>Album</th>
+                    <th>Artist</th>
+                    <th>Category</th>
+                    <th>Playing</th>
+                    <th>Track</th>
+                    <th>Front</th>
+                    <th>Back</th>
+                    <th>Cover</th>
+                    <th></th>
+                </tr>
+                `;
+            for (let track of data) {
+
+                if (track.playing == "true") {
+                    trackPlaying = goodSymbol;
+                } else {
+                    trackPlaying = badSymbol;
+                }
+
+                if (track.track_exists) {
+                    trackExists = `<a href="${track.track_path}" target="_blank">${goodSymbol}</a>`;
+                } else {
+                    trackExists = badSymbol;
+                }
+
+                if (track.front_anno_exists) {
+                    frontAnnoExists = `<a href="${track.front_anno_path}" target="_blank">${goodSymbol}</a>`;
+                } else {
+                    frontAnnoExists = badSymbol;
+                }
+
+                if (track.back_anno_exists) {
+                    backAnnoExists = `<a href="${track.back_anno_path}" target="_blank">${goodSymbol}</a>`;
+                } else {
+                    backAnnoExists = badSymbol;
+                }
+
+                if (track.cover_exists) {
+                    coverExists = `<a href="${track.cover_path}" target="_blank">${goodSymbol}</a>`;
+                } else {
+                    coverExists = badSymbol;
+                }
+
+                html += `
+                <tr id="track${track.id}">
+                    <td><img class="smallIcon" src="${track.icon_path}" /></td>
+                    <td>${track.id}</td>
+                    <td>${track.title}</td>
+                    <td>${track.album}</td>
+                    <td>${track.artist}</td>
+                    <td>${track.category}</td>
+                    <td>${trackPlaying}</td>
+                    <td>${trackExists}</td>
+                    <td>${frontAnnoExists}</td>
+                    <td>${backAnnoExists}</td>
+                    <td>${coverExists}</td>
+                    <td>
+                        <input type="button" value="Edit track" onclick="editTrack(${track.id});" />
+                        <input type="button" value="Delete track" onclick="deleteTrack(${track.id});" />
+                    </td>
+                </tr>
+                `
+            };
+            return html
+        })
+        .then(data => document.getElementById("trackListFull").innerHTML = data);
+}
+
+function newTrack () {
+    const elements = document.getElementsByClassName("mainForm");
+    console.log(elements)
+    for (const e of elements) {
+        e.value = "";
+    }
+    document.getElementById("id").value = "New track";
+    document.getElementById("playing").checked = true;
+    document.getElementById("thumbnail").src = `/api/cover/0`;
+}
+
+function editTrack (id) {
+    document.getElementById("thumbnail").src = `/api/cover/${id}`
+    fetch(`/api/${id}`)
+    .then(data => data.text())
+    .then(data => JSON.parse(data))
+    .then(data => {
+        for (let x in data) {
+            document.getElementById(x).value = data[x];
+        }
+        if (data.playing == "true") {
+            document.getElementById("playing").checked = true;
+        } else {
+            document.getElementById("playing").checked = false;
+        }
+    });
+}
+
+function deleteTrack (id) {
+    const form = new FormData();
+    form.append("id", id);
+    form.append("delete", 1);
+
+    fetch("/admin", {
+        method: "POST",
+        body: form
+    })
+    .then(document.getElementById(`track${id}`).remove());
+}
+
+getTrackList();
diff --git a/static/pause.svg b/static/pause.svg
new file mode 100644 (file)
index 0000000..d48e265
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="1000"
+   height="1000"
+   viewBox="0 0 1000 1000"
+   version="1.1"
+   xml:space="preserve"
+   id="SVGRoot"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs9" />
+
+<style
+   type="text/css"
+   id="style1">
+g.prefab path {
+  vector-effect:non-scaling-stroke;
+  -inkscape-stroke:hairline;
+  fill: none;
+  fill-opacity: 1;
+  stroke-opacity: 1;
+  stroke: #00349c;
+}
+</style>
+
+<path
+   id="rect10"
+   style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
+   d="M 300,250 H 450 V 750 H 300 Z m 250,0 H 700 V 750 H 550 Z" /><path
+   style="display:none;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
+   id="path10"
+   d="M 800,500 574.99999,629.90381 350,759.80762 l 0,-259.80763 0,-259.80761 225.00001,129.90381 z"
+   transform="translate(-50)" /></svg>
diff --git a/static/play.svg b/static/play.svg
new file mode 100644 (file)
index 0000000..7ba5940
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="1000"
+   height="1000"
+   viewBox="0 0 1000 1000"
+   version="1.1"
+   xml:space="preserve"
+   id="SVGRoot"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs9" />
+
+<style
+   type="text/css"
+   id="style1">
+g.prefab path {
+  vector-effect:non-scaling-stroke;
+  -inkscape-stroke:hairline;
+  fill: none;
+  fill-opacity: 1;
+  stroke-opacity: 1;
+  stroke: #00349c;
+}
+</style>
+
+<path
+   id="rect10"
+   style="display:none;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
+   d="M 300,250 H 450 V 750 H 300 Z m 250,0 H 700 V 750 H 550 Z" /><path
+   style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
+   id="path10"
+   d="M 800,500 574.99999,629.90381 350,759.80762 l 0,-259.80763 0,-259.80761 225.00001,129.90381 z"
+   transform="translate(-50)" /></svg>
diff --git a/static/player.html b/static/player.html
new file mode 100644 (file)
index 0000000..9cee960
--- /dev/null
@@ -0,0 +1,198 @@
+<html>
+       <head>
+               <style>
+
+body {
+       position: absolute;
+       top: 0;
+       bottom: 0;
+       left: 0;
+       right: 0;
+       margin: 0;
+       overflow: hidden;
+       color: var(--background)
+}
+img {
+       height: 100vh;
+}
+audio {
+       margin: 4px;
+       width: calc(100% - 8px);
+       height: 20px;
+}
+#playerMain {
+       display: inline-block;
+       vertical-align: top;
+       width: calc((100vw - 100vh) * 0.5);
+       height: 100vh;
+
+       background-color: var(--primary);
+}
+#playerInfo {
+       display: inline-block;
+       vertical-align: top;
+       width: calc(((100vw - 100vh) * 0.5) - 1px);
+       height: 100vh;
+       overflow: scroll;
+
+       background-color: var(--secondary);
+}
+#stationName {
+       position: absolute;
+       bottom: 0;
+       left: 100vh;
+       margin: 0;
+       color: var(--off-primary);
+       font-size: 2em;
+       line-height: 1em;
+}
+#playerPlaying {
+       width: calc(100% - 16px);
+       height: 20px;
+       margin: 4px;
+       padding: 4px;
+       color: var(--primary);
+       background-color: var(--dark);
+}
+#pauseIcon, #playIcon {
+       position: absolute;
+       top: 0;
+       left: 0;
+       width: 100vh;
+       height: 100vh;
+}
+#allIcon {
+       opacity: 0;
+       transition: opacity 0.5s;
+}
+#allIcon:hover {
+       opacity: 1;
+}
+
+@media only screen and (max-width : 700px) {
+       #playerMain {
+               width: calc((100vw - 100vh) - 1px);
+       }
+       #playerInfo {
+               display: none;
+       }
+}
+
+/* Remove default apperance */
+input[type="range"] {
+       margin: 4px;
+       margin-bottom: 0;
+       width: calc(100% - 8px);
+       height: 10px;
+  -webkit-appearance: none;
+  appearance: none;
+  cursor: pointer;
+  outline: none;
+  /*  overflow: hidden;  remove this line*/
+  background: var(--background);
+}
+
+/* Thumb: webkit */
+input[type="range"]::-webkit-slider-thumb {
+  -webkit-appearance: none;
+  appearance: none;
+  height: 10px;
+  width: 10px;
+  background-color: var(--off-primary);
+  border-radius: 0;
+  border: none;
+  transition: .2s ease-in-out;
+}
+
+/* Thumb: Firefox */
+input[type="range"]::-moz-range-thumb {
+  height: 10px;
+  width: 30px;
+  background-color: var(--off-primary);
+  border-radius: 0;
+  border: none;
+  transition: .2s ease-in-out;
+}
+
+/* Hover, active & focus Thumb: Webkit */
+
+/*input[type="range"]::-webkit-slider-thumb:hover {
+  box-shadow: 0 0 0 10px rgba(255,85,0, .1)
+}
+input[type="range"]:active::-webkit-slider-thumb {
+  box-shadow: 0 0 0 13px rgba(255,85,0, .2)
+}
+input[type="range"]:focus::-webkit-slider-thumb {
+  box-shadow: 0 0 0 13px rgba(255,85,0, .2)
+}*/
+
+/* Hover, active & focus Thumb: Firfox */
+
+/*input[type="range"]::-moz-range-thumb:hover {
+  box-shadow: 0 0 0 10px rgba(255,85,0, .1)
+}
+input[type="range"]:active::-moz-range-thumb {
+  box-shadow: 0 0 0 13px rgba(255,85,0, .2)
+}
+input[type="range"]:focus::-moz-range-thumb {
+  box-shadow: 0 0 0 13px rgba(255,85,0, .2)
+}*/
+               </style>
+               <link rel="stylesheet" href="/static/style.css">
+               <script>
+
+const player = new Audio("https://stream.ozva.co.uk:8443/critters");
+var playing = false;
+
+function getInfo () {
+    fetch("/api/0")
+    .then(data => data.text())
+    .then(data => JSON.parse(data))
+    .then(data => {
+        document.getElementById("playerCover").src = data.cover_path;
+        document.getElementById("playerInfo").innerHTML = data.info;
+        document.getElementById("playerPlaying").innerHTML = `
+        <em>Now playing:</em> <a href="${data.link}">${data.title}</a> - ${data.artist} <em>(${data.year})</em>
+        `;
+    })
+}
+
+function setVolume () {
+       player.volume = document.getElementById("volumeControl").value;
+}
+
+function toggleAudio () {
+       if (playing) {
+               player.pause();
+               player.load();
+               playing = false;
+               document.getElementById("playIcon").style = "";
+               document.getElementById("pauseIcon").style = "display: none;";
+       } else {
+               player.play();
+               playing = true;
+               document.getElementById("playIcon").style = "display: none;";
+               document.getElementById("pauseIcon").style = "";
+       }
+}
+
+setInterval(setVolume, 100);
+setInterval(getInfo, 4000);
+               </script>
+       </head>
+       <body onload="getInfo();document.getElementById('volumeControl').style = '';">
+               <img id="playerCover" src="/api/cover/0" /><div id="playerMain">
+                       <input id="volumeControl" style="display: none;" type="range" min="0" max="1" step="0.01"/>
+                       <noscript>
+                               <audio src="https://stream.ozva.co.uk:8443/critters" controls></audio><br>
+                       </noscript>
+                       <p id="playerPlaying">Currently playing track info available with the JS player</p>
+               </div><div id="playerInfo">
+               </div>
+               <h1 id="stationName"><em>Tree Critters Radio</em></h1>
+               <div id="allIcon">
+                       <img onclick="toggleAudio();" id="playIcon" style="" src="/static/play.svg" />
+                       <img onclick="toggleAudio();" id="pauseIcon" style="display: none;" src="/static/pause.svg" />
+               </div>
+       </body>
+</html>
diff --git a/static/style.css b/static/style.css
new file mode 100644 (file)
index 0000000..55cfd75
--- /dev/null
@@ -0,0 +1,25 @@
+:root {
+    --background: #111111;
+    --dark: #151515;
+    --primary: #70b783;
+    --off-primary: #4d9961;
+    --secondary: #c6ce73;
+    --tertiary: #2b5536;
+
+    font-family: sans-serif;
+    color: var(--primary);
+    background-color: var(--background);
+}
+
+a:link {
+    color: var(--secondary);
+}
+a:visited {
+    color: var(--secondary);
+}
+a:hover {
+    color: var(--primary);
+}
+a:active {
+    color: white;
+}
diff --git a/templates/admin.html b/templates/admin.html
new file mode 100644 (file)
index 0000000..9951809
--- /dev/null
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<html>
+       <head>
+        <title>Tree Critters</title>
+               <script src="static/admin.js"></script>
+               <style>
+
+input[type="submit"], input[type="button"] {
+    color: var(--background);
+    background-color: var(--secondary);
+    border: none;
+}
+input[type="submit"]:hover, input[type="button"]:hover {
+    background-color: var(--primary);
+}
+
+#trackList {
+    display: inline-block;
+    width: 78%;
+    margin: 1%;
+    vertical-align: top;
+}
+#editPannel {
+    display: inline-block;
+    width: 18%;
+    margin: 1%;
+    vertical-align: top;
+}
+
+table, input[type="text"] {
+    width: 100%;
+    padding: 0;
+    border-collapse: collapse;
+}
+th {
+    text-align: left;
+}
+
+#thumbnail {
+    width: 100%;
+}
+
+.smallIcon {
+    width: 1em;
+    height: 1em;
+}
+.mainForm {
+    color: var(--background);
+}
+
+               </style>
+               <link rel="stylesheet" href="/static/style.css">
+       </head>
+       <body>
+        <h1>Tree Critters Admin pannel</h1>
+        <p>Signed in as <b>{{user}}</b></p>
+        <input type="button" value="Refresh" onclick="getTrackList();" /><br>
+        <div id="editPannel">
+            <img id="thumbnail" src="/api/cover/0" />
+            <span id="cover_path" value=""></span>
+            <input type="button" value="New track" onclick="newTrack();" />
+            <form method="POST" enctype=multipart/form-data>
+                <table>
+                    <tr>
+                        <td><label for="id">Track ID</label></td>
+                        <td><input type="text" id="id" class="mainForm" name="id" value="New track" readonly></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="title">Title</label></td>
+                        <td><input type="text" id="title" class="mainForm" name="title"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="album">Album</label></td>
+                        <td><input type="text" id="album" class="mainForm" name="album"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="artist">Artist</label></td>
+                        <td><input type="text" id="artist" class="mainForm" name="artist"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="year">Year</label></td>
+                        <td><input type="text" id="year" class="mainForm" name="year"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="link">URL</label></td>
+                        <td><input type="text" id="link" class="mainForm" name="link"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="info">Track info</label></td>
+                        <td><input type="text" id="info" class="mainForm" name="info"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="category">Category</label></td>
+                        <td><input type="text" id="category" class="mainForm" name="category"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="playing">Playing</label></td>
+                        <td><input type="checkbox" id="playing" class="mainForm" name="playing" value="true"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="intime">In-time</label></td>
+                        <td><input type="number" id="intime" class="mainForm" name="intime"></input></td>
+                    </tr>
+                    <tr>
+                        <td><label for="outtime">Out-time</label></td>
+                        <td><input type="number" id="outtime" class="mainForm" name="outtime"></input></td>
+                    </tr>
+
+
+                    <tr>
+                        <td><label for="audio">Track</label></td>
+                        <td><input type="file" id="audio" name="audio"></td>
+                    </tr>
+                    <tr>
+                        <td><label for="front">Front</label></td>
+                        <td><input type="file" id="front" name="front"></td>
+                    </tr>
+                    <tr>
+                        <td><label for="back">Back</label></td>
+                        <td><input type="file" id="back" name="back"></td>
+                    </tr>
+                    <tr>
+                        <td><label for="cover">Cover</label></td>
+                        <td><input type="file" id="cover" name="cover"></td>
+                    </tr>
+
+
+                </table>
+                <input type="submit" value="Save data" />
+            </form>
+        </div><div id="trackList"><table id="trackListFull"></table></div>
+       </body>
+</html>
diff --git a/templates/home.html b/templates/home.html
new file mode 100644 (file)
index 0000000..d7d51b1
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+       <head>
+        <title>Tree Critters</title>
+               <link rel="stylesheet" href="static/style.css">
+       </head>
+       <body>
+               <h1>Tree Critters Radio</h1>
+               <h2>Player:</h2>
+               <iframe style="border: none; width: 700px; height: 100px;" src="/static/player.html"></iframe>
+               <p><a href="/admin">Control pannel</a></p>
+       </body>
+</html>
diff --git a/test.txt b/test.txt
deleted file mode 100644 (file)
index e69de29..0000000