package post import ( "os" "path/filepath" "sort" "strings" "time" "go.jolheiser.com/blog/markdown" "github.com/rs/zerolog/log" ) func NewBlog(basePath string) (*Blog, error) { posts, err := Scan(basePath) if err != nil { return nil, err } return &Blog{ Path: basePath, Posts: posts, }, nil } func Scan(basePath string) (map[string]*Post, error) { posts := make(map[string]*Post) ents, err := os.ReadDir(basePath) if err != nil { return nil, err } for _, ent := range ents { var apn string if ent.IsDir() { apn = filepath.Join(basePath, ent.Name(), "index.md") if _, err := os.Stat(apn); err != nil { log.Error().Err(err).Msgf("could not parse %s", ent.Name()) continue } } else { if !strings.HasSuffix(ent.Name(), ".md") { continue } apn = filepath.Join(basePath, ent.Name()) } fi, err := os.Open(apn) if err != nil { log.Error().Err(err).Msg("could not open file") continue } post := &Post{Path: apn, Slug: strings.TrimSuffix(ent.Name(), ".md")} if err := markdown.Meta(fi, &post); err != nil { log.Error().Err(err).Msg("could not extract meta") continue } posts[post.Slug] = post if err := fi.Close(); err != nil { log.Error().Err(err).Msg("could not close file") continue } } return posts, nil } type Blog struct { Path string Posts map[string]*Post } func (b *Blog) SortedPosts() []*Post { posts := make([]*Post, 0, len(b.Posts)) for _, post := range b.Posts { posts = append(posts, post) } sort.Slice(posts, func(i, j int) bool { return posts[i].Date.After(posts[j].Date) }) return posts } type Post struct { Path string `toml:"-"` Slug string `toml:"-"` Title string `toml:"title"` Author string `toml:"author"` Date time.Time `toml:"date"` Tags []string `toml:"tags"` }