Compare commits

...

14 commits

Author SHA1 Message Date
0e999284b9 Add a --date argument to new-photo-post script
If this argument is passed, skip pulling dates from the EXIF data and use it as
the post date.

I recently tried to post a photo that had no EXIF data. This argument provides
an override so the script doesn't 💥 on missing metadata.
2025-10-08 09:04:05 -07:00
d4f286d723 Harvest Moon post 2025-10-08 09:00:30 -07:00
0939fc6847 Permalink configuration for the twitter section 2025-10-06 08:21:59 -07:00
49a28973ce A tag page for EJ 2025-10-06 08:20:45 -07:00
9e54fb8216 Draft translation of my /uses page in toki pona 2025-10-06 08:20:35 -07:00
ca09a1372d Spanish language version of index page is a DRAFT 2025-10-06 08:20:17 -07:00
b8372626bf Improve type annotations in WeeknotesCommand 2025-10-06 08:17:40 -07:00
6f8987d393 Add root_dir() and assets_path() to paths module
A few more repo paths.
2025-10-06 08:17:11 -07:00
342a4af782 In website, cd to root of website repo before proceeding 2025-10-06 08:16:06 -07:00
a5927fbc9a Improve program name in website --help
Take basename of argv[0] so the help message is a little more succinct.
2025-10-06 08:15:42 -07:00
46ee9ff892 Remove the deploy.sh script
Deployment is done through the Makefile now.
2025-09-27 10:37:22 -07:00
79674d4a07 Future 38th birthday post 2025-09-27 10:35:04 -07:00
00d710e00b Collapse the space at the end of the {{< abbr >}} shortcode 2025-09-27 10:33:55 -07:00
5dae68f714 Home page copy updates 2025-09-27 10:33:16 -07:00
14 changed files with 282 additions and 51 deletions

View file

@ -1,2 +1,3 @@
blog: blog/:year/:month/:slug/
photos: photos/:year/:month/:slug/
twitter: twitter/:year/:month/:slug/

View file

@ -1,8 +1,20 @@
---
title: Eryn Rachel Wells
layout: single
draft: true
params:
renderHeadingAnchors: false
---
{{< nobreak >}}Ingeniera de software,{{< /nobreak >}}
alfarera, música, y
{{< nobreak >}}nerd en general.{{< /nobreak >}}
¡Hola! Me llamo Eryn Wells. Este es mi sitio web. ¡Bienvenidos!
## Personal
Soy mujer queer,
## Profesional
Desde 2011, he trabajado como ingeniera de software en varios companías alrededor del área
del Bahía de San Francisco. En 2016, me uní a [Apple][]. Hoy, trabajo en
tecnologías que

View file

