- moved Tips from footer to bottom of each singular with an "encourage creation" header

- google vision api binding for images (not in use yet)
- konami code css preparations
- experimental gallery css
- minor code cleanups
This commit is contained in:
Peter Molnar 2018-12-01 10:43:13 +00:00
parent 9af56f89e7
commit de269ef39e
9 changed files with 191 additions and 49 deletions

View file

@ -2,22 +2,28 @@ import re
import subprocess import subprocess
import json import json
import os import os
import keys
import requests
from pprint import pprint
EXIFDATE = re.compile( EXIFDATE = re.compile(
r'^(?P<year>[0-9]{4}):(?P<month>[0-9]{2}):(?P<day>[0-9]{2})\s+' r'^(?P<year>[0-9]{4}):(?P<month>[0-9]{2}):(?P<day>[0-9]{2})\s+'
r'(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2})$' r'(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2})$'
) )
class Exif(dict): class CachedMeta(dict):
def __init__(self, fpath): def __init__(self, fpath):
self.fpath = fpath self.fpath = fpath
self._read()
@property @property
def cfile(self): def cfile(self):
return os.path.join( return os.path.join(
os.path.dirname(self.fpath), os.path.dirname(self.fpath),
".%s.json" % (os.path.basename(self.fpath)) ".%s.%s.json" % (
self.__class__.__name__,
os.path.basename(self.fpath)
)
) )
@property @property
@ -31,7 +37,7 @@ class Exif(dict):
def _read(self): def _read(self):
if not self._is_cached: if not self._is_cached:
self._call_exiftool() self._call_tool()
self._cache_update() self._cache_update()
else: else:
self._cache_read() self._cache_read()
@ -44,9 +50,65 @@ class Exif(dict):
with open(self.cfile, 'rt') as f: with open(self.cfile, 'rt') as f:
data = json.loads(f.read()) data = json.loads(f.read())
for k, v in data.items(): for k, v in data.items():
self[k] = self.exifdate2rfc(v) self[k] = v
def _call_exiftool(self): class GoogleVision(CachedMeta):
def __init__(self, fpath, imgurl):
self.fpath = fpath
self.imgurl = imgurl
self._read()
@property
def cntr(self):
curr = 0
if os.path.exists('/tmp/visionapicallcounter'):
with open('/tmp/visionapicallcounter', 'rt') as f:
curr = int(f.read())
curr = curr + 1
with open('/tmp/visionapicallcounter', 'wt') as f:
f.write("%d" % curr)
return curr
def _call_tool(self):
if (self.cntr >= 500 ):
raise ValueError('already at 500 requests!')
params = {
"requests": [
{
"image": {
"source": {
"imageUri": self.imgurl,
}
},
"features": [
{
"type": "LANDMARK_DETECTION",
},
{
"type": "LABEL_DETECTION",
},
]
}
]
}
url = "https://vision.googleapis.com/v1/images:annotate?key=%s" % (keys.gcloud.get('key'))
r = requests.post(url, json=params)
try:
resp = r.json()
resp = resp['responses'][0]
for k, v in resp.items():
self[k] = v
except Exception as e:
logging.error('failed to call Google Vision API on: %s, reason: %s', self.fpath, e)
class Exif(CachedMeta):
def __init__(self, fpath):
self.fpath = fpath
self._read()
def _call_tool(self):
""" """
Why like this: the # on some of the params forces exiftool to Why like this: the # on some of the params forces exiftool to
display values like decimals, so the latitude / longitude params display values like decimals, so the latitude / longitude params

12
nasg.py
View file

@ -31,7 +31,7 @@ from emoji import UNICODE_EMOJI
from slugify import slugify from slugify import slugify
import requests import requests
from pandoc import Pandoc from pandoc import Pandoc
from exiftool import Exif from exiftool import Exif, GoogleVision
import settings import settings
import keys import keys
@ -717,6 +717,10 @@ class WebImage(object):
tmpl = J2.get_template("%s.j2.html" % (self.__class__.__name__)) tmpl = J2.get_template("%s.j2.html" % (self.__class__.__name__))
return tmpl.render(self.tmplvars) return tmpl.render(self.tmplvars)
@cached_property
def vision(self):
return GoogleVision(self.fpath, self.src)
@cached_property @cached_property
def meta(self): def meta(self):
return Exif(self.fpath) return Exif(self.fpath)
@ -1737,11 +1741,11 @@ def make():
start = int(round(time.time() * 1000)) start = int(round(time.time() * 1000))
last = 0 last = 0
if not settings.args.get('nosync'):
try: try:
makecomments() makecomments()
except Exception as e: except Exception as e:
logger.error('failed to make comments: %s', e) logger.error('failed to make comments: %s', e)
makeposts(); makeposts();
content = settings.paths.get('content') content = settings.paths.get('content')
@ -1817,8 +1821,8 @@ def make():
staticfiles = [] staticfiles = []
staticpaths = [ staticpaths = [
os.path.join(content, '*.*'), os.path.join(content, '*.*'),
os.path.join(settings.paths.get('tmpl'), '*.css'), #os.path.join(settings.paths.get('tmpl'), '*.css'),
os.path.join(settings.paths.get('tmpl'), '*.js'), #os.path.join(settings.paths.get('tmpl'), '*.js'),
] ]
for p in staticpaths: for p in staticpaths:
staticfiles = staticfiles + glob.glob(p) staticfiles = staticfiles + glob.glob(p)

