Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ venv

key_env.bat

.vscode
.vscode

voice_announce_tmp
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ ENV UWSGI_INI /srv/www/yogsite/uwsgi.ini
COPY . /srv/www/yogsite
COPY nginx.conf /etc/nginx/sites-available/

RUN echo "deb http://deb.debian.org/debian experimental main" >> /etc/apt/sources.list
RUN echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y -t experimental ffmpeg

RUN pip install -r /srv/www/yogsite/requirements.txt

WORKDIR /srv/www/yogsite
11 changes: 10 additions & 1 deletion config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ items_per_page: 20
servers:
main:
id: "main"
sqlname: "yogstation"
host: "game.yogstation.net"
port: 4133
name: "YogStation Main"
primary: true
comms_key: $COMMS_KEY

logs:
directory: $GAME_LOGS_DIR
Expand Down Expand Up @@ -103,7 +105,11 @@ roles: [
"gangster",
"darkspawn",
"Holoparasite",
"Zombie"
"Zombie",
"Appearance",
"Emote",
"OOC",
"Voice Announcements"
]

library:
Expand Down Expand Up @@ -133,6 +139,9 @@ paypal:
return_url: "/donate?confirm=1"
notify_url: "/api/paypal_donate"

voice_announce:
directory: $GAME_VOICE_ANNOUNCE_DIR

donation:
tiers:
- amount: 7.00
Expand Down
3 changes: 3 additions & 0 deletions run_with_env_vars.bat
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ set DB_GAME_PORT=3306
set DB_GAME_NAME="yogstation"

set FLASK_SECRET_KEY="geiogjiovheiofhweiofh"
set COMMS_KEY=""

set GAME_VOICE_ANNOUNCE_DIR=".\\voice_announce_tmp"

python wsgi.py
4 changes: 3 additions & 1 deletion yogsite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def modify_query(**new_values):
from yogsite.modules.login import blueprint as bp_login
from yogsite.modules.home import blueprint as bp_home
from yogsite.modules.rounds import blueprint as bp_rounds
from yogsite.modules.voice_announce import blueprint as bp_voice_announce

app.register_blueprint(bp_admin)
app.register_blueprint(bp_api)
Expand All @@ -94,4 +95,5 @@ def modify_query(**new_values):
app.register_blueprint(bp_home)
app.register_blueprint(bp_library)
app.register_blueprint(bp_login)
app.register_blueprint(bp_rounds)
app.register_blueprint(bp_rounds)
app.register_blueprint(bp_voice_announce)
2 changes: 1 addition & 1 deletion yogsite/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

cfg = EnvYAML("config.yml")

XENFORO_HEADERS = {"XF-Api-Key": cfg.get("xenforo_key")}
XENFORO_HEADERS = {"XF-Api-Key": cfg.get("xenforo_key")}
1 change: 1 addition & 0 deletions yogsite/modules/voice_announce/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .routes import blueprint
102 changes: 102 additions & 0 deletions yogsite/modules/voice_announce/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from flask import Blueprint, Response, request, render_template
from werkzeug.utils import secure_filename
from io import open
from os import path, remove
from yogsite.extensions import flask_csrf_ext
from yogsite.config import cfg
from yogsite.util import topic_query
from subprocess import run,DEVNULL

blueprint = Blueprint("voice_announce", __name__)

type_extensions = {
"audio/aac": ".aac",
"audio/mpeg": ".mp3",
"audio/ogg": ".ogg",
"audio/opus": ".opus",
"audio/wav": ".wav",
"audio/webm": ".weba"
}

@blueprint.route("/voice_announce/<string:serversqlname>/<string:id>")
def page_voice_announce(serversqlname, id):
for s in cfg.get("servers").values():
if s["sqlname"] == serversqlname:
server = s
res = topic_query(server, "", args = {
"voice_announce_query": id,
"key": server["comms_key"]
})
if (not res) or (not int(res["exists"])):
return Response("Invalid voice announcement URL", status=404)

return render_template("voice_announce/voice_announce.html", enable_robot_voice = int(res["is_ai"]))

@blueprint.route("/voice_announce/<string:serversqlname>/<string:id>/upload", methods=["POST"])
@flask_csrf_ext.exempt
def voice_announce_upload(serversqlname, id):
for s in cfg.get("servers").values():
if s["sqlname"] == serversqlname:
server = s
id = secure_filename(id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome

dir = cfg.get('voice_announce.directory')
res = topic_query(server, "", args = {
"voice_announce_query": id,
"key": server["comms_key"]
})
if (not res) or (not int(res["exists"])):
return Response("Invalid voice announcement URL", status=404)

if request.content_length > 120000:
return Response("File too large", status=400)
ct = request.content_type
semicolon_loc = ct.find(";")
if semicolon_loc != -1:
ct = ct[:semicolon_loc]
if type_extensions[ct] == None:
return Response("Invalid file type", status=400)
filename_base = id
filename = filename_base + "_base" + type_extensions[ct]
ogg_filename = filename_base + "_converted.ogg"
with open(path.join(dir,filename), "wb") as file:
file.write(request.get_data())

result = run(["ffmpeg", "-i", path.join(dir,filename), "-c:a", "libvorbis", "-y", path.join(dir,ogg_filename)], stdin=DEVNULL,stdout=DEVNULL,stderr=DEVNULL)
if result.returncode != 0:
remove(path.join(dir, filename))
return Response("Conversion failed", status=500)
probe_result = run(["ffprobe", "-i", path.join(dir, ogg_filename), "-show_entries", "format=duration", "-v", "quiet", "-of", "csv=p=0"], capture_output=True)
if probe_result.returncode != 0:
remove(path.join(dir, filename))
remove(path.join(dir, ogg_filename))
return Response("ffprobe failed: " + probe_result.stderr.decode("utf-8"), status=500)
duration = float(probe_result.stdout)
if duration > 35:
remove(path.join(dir, filename))
remove(path.join(dir, ogg_filename))
return Response("Duration too long!", status=400)

topic_query(server, "", args = {
"voice_announce": id,
"ogg_file": ogg_filename,
"uploaded_file": filename,
"ip": request.remote_addr,
"duration": duration,
"key": server["comms_key"]
})

return Response(None, status=204)

@blueprint.route("/voice_announce/<string:serversqlname>/<string:id>/cancel", methods=["GET","POST"])
@flask_csrf_ext.exempt
def voice_announce_cancel(serversqlname, id):
for s in cfg.get("servers").values():
if s["sqlname"] == serversqlname:
server = s

topic_query(server, "", args = {
"voice_announce_cancel": id,
"key": server["comms_key"]
})

return Response(None, status=204)
Loading