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()


  • I wanted to use the former site’s RSS configuration that outputs the feed data to rss.xml. This seems doable, but it is unnecessarily complex in Hugo.

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

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

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

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

To make an AWS 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/*"
        }
    ]
}

It’s possible to grant 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.