diff --git a/app/src/content.go b/app/src/content.go index f0a910a..def0ca8 100644 --- a/app/src/content.go +++ b/app/src/content.go @@ -443,4 +443,37 @@ func firstSubjects(s []*Subject, n int) []*Subject { return s[:n] } return s -} \ No newline at end of file +} +// resolveMediaPath maps a media reference like "chinese-chips/aboutme.jpeg" to an +// existing file under the content root. The reference is relative to the article +// folder, which sits under subjects/// — so search each subject's +// article folders for the first segment. Returns "" if not found. +func (c *Content) resolveMediaPath(root, name string) string { + // fast path: exact repo-relative path + if data, err := os.ReadFile(path.Join(root, name)); err == nil { + _ = data + return path.Join(root, name) + } + // search: first path element = folder under any subject + i := strings.IndexByte(name, '/') + if i < 0 { + return "" + } + folder := name[:i] + rest := name[i+1:] + subjDir := path.Join(root, "subjects") + if entries, err := os.ReadDir(subjDir); err == nil { + for _, e := range entries { + if !e.IsDir() { + continue + } + candidate := path.Join(subjDir, e.Name(), folder, rest) + if data2, err2 := os.ReadFile(candidate); err2 == nil { + _ = data2 + return candidate + } + } + } + return "" +} + diff --git a/app/src/server.go b/app/src/server.go index 8e74829..5abc143 100644 --- a/app/src/server.go +++ b/app/src/server.go @@ -27,7 +27,11 @@ func (s *Site) media(w http.ResponseWriter, r *http.Request, name string) { http.Error(w, "bad media path", http.StatusBadRequest) return } - full := path.Join(root, name) + full := s.Content.resolveMediaPath(root, name) + if full == "" { + http.Error(w, "media not found", http.StatusNotFound) + return + } data, err := os.ReadFile(full) if err != nil { http.Error(w, "media not found", http.StatusNotFound)