@ -6,53 +6,61 @@ params:
Hi, I'm Eryn Wells. This is my website. Welcome!
## Latest
Here are some of my most recent posts.
{{< home/latest >}}
## Personal
I'm a queer trans woman, {{< tess >}}' partner, and mom of [two cats][cats]. I
I'm a queer woman, {{< tess >}}' partner, and mom of [two cats][cats]. I
was born in Seattle, {{< abbr Washington >}}WA{{< /abbr >}} and grew up in
Phoenix, {{< abbr Arizona >}}AZ{{< /abbr >}}. I attended [Oberlin College][ob]
Phoenix, {{< abbr Arizona >}}AZ{{< /abbr >}}. I attended [Oberlin College][]
where I got a degree in Computer Science. My pronouns are [she/her][pronouns].
You can read more about me on my [about][ab] page, or [get in touch][where-am-i].
## Professional
I've worked as a software engineer since 2011 for a variety of companies around
the San Francisco Bay Area. I joined [Apple][a] in 2016, where I currently work
the San Francisco Bay Area. I joined [Apple][] in 2016, where I currently work
on password management and authentication technologies.
My [résumé][r] has all the details.
## Hobbies
When I'm not working, you can reliably find me hacking on this website or [some
coding other project][gh]. I'm also a musician, and play piano, Irish tin
whistle, and modular synthesizer. Occasionally I [record][bc] [things][sc]. I
love outer space and astronomy; I will always get excited to look at the moon
with you, or check out anything through a telescope. I enjoy [photograhy][p],
mostly as a travel hobby. And I've been practicing iaido, a traditional Japanese
sword art, since early 2024. Other things I've been into include: bread baking,
other coding project][src]. I'm also a musician: I play piano, Irish tin
whistle, and modular synthesizer. Occasionally I [record things][sc] or offer
them [for sale][sc]. I love outer space and astronomy; I will always get excited
to look at the moon with you, or check out anything through a telescope. I enjoy
[photograhy][p], mostly as a travel hobby. And I've been practicing
[iaidō][mjer], a traditional Japanese sword art, at [Nishi Kaigan Iaidō
Dōjō][nkid] since early 2024. Other things I've been into include: bread baking,
bicycling, calligraphy, ceramics, and knitting.
[a]: https://apple.com
[Apple]: https://apple.com
[ab]: {{< ref "/about" >}}
[b]: {{< ref "/blog" >}}
[bc]: https://erynwells.bandcamp.com/releases
[cats]: {{< ref "/cats" >}}
[eml]: mailto:Eryn%20Wells<eryn@erynwells.me>
[gh]: https://github.com/erynofwales
[src]: https://source.erynwells.me/eryn
[ig]: https://www.instagram.com/erynofwales
[m]: https://mastodon.social/@erynofwales
[n]: {{< ref "/now" >}}
[ob]: https://www.oberlin.edu
[Oberlin College]: https://www.oberlin.edu
[p]: {{< ref "/photos" >}}
[pronouns]: http://pronoun.is/she
[r]: {{< ref "/resume" >}}
[sc]: https://soundcloud.com/purlsnbeeps
[where-am-i]: {{< ref "/about/where-am-i" >}}
[mjer]: https://en.wikipedia.org/wiki/Mus%C5%8D_Jikiden_Eishin-ry%C5%AB
[nkid]: https://iaido.org

View file

@ -0,0 +1,14 @@
---
title: "Thirty Eight"
date: 2026-01-14
draft: true
tags:
- Me
- Birthdays
---
I'm turning thirty eight today!
Neil Armstrong was 38 when he walked on the moon. (Buzz Aldrin was 39.) Jack
Swigert was 38 when he timed the 14 second burn that brought Apollo 13 back into
position for reentry to Earth.

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

View file

@ -0,0 +1,23 @@
---
title: "Harvest Moon"
date: 2025-10-06T22:00:00-07:00
tags:
- Space
- Astrophotography
- Moon
---
Monday October 6 was the full moon. As the closest full moon to the [autumnal
equinox][], it is the [Harvest Moon][]. It also happened to be a [supermoon][],
making it slightly bigger in the night sky.
I shot this photo from my back deck with my Fujifilm X-T5 and a Canon 100mm
macro prime[^1]. Amazingly, this is a handheld shot too. I couldn't find a
necessary bit of my tripod to mount the camera, so I made do.
[^1]: Photography nerds will notice these are _not_ compatible components; I use
a Fringer EF-FX mount adapter for this.
[autumnal equinox]: https://en.wikipedia.org/wiki/September_equinox
[Harvest Moon]: https://en.wikipedia.org/wiki/Full_moon#Harvest_moon
[supermoon]: https://science.nasa.gov/moon/supermoons/

View file

@ -0,0 +1,5 @@
---
title: Erin Anne O'Connor
linkTitle: EAOC
slug: eaoc
---

138
content/uses/index.tok.md Normal file
View file