View file

@ -3,10 +3,6 @@ import logging
class Pandoc(str): class Pandoc(str):
def __new__(cls, text): def __new__(cls, text):
# TODO: cache?
# import hashlib
# print(hashlib.md5("whatever your string is".encode('utf-8')).hexdigest())
""" Pandoc command line call with piped in- and output """ """ Pandoc command line call with piped in- and output """
cmd = ( cmd = (
'pandoc', 'pandoc',

View file

@ -9,9 +9,12 @@
{% block meta %} {% block meta %}
<link rel="alternate" type="application/rss+xml" title="{{ category.title }} RSS feed" href="{{ category.feed }}" /> <link rel="alternate" type="application/rss+xml" title="{{ category.title }} RSS feed" href="{{ category.feed }}" />
<link rel="alternate" type="application/atom+xml" title="{{ category.title }} ATOM feed" href="{{ category.feed }}atom.xml" /> <link rel="alternate" type="application/atom+xml" title="{{ category.title }} ATOM feed" href="{{ category.feed }}atom.xml" />
<style id="css_gallery" media="speech">
{% include 'style-gallery.css' %}
</style>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<main class="content-body h-feed hfeed" property="h-feed"> <main class="content-body h-feed hfeed {{ category.name }}" property="h-feed">
<header> <header>
<h1 class="p-name" property="p-name">{{ category.name }}</h1> <h1 class="p-name" property="p-name">{{ category.name }}</h1>
</header> </header>

View file

@ -17,6 +17,9 @@
<style id="css_alt" media="speech"> <style id="css_alt" media="speech">
{% include 'style-alt.css' %} {% include 'style-alt.css' %}
</style> </style>
<style id="css_kcl" media="speech">
{% include 'style-kcl.css' %}
</style>
<style media="print"> <style media="print">
{% include 'style-print.css' %} {% include 'style-print.css' %}
</style> </style>
@ -72,10 +75,6 @@
<svg width="16" height="16"> <svg width="16" height="16">
<use xlink:href="#icon-contrast"></use> <use xlink:href="#icon-contrast"></use>
</svg> </svg>
<span>
<input name="colorscheme" value="auto" id="autoscheme" type="radio">
<label for="autoscheme">auto</label>
</span>
<span> <span>
<input name="colorscheme" value="dark" id="darkscheme" type="radio"> <input name="colorscheme" value="dark" id="darkscheme" type="radio">
<label for="darkscheme">dark</label> <label for="darkscheme">dark</label>
@ -272,6 +271,27 @@
</section> </section>
{% endif %} {% endif %}
<section class="encourage">
<hr />
<h2>Encourage creation!</h2>
<p>If this entry helped you, or you simply liked it, leave a tip.</p>
<nav>
<ul>
<li>
<a rel="payment" href="https://paypal.me/petermolnar/3GBP">
<svg width="16" height="16">
<use xlink:href="#icon-paypal"></use>
</svg> Paypal</a>
</li>
<li>
<a rel="payment" href="https://monzo.me/petermolnar/3">
<svg width="16" height="16">
<use xlink:href="#icon-monzo"></use>
</svg> Monzo (UK or Google Pay)</a>
</li>
</ul>
</nav>
</section>
{% if post.replies|length %} {% if post.replies|length %}
<section class="replies"> <section class="replies">
@ -370,12 +390,11 @@
alt="Photo of {{ author.name }}" alt="Photo of {{ author.name }}"
itemprop="image url" /> itemprop="image url" />
</span> </span>
<a class="fn p-name url u-url u-uid" property="p-name u-url u-uid" rel="me" href="{{ site.url }}/about.html"> <a class="fn p-name url u-url u-uid" property="p-name u-url u-uid" rel="me" href="{{ site.url }}"><span itemprop="name">{{ author.name }}</span></a>
<span itemprop="name">{{ author.name }}</span> <!--
</a> <a class="u-url" property="u-url" rel="me" href="{{ site.url }}/about.html">CV</a>
<a class="u-email email" property="u-email" rel="me" href="mailto:{{ author.email }}"> -->
<span itemprop="email">{{ author.email }}</span> <a class="u-email email" property="u-email" rel="me" href="mailto:{{ author.email }}"><span itemprop="email">{{ author.email }}</span></a>
</a>
</p> </p>
<nav> <nav>
<ul> <ul>
@ -392,18 +411,6 @@
</ul> </ul>
</nav> </nav>
</div> </div>
<p>
Leave a tip!
<a rel="payment" href="{{ tips.paypal }}">
<svg width="16" height="16">
<use xlink:href="#icon-paypal"></use>
</svg> Paypal</a>
or
<a rel="payment" href="{{ tips.monzo }}">
<svg width="16" height="16">
<use xlink:href="#icon-monzo"></use>
</svg> Monzo</a> (UK only).
</p>
<p> <p>
<a href="https://xn--sr8hvo.ws/🇻🇮📢/previous"></a> <a href="https://xn--sr8hvo.ws/🇻🇮📢/previous"></a>
Member of <a href="https://xn--sr8hvo.ws">IndieWeb Webring</a> Member of <a href="https://xn--sr8hvo.ws">IndieWeb Webring</a>

View file

@ -0,0 +1,34 @@
main.photo {
display: flex;
flex-wrap: wrap;
}
main.photo article {
max-width: 24em;
margin: 0.6em;
display: grid;
position: relative;
}
main.photo article figure {
margin: 0;
padding: 0;
}
main.photo article h2 {
margin: 0;
padding: 0.6em;
background: rgba(0,0,0,0.7);
position: absolute;
top: 50%;
left: 0;
right: 0;
text-align: center;
}
main.photo article figcaption,
main.photo article p,
main.photo article section {
display: none;
}

5
templates/style-kcl.css Normal file
View file

@ -0,0 +1,5 @@
body {
font-family: serif;
background-color: #0f0;
color: #f00;
}

View file

@ -319,6 +319,19 @@ body > footer h2,
display: none; display: none;
} }
.encourage {
text-align: center;
padding-bottom: 2em;
}
.encourage h2 {
color: #080;
}
.encourage li {
margin: 0 0.6em;
}
@media all and (min-width: 58em) { @media all and (min-width: 58em) {
body > header { body > header {
text-align: unset; text-align: unset;

View file

@ -23,28 +23,28 @@ function applyTheme(mode) {
function setTheme(e) { function setTheme(e) {
var mode = e.target.value; var mode = e.target.value;
if (mode == 'auto') { var mql = window.matchMedia('(prefers-color-scheme: ' + ALT_THEME + ')');
/* user wants == mql match => remove storage */
if ((mode == DEFAULT_THEME && !mql.matches) || (mode == ALT_THEME && mql.matches)) {
localStorage.removeItem(STORAGE_KEY); localStorage.removeItem(STORAGE_KEY);
} }
else { else {
localStorage.setItem(STORAGE_KEY, mode); localStorage.setItem(STORAGE_KEY, mode);
} }
var e = window.matchMedia('(prefers-color-scheme: ' + ALT_THEME + ')'); autoTheme(mql);
autoTheme(e);
} }
function autoTheme(e) { function autoTheme(e) {
var mode = DEFAULT_THEME;
var current = localStorage.getItem(STORAGE_KEY); var current = localStorage.getItem(STORAGE_KEY);
var mode = 'auto';
var indicate = 'auto';
if ( current != null) { if ( current != null) {
indicate = mode = current; mode = current;
} }
else if (e.matches) { else if (e.matches) {
mode = ALT_THEME; mode = ALT_THEME;
} }
applyTheme(mode); applyTheme(mode);
indicateTheme(indicate); indicateTheme(mode);
} }
var mql = window.matchMedia('(prefers-color-scheme: ' + ALT_THEME + ')'); var mql = window.matchMedia('(prefers-color-scheme: ' + ALT_THEME + ')');
@ -59,3 +59,21 @@ var themeforms = document.getElementsByClassName(STORAGE_KEY);
for(var i = themeforms.length; i--; ) { for(var i = themeforms.length; i--; ) {
themeforms[i].style.display = 'inline-block'; themeforms[i].style.display = 'inline-block';
} }
function kcl(cb) {
var input = '';
var key = '38384040373937396665';
document.addEventListener('keydown', function (e) {
input += ("" + e.keyCode);
if (input === key) {
return cb();
}
if (!key.indexOf(input)) return;
input = ("" + e.keyCode);
});
}
kcl(function () {
var st = document.getElementById('css_kcl');
st.setAttribute('media', 'all');
})