| @@ -1,3 +1,5 @@ | |||||
| *.pyc | *.pyc | ||||
| __pycache__/ | __pycache__/ | ||||
| config/ | |||||
| data/ | |||||
| venv/ | venv/ | ||||
| @@ -1,19 +1,29 @@ | |||||
| #! /usr/bin/env python3 | #! /usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| from pathlib import Path | |||||
| from flask import Flask, g | from flask import Flask, g | ||||
| from flask_mako import MakoTemplates, render_template | from flask_mako import MakoTemplates, render_template | ||||
| from calefaction import __version__ as version | |||||
| from calefaction.config import Config | |||||
| from calefaction.eve import EVE | |||||
| from calefaction.util import catch_errors, set_up_hash_versioning | from calefaction.util import catch_errors, set_up_hash_versioning | ||||
| basepath = Path(__file__).resolve().parent | |||||
| app = Flask(__name__) | app = Flask(__name__) | ||||
| config = Config(basepath / "config") | |||||
| eve = EVE() | |||||
| MakoTemplates(app) | MakoTemplates(app) | ||||
| set_up_hash_versioning(app) | set_up_hash_versioning(app) | ||||
| @app.before_request | @app.before_request | ||||
| def prepare_request(): | def prepare_request(): | ||||
| g.something = None # ... | |||||
| g.config = config | |||||
| g.eve = eve | |||||
| g.version = version | |||||
| @app.route("/") | @app.route("/") | ||||
| @catch_errors(app) | @catch_errors(app) | ||||
| @@ -0,0 +1 @@ | |||||
| __version__ = "0.1" | |||||
| @@ -0,0 +1,24 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| import yaml | |||||
| __all__ = ["Config"] | |||||
| class Config: | |||||
| def __init__(self, confdir): | |||||
| self._filename = confdir / "config.yml" | |||||
| self._data = None | |||||
| self._load() | |||||
| def _load(self): | |||||
| with self._filename.open("rb") as fp: | |||||
| self._data = yaml.load(fp) | |||||
| def get(self, key="", default=None): | |||||
| obj = self._data | |||||
| for item in key.split("."): | |||||
| if item not in obj: | |||||
| return default | |||||
| obj = obj[item] | |||||
| return obj | |||||
| @@ -0,0 +1,14 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| from .image import ImageServer | |||||
| __all__ = ["EVE"] | |||||
| class EVE: | |||||
| def __init__(self): | |||||
| self._image = ImageServer() | |||||
| @property | |||||
| def image(self): | |||||
| return self._image | |||||
| @@ -0,0 +1,50 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| __all__ = ["ImageServer"] | |||||
| class ImageServer: | |||||
| def __init__(self): | |||||
| self._url = "https://imageserver.eveonline.com/" | |||||
| @property | |||||
| def alliance_widths(self): | |||||
| return [32, 64, 128] | |||||
| @property | |||||
| def corp_widths(self): | |||||
| return [32, 64, 128, 256] | |||||
| @property | |||||
| def character_widths(self): | |||||
| return [32, 64, 128, 256, 512, 1024] | |||||
| @property | |||||
| def faction_widths(self): | |||||
| return [32, 64, 128] | |||||
| @property | |||||
| def inventory_widths(self): | |||||
| return [32, 64] | |||||
| @property | |||||
| def render_widths(self): | |||||
| return [32, 64, 128, 256, 512] | |||||
| def alliance(self, id, width): | |||||
| return self._url + "Alliance/{}_{}.png".format(id, width) | |||||
| def corp(self, id, width): | |||||
| return self._url + "Corporation/{}_{}.png".format(id, width) | |||||
| def character(self, id, width): | |||||
| return self._url + "Character/{}_{}.jpg".format(id, width) | |||||
| def faction(self, id, width): | |||||
| return self._url + "Alliance/{}_{}.jpg".format(id, width) | |||||
| def inventory(self, id, width): | |||||
| return self._url + "Type/{}_{}.jpg".format(id, width) | |||||
| def render(self, id, width): | |||||
| return self._url + "Render/{}_{}.jpg".format(id, width) | |||||
| @@ -30,7 +30,10 @@ def set_up_hash_versioning(app): | |||||
| if endpoint == "staticv": | if endpoint == "staticv": | ||||
| filename = values["filename"] | filename = values["filename"] | ||||
| fpath = path.join(app.static_folder, filename) | fpath = path.join(app.static_folder, filename) | ||||
| mtime = path.getmtime(fpath) | |||||
| try: | |||||
| mtime = path.getmtime(fpath) | |||||
| except OSError: | |||||
| return url_for("static", filename=filename) | |||||
| cache = app._hash_cache.get(fpath) | cache = app._hash_cache.get(fpath) | ||||
| if cache and cache[0] == mtime: | if cache and cache[0] == mtime: | ||||
| hashstr = cache[1] | hashstr = cache[1] | ||||
| @@ -1,3 +1,4 @@ | |||||
| Flask==0.11.1 | Flask==0.11.1 | ||||
| Flask-Mako==0.4 | Flask-Mako==0.4 | ||||
| PyYAML==3.12 | |||||
| requests==2.12.4 | requests==2.12.4 | ||||
| @@ -1,14 +1,29 @@ | |||||
| /* FONT... */ | |||||
| /* MOBILE... */ | /* MOBILE... */ | ||||
| @import url(//fonts.googleapis.com/css?family=Open+Sans:400,400italic,700); | |||||
| body { | body { | ||||
| display: flex; | display: flex; | ||||
| min-height: 100vh; | min-height: 100vh; | ||||
| flex-direction: column; | flex-direction: column; | ||||
| margin: 0; | margin: 0; | ||||
| font-family: sans-serif; | |||||
| background-color: #173350; | |||||
| color: #E6EAEF; | |||||
| font-family: "Open Sans", sans-serif; | |||||
| line-height: 1.3; | |||||
| color: #EAEAEA; | |||||
| background-color: black; | |||||
| background-size: cover; | |||||
| background-position: center; | |||||
| background-attachment: fixed; | |||||
| } | |||||
| a { | |||||
| color: #78CEFF; | |||||
| text-decoration: none; | |||||
| } | |||||
| a:hover { | |||||
| color: #68BEDD; | |||||
| text-decoration: underline; | |||||
| } | } | ||||
| #container { | #container { | ||||
| @@ -21,27 +36,46 @@ body { | |||||
| } | } | ||||
| main, header, footer { | main, header, footer { | ||||
| background-color: rgba(0, 0, 0, 0.85); | |||||
| background-color: rgba(0, 0, 0, 0.8); | |||||
| border-color: #4A4A4A; | |||||
| } | |||||
| main { | |||||
| margin: 2em auto; | |||||
| padding: 0 1em; | |||||
| border-width: 1px; | |||||
| border-style: solid; | |||||
| } | |||||
| header { | |||||
| font-size: 120%; | |||||
| border-bottom-width: 1px; | |||||
| border-bottom-style: solid; | |||||
| } | |||||
| footer { | |||||
| font-size: 85%; | |||||
| border-top-width: 1px; | |||||
| border-top-style: solid; | |||||
| } | } | ||||
| main, header > div, footer > div { | main, header > div, footer > div { | ||||
| max-width: 1000px; | max-width: 1000px; | ||||
| width: 80%; | width: 80%; | ||||
| padding: 1em; | |||||
| } | } | ||||
| main { | |||||
| margin: 2em auto; | |||||
| border: 1px solid #364A5F; | |||||
| header > div { | |||||
| margin: 0 auto; | |||||
| padding: 0.5em; | |||||
| } | } | ||||
| header > div, footer > div { | |||||
| footer > div { | |||||
| margin: 0 auto; | margin: 0 auto; | ||||
| padding: 1em; | |||||
| } | } | ||||
| header > div > div { | header > div > div { | ||||
| display: inline-block; | display: inline-block; | ||||
| vertical-align: middle; | |||||
| } | } | ||||
| header > div > .left { | header > div > .left { | ||||
| @@ -54,24 +88,25 @@ header > div > .right { | |||||
| width: 30%; | width: 30%; | ||||
| } | } | ||||
| header { | |||||
| font-size: 120%; | |||||
| border-bottom: 1px solid #364A5F; | |||||
| header a { | |||||
| color: #EAEAEA; | |||||
| } | } | ||||
| footer { | |||||
| font-size: 85%; | |||||
| border-top: 1px solid #364A5F; | |||||
| header a:hover { | |||||
| color: #CACACA; | |||||
| } | } | ||||
| a { | |||||
| color: #78CEFF; | |||||
| text-decoration: none; | |||||
| header .aligned { | |||||
| vertical-align: middle; | |||||
| } | } | ||||
| a:hover { | |||||
| color: #68BEDD; | |||||
| text-decoration: underline; | |||||
| #corp-masthead { | |||||
| height: 30px; | |||||
| margin-right: 0.5em; | |||||
| } | |||||
| #login-button { | |||||
| height: 30px; | |||||
| } | } | ||||
| #error pre { | #error pre { | ||||
| @@ -0,0 +1,7 @@ | |||||
| body { | |||||
| background-image: url("/static/images/amarr.jpg"); | |||||
| } | |||||
| main, header, footer { | |||||
| border-color: #5F4A26; | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| body { | |||||
| background-image: url("/static/images/caldari.jpg"); | |||||
| } | |||||
| main, header, footer { | |||||
| border-color: #364A5F; | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| body { | |||||
| background-image: url("/static/images/gallente.jpg"); | |||||
| } | |||||
| main, header, footer { | |||||
| border-color: #365F4A; | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| body { | |||||
| background-image: url("/static/images/minmatar.jpg"); | |||||
| } | |||||
| main, header, footer { | |||||
| border-color: #5F3C42; | |||||
| } | |||||
| @@ -6,21 +6,22 @@ | |||||
| <head> | <head> | ||||
| <meta charset="utf-8"> | <meta charset="utf-8"> | ||||
| <title> | <title> | ||||
| <%block name="title">CORP_NAME...</%block> | |||||
| <%block name="title">${g.config.get("corp.name")}</%block> | |||||
| </title> | </title> | ||||
| <link rel="stylesheet" href="${url_for('staticv', filename='style.css')}" type="text/css" /> | |||||
| <!-- FAVICONS... --> | |||||
| <link rel="stylesheet" type="text/css" href="${url_for('staticv', filename='main.css')}" /> | |||||
| <link rel="stylesheet" type="text/css" href="${url_for('staticv', filename='styles/minmatar.css')}" /> | |||||
| % for size in g.eve.image.corp_widths: | |||||
| <link rel="icon" type="image/png" sizes="${size}x${size}" href="${g.eve.image.corp(g.config.get('corp.id'), size)}" /> | |||||
| % endfor | |||||
| </head> | </head> | ||||
| <body> | <body> | ||||
| ${next.body()} | ${next.body()} | ||||
| <footer> | <footer> | ||||
| <div> | <div> | ||||
| <% | |||||
| copyright_year = datetime.now().year | |||||
| %> | |||||
| Copyright © ${copyright_year} COPYRIGHT_HOLDER... | |||||
| <% copyright_year = datetime.now().year %> | |||||
| Copyright © ${copyright_year} ${g.config.get("corp.copyright")} | |||||
| • | • | ||||
| Running <a href="https://github.com/earwig/calefaction">Calefaction</a> CALEFACTION_VERSION... | |||||
| Running <a href="https://github.com/earwig/calefaction">Calefaction</a> ${g.version} | |||||
| • | • | ||||
| <a href="https://eveonline.com">EVE Online</a> and all related trademarks are property of <a href="https://ccpgames.com">CCP hf</a>. | <a href="https://eveonline.com">EVE Online</a> and all related trademarks are property of <a href="https://ccpgames.com">CCP hf</a>. | ||||
| </div> | </div> | ||||
| @@ -1,9 +1,14 @@ | |||||
| <%inherit file="_layout.mako"/> | <%inherit file="_layout.mako"/> | ||||
| <%block name="lefthead"> | <%block name="lefthead"> | ||||
| [CORP_LOGO] CORP_NAME... | |||||
| <nav>Campaign: XYZ | Map | Intel | Members</nav> | |||||
| <a href="/"> | |||||
| <img id="corp-masthead" class="aligned" src="${g.eve.image.corp(g.config.get('corp.id'), 256)}"/> | |||||
| </a> | |||||
| <a href="/" class="aligned">${g.config.get("corp.name")}</a> | |||||
| <nav> | |||||
| Campaign: XYZ | Map | Intel | Members... | |||||
| </nav> | |||||
| </%block> | </%block> | ||||
| <%block name="righthead-"> | |||||
| PLAYER_NAME [logout] | |||||
| <%block name="righthead"> | |||||
| PLAYER_NAME... [logout] | |||||
| </%block> | </%block> | ||||
| ${next.body()} | ${next.body()} | ||||
| @@ -1,6 +1,6 @@ | |||||
| <%inherit file="_base.mako"/> | <%inherit file="_base.mako"/> | ||||
| <%block name="title"> | <%block name="title"> | ||||
| Error – ...name... | |||||
| Error – ${g.config.get("corp.name")} | |||||
| </%block> | </%block> | ||||
| <div id="container"> | <div id="container"> | ||||
| <div> | <div> | ||||
| @@ -1,8 +1,11 @@ | |||||
| <%inherit file="_layout.mako"/> | <%inherit file="_layout.mako"/> | ||||
| <%block name="lefthead"> | <%block name="lefthead"> | ||||
| [C_LOGO] C_NAME... | |||||
| <a href="/"> | |||||
| <img id="corp-masthead" class="aligned" src="${g.eve.image.corp(g.config.get('corp.id'), 256)}"/> | |||||
| </a> | |||||
| <a href="/" class="aligned">${g.config.get("corp.name")}</a> | |||||
| </%block> | </%block> | ||||
| <%block name="righthead"> | <%block name="righthead"> | ||||
| <img id="login-button" src="${url_for('staticv', filename='images/eve-login.png')}"/> | |||||
| <img id="login-button" class="aligned" src="${url_for('staticv', filename='images/eve-login.png')}"/> | |||||
| </%block> | </%block> | ||||
| <p>Hello, world!</p> | <p>Hello, world!</p> | ||||