Posted on

This blog has now moved to Amazon Amplify. It’s connected to a Bitbucket git repository, and AWS pulls it as soon as it’s pushed. Previously, I was polling the repository manually on a VPS, but this is much quicker.

  • Setting your domain name for Amplify requires:

    1. Writing a CNAME record to prove ownership.
    2. Modifying the ALIAS and CNAME records of @ and www to a CloudFront URL provided to you. This automatically enables HTTPS for your site. My domains are in Namecheap, but AWS advertises that using Route 53 is much simpler.
  • I wrote a script to convert from Pelican’s front matter to YAML front matter used in Hugo. It receives a filename argument (e.g., a/index.md) and converts the header to YAML format, backing up the old file as a/index.md.old. For my Turkish blog, it converted about 400 posts quickly. Hugo gives errors in YAML headers with quotation marks, but there were only a few, and I corrected them manually.


```python
#!/usr/bin/python3

import sys
import re
from dateutil import parser
import datetime
import os

fn = sys.argv[1]

fread = open(fn, encoding="utf-8")
lines = fread.readlines()
fread.close()


fmorig = []

for i, l in enumerate(lines):
    if len(l.strip()) == 0:
        blank_line_i = i
        break
    else:
        fmorig.append(l)

print(fmorig)

fmtarget = {}

for fm in fmorig:
    if fm.startswith('Date'):
        dt = parser.parse(fm[5:].strip())
        fmtarget['date'] = dt
        expiryDate = dt + datetime.timedelta(days=365)
        fmtarget['expiryDate'] = expiryDate
    elif fm.startswith('Title'):
        fmtarget['title'] = fm[6:].strip()
    elif fm.startswith('Author'):
        fmtarget['author'] = fm[7:].strip()
    elif fm.startswith('Image'):
        imageName = fm[6:].strip().split('/')[2]
        fmtarget['image'] = "/images/{}".format(imageName)
    elif fm.startswith('Status'):
        fmtarget['status'] = fm[7:].strip()
    elif fm.startswith('Dp'):
        fmtarget['dp'] = fm[3:].strip()
    elif fm.startswith('Tags'):
        fmtarget['tags'] = fm[5:].strip().split(',')
    else:
        fmtarget[fm] = fm


dt = fmtarget['date']
dn, bn = os.path.split(fn)



newfrontmatter = """---
title: "{title}"
date: {dt}
expiryDate: {expiryDate}
dp: {dp}
featured_image: "{image}"
images: ["{image}"]
published: {status}
tags: [{tags}]
---
""".format(title=fmtarget['title'],
           dt=fmtarget['date'].strftime("%F %H:%M:%S"),
           expiryDate = fmtarget['expiryDate'].strftime("%F %H:%M:%S"),
           dp = fmtarget['dp'],
           image = fmtarget['image'],
           status = "true" if fmtarget['status'] == "published" else "false",
           tags = ",".join(fmtarget['tags']) if 'tags' in fmtarget else '')


newcontent="""{}

{}
""".format(newfrontmatter, "".join(lines[blank_line_i:]))

print(newfrontmatter)

backup_filename = fn + ".old"
os.rename(fn, backup_filename)

fwrite = open(fn, mode="w", encoding="utf-8")
fwrite.write(newcontent)
fwrite.close()
DEFAULT


To achieve this, add the following to config.toml:

[outputs]
home = [ "RSS", "HTML"]

[outputFormats]
[outputFormats.RSS]
mediatype = "application/rss"
baseName = "rss"
TOML

  • I created two Firefox searches similar to DuckDuckGo bangs. Typing !g in the omnibar makes a Google search, and !pb searches my Pinboard bookmarks. This avoids a roundtrip from DuckDuckGo if I’m already using the browser.

To make an S3 bucket public, add the following to the Bucket Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::subdomain.example.com/*"
        }
    ]
}
JSON

It’s possible to give permissions to subfolders by right-clicking on them, but for the entire bucket, you need to write this policy.


  • Python’s datetime.timedelta doesn’t have a years parameter. It accepts weeks as the longest period, as it’s the longest unambiguous period of 7 days.