diff --git a/metal/cli/seo/generator.go b/metal/cli/seo/generator.go index 42f17ca0..5129f0ad 100644 --- a/metal/cli/seo/generator.go +++ b/metal/cli/seo/generator.go @@ -294,6 +294,8 @@ func (g *Generator) GeneratePosts() error { for _, post := range posts { cli.Cyanln(fmt.Sprintf("Building SEO for post: %s", post.Slug)) response := payload.GetPostsResponse(post) + cli.Grayln(fmt.Sprintf("Post slug: %s", response.Slug)) + cli.Grayln(fmt.Sprintf("Post title: %s", response.Title)) body := []template.HTML{sections.Post(&response)} data, buildErr := g.BuildForPost(response, body) @@ -457,6 +459,22 @@ func (g *Generator) TitleFor(pageName string) string { return fmt.Sprintf("%s ยท %s", pageName, g.Page.SiteName) } +func truncateForLog(value string) string { + const maxRunes = 80 + + cleaned := strings.TrimSpace(value) + if cleaned == "" { + return "(empty)" + } + + if utf8.RuneCountInString(cleaned) <= maxRunes { + return cleaned + } + + runes := []rune(cleaned) + return string(runes[:maxRunes-3]) + "..." +} + func (g *Generator) BuildForPost(post payload.PostResponse, body []template.HTML) (TemplateData, error) { path := g.CanonicalPostPath(post.Slug) imageAlt := g.SanitizeAltText(post.Title, g.Page.SiteName) @@ -464,11 +482,19 @@ func (g *Generator) BuildForPost(post payload.PostResponse, body []template.HTML image := g.PreferredImageURL(post.CoverImageURL, g.Page.AboutPhotoUrl) imageType := "image/png" + cli.Grayln(fmt.Sprintf("Preparing post metadata")) + cli.Grayln(fmt.Sprintf(" Canonical path: %s", path)) + cli.Grayln(fmt.Sprintf(" Sanitised alt text: %s", imageAlt)) + cli.Grayln(fmt.Sprintf(" Description preview: %s", truncateForLog(description))) + cli.Grayln(fmt.Sprintf(" Preferred image candidate: %s", image)) + if prepared, err := g.preparePostImage(post); err == nil && prepared.URL != "" { + cli.Grayln(fmt.Sprintf(" Post image prepared at: %s (%s)", prepared.URL, prepared.Mime)) image = prepared.URL imageType = prepared.Mime } else if err != nil { cli.Errorln(fmt.Sprintf("failed to prepare post image for %s: %v", post.Slug, err)) + cli.Grayln(fmt.Sprintf(" Falling back to preferred image URL: %s", image)) } return g.buildForPage(post.Title, path, body, func(data *TemplateData) { diff --git a/metal/cli/seo/pictures.go b/metal/cli/seo/pictures.go index 0ce6c37f..6ba012be 100644 --- a/metal/cli/seo/pictures.go +++ b/metal/cli/seo/pictures.go @@ -27,11 +27,15 @@ const ( func (g *Generator) preparePostImage(post payload.PostResponse) (preparedImage, error) { source := strings.TrimSpace(post.CoverImageURL) if source == "" { + cli.Grayln(fmt.Sprintf("Skipping image preparation for %s: no cover image", post.Slug)) return preparedImage{}, errors.New("post has no cover image url") } + cli.Grayln(fmt.Sprintf("Preparing post image for %s from %s", post.Slug, source)) + spaImagesDir, err := g.spaImagesDir() if err != nil { + cli.Errorln(fmt.Sprintf("Could not determine SPA images directory: %v", err)) return preparedImage{}, err } @@ -48,22 +52,29 @@ func (g *Generator) preparePostImage(post payload.PostResponse) (preparedImage, return preparedImage{}, err } + bounds := img.Bounds() + cli.Grayln(fmt.Sprintf("Fetched image %s (%s) with bounds %dx%d", source, format, bounds.Dx(), bounds.Dy())) + resized := pkgimages.Resize(img, seoImageWidth, seoImageHeight) + cli.Grayln(fmt.Sprintf("Resized image to %dx%d", seoImageWidth, seoImageHeight)) ext := pkgimages.DetermineExtension(source, format) fileName := pkgimages.BuildFileName(post.Slug, ext, "post-image") if err := os.MkdirAll(spaImagesDir, 0o755); err != nil { + cli.Errorln(fmt.Sprintf("Unable to create SPA images directory %s: %v", spaImagesDir, err)) return preparedImage{}, fmt.Errorf("create destination dir: %w", err) } destPath := filepath.Join(spaImagesDir, fileName) if err := pkgimages.Save(destPath, resized, ext, pkgimages.DefaultJPEGQuality); err != nil { + cli.Errorln(fmt.Sprintf("Unable to save resized image to %s: %v", destPath, err)) return preparedImage{}, fmt.Errorf("write resized image: %w", err) } relativeDir, err := filepath.Rel(g.Page.OutputDir, spaImagesDir) if err != nil { + cli.Errorln(fmt.Sprintf("Unable to determine relative path for %s: %v", spaImagesDir, err)) return preparedImage{}, fmt.Errorf("determine relative image path: %w", err) } @@ -73,6 +84,8 @@ func (g *Generator) preparePostImage(post payload.PostResponse) (preparedImage, relative := path.Join(relativeDir, fileName) relative = pkgimages.NormalizeRelativeURL(relative) + cli.Grayln(fmt.Sprintf("Post image relative path: %s", relative)) + return preparedImage{ URL: g.siteURLFor(relative), Mime: pkgimages.MIMEFromExtension(ext),