fix(og): match plain URL slugs; fix Funkwhale GC wipe
Build & Deploy / build-and-deploy (push) Successful in 1m19s

og-fix transform was matching date-based URL segments
(/type/yyyy/MM/dd/slug/) that this site never uses — posts live at
/type/slug/. Every post therefore fell through to the default OG image.

Fixed by updating the regex to /type/slug/index.html and deriving the OG
slug as the bare last URL segment, which matches the filename og.js
already generates. The ogSlug filter is simplified accordingly.

Funkwhale GC bug: gcFunkwhaleImages() deleted the entire image cache
whenever _activeFilenames was empty — which happens if the API returns
valid stats but no listenings with cover URLs. Guard added: GC is
skipped when no images were referenced this build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
svemagie
2026-03-31 14:04:34 +02:00
parent b50006245d
commit 219c18138c
3 changed files with 16 additions and 18 deletions
+10 -17
View File
@@ -403,19 +403,18 @@ export default function (eleventyConfig) {
if (!outputPath || !outputPath.endsWith(".html")) return content;
// Derive correct page URL and OG slug from outputPath (immune to race condition)
// Content pages match: .../type/yyyy/MM/dd/slug/index.html
const dateMatch = outputPath.match(
/\/([\w-]+)\/(\d{4})\/(\d{2})\/(\d{2})\/([\w-]+)\/index\.html$/
// Content pages match: .../type/slug/index.html (plain URLs, no date segments)
const postMatch = outputPath.match(
/\/([\w-]+)\/([\w-]+)\/index\.html$/
);
if (dateMatch) {
const [, type, year, month, day, slug] = dateMatch;
const pageUrlPath = `/${type}/${year}/${month}/${day}/${slug}/`;
if (postMatch) {
const [, type, slug] = postMatch;
const pageUrlPath = `/${type}/${slug}/`;
const correctFullUrl = `${siteUrl}${pageUrlPath}`;
const ogSlug = `${year}-${month}-${day}-${slug}`;
const hasOg = hasOgImage(ogSlug);
const hasOg = hasOgImage(slug);
const ogImageUrl = hasOg
? `${siteUrl}/og/${ogSlug}.png`
? `${siteUrl}/og/${slug}.png`
: `${siteUrl}/images/og-default.png`;
const twitterCard = hasOg ? "summary_large_image" : "summary";
@@ -433,7 +432,7 @@ export default function (eleventyConfig) {
content = content.replace(/__OG_IMAGE_PLACEHOLDER__/g, ogImageUrl);
content = content.replace(/__TWITTER_CARD_PLACEHOLDER__/g, twitterCard);
} else {
// Non-date pages (homepage, about, etc.): use defaults
// Non-post pages (homepage, archives, etc.): use defaults
content = content.replace(
/__OG_IMAGE_PLACEHOLDER__/g,
`${siteUrl}/images/og-default.png`
@@ -916,16 +915,10 @@ export default function (eleventyConfig) {
// Derive OG slug from page.url (reliable) instead of page.fileSlug
// (which suffers from Nunjucks race conditions in Eleventy 3.x parallel rendering).
// OG images are named with the full date prefix to match URL segments exactly.
// URLs are plain (/type/slug/), so the slug is the last path segment.
eleventyConfig.addFilter("ogSlug", (url) => {
if (!url) return "";
const segments = url.split("/").filter(Boolean);
// Date-based URL: /type/yyyy/MM/dd/slug/ → 5 segments → "yyyy-MM-dd-slug"
if (segments.length === 5) {
const [, year, month, day, slug] = segments;
return `${year}-${month}-${day}-${slug}`;
}
// Fallback: last segment (for pages, legacy URLs)
return segments[segments.length - 1] || "";
});
+4
View File
@@ -76,6 +76,10 @@ export async function cacheFunkwhaleImage(url) {
*/
export function gcFunkwhaleImages() {
if (!existsSync(CACHE_DIR)) return;
// If no images were referenced this build, skip GC — likely the API returned no
// cover URLs (empty listenings, null covers, or stats-only response). Deleting
// everything from an empty _activeFilenames set would wipe a valid cache.
if (_activeFilenames.size === 0) return;
let deleted = 0;
for (const file of readdirSync(CACHE_DIR)) {
if (!_activeFilenames.has(file)) {
+2 -1
View File
@@ -126,7 +126,8 @@ function formatDate(dateStr) {
}
/**
* Use the full filename (with date prefix) as the OG image slug.
* Use the filename (without extension) as the OG image slug.
* Matches the last URL path segment, which Eleventy derives from the filename.
*/
function toOgSlug(filename) {
return filename;