From c9c322ff9512eb1c1b8447176c115db3f3bf1ac5 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Sat, 14 Mar 2026 11:17:49 +0100 Subject: [PATCH] Fix duplicate blog entries and image paths - Add deduplication logic to avoid showing same blog twice - Add extractBlogID function to get correct numeric ID from meta tags - Use blogID for image paths instead of filename ID - This fixes duplicate entries in admin interface and broken images --- backend/main.go | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/backend/main.go b/backend/main.go index 6172764..6ff96ec 100644 --- a/backend/main.go +++ b/backend/main.go @@ -554,6 +554,22 @@ func extractSlug(path, filename string) string { return strings.TrimSuffix(filename, ".html") } +func extractBlogID(path, filename string) string { + b, err := os.ReadFile(path) + if err != nil { + return strings.TrimSuffix(filename, ".html") + } + s := string(b) + // Try to find ID in meta tag first + re := regexp.MustCompile(`(?is)= 2 { + return m[1] + } + // Fallback: use filename without extension + return strings.TrimSuffix(filename, ".html") +} + func listLatestBlogs(siteRoot string, limit int) ([]BlogItem, error) { // Use the siteRoot path where blogs are actually located blogDir := filepath.Join(siteRoot, "blog") @@ -576,24 +592,35 @@ func listLatestBlogs(siteRoot string, limit int) ([]BlogItem, error) { // Match both numeric (0001.html) and slug-based filenames re := regexp.MustCompile(`^(\d{4}|[a-z0-9-]+)\.html$`) var items []BlogItem + seenIDs := make(map[string]bool) // Track seen IDs to avoid duplicates for _, e := range entries { name := e.Name() if !re.MatchString(name) { continue } id := strings.TrimSuffix(name, ".html") + + // Skip if this ID was already processed (deduplication) + if seenIDs[id] { + continue + } + // Title and categories extraction from blog HTML blogPath := filepath.Join(blogDir, name) title := extractTitle(blogPath) slug := extractSlug(blogPath, name) cats := extractCategories(blogPath) + blogID := extractBlogID(blogPath, name) + + // Mark this ID as seen + seenIDs[id] = true // Determine mod time - prefer image modtime if exists, else html mtime := time.Time{} htmlInfo, err1 := os.Stat(filepath.Join(blogDir, name)) if err1 == nil { mtime = htmlInfo.ModTime() } - if imgInfo, err2 := os.Stat(filepath.Join(imgDir, id+".png")); err2 == nil { + if imgInfo, err2 := os.Stat(filepath.Join(imgDir, blogID+".png")); err2 == nil { // If image is newer, use that as a proxy for recency if imgInfo.ModTime().After(mtime) { mtime = imgInfo.ModTime() @@ -611,7 +638,7 @@ func listLatestBlogs(siteRoot string, limit int) ([]BlogItem, error) { Title: title, Slug: slug, Link: link, - Image: "/img/blog/" + id + ".png", + Image: "/img/blog/" + blogID + ".png", MTime: mtime, Categories: cats, })