package blog import ( "html/template" "io/ioutil" "os" "path/filepath" "sort" "strings" "time" "christine.website/cmd/site/internal/front" "github.com/russross/blackfriday" ) // Post is a single blogpost. type Post struct { Title string `json:"title"` Link string `json:"link"` Summary string `json:"summary,omitifempty"` Body string `json:"body_markdown"` BodyHTML template.HTML `json:"body,omitempty"` Series string `json:"series,omitempty"` Tags []string `json:"tags,omitempty"` SlidesLink string `json:"slides_link,omitempty"` ImageURL string `json:"image_url,omitempty"` ThumbURL string `json:"thumb_url,omitempty"` Date time.Time DateString string `json:"date"` } // Posts implements sort.Interface for a slice of Post objects. type Posts []Post func (p Posts) Series() []string { names := map[string]struct{}{} for _, ps := range p { if ps.Series != "" { names[ps.Series] = struct{}{} } } var result []string for name := range names { result = append(result, name) } return result } func (p Posts) Len() int { return len(p) } func (p Posts) Less(i, j int) bool { iDate := p[i].Date jDate := p[j].Date return iDate.Unix() < jDate.Unix() } func (p Posts) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // LoadPosts loads posts for a given directory. func LoadPosts(path string, prepend string) (Posts, error) { type postFM struct { Title string Date string Series string Tags []string SlidesLink string `yaml:"slides_link"` Image string Thumb string } var result Posts err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } fin, err := os.Open(path) if err != nil { return err } defer fin.Close() content, err := ioutil.ReadAll(fin) if err != nil { return err } var fm postFM remaining, err := front.Unmarshal(content, &fm) if err != nil { return err } output := blackfriday.Run(remaining) const timeFormat = `2006-01-02` date, err := time.Parse(timeFormat, fm.Date) if err != nil { return err } fname := filepath.Base(path) fname = strings.TrimSuffix(fname, filepath.Ext(fname)) p := Post{ Title: fm.Title, Date: date, DateString: fm.Date, Link: filepath.Join(prepend, fname), Body: string(remaining), BodyHTML: template.HTML(output), SlidesLink: fm.SlidesLink, Series: fm.Series, Tags: fm.Tags, ImageURL: fm.Image, ThumbURL: fm.Thumb, } result = append(result, p) return nil }) if err != nil { return nil, err } sort.Sort(sort.Reverse(result)) return result, nil }