Uploaded to gitea
This commit is contained in:
parent
c23a61a0bb
commit
0f74212063
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
api/devapi.conf
|
||||||
|
site/devsite.conf
|
||||||
11
api/api.conf
Normal file
11
api/api.conf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[Database]
|
||||||
|
db_type = MySQL
|
||||||
|
host = 172.29.29.15
|
||||||
|
user = user
|
||||||
|
pass = pass
|
||||||
|
db_name = gamedistrosys
|
||||||
|
|
||||||
|
[Running]
|
||||||
|
host = localhost
|
||||||
|
port = 5501
|
||||||
|
|
||||||
48
api/api.py
Normal file
48
api/api.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
from flask import request, jsonify, Flask
|
||||||
|
from flask.json import JSONEncoder
|
||||||
|
from datetime import date
|
||||||
|
import modules.db_connect
|
||||||
|
|
||||||
|
|
||||||
|
class MyJSONEncoder(JSONEncoder):
|
||||||
|
def default(self, o):
|
||||||
|
if isinstance(o, date):
|
||||||
|
return o.isoformat()
|
||||||
|
|
||||||
|
return super().default(o)
|
||||||
|
|
||||||
|
|
||||||
|
class MyFlask(Flask):
|
||||||
|
json_encoder = MyJSONEncoder
|
||||||
|
|
||||||
|
|
||||||
|
app = MyFlask(__name__)
|
||||||
|
modules.db_connect.init()
|
||||||
|
import modules.gamelist # noqa: E402
|
||||||
|
import modules.game # noqa: E402
|
||||||
|
|
||||||
|
# Important initialization stuff
|
||||||
|
config = modules.db_connect.config
|
||||||
|
|
||||||
|
|
||||||
|
# Just a simple homepage, nothing fancy
|
||||||
|
@app.route('/', methods=['GET'])
|
||||||
|
def home():
|
||||||
|
if 'id' not in request.args:
|
||||||
|
return "<h1>BCNS Game Distribution System</h1><p>API-endpoint</p>"
|
||||||
|
else:
|
||||||
|
return jsonify("I see you're a man of culture as well")
|
||||||
|
|
||||||
|
|
||||||
|
# Fetch a list of one users owned vehicles
|
||||||
|
@app.route('/<userid>/vehiclelist', methods=['GET'])
|
||||||
|
def user_vehiclelist(userid):
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.config['JSON_AS_ASCII'] = False
|
||||||
|
app.run(
|
||||||
|
host=config.get('Running', 'host'),
|
||||||
|
port=config.get('Running', 'Port'))
|
||||||
34
api/modules/db_connect.py
Normal file
34
api/modules/db_connect.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
|
def init():
|
||||||
|
global config
|
||||||
|
|
||||||
|
# Decide what config-file to use
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-e', '--environment', choices=['dev', 'prod', 'test'],
|
||||||
|
default='prod',
|
||||||
|
help='choose what environment type to run.'
|
||||||
|
' Defaults to prod')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.environment == 'dev':
|
||||||
|
print("Using devapi.conf")
|
||||||
|
configfile = '/../devapi.conf'
|
||||||
|
elif args.environment == 'test':
|
||||||
|
print("Using testapi.conf")
|
||||||
|
configfile = '/../testapi.conf'
|
||||||
|
else:
|
||||||
|
print("Using api.conf")
|
||||||
|
configfile = '/../api.conf'
|
||||||
|
|
||||||
|
config = configparser.RawConfigParser()
|
||||||
|
config.read(os.path.dirname(
|
||||||
|
os.path.abspath(inspect.getfile(
|
||||||
|
inspect.currentframe()))) + configfile)
|
||||||
|
|
||||||
|
def contentpath():
|
||||||
|
return(config.get('Database','contentpath'))
|
||||||
20
api/modules/functions.py
Normal file
20
api/modules/functions.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from io import BytesIO
|
||||||
|
from PIL import Image
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
|
# Reducing the size of an artwork/image (PNG to JPEG) and base64-encode it.
|
||||||
|
# imagepath = full file image path
|
||||||
|
# expectedsize = medium or thumbnail
|
||||||
|
def reduceart(imagepath, expectedsize):
|
||||||
|
image = Image.open(imagepath)
|
||||||
|
rgb_image = image.convert("RGB")
|
||||||
|
with BytesIO() as f:
|
||||||
|
rgb_image.save(f, format="JPEG")
|
||||||
|
f.seek(0)
|
||||||
|
|
||||||
|
if expectedsize == 'thumbnail':
|
||||||
|
rgb_image.thumbnail([90,90])
|
||||||
|
rgb_image.save(f, format="JPEG")
|
||||||
|
f.seek(0)
|
||||||
|
return base64.b64encode(f.getvalue()).decode()
|
||||||
65
api/modules/game.py
Normal file
65
api/modules/game.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
from __main__ import app
|
||||||
|
from flask import jsonify, request
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import modules.db_connect
|
||||||
|
from modules.functions import reduceart
|
||||||
|
import os
|
||||||
|
|
||||||
|
contentpath = modules.db_connect.contentpath()
|
||||||
|
|
||||||
|
|
||||||
|
# Fetch and present all information from one _index.nfo-file
|
||||||
|
@app.route('/game', methods=['POST'])
|
||||||
|
def game(predefinednfo=False, return_dict=False, skip_artwork=False):
|
||||||
|
nfopath = ""
|
||||||
|
if predefinednfo is not False:
|
||||||
|
nfopath = predefinednfo
|
||||||
|
else:
|
||||||
|
nfopath = base64.b64decode(request.json).decode()
|
||||||
|
nfo = json.load(open(nfopath, 'r'))
|
||||||
|
nfo['path'] = base64.b64encode(nfopath.encode('utf-8')).decode()
|
||||||
|
|
||||||
|
# Add front cover artwork in medium size
|
||||||
|
artpath = os.path.dirname(nfopath)+'/art/'
|
||||||
|
i = 0
|
||||||
|
for art in nfo['game']['artwork']:
|
||||||
|
if skip_artwork is False:
|
||||||
|
nfo['game']['artwork'][i]['data'] = reduceart(
|
||||||
|
artpath+art['filename'], 'thumbnail')
|
||||||
|
if art['type'] == 'front':
|
||||||
|
nfo['game']['displayimage'] = reduceart(
|
||||||
|
artpath+art['filename'], 'thumbnail')
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if return_dict is False:
|
||||||
|
return jsonify(nfo)
|
||||||
|
return nfo
|
||||||
|
|
||||||
|
|
||||||
|
# Fetch all artwork from a given _index.nfo-file
|
||||||
|
@app.route('/game/artwork/size/<size>', methods=['POST'])
|
||||||
|
@app.route('/game/artwork', methods=['POST'])
|
||||||
|
def artwork(size='max'):
|
||||||
|
f = open(request.json['nfo'], 'r')
|
||||||
|
nfo = json.load(f)
|
||||||
|
|
||||||
|
artpath = os.path.dirname(request.json['nfo'])+'/art/'
|
||||||
|
artlist = []
|
||||||
|
for art in nfo['game']['artwork']:
|
||||||
|
img = ""
|
||||||
|
|
||||||
|
# If max size, send image as-is
|
||||||
|
if size == 'max':
|
||||||
|
with open(artpath+art['filename'], mode='rb') as file:
|
||||||
|
img = file.read()
|
||||||
|
art['img'] = base64.b64encode(img).decode()
|
||||||
|
|
||||||
|
# Changes filetype to jpeg for size reduction. This also drops
|
||||||
|
# Alpha-channel
|
||||||
|
else:
|
||||||
|
art['img'] = reduceart(artpath+art['filename'], size)
|
||||||
|
|
||||||
|
artlist.append(art)
|
||||||
|
|
||||||
|
return jsonify(artlist)
|
||||||
24
api/modules/gamelist.py
Normal file
24
api/modules/gamelist.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from __main__ import app
|
||||||
|
from flask import jsonify, request
|
||||||
|
import modules.db_connect
|
||||||
|
import modules.game
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import base64
|
||||||
|
|
||||||
|
contentpath = modules.db_connect.contentpath()
|
||||||
|
|
||||||
|
# Fetch all _index.nfo-files present in given path and corresponding data
|
||||||
|
@app.route('/gamelist', methods=['GET'])
|
||||||
|
def gamelist():
|
||||||
|
|
||||||
|
nfolist = list(dict.fromkeys(glob.glob(str(contentpath)+'/**/**/*_index.nfo',recursive=True)))
|
||||||
|
|
||||||
|
gamelist = []
|
||||||
|
for nfo in nfolist:
|
||||||
|
# f = open(nfo, encoding="UTF-8")
|
||||||
|
game = modules.game.game(nfo, True, True)
|
||||||
|
# game['game']['path'] = base64.b64encode(nfo.encode('utf-8')).decode()
|
||||||
|
gamelist.append(game)
|
||||||
|
|
||||||
|
return jsonify(gamelist)
|
||||||
76
site/index.py
Normal file
76
site/index.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
from datetime import date
|
||||||
|
from flask import render_template, Flask, request
|
||||||
|
from flask.json import JSONEncoder
|
||||||
|
import modules.init
|
||||||
|
import os
|
||||||
|
import inspect
|
||||||
|
import json
|
||||||
|
import glob
|
||||||
|
|
||||||
|
|
||||||
|
class MyJSONEncoder(JSONEncoder):
|
||||||
|
def default(self, o):
|
||||||
|
if isinstance(o, date):
|
||||||
|
return o.isoformat()
|
||||||
|
|
||||||
|
return super().default(o)
|
||||||
|
|
||||||
|
|
||||||
|
class MyFlask(Flask):
|
||||||
|
json_encoder = MyJSONEncoder
|
||||||
|
|
||||||
|
|
||||||
|
app = MyFlask(__name__)
|
||||||
|
modules.init.init()
|
||||||
|
import modules.gamelist # noqa: E402
|
||||||
|
import modules.game # noqa: E402
|
||||||
|
|
||||||
|
# Init stuff
|
||||||
|
config = modules.init.config
|
||||||
|
host_endpoint = modules.init.host_endpoint()
|
||||||
|
languages = modules.init.get_languages()
|
||||||
|
# App-server-stuff
|
||||||
|
app.config["DEBUG"] = True
|
||||||
|
|
||||||
|
|
||||||
|
# Check if valid language code is set. If not, return app default
|
||||||
|
def lang(lang_code):
|
||||||
|
if lang_code not in languages:
|
||||||
|
return app_language
|
||||||
|
return lang_code
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/", methods=["GET", "POST"])
|
||||||
|
@app.route("/<lang_code>/", methods=["GET", "POST"])
|
||||||
|
def home(lang_code=False):
|
||||||
|
lang_code = lang(lang_code)
|
||||||
|
if request.form:
|
||||||
|
lang_code = request.form["language_select"]
|
||||||
|
return render_template('home.html', **languages[lang_code],
|
||||||
|
lang_code=lang_code,
|
||||||
|
languages=languages.keys())
|
||||||
|
|
||||||
|
|
||||||
|
# Initiation
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.config['JSON_AS_ASCII'] = False
|
||||||
|
|
||||||
|
# Language stuff
|
||||||
|
app_language = 'en_US'
|
||||||
|
date_format = "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
|
languages_path = os.path.dirname(
|
||||||
|
os.path.abspath(inspect.getfile(
|
||||||
|
inspect.currentframe())))
|
||||||
|
language_list = glob.glob(languages_path + "/language/*.json")
|
||||||
|
print("### Loaded languages")
|
||||||
|
for language in language_list:
|
||||||
|
filename = os.path.basename(language)
|
||||||
|
lang_code = filename.split('.')[0]
|
||||||
|
|
||||||
|
with open(language, 'r', encoding='utf-8') as file:
|
||||||
|
print("# ", lang_code)
|
||||||
|
languages[lang_code] = json.loads(file.read())
|
||||||
|
app.run(
|
||||||
|
host=config.get('Main', 'host'),
|
||||||
|
port=config.get('Main', 'port'))
|
||||||
35
site/language/en_US.json
Normal file
35
site/language/en_US.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"lang_home_body_header": "Hello and welcome",
|
||||||
|
"lang_home_change_language": "Change language",
|
||||||
|
"lang_home_change_language_button": "CHange",
|
||||||
|
"lang_navigation_home": "Home",
|
||||||
|
"lang_navigation_gamelist": "Game list",
|
||||||
|
"lang_gamelist_title": "Gamelist",
|
||||||
|
"lang_gamelist_body_header": "Gamelist",
|
||||||
|
"lang_gamelist_body_ingress": "Here there be a bunch of games listed",
|
||||||
|
"lang_game_title": "Game",
|
||||||
|
"lang_game_body_header": "Game",
|
||||||
|
"lang_game_body_ingress": "Here there be info about games n stuff",
|
||||||
|
"lang_game_plot": "Plot",
|
||||||
|
"lang_game_download_header": "Download game",
|
||||||
|
"lang_game_download_ingress": "Here you can download the game using either torrent file or a magnet-link!",
|
||||||
|
"lang_game_download_torrent_button": "Download",
|
||||||
|
"lang_game_download_magnet_link": "Magnet link",
|
||||||
|
"lang_game_artwork": "Artwork",
|
||||||
|
"lang_game_year": "Release date",
|
||||||
|
"lang_game_genre": "Genre",
|
||||||
|
"lang_game_originaltitle": "Original title",
|
||||||
|
"lang_game_developer": "Developer",
|
||||||
|
"lang_game_playermodes": "Player modes",
|
||||||
|
"lang_game_collab": "In collaboration with",
|
||||||
|
"lang_game_credits": "Credits",
|
||||||
|
"lang_game_rating": "Rating",
|
||||||
|
"lang_game_recommendedspecs": "Recommended specs.",
|
||||||
|
"lang_game_systemrequirements": "System requirements",
|
||||||
|
"lang_game_images_header": "Images",
|
||||||
|
"lang_game_disctitle": "Disc name",
|
||||||
|
"lang_game_disctype": "Medium",
|
||||||
|
"lang_game_image_files": "Image files",
|
||||||
|
"lang_game_cd_key": "CD-Key",
|
||||||
|
"lang_game_linuxinstructions": "Linux instructions"
|
||||||
|
}
|
||||||
7
site/language/sv_SE.json
Normal file
7
site/language/sv_SE.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"lang_home_body_header": "Hej och välkommen",
|
||||||
|
"lang_home_change_language": "Byt språk",
|
||||||
|
"lang_home_change_language_button": "Byt",
|
||||||
|
"lang_navigation_home": "Hem",
|
||||||
|
"lang_navigation_gamelist": "Spellista"
|
||||||
|
}
|
||||||
44
site/modules/game.py
Normal file
44
site/modules/game.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from __main__ import app
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from flask import render_template, request
|
||||||
|
import modules.init
|
||||||
|
|
||||||
|
host_endpoint = modules.init.host_endpoint()
|
||||||
|
languages = modules.init.get_languages()
|
||||||
|
app_language = modules.init.app_language
|
||||||
|
|
||||||
|
|
||||||
|
# Check if valid language code is set. If not, return app default
|
||||||
|
def lang(lang_code):
|
||||||
|
if lang_code not in languages:
|
||||||
|
return app_language
|
||||||
|
return lang_code
|
||||||
|
|
||||||
|
|
||||||
|
# Show game
|
||||||
|
@app.route("/<lang_code>/game")
|
||||||
|
def game(lang_code):
|
||||||
|
lang_code = lang(lang_code)
|
||||||
|
gamepath = request.args.get("gamepath")
|
||||||
|
|
||||||
|
game = json.loads((requests.post(
|
||||||
|
host_endpoint + '/game', json=gamepath).content).decode())
|
||||||
|
|
||||||
|
# game['game']['plot'] = game['game']['plot'].replace("\\n", "<br />")
|
||||||
|
game['game']['plot'] = game['game']['plot'].split('\\n')
|
||||||
|
game['game']['linuxinstructions'] = game['game']['linuxinstructions'].split('\\n')
|
||||||
|
return render_template('game.html', game=game,
|
||||||
|
**languages[lang_code], lang_code=lang_code)
|
||||||
|
|
||||||
|
|
||||||
|
# Show game artwork
|
||||||
|
@app.route("/<lang_code>/game/artwork")
|
||||||
|
def artwork(lang_code):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Download a game
|
||||||
|
@app.route("/<lang_code>/game/download")
|
||||||
|
def download(lang_code):
|
||||||
|
pass
|
||||||
29
site/modules/gamelist.py
Normal file
29
site/modules/gamelist.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from __main__ import app
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from flask import render_template, redirect, request, url_for
|
||||||
|
import modules.init
|
||||||
|
|
||||||
|
host_endpoint = modules.init.host_endpoint()
|
||||||
|
languages = modules.init.get_languages()
|
||||||
|
app_language = modules.init.app_language
|
||||||
|
|
||||||
|
|
||||||
|
# Check if valid language code is set. If not, return app default
|
||||||
|
def lang(lang_code):
|
||||||
|
if lang_code not in languages:
|
||||||
|
return app_language
|
||||||
|
return lang_code
|
||||||
|
|
||||||
|
|
||||||
|
# Show gamelist
|
||||||
|
@app.route("/<lang_code>/gamelist")
|
||||||
|
# @app.route("/gamelist")
|
||||||
|
def gamelist(lang_code):
|
||||||
|
lang_code = lang(lang_code)
|
||||||
|
glist = json.loads((requests.get(
|
||||||
|
host_endpoint + '/gamelist').content).decode())
|
||||||
|
|
||||||
|
return render_template('gamelist.html', gamelist=glist,
|
||||||
|
**languages[lang_code], lang_code=lang_code)
|
||||||
54
site/modules/init.py
Normal file
54
site/modules/init.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
global languages
|
||||||
|
languages = {}
|
||||||
|
|
||||||
|
|
||||||
|
def set_languages(languages_dict):
|
||||||
|
global languages
|
||||||
|
languages = languages_dict
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_languages():
|
||||||
|
global languages
|
||||||
|
return languages
|
||||||
|
|
||||||
|
|
||||||
|
def init():
|
||||||
|
global config
|
||||||
|
global app_language
|
||||||
|
|
||||||
|
app_language = 'en_US'
|
||||||
|
# Decide what config-file to use
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-e', '--environment', choices=['dev', 'prod', 'test'],
|
||||||
|
default='prod',
|
||||||
|
help='choose what environment type to run.'
|
||||||
|
' Defaults to prod')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.environment == 'dev':
|
||||||
|
print("Using devsite.conf")
|
||||||
|
configfile = '/../devsite.conf'
|
||||||
|
elif args.environment == 'test':
|
||||||
|
print("Using testsite.conf")
|
||||||
|
configfile = '/../testsite.conf'
|
||||||
|
else:
|
||||||
|
print("Using site.conf")
|
||||||
|
configfile = '/../site.conf'
|
||||||
|
|
||||||
|
config = configparser.RawConfigParser()
|
||||||
|
config.read(os.path.dirname(
|
||||||
|
os.path.abspath(inspect.getfile(
|
||||||
|
inspect.currentframe()))) + configfile)
|
||||||
|
|
||||||
|
|
||||||
|
# Constructor for the API-endpoint
|
||||||
|
def host_endpoint():
|
||||||
|
return ('http://' + config.get('API', 'host') + ':' +
|
||||||
|
config.get('API', 'port'))
|
||||||
8
site/site.conf
Normal file
8
site/site.conf
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[Main]
|
||||||
|
hostip = 172.29.29.31
|
||||||
|
debug = True
|
||||||
|
host = localhost
|
||||||
|
port = 5500
|
||||||
|
|
||||||
|
[API]
|
||||||
|
apihost = 172.29.29.17
|
||||||
116
site/static/css/template.css
Normal file
116
site/static/css/template.css
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Formatting the header area
|
||||||
|
*/
|
||||||
|
header {
|
||||||
|
background-color: #DFB887;
|
||||||
|
height: 35px;
|
||||||
|
width: 100%;
|
||||||
|
opacity: .9;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
header h1.logo {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.7em;
|
||||||
|
color: #fff;
|
||||||
|
text-transform: uppercase;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
header h1.logo:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Centering the body content
|
||||||
|
*/
|
||||||
|
.container {
|
||||||
|
width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
div.home {
|
||||||
|
padding: 10px 0 30px 0;
|
||||||
|
background-color: #E6E6FA;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
div.about {
|
||||||
|
padding: 10px 0 30px 0;
|
||||||
|
background-color: #E6E6FA;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 3em;
|
||||||
|
margin-top: 40px;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: -2px;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1.7em;
|
||||||
|
font-weight: 100;
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: -1px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.menu {
|
||||||
|
float: right;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.menu li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.menu li + li {
|
||||||
|
margin-left: 35px;
|
||||||
|
}
|
||||||
|
.menu li a {
|
||||||
|
color: #444;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.fleet {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.vehicle_basic_info {
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.vehicle_owner_history {
|
||||||
|
position: right;
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.last_inspection {
|
||||||
|
position: right;
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.general_table {
|
||||||
|
position: right;
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.tooltip {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.tooltip .tooltiptext {
|
||||||
|
visibility: hidden;
|
||||||
|
width: 120px;
|
||||||
|
background-color: black;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px 0;
|
||||||
|
|
||||||
|
position: absolute:
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.tooltip:hover .tooltiptext {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
84
site/templates/game.html
Normal file
84
site/templates/game.html
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{lang_game_title}}</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/template.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% extends "navigation.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{lang_game_body_header}}</h1>
|
||||||
|
<p>{{lang_game_body_inress}}</p>
|
||||||
|
<h2>{{game.game.title}}</h2>
|
||||||
|
<h3>{{lang_game_plot}}</h3>
|
||||||
|
{% for part in game.game.plot %}
|
||||||
|
<p>{{part}}</p>
|
||||||
|
{% endfor %}
|
||||||
|
<h3>{{lang_game_download_header}}</h3>
|
||||||
|
<p>{{lang_game_download_ingress}}</p>
|
||||||
|
<a href="{{ url_for('download', gamepath=game.path, lang_code=lang_code)}}"><button type="button">{{lang_game_download_torrent_button}}</button></a>
|
||||||
|
<p><a href="">{{lang_game_download_magnet_link}}</a></p>
|
||||||
|
<table class="game">
|
||||||
|
<tr>
|
||||||
|
<th>{{lang_game_artwork}}</th>
|
||||||
|
<td><div class="tooltip">
|
||||||
|
{% for part in game.game.artwork %}
|
||||||
|
<span class="tooltiptext">{{part.type}}</span><a href="{{ url_for('artwork', gamepath=game.path, art=part.filename, lang_code=lang_code)}}"><img src="data:image/jpeg;base64,{{part.data}}"></img></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div></td>
|
||||||
|
</tr><tr>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_year}}</th>
|
||||||
|
<td>{{game.game.year}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_genre}}</th>
|
||||||
|
<td>{{game.game.genre}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_originaltitle}}</th>
|
||||||
|
<td>{{game.game.originaltitle}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_developer}}</th>
|
||||||
|
<td>{{game.game.developer}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_playermodes}}</th>
|
||||||
|
<td>{{game.game.playermodes}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_collab}}</th>
|
||||||
|
<td>{{game.game.collab}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_credits}}</th>
|
||||||
|
<td>{{game.game.credits}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_rating}}</th>
|
||||||
|
<td>{{game.game.rating}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_recommendedspecs}}</th>
|
||||||
|
<td>{{game.game.recommendedspecs}}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>{{lang_game_systemrequirements}}</th>
|
||||||
|
<td>{{game.game.systemrequirements}}</td>
|
||||||
|
</table>
|
||||||
|
<h3>{{lang_game_images_header}}</h3>
|
||||||
|
{% for part in game.game.imagelist %}
|
||||||
|
<p>{{lang_game_disctitle}}: {{part.title}}</p>
|
||||||
|
<p>{{lang_game_disctype}}: {{part.type}}</p>
|
||||||
|
<p>{{lang_game_image_files}}:
|
||||||
|
{% for partname in part.name %}
|
||||||
|
{{partname}}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if game.game.cdkey != "" %}
|
||||||
|
<h3>{{lang_game_cd_key}}</h3>
|
||||||
|
<p>{{game.game.cdkey}}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h3>{{lang_game_linuxinstructions}}</h3>
|
||||||
|
{% for part in game.game.linuxinstructions %}
|
||||||
|
<p>{{part}}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
34
site/templates/gamelist.html
Normal file
34
site/templates/gamelist.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{lang_gamelist_title}}</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/template.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% extends "navigation.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{lang_gamelist_body_header}}</h1>
|
||||||
|
<p>{{lang_gamelist_body_ingress}}</p>
|
||||||
|
<table class="game">
|
||||||
|
<tr>
|
||||||
|
<th>{{lang_game_artwork}}</th>
|
||||||
|
<th>{{lang_game_title}}</th>
|
||||||
|
<th>{{lang_game_year}}</th>
|
||||||
|
<th>{{lang_game_genre}}</th>
|
||||||
|
<th>{{lang_game_developer}}</th>
|
||||||
|
<th>{{lang_game_playermodes}}</th>
|
||||||
|
</tr>
|
||||||
|
{% for item in gamelist %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{{ url_for('game', gamepath=item.path, lang_code=lang_code)}}"><img src="data:image/jpeg;base64,{{item.game.displayimage}}"></img></a></td>
|
||||||
|
<td><a href="{{ url_for('game', gamepath=item.path, lang_code=lang_code)}}">{{item.game.title}}</a></td>
|
||||||
|
<td>{{item.game.year}}</td>
|
||||||
|
<td>{{item.game.genre}}</td>
|
||||||
|
<td>{{item.game.developer}}</td>
|
||||||
|
<td>{{item.game.playermodes}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
site/templates/home.html
Normal file
25
site/templates/home.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>BCNS</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% extends "navigation.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{lang_home_body_header}}</h1>
|
||||||
|
<form action="{{url_for('home')}}" method="POST">
|
||||||
|
<p>{{lang_home_change_language}}</p>
|
||||||
|
<select name="language_select">
|
||||||
|
{% for language in languages %}
|
||||||
|
{% if lang_code == language %}
|
||||||
|
<option selected>{{language}}</option>
|
||||||
|
{% else %}
|
||||||
|
<option>{{language}}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<button type="submit" name="change_language">{{lang_home_change_language_button}}</input>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
site/templates/navigation.html
Normal file
25
site/templates/navigation.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>BCNS</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/template.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="logo">BCNS Game Distribution System</h1>
|
||||||
|
<strong>
|
||||||
|
<nav>
|
||||||
|
<ul class="menu">
|
||||||
|
<li><a href="{{ url_for('home', lang_code=lang_code) }}">{{lang_navigation_home}}</a></li>
|
||||||
|
<li><a href="{{ url_for('gamelist', lang_code=lang_code) }}">{{lang_navigation_gamelist}}</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user