July 2020 (#2)
* wip * Forked lektor-thumbnail-generator * Post Co-authored-by: Felipe M <fmartingr@Going-Merry.local>
This commit is contained in:
parent
b7799aac92
commit
9709127df1
8 changed files with 258 additions and 1 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -21,5 +21,7 @@ public
|
||||||
# Lektor
|
# Lektor
|
||||||
.lektor
|
.lektor
|
||||||
|
|
||||||
|
packages/**/*.egg-info
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
|
@ -8,4 +8,4 @@ lektor-markdown-header-anchors = 0.3.1
|
||||||
lektor-atom = 0.3
|
lektor-atom = 0.3
|
||||||
lektor-htmlmin = 1.0.2
|
lektor-htmlmin = 1.0.2
|
||||||
lektor-markdown-highlighter = 0.3.1
|
lektor-markdown-highlighter = 0.3.1
|
||||||
lektor-thumbnail-generator = 0.4.0
|
# lektor-thumbnail-generator = 0.4.0
|
||||||
|
|
118
content/blog/2020-08-02-july/contents.lr
Normal file
118
content/blog/2020-08-02-july/contents.lr
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
title: July 2020
|
||||||
|
---
|
||||||
|
pub_date: 2020-08-02
|
||||||
|
---
|
||||||
|
_template: blog/post.html
|
||||||
|
---
|
||||||
|
body:
|
||||||
|
|
||||||
|
Summer is here!
|
||||||
|
|
||||||
|
Even without restrictions or quarantine is has been a weird month. Cases here are going up and down,
|
||||||
|
I don't want to go back to the gym (and I think I won't until next year), some restaurants and cafe
|
||||||
|
have closed permanently and the ones that are still standing are usually full (which is good). We're
|
||||||
|
just trying to go back to normal, step by step, and having some friends stay at home a few days
|
||||||
|
helped a lot.
|
||||||
|
|
||||||
|
[](./image-1024.jpg)
|
||||||
|
|
||||||
|
<!-- readmore -->
|
||||||
|
|
||||||
|
This month I have focused on getting more organized. As I said [last month](/blog/2020/06/02/june/)
|
||||||
|
I badly needed it.
|
||||||
|
|
||||||
|
I have managed to move almost everything into my [notion.so](https://notion.so/) workspace.
|
||||||
|
I had some boards and notes here and there but Notion is so powerful and comfortable to use that I
|
||||||
|
just went all in. There's some cleanup to do, but my main points of interes are already there. I have
|
||||||
|
a board with my personal tasks and some metadata about them, and secondary boards for my hobbies
|
||||||
|
(Games, Books, TVShows, etc), Blog related posts, ... I may go into more detail in the future.
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div class="col-1-2">
|
||||||
|
<a href="./notion-tasks.png">
|
||||||
|
<img src="./notion-tasks-320.png" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-1-2">
|
||||||
|
<a href="./notion-games.png">
|
||||||
|
<img src="./notion-games-320.png" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Related to this I'm also starting to cleanup every last drawer at home. I got a bit tired of not
|
||||||
|
knowing how much stuff I have so I'm making a full inventory of _everything_. It all started
|
||||||
|
reviewing how many of my clothers would still fit me after quarantine, and it snapped on me. I
|
||||||
|
don't know how much I own, and I think it happens to all of us at different levels.
|
||||||
|
|
||||||
|
With tech this is gonna be very difficult, I have managed to stash a lot (**a lot**) of cables
|
||||||
|
during the years. Just imagine how many HDMI and USB cables the average tech guy can get a hold
|
||||||
|
of... Arduinos, Raspberries... etc.
|
||||||
|
|
||||||
|
This will take time, but I'm very happy with the progress I already had and all the things I've
|
||||||
|
already donated or sold.
|
||||||
|
|
||||||
|
## Projects
|
||||||
|
|
||||||
|
- My **local infra** is mostly done at this point. I just need to secure everything a bit more
|
||||||
|
but has been working fine (with some hiccups) for the past months. I may need to check some
|
||||||
|
networking alternatives and move all SSL negotiation to the main node (avoiding re-encrypting
|
||||||
|
traffic on a non-controlled node).
|
||||||
|
|
||||||
|
- **Butterrobot** got some love this month. I'm _slowly_ setting up an automated CI/CD system to
|
||||||
|
deploy the application in my local infra, but I need to setup some other details as well. Source
|
||||||
|
code is already on Github though repository is private while I made last minute changes. I'm
|
||||||
|
hoping to release it this month.
|
||||||
|
|
||||||
|
- I'm also cleaning up my **Home Assistant** node. What that really means that I'm re-deploying a
|
||||||
|
new instance on a more powerful Raspberry Pi. I have been playing with this software for years
|
||||||
|
and my current pi is a bit underpowered and messy, so the plan is start from scratch trying to
|
||||||
|
make the connected devices local trying to avoid third-party clouds as much as possible and
|
||||||
|
document everything in some blog posts. Let see how that goes.
|
||||||
|
|
||||||
|
## TV Shows
|
||||||
|
|
||||||
|
I watched something!
|
||||||
|
|
||||||
|
- **M.A.R.V.E.L.s Agents of Shield**
|
||||||
|
|
||||||
|
Some chapters of the last season. This may be the worst season so far...? (At least the few I saw)
|
||||||
|
|
||||||
|
- **The 100**
|
||||||
|
|
||||||
|
Up to date with this one, without much focus because some interdimensional time thingy is not very
|
||||||
|
appealing to me, just want to know how it all ends. If it doesn't end this season, I'm done with it.
|
||||||
|
|
||||||
|
- **Sword Art Online (Aincrad saga only)**
|
||||||
|
|
||||||
|
Rewatched this one (a friend's fault) as series to have while cooking and doing chores. A bit complex
|
||||||
|
to read subtitles the same time you do other things, but since this is a re-watch... Now looking for
|
||||||
|
some other series with the same "protagonist sent to fantasy world" genre.
|
||||||
|
|
||||||
|
## Games
|
||||||
|
|
||||||
|
- [**Final Fantasy VII: Remake**](https://store.playstation.com/es-es/product/EP0082-CUSA07187_00-FFVIIREMAKE00000)
|
||||||
|
|
||||||
|
I have gone through a bit more of the story, trying to enjoy the story till the end. And wait
|
||||||
|
another five years for the next chapter...?
|
||||||
|
|
||||||
|
- [**Reventure**](https://store.steampowered.com/app/900270/Reventure/)
|
||||||
|
|
||||||
|
Quick play sessions are quick. Oh my god this game has soooo many endings...
|
||||||
|
|
||||||
|
- [**Carrion**](https://www.xbox.com/en-US/games/carrion)
|
||||||
|
|
||||||
|
This has been on my radar for quite some time. It's a shame is so short! Finished in a few hours, but that didn't mean
|
||||||
|
is not great, because it is. Being the monster trapped wanted to go out instead of the _"Hero"_ killing monsters is
|
||||||
|
a really appreciated change of perspective. The mechanics were amazing and the graphics gorgeous, it was very fun while it
|
||||||
|
lasted.
|
||||||
|
|
||||||
|
- [**Rick and Morty: Virtual Rick-ality**](https://store.steampowered.com/app/469610/Rick_and_Morty_Virtual_Rickality/)
|
||||||
|
|
||||||
|
I got time to play some VR, and I had this in the backlog for quite some time. I love Rick and Morty and this was
|
||||||
|
a short and fun puzzle adventure, just what I expected. I could get on with the optional stuff but I just have too much
|
||||||
|
on backlog!
|
||||||
|
|
||||||
|
## Articles
|
||||||
|
|
||||||
|
I forgot to take note of the interesting ones this month. :sweat_smile:
|
BIN
content/blog/2020-08-02-july/image.jpg
Normal file
BIN
content/blog/2020-08-02-july/image.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 706 KiB |
BIN
content/blog/2020-08-02-july/notion-games.png
Normal file
BIN
content/blog/2020-08-02-july/notion-games.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 548 KiB |
BIN
content/blog/2020-08-02-july/notion-tasks.png
Normal file
BIN
content/blog/2020-08-02-july/notion-tasks.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
|
@ -0,0 +1,120 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from lektor.build_programs import AttachmentBuildProgram, buildprogram
|
||||||
|
from lektor.context import get_ctx
|
||||||
|
from lektor.db import Image
|
||||||
|
from lektor.imagetools import (computed_height, find_imagemagick,
|
||||||
|
get_image_info, get_quality)
|
||||||
|
from lektor.pluginsystem import Plugin
|
||||||
|
from lektor.reporter import reporter
|
||||||
|
from lektor.utils import portable_popen
|
||||||
|
from werkzeug.utils import cached_property
|
||||||
|
|
||||||
|
|
||||||
|
# We override process_image here because Lektor does not support adding extra
|
||||||
|
# parameters yet, but it will soon, and this can be removed when it does.
|
||||||
|
def process_image(
|
||||||
|
ctx,
|
||||||
|
source_image,
|
||||||
|
dst_filename,
|
||||||
|
width=None,
|
||||||
|
height=None,
|
||||||
|
mode=None,
|
||||||
|
quality=None,
|
||||||
|
extra_params=None,
|
||||||
|
):
|
||||||
|
"""Build image from source image, optionally compressing and resizing.
|
||||||
|
"source_image" is the absolute path of the source in the content directory,
|
||||||
|
"dst_filename" is the absolute path of the target in the output directory.
|
||||||
|
"""
|
||||||
|
if width is None and height is None:
|
||||||
|
raise ValueError("Must specify at least one of width or height.")
|
||||||
|
|
||||||
|
im = find_imagemagick(ctx.build_state.config["IMAGEMAGICK_EXECUTABLE"])
|
||||||
|
|
||||||
|
if quality is None:
|
||||||
|
quality = get_quality(source_image)
|
||||||
|
|
||||||
|
resize_key = ""
|
||||||
|
if width is not None:
|
||||||
|
resize_key += str(width)
|
||||||
|
if height is not None:
|
||||||
|
resize_key += "x" + str(height)
|
||||||
|
|
||||||
|
cmdline = [im, source_image, "-auto-orient"]
|
||||||
|
cmdline += ["-resize", resize_key]
|
||||||
|
|
||||||
|
if extra_params:
|
||||||
|
cmdline.extend(extra_params)
|
||||||
|
|
||||||
|
cmdline += ["-quality", str(quality), dst_filename]
|
||||||
|
|
||||||
|
reporter.report_debug_info("imagemagick cmd line", cmdline)
|
||||||
|
portable_popen(cmdline).wait()
|
||||||
|
|
||||||
|
|
||||||
|
@buildprogram(Image)
|
||||||
|
class ResizedImageBuildProgram(AttachmentBuildProgram):
|
||||||
|
def build_artifact(self, artifact):
|
||||||
|
ctx = get_ctx()
|
||||||
|
plugin = ctx.env.plugins["thumbnail-generator"]
|
||||||
|
config = plugin.config
|
||||||
|
|
||||||
|
artifact.ensure_dir()
|
||||||
|
AttachmentBuildProgram.build_artifact(self, artifact)
|
||||||
|
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
source_img = artifact.source_obj.attachment_filename
|
||||||
|
|
||||||
|
with open(source_img, "rb") as f:
|
||||||
|
_, w, h = get_image_info(f)
|
||||||
|
|
||||||
|
# For every section in the config, we need to generate one image.
|
||||||
|
for item, conf in config.items():
|
||||||
|
width = int(conf["max_width"])
|
||||||
|
height = int(conf.get("max_height", "0"))
|
||||||
|
quality = int(conf.get("quality", "100"))
|
||||||
|
|
||||||
|
if not height:
|
||||||
|
height = computed_height(source_img, width, w, h)
|
||||||
|
|
||||||
|
df = artifact.source_obj.url_path
|
||||||
|
ext_pos = df.rfind(".")
|
||||||
|
dst_filename = "%s-%s.%s" % (df[:ext_pos], item, df[ext_pos + 1 :])
|
||||||
|
|
||||||
|
def closure(dst_filename, source_img, width, height, resize_image=True):
|
||||||
|
# We need this closure, otherwise variables get updated and this
|
||||||
|
# doesn't work at all.
|
||||||
|
@ctx.sub_artifact(artifact_name=dst_filename, sources=[source_img])
|
||||||
|
def build_thumbnail_artifact(artifact):
|
||||||
|
artifact.ensure_dir()
|
||||||
|
if not resize_image:
|
||||||
|
shutil.copy2(source_img, artifact.dst_filename)
|
||||||
|
else:
|
||||||
|
process_image(
|
||||||
|
ctx,
|
||||||
|
source_img,
|
||||||
|
artifact.dst_filename,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
quality=100,
|
||||||
|
)
|
||||||
|
|
||||||
|
# If the image is larger than the max_width, resize it, otherwise
|
||||||
|
# just copy it.
|
||||||
|
resize_image = w > width or h > height
|
||||||
|
closure(dst_filename, source_img, width, height, resize_image)
|
||||||
|
|
||||||
|
|
||||||
|
class ThumbnailGeneratorPlugin(Plugin):
|
||||||
|
name = u"thumbnail-generator"
|
||||||
|
description = u"A configurable way to generate thumbnails."
|
||||||
|
image_exts = ["png", "jpg", "jpeg", "gif"]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def config(self):
|
||||||
|
conf = self.get_config()
|
||||||
|
return {section: conf.section_as_dict(section) for section in conf.sections()}
|
17
packages/lektor-thumbnail-generator/setup.py
Normal file
17
packages/lektor-thumbnail-generator/setup.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='lektor-thumbnail-generator',
|
||||||
|
version='0.4.0',
|
||||||
|
author=u'Stavros Korokithakis,,,',
|
||||||
|
author_email='hi@stavros.io',
|
||||||
|
url='https://github.com/skorokithakis/lektor-thumbnail-generator/',
|
||||||
|
description="This plugin automatically generates thumbnails for any images in your Lektor content. The difference between this plugin and the `thumbnail` filter is that this is geared towards content, i.e. you don't need to have any references to the images in your templates at all.",
|
||||||
|
license='MIT',
|
||||||
|
py_modules=['lektor_thumbnail_generator'],
|
||||||
|
entry_points={
|
||||||
|
'lektor.plugins': [
|
||||||
|
'thumbnail-generator = lektor_thumbnail_generator:ThumbnailGeneratorPlugin',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
Loading…
Add table
Add a link
Reference in a new issue