@ -0,0 +1,138 @@
---
title: "mi kepeken e ni"
draft: true
toc: open
---
## Tech
### Hardware
[Apple M2 MacBook Air from 2022](https://www.apple.com/macbook-air-13-and-15-m2/)
: mi olin e ilo sona ni. tenpo pini la mi olin e ilo sona ante. ilo sona ante en
ilo sona ni li MacBook Air. tenpo ale la mi jo e ilo sona ante. kin la tenpo ale
la mi jo e ilo sona ni.
[Apple Studio Display](https://www.apple.com/studio-display/)
: I was on the fence about a Cinema Display for a long time. I ordered and
canceled three times. Ultimately I gave in, and I'm quite happy with it. It's
mounted on a VESA arm attached to my desktop.
### Software
#### Development
[Neovim](https://neovim.io/)
: tenpo suli la, mi kepeken e `vim`. ona li ilo nanpa wan pi pali lipu mi.
[Visual Studio Code](https://code.visualstudio.com/)
: tenpo sike mute la mi alasa e VSCode. ona li jo e ijo pona mute.
[Xcode](https://developer.apple.com/xcode/)
: mi pali lon [kulupu kili][apple]. Xcode li ilo pi pali lipu tawa. lon kulupu
kili la mi kepeken e Xcode. lon tomo mi, mi kepeken kin e Xcode. Xcode li pona.
[Fork](https://fork.dev)
: A GUI client for `git`. I think Fork has totally changed how I use `git`. I
still use the command line for many things, but working through diffs, staging
changes, and even rebasing is so much easier in a GUI.
#### Terminal
[Terminal.app](https://support.apple.com/guide/terminal/welcome/mac)
: macOS's built in terminal emulator is solid. The only thing I miss from it now
and then is "true color" support, and that's only when I try to install a new
color theme in Neovim and everything goes haywire.
[Zsh](https://www.zsh.org)
: I've been using Zsh since before it was cool. My shell config is full of
bespoke tweaks, including a prompt theme I'm rather proud of.
#### Hosting
[Digital Ocean](https://www.digitalocean.com)
: DO has hosted my VPS for a number of years. I moved there from Linode because
I wanted to run FreeBSD on my server.
[FreeBSD](https://www.freebsd.org)
: My server OS of choice. It's secure, simple, and resilient, and I appreciate
the less-encumbered BSD license.
[FastMail](https://www.fastmail.com/)
: I've used FastMail for years now as my email host. Their annual fees are quite
modest and they have a great feature set including a Sieve email filter editor,
and Masked Email for genearating ad hoc email addresses. I've never had a
problem with uptime, and the few times I've contacted support, they've been
helpful.
[Hugo](https://gohugo.io)
: This whole website is built with Hugo.
### Mobile
[Doppler](https://brushedtype.co/doppler/)
: File-based music player.
[Ivory](https://tapbots.com/ivory/)
: My Mastodon client of choice for macOS and iOS.
[Overcast](https://overcast.fm/podcasts)
: My podcast player of choice.
[Reeder](https://www.reederapp.com)
: RSS feed organizer and reader. I'm doing a lot more RSS these days.
[Transit](https://transitapp.com)
: Helps me stay on top of bus schedules in San Francisco.
## Music
[Logic Pro](https://www.apple.com/logic-pro/)
: Apple's DAW is full of features and plugins (far more than I could ever use)
and it's hard to beat the corporate discount, much as I also love Ableton.
[Shure SM7B](https://www.shure.com/en-US/products/microphones/sm7b)
: The SM7 is an iconic mic, and has been the go-to for voice actors, podcasters,
and musicians for 50 years. The excellent podcast Twenty Thousand Hertz did a
great [deep dive episode][20ksm7] on its history and place in the audio
industry. I have one on my desk at home, and it makes me sound great on work
video calls, and the occasional audio recording.
[Moog Matriarch](https://www.moogmusic.com/synthesizers?type=202)
: I'm a bit of a Moog fangirl, and this might be my favorite of their synths.
It's just hard to beat the sound of a Moog.
[Kawaii CA-65](https://kawaius.com/product/ca65/)
: I've been playing piano since I was seven years old. A digital piano is
perfect for the small apartments I've called home. This one has a fantastic
realistic action and it sounds great.
## Coffee
[Baratza Encore](https://www.baratza.com/product/encoretm-zcg485)
: It's affordable and does a pretty good job.
[Kalita Wave](https://kalitausa.com/products/kalita-wave-185-stainless-steel-coffee-dripper)
: The Kalita is probably the easist single serve pour over dripper I've used.
[Chemex](https://www.chemexcoffeemaker.com/six-cup-classic-series-coffeemaker.html)
: If I'm making coffee for more than just me, the Chemex is the biggest pour
over vessel I have. Makes yummy coffee too.
## Gaming
[Nintendo Switch](https://www.nintendo.com/us/switch/)
: Most of my gaming happens here. I play a lot of Mario Kart online with
friends, and I'm a big fan of both of the major Legend of Zelda titles that have
come out for it: Breath of the Wild and Tears of the Kingdom.
[PlayStation 5](https://www.playstation.com/en-us/ps5/)
: I also have a PS5. I've played a ton of Horizon: Zero Dawn and the new Final
Fantasy 7 games.
[Analogue Pocket](https://www.analogue.co/pocket)
: When I want to play my stock of Game Boy games, this thing is great.
[apple]: https://www.apple.com
[vscode-vim]: https://marketplace.visualstudio.com/items?itemName=vscodevim.vim
[20ksm7]: https://www.20k.org/episodes/sm7

View file

@ -1,14 +0,0 @@
#!/usr/bin/env zsh
# Deploy erynwells.me to my web root
# Eryn Wells <eryn@erynwells.me>
print -P "%BFiltering .DS_Store files%b"
find . -name '.DS_Store' -print -delete
print -P "%BGenerating site%b"
hugo
echo
print -P "%BRsyncing site to nutmeg.erynwells.me%b"
rsync -avz --no-times --no-perms --delete public/ \
eryn@nutmeg.erynwells.me:/srv/www/erynwells.me/html

View file

@ -1 +1 @@
<abbr title="{{ .Get 0 }}">{{ .Inner }}</abbr>
<abbr title="{{ .Get 0 }}">{{ .Inner }}</abbr>{{- "" -}}

View file

@ -4,16 +4,33 @@
import os.path as osp
def root_dir() -> str:
'''Return the path to the root of the repository.'''
return osp.normpath(osp.join(osp.dirname(__file__), '..', '..'))
def assets_path() -> str:
'''Return the path to the assets directory.'''
path = osp.join(root_dir(), 'assets')
return path
def content_path() -> str:
'''Return the path to the content directory.'''
path = osp.abspath(osp.join(osp.dirname(__file__), '..', '..', 'content'))
assert osp.isdir(path)
path = osp.join(root_dir(), 'content')
return path
def blog_path() -> str:
'''Return the path to the blog content directory.'''
return osp.join(content_path(), 'blog')
def photos_path() -> str:
'''Return the path to the photos content directory.'''
return osp.join(content_path(), 'photos')
content_dir = content_path
blog_dir = blog_path
photos_dir = photos_path

View file

@ -12,7 +12,7 @@ from .scripting import Command
class WeeknotesCommand(Command):
@staticmethod
def weeknotes_filename(year: str, week: str) -> str:
def weeknotes_filename(year: str | int, week: str | int) -> str:
return f'weeknotes-{year}w{week}.md'
@staticmethod
@ -26,7 +26,7 @@ class WeeknotesCommand(Command):
week_number_str = next_sunday.strftime('%V')
return blog.post_path(WeeknotesCommand.weeknotes_filename(
str(year),
year,
week_number_str
))

View file

@ -14,12 +14,23 @@ from erynwells_me.metadata import slugify
from erynwells_me.paths import photos_path
def date_argument(value: str) -> datetime.datetime:
parsed_date = datetime.datetime.fromisoformat(value)
if not parsed_date.tzinfo:
local_timezone = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
parsed_date = datetime.datetime.combine(parsed_date.date(), parsed_date.time(), local_timezone)
return parsed_date
def parse_args(argv, *a, **kw):
parser = argparse.ArgumentParser(*a, **kw)
parser.add_argument('-e', '--edit', action='store_true')
parser.add_argument('-n', '--dry-run', action='store_true')
parser.add_argument('-t', '--title')
parser.add_argument('-s', '--slug')
parser.add_argument('-d', '--date', type=date_argument)
parser.add_argument('--dump-exif', action='store_true')
parser.add_argument('photos', nargs='+')
args = parser.parse_args(argv)
@ -29,7 +40,7 @@ def parse_args(argv, *a, **kw):
def main(argv):
args = parse_args(argv[1:], prog=argv[0])
earliest_exif_date: Optional[datetime.datetime] = None
post_date: Optional[datetime.datetime] = args.date
for index, photo in enumerate(args.photos):
print(f'image\t\t{photo}')
@ -40,14 +51,20 @@ def main(argv):
continue
raw_exif = image._getexif()
friendly_exif = {TAGS[k]: v for k, v in raw_exif.items() if k in TAGS}
friendly_exif = {}
if raw_exif:
friendly_exif = {TAGS[k]: v for k, v in raw_exif.items() if k in TAGS}
try:
date_string = f'{friendly_exif["DateTime"]} {friendly_exif["OffsetTime"]}'
exif_date = datetime.datetime.strptime(date_string, '%Y:%m:%d %H:%M:%S %z')
except KeyError:
exif_date = datetime.datetime.strptime(friendly_exif["DateTime"], '%Y:%m:%d %H:%M:%S')
print(f'capture-time\t{exif_date.isoformat()}')
photo_date = None
if not args.date:
try:
date_string = f'{friendly_exif["DateTime"]} {friendly_exif["OffsetTime"]}'
photo_date = datetime.datetime.strptime(date_string, '%Y:%m:%d %H:%M:%S %z')
except KeyError:
photo_date = datetime.datetime.strptime(friendly_exif["DateTime"], '%Y:%m:%d %H:%M:%S')
else:
photo_date = args.date
print(f'capture-time\t{photo_date.isoformat()}')
iso_rating = friendly_exif.get('ISOSpeedRatings')
if iso_rating:
@ -66,23 +83,24 @@ def main(argv):
if exposure_time:
print(f'exposure-time\t{exposure_time}')
if not earliest_exif_date or exif_date < earliest_exif_date:
earliest_exif_date = exif_date
if not post_date or photo_date < post_date:
post_date = photo_date
if index < len(args.photos) - 1:
print()
if not earliest_exif_date:
earliest_exif_date = datetime.datetime.now()
if not post_date:
post_date = datetime.datetime.now()
year = earliest_exif_date.year
month = earliest_exif_date.month
year = post_date.year
month = post_date.month
if args.slug:
name = args.slug
elif args.title:
name = slugify(args.title)
else:
photo = args.photos[0]
name = osp.splitext(osp.basename(photo))[0]
post_path_year = os.path.join(photos_path(), f'{year:04}', name)
@ -100,7 +118,7 @@ def main(argv):
post_path = post_path_year
try:
hugo_command = ['hugo', 'new', '--clock', earliest_exif_date.isoformat(), post_path]
hugo_command = ['hugo', 'new', '--clock', post_date.isoformat(), post_path]
if not args.dry_run:
result = subprocess.run(hugo_command)
result.check_returncode()

View file

@ -6,6 +6,8 @@ A Python interface to my personal website, Erynwells.me.
'''
import argparse
import os
import os.path as osp
from typing import List
from erynwells_me.scripting import Command
from erynwells_me.weeknotes import WeeknotesCommand
@ -31,7 +33,14 @@ def parse_args(commands: List[Command], argv, *a, **kw):
def main(argv):
args = parse_args(COMMANDS, argv[1:], prog=argv[0])
program_name = osp.basename(argv[0])
args = parse_args(COMMANDS, argv[1:], prog=program_name)
scripts_dir = osp.dirname(__file__)
repo_root_dir = osp.normpath(osp.join(scripts_dir, '..'))
if os.getcwd() != repo_root_dir:
os.chdir(repo_root_dir)
return args.handler(args)