Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
|
6810cc315c | |
|
c60f596816 | |
|
b343af8dfe | |
|
bff08ceddf | |
|
84371968e5 | |
|
3a4602be36 | |
|
8eab8ada15 | |
|
8b4ff7df58 |
36
README.md
36
README.md
|
@ -2,6 +2,10 @@
|
|||
|
||||
Simple choice game.
|
||||
|
||||
## Demo
|
||||
|
||||
https://ab.21x9.org
|
||||
|
||||
## Installation
|
||||
|
||||
0. Install `python3` (and `pip` if needed)
|
||||
|
@ -28,3 +32,35 @@ Or just run `python3 ./game.py`
|
|||
## Use
|
||||
|
||||
Open your browser and navigate to `http://localhost:5000` or whatever you configured as `bind` and `port` in your `config.ini`.
|
||||
|
||||
## Reverse Proxy
|
||||
|
||||
To run this game in an production environment it's strongly recommended to set up an reverse proxy upfront.
|
||||
|
||||
### nginx
|
||||
|
||||
Make sure you understand the config and replace the `location` and/or `proxy_pass` value if necessary.
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:5000/;
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
client_max_body_size 32M;
|
||||
proxy_redirect off;
|
||||
proxy_intercept_errors off;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_ignore_client_abort on;
|
||||
proxy_connect_timeout 120s;
|
||||
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
proxy_busy_buffers_size 256k;
|
||||
|
||||
proxy_headers_hash_max_size 512;
|
||||
proxy_buffering on;
|
||||
proxy_cache_bypass $http_pragma $http_authorization $cookie_nocache;
|
||||
}
|
||||
```
|
||||
|
|
2
ab.txt
2
ab.txt
|
@ -1035,7 +1035,7 @@ Multiplayer;Einzelspieler
|
|||
Pizza Hawaii;keine Pizza
|
||||
Pacman;Tetris
|
||||
Tischfußball;Tischtennis
|
||||
Computer;Spielkonsolen
|
||||
PC;Spielkonsolen
|
||||
Live-Action-Rollenspiele;Online-Spiele
|
||||
Wrestling;Mix Martial Arts
|
||||
Bowling;Tennis
|
||||
|
|
|
@ -18,7 +18,7 @@ more = Weiter »»»
|
|||
title = A oder B
|
||||
mail_link = Einreichen!
|
||||
help_link = Hilfe?
|
||||
help = <strong>Hilfe</strong><p>Wähle die Antworten durch Klicken/Tippen oder mit der Tastatur durch Drücken der Tasten "a" bzw. "b" aus (beantwortet die jeweils nächste unbeantwortete Frage). Sobald alle Antworten ausgewählt wurden, werden nach einer kurzen Wartezeit automatisch neue Fragen geladen.</p><p>Möchtest Du nicht alle Fragen beantworten, klicke einfach auf die Schaltfläche "Weiter" unten rechts oder drücke "F5" (beides klappt auch, während der Countdown läuft).</p><p>Klicke/tippe außerhalb dieses Fensters oder bewege die Maus, um fortzufahren.</p><p>Diese Webseite zeichnet keine Daten auf und verwendet keine Cookies.</p>
|
||||
help = <strong>Hilfe</strong><p>Wähle die Antworten durch Klicken/Tippen oder mit der Tastatur durch Drücken der Tasten "a" bzw. "b" aus (beantwortet die jeweils nächste unbeantwortete Frage), eine Frage kann mit "o" übersprungen werden. Sobald alle Antworten ausgewählt wurden, werden nach einer kurzen Wartezeit automatisch neue Fragen geladen.</p><p>Möchtest Du nicht alle Fragen beantworten, klicke einfach auf die Schaltfläche "Weiter" unten rechts oder drücke "F5" (beides klappt auch, während der Countdown läuft) bzw. "s" für Skip (mit kurzer Wartezeit).</p><p>Klicke/tippe außerhalb dieses Fensters oder bewege die Maus, um fortzufahren.</p><p>Diese Webseite zeichnet keine Daten auf und verwendet keine Cookies.</p>
|
||||
separator = oder
|
||||
questions_prefix = Es gibt derzeit
|
||||
questions_suffix = Fragen.
|
||||
|
|
90
game.py
90
game.py
|
@ -1,12 +1,16 @@
|
|||
#! /bin/python3
|
||||
|
||||
from flask import Flask, render_template, request
|
||||
"""
|
||||
Simple A/B choice game
|
||||
"""
|
||||
|
||||
from configparser import ConfigParser
|
||||
from datetime import datetime
|
||||
from email.message import EmailMessage
|
||||
import smtplib
|
||||
import random
|
||||
import pytz
|
||||
from flask import Flask, render_template, request
|
||||
|
||||
app = Flask(__name__,
|
||||
static_url_path='',
|
||||
|
@ -45,10 +49,14 @@ conf = {
|
|||
'animations': config.get('main', 'animations')
|
||||
}
|
||||
|
||||
with open("ab.txt", "r") as f:
|
||||
with open("ab.txt", "r", encoding="utf-8") as f:
|
||||
num_lines = sum(1 for _ in f)
|
||||
|
||||
def getEpoch():
|
||||
def get_epoch():
|
||||
"""
|
||||
Get current time as epoch timestamp
|
||||
"""
|
||||
|
||||
now = datetime.now(tz=tz)
|
||||
epoch = now.timestamp()
|
||||
epoch = int(epoch)
|
||||
|
@ -56,24 +64,47 @@ def getEpoch():
|
|||
return epoch
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
epoch = getEpoch()
|
||||
def page_not_found():
|
||||
"""
|
||||
404 Error Page
|
||||
"""
|
||||
epoch = get_epoch()
|
||||
return render_template('404.html', config=conf, i18n=i18n, epoch=epoch), 404
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_server_error(e):
|
||||
epoch = getEpoch()
|
||||
return render_template('500.html', config=conf, i18n=i18n, epoch=epoch), 500
|
||||
def internal_server_error():
|
||||
"""
|
||||
500 Error Page
|
||||
"""
|
||||
epoch = get_epoch()
|
||||
return render_template(
|
||||
'500.html',
|
||||
config=conf,
|
||||
i18n=i18n,
|
||||
epoch=epoch
|
||||
), 500
|
||||
|
||||
if conf['mailform'] == "true":
|
||||
@app.route("/form")
|
||||
def mailform():
|
||||
epoch = getEpoch()
|
||||
return render_template('mailform.html', config=conf, i18n=i18n, epoch=epoch, num_lines=num_lines)
|
||||
"""
|
||||
Mail form
|
||||
"""
|
||||
epoch = get_epoch()
|
||||
return render_template(
|
||||
'mailform.html',
|
||||
config=conf,
|
||||
i18n=i18n,
|
||||
epoch=epoch,
|
||||
num_lines=num_lines
|
||||
)
|
||||
|
||||
@app.route("/send", methods=['POST', 'GET'])
|
||||
def sendmail():
|
||||
epoch = getEpoch()
|
||||
"""
|
||||
Send form data via E-Mail
|
||||
"""
|
||||
epoch = get_epoch()
|
||||
|
||||
if request.method == 'POST':
|
||||
mailcontent = request.form['questions']
|
||||
|
@ -90,29 +121,48 @@ if conf['mailform'] == "true":
|
|||
smtp_server.send_message(message)
|
||||
smtp_server.quit()
|
||||
|
||||
return render_template('thanks.html', config=conf, i18n=i18n, epoch=epoch, questions=mailcontent)
|
||||
return render_template(
|
||||
'thanks.html',
|
||||
config=conf,
|
||||
i18n=i18n,
|
||||
epoch=epoch,
|
||||
questions=mailcontent
|
||||
)
|
||||
|
||||
@app.route("/")
|
||||
def hello():
|
||||
"""
|
||||
Default/Main page
|
||||
"""
|
||||
ablines = []
|
||||
epoch = getEpoch()
|
||||
epoch = get_epoch()
|
||||
|
||||
lines = getContent()
|
||||
lines = get_content()
|
||||
while len(lines) < 2:
|
||||
print('Error reading content')
|
||||
print(lines)
|
||||
lines = getContent()
|
||||
lines = get_content()
|
||||
|
||||
for line in lines:
|
||||
ab = line.split(conf['separator_char'])
|
||||
abq = line.split(conf['separator_char'])
|
||||
ablines.append(
|
||||
{'A': str(ab[0]), 'B': str(ab[1])}
|
||||
{'A': str(abq[0]), 'B': str(abq[1])}
|
||||
)
|
||||
|
||||
return render_template('index.html', content=ablines, config=conf, i18n=i18n, num_lines=num_lines, epoch=epoch)
|
||||
return render_template(
|
||||
'index.html',
|
||||
content=ablines,
|
||||
config=conf,
|
||||
i18n=i18n,
|
||||
num_lines=num_lines,
|
||||
epoch=epoch
|
||||
)
|
||||
|
||||
def getContent():
|
||||
lines = [a.strip() for a in open("ab.txt", "r").readlines()]
|
||||
def get_content():
|
||||
"""
|
||||
Read content from file
|
||||
"""
|
||||
lines = [a.strip() for a in open("ab.txt", "r", encoding="utf-8").readlines()]
|
||||
result = random.sample(lines, 5)
|
||||
|
||||
return result
|
||||
|
|
|
@ -30,7 +30,7 @@ a #help {
|
|||
|
||||
a:hover #help {
|
||||
position: absolute;
|
||||
top: 125px;
|
||||
top: 105px;
|
||||
left: 50%;
|
||||
height: auto;
|
||||
width: 50%;
|
||||
|
@ -46,6 +46,7 @@ a:hover #help {
|
|||
display: inline-block;
|
||||
text-align: center;
|
||||
transform: translate(-50%);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
@ -188,6 +189,9 @@ input[type="radio"] {
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--fg-sep);
|
||||
border-radius: 10px;
|
||||
z-index: 5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#footer {
|
||||
|
@ -241,6 +245,33 @@ input[type="radio"] {
|
|||
}
|
||||
|
||||
@media only screen and (max-width:640px) {
|
||||
#header {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
a:hover #help {
|
||||
top: 5px;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.a {
|
||||
padding: 15px;
|
||||
font-size: small;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
.b {
|
||||
padding: 15px;
|
||||
font-size: small;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
.o {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#content {
|
||||
min-width: 95%;
|
||||
transform: none;
|
||||
|
@ -252,7 +283,8 @@ input[type="radio"] {
|
|||
|
||||
#next {
|
||||
min-width: 100%;
|
||||
margin-top: 20px;
|
||||
margin-top: 10px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
#questions {
|
||||
|
|
|
@ -9,7 +9,7 @@ function countdown() {
|
|||
document.getElementById("next").innerHTML = timeleft;
|
||||
}
|
||||
timeleft -= 1;
|
||||
}, 750);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function autoReload() {
|
||||
|
|
|
@ -53,6 +53,12 @@ window.addEventListener("keydown", function (event) {
|
|||
case "b":
|
||||
check("b");
|
||||
break;
|
||||
case "o":
|
||||
check("o");
|
||||
break;
|
||||
case "s":
|
||||
countdown();
|
||||
break;
|
||||
default:
|
||||
checkCount();
|
||||
return;
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
<div class="ab">
|
||||
<input type="radio" id="a{{ id.value }}" class="a" name="group-{{ id.value }}">
|
||||
<label for="a{{ id.value }}" class="a slide{{ id.value }}" title="{{ question['A'] }}"> A) {{ question['A'] }}</label>
|
||||
<div class="separator">{{ i18n.separator }}</div>
|
||||
<input type="radio" id="o{{ id.value }}" class="separator" name="group-{{ id.value }}">
|
||||
<label for="o{{ id.value }}" class="separator">{{ i18n.separator }}</label>
|
||||
<input type="radio" id="b{{ id.value }}" class="b" name="group-{{ id.value }}">
|
||||
<label for="b{{ id.value }}" class="b slide{{ id.value }}" title="{{ question['B'] }}">B) {{ question['B'] }}</label>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue