Compare commits

..

8 Commits

Author SHA1 Message Date
David Eisinger
63467ce25f Gitea links in footer + Gemini
All checks were successful
Deploy / deploy (push) Successful in 12m15s
2026-04-16 23:42:29 -04:00
David Eisinger
a65638b1f3 Add cspell to Gitea Action
All checks were successful
Deploy / deploy (push) Successful in 3m17s
2026-04-15 01:01:18 -04:00
David Eisinger
816ae727f3 Fix Gemini photos w/ captions
All checks were successful
Deploy / deploy (push) Successful in 1m29s
2026-04-15 00:28:07 -04:00
David Eisinger
296ce3c0e6 Punctuation fix
All checks were successful
Deploy / deploy (push) Successful in 1m25s
2026-04-13 09:36:29 -04:00
David Eisinger
c41e908ed5 Fix cache key error
All checks were successful
Deploy / deploy (push) Successful in 1m33s
2026-04-09 00:26:36 -04:00
David Eisinger
a0a120b31e Cache dither results
Some checks failed
Deploy / deploy (push) Has been cancelled
2026-04-08 23:54:20 -04:00
David Eisinger
7b769b3e1f Revert README change
Some checks failed
Deploy / deploy (push) Has been cancelled
2026-04-08 23:47:58 -04:00
David Eisinger
778cae07b9 Make dither server more efficient
All checks were successful
Deploy / deploy (push) Successful in 9m4s
2026-04-08 23:02:20 -04:00
10 changed files with 101 additions and 45 deletions

View File

@@ -9,6 +9,7 @@ on:
env: env:
HUGO_VERSION: 0.160.1 HUGO_VERSION: 0.160.1
DEPLOY_DIR: /var/www/davideisinger.com DEPLOY_DIR: /var/www/davideisinger.com
DITHER_CACHE_DIR: /workspace-cache/dither
jobs: jobs:
deploy: deploy:
@@ -18,6 +19,11 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install packages - name: Install packages
run: | run: |
apt-get update apt-get update
@@ -35,6 +41,9 @@ jobs:
- name: Verify RSS template diff - name: Verify RSS template diff
run: ./bin/check-rss-template run: ./bin/check-rss-template
- name: Spellcheck Markdown
run: npx -y cspell "content/**/*.md"
- name: Build site - name: Build site
run: ./bin/build run: ./bin/build

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.hugo_build.lock .hugo_build.lock
.cache
public public
resources/_gen resources/_gen
secret.key secret.key

View File

@@ -2,18 +2,6 @@
[1]: https://davideisinger.com [1]: https://davideisinger.com
## Deployment
SourceHut still uses [`.build.yml`](/Users/dce/code/davideisinger.com/.build.yml).
Gitea uses [`.gitea/workflows/deploy.yaml`](/Users/dce/code/davideisinger.com/.gitea/workflows/deploy.yaml), which mirrors the same build steps and deploys directly into `/var/www/davideisinger.com`.
For that workflow to succeed, the Gitea runner needs:
- a `SECRET_KEY` Actions secret containing the contents of `secret.key`
- write access to `/var/www/davideisinger.com`
- that path mounted into the job environment if the runner is containerized
--- ---
© [CC BY 4.0 License][2] © [CC BY 4.0 License][2]

View File

@@ -3,10 +3,13 @@ set -euo pipefail
repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
dither_dir="${repo_root}/bin/dither" dither_dir="${repo_root}/bin/dither"
cache_dir="${DITHER_CACHE_DIR:-${repo_root}/.cache/dither}"
mkdir -p "${cache_dir}"
pushd "${dither_dir}" >/dev/null pushd "${dither_dir}" >/dev/null
bundle install bundle install
ROOT="${repo_root}/content" KEY="${repo_root}/secret.key" bundle exec rackup -p 4567 & ROOT="${repo_root}/content" KEY="${repo_root}/secret.key" DITHER_CACHE_DIR="${cache_dir}" bundle exec rackup -p 4567 &
dither_pid=$! dither_pid=$!
popd >/dev/null popd >/dev/null

View File

@@ -1,5 +1,8 @@
require "sinatra" require "sinatra"
require "mini_magick" require "mini_magick"
require "digest"
require "fileutils"
require "tempfile"
MiniMagick.logger.level = Logger::DEBUG MiniMagick.logger.level = Logger::DEBUG
@@ -7,6 +10,24 @@ ROOT = ENV.fetch("ROOT")
KEY = ENV.fetch("KEY") KEY = ENV.fetch("KEY")
DITHER = ENV["DITHER"] != "0" DITHER = ENV["DITHER"] != "0"
FORMAT = "png" FORMAT = "png"
CACHE_DIR = ENV["DITHER_CACHE_DIR"]
def cache_path_for(path, geometry)
return unless CACHE_DIR
source_path = "#{ROOT}/#{path}.enc"
cache_key = Digest::SHA256.hexdigest([
path,
Digest::SHA256.file(source_path).hexdigest,
geometry,
DITHER,
FORMAT,
1
].join("\0"))
FileUtils.mkdir_p(CACHE_DIR)
File.join(CACHE_DIR, "#{cache_key}.#{FORMAT}")
end
get "/*" do |path| get "/*" do |path|
halt 404, {"Content-Type" => "text/plain"}, "not found" unless File.exist?("#{ROOT}/#{path}.enc") halt 404, {"Content-Type" => "text/plain"}, "not found" unless File.exist?("#{ROOT}/#{path}.enc")
@@ -16,37 +37,63 @@ get "/*" do |path|
geometry = params["geo"] unless params["geo"] == "" geometry = params["geo"] unless params["geo"] == ""
geometry.gsub!(/\d+/) { |n| n.to_i * 2 } if geometry && !DITHER geometry.gsub!(/\d+/) { |n| n.to_i * 2 } if geometry && !DITHER
decrypted = %x( cached_path = cache_path_for(path, geometry)
openssl \ if cached_path && File.exist?(cached_path)
aes-256-cbc \ return File.binread(cached_path)
-d \ end
-in #{ROOT}/#{path}.enc \
-pass file:#{KEY} \
-iter 1000000
)
convert = MiniMagick::Tool::Convert.new decrypted = Tempfile.new(["dither", File.extname(path)])
convert.stdin decrypted.binmode
convert.background("white") decrypted.close
convert.layers("flatten")
convert.strip
convert.auto_orient
if geometry begin
if geometry.match?(/^\d+x\d+$/) openssl_ok = system(
convert.resize "#{geometry}^" "openssl",
convert.gravity "center" "aes-256-cbc",
convert.extent geometry "-d",
else "-in", "#{ROOT}/#{path}.enc",
convert.resize geometry "-out", decrypted.path,
"-pass", "file:#{KEY}",
"-iter", "1000000"
)
halt 500, {"Content-Type" => "text/plain"}, "decrypt failed" unless openssl_ok
convert = MiniMagick::Tool::Convert.new
convert.limit("memory", "128MiB")
convert.limit("map", "256MiB")
convert.limit("disk", "1GiB")
convert << decrypted.path
convert.background("white")
convert.layers("flatten")
convert.strip
convert.auto_orient
if geometry
if geometry.match?(/^\d+x\d+$/)
convert.resize "#{geometry}^"
convert.gravity "center"
convert.extent geometry
else
convert.resize geometry
end
end end
end
if DITHER if DITHER
convert.ordered_dither "o8x8" convert.ordered_dither "o8x8"
convert.monochrome convert.monochrome
end end
convert << "#{FORMAT.upcase}:-" convert << "#{FORMAT.upcase}:-"
convert.call(stdin: decrypted) output = convert.call
if cached_path
temp_cache_path = "#{cached_path}.tmp-#{Process.pid}"
File.binwrite(temp_cache_path, output)
FileUtils.mv(temp_cache_path, cached_path)
end
output
ensure
decrypted.unlink
end
end end

View File

@@ -3,9 +3,12 @@ set -euo pipefail
repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
dither_dir="${repo_root}/bin/dither" dither_dir="${repo_root}/bin/dither"
cache_dir="${DITHER_CACHE_DIR:-${repo_root}/.cache/dither}"
mkdir -p "${cache_dir}"
pushd "${dither_dir}" >/dev/null pushd "${dither_dir}" >/dev/null
ROOT="${repo_root}/content" KEY="${repo_root}/secret.key" bundle exec ruby dither.rb & ROOT="${repo_root}/content" KEY="${repo_root}/secret.key" DITHER_CACHE_DIR="${cache_dir}" bundle exec ruby dither.rb &
dither_pid=$! dither_pid=$!
popd >/dev/null popd >/dev/null

View File

@@ -53,7 +53,7 @@ Finally warming up around here (though we did get hit by the [largest 24-hour te
{{<dither IMG_0004.jpeg "782x600">}}Face-first into the color chaos.{{</dither>}} {{<dither IMG_0004.jpeg "782x600">}}Face-first into the color chaos.{{</dither>}}
{{<dither IMG_0009.jpeg "782x600">}}Blue faces, red popsicles, and the kind of chaos that means the afternoon went well.{{</dither>}} {{<dither IMG_0009.jpeg "782x600">}}Blue faces, red popsicles, and the kind of chaos that means the afternoon went well.{{</dither>}}
Then we drove up to DC, left the kids with my folks, and took the train to Baltimore to catch [my friend's][3] show and spend a little bit of time in the city. We stayed at the [Pendry][4] which was super nice -- we'll be back. Sold the old car while were up there -- 🪦 legend. Then we drove up to DC, left the kids with my folks, and took the train to Baltimore to catch [my friend's][3] show and spend a little bit of time in the city. We stayed at the [Pendry][4] which was super nice. We'll be back. Sold the old car while were up there -- 🪦 legend.
[3]: https://www.instagram.com/__carillon/ [3]: https://www.instagram.com/__carillon/
[4]: https://www.pendry.com/baltimore/ [4]: https://www.pendry.com/baltimore/

View File

@@ -8,7 +8,7 @@
Rendered {{ now | dateFormat "2006-01-02 15:04:05 MST" }} Rendered {{ now | dateFormat "2006-01-02 15:04:05 MST" }}
{{- with site.Params.git.commit }} {{- with site.Params.git.commit }}
=> https://git.sr.ht/~dce/davideisinger.com/commit/{{ . }} {{ . }} => https://git.davideisinger.com/dce/davideisinger.com/commit/{{ . }} {{ . }}
{{ end -}} {{ end -}}
=> https://creativecommons.org/licenses/by/4.0/deed.en © CC BY 4.0 => https://creativecommons.org/licenses/by/4.0/deed.en © CC BY 4.0

View File

@@ -12,7 +12,7 @@
<div class="mobile-hidden"> <div class="mobile-hidden">
Rendered {{ now | dateFormat "2006-01-02 15:04:05 MST" }} Rendered {{ now | dateFormat "2006-01-02 15:04:05 MST" }}
{{ with site.Params.git.commit }} {{ with site.Params.git.commit }}
<a href="https://git.sr.ht/~dce/davideisinger.com/commit/{{ . }}">{{ substr . 0 7}}</a> <a href="https://git.davideisinger.com/dce/davideisinger.com/commit/{{ . }}">{{ substr . 0 7}}</a>
{{ end }} {{ end }}
</div> </div>

View File

@@ -39,6 +39,11 @@
{{- end -}} {{- end -}}
{{- /* Photo processing */ -}} {{- /* Photo processing */ -}}
{{- range findRE `(?s){{<dither[^>]*>}}.*?{{</dither>}}` $content -}}
{{- $rendered := $page.RenderString . -}}
{{- $url := $rendered | replaceRE `(?s).*src="([^"]+)".*` "=> $1" -}}
{{- $content = replace $content . $url -}}
{{- end -}}
{{- range findRE `{{<(dither|thumbnail) [^/]+/>}}` $content -}} {{- range findRE `{{<(dither|thumbnail) [^/]+/>}}` $content -}}
{{- $rendered := $page.RenderString . -}} {{- $rendered := $page.RenderString . -}}
{{- $url := $rendered | replaceRE `(?s).*src="([^"]+)".*` "=> $1" -}} {{- $url := $rendered | replaceRE `(?s).*src="([^"]+)".*` "=> $1" -}}