201 lines
4.2 KiB
Go
201 lines
4.2 KiB
Go
package importer
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"path"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
type ReplyData struct {
|
|
Url string `yaml:"url"`
|
|
Text string `yaml:"text"`
|
|
}
|
|
type BookmarkData struct {
|
|
Url string `yaml:"url"`
|
|
Text string `yaml:"text"`
|
|
}
|
|
|
|
type RecipeData struct {
|
|
Yield string `yaml:"yield"`
|
|
Duration string `yaml:"duration"`
|
|
Ingredients []string `yaml:"ingredients"`
|
|
}
|
|
|
|
type PostMeta struct {
|
|
Type string `yaml:"type"`
|
|
Title string `yaml:"title"`
|
|
Description string `yaml:"description"`
|
|
Aliases []string `yaml:"aliases"`
|
|
Date time.Time `yaml:"date"`
|
|
Draft bool `yaml:"draft"`
|
|
Reply ReplyData `yaml:"reply"`
|
|
Bookmark BookmarkData `yaml:"bookmark"`
|
|
Recipe RecipeData `yaml:"recipe"`
|
|
PhotoPath string `yaml:"photo"`
|
|
}
|
|
|
|
type Post struct {
|
|
Id string
|
|
Meta PostMeta
|
|
Content string
|
|
}
|
|
|
|
func (pm *PostMeta) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
type T struct {
|
|
Type string `yaml:"type"`
|
|
Title string `yaml:"title"`
|
|
Description string `yaml:"description"`
|
|
Aliases []string `yaml:"aliases"`
|
|
Draft bool `yaml:"draft"`
|
|
Reply ReplyData `yaml:"reply"`
|
|
Bookmark BookmarkData `yaml:"bookmark"`
|
|
Recipe RecipeData `yaml:"recipe"`
|
|
PhotoPath string `yaml:"photo"`
|
|
}
|
|
type S struct {
|
|
Date string `yaml:"date"`
|
|
}
|
|
|
|
var t T
|
|
var s S
|
|
if err := unmarshal(&t); err != nil {
|
|
return err
|
|
}
|
|
if err := unmarshal(&s); err != nil {
|
|
return err
|
|
}
|
|
|
|
pm.Type = t.Type
|
|
if pm.Type == "" {
|
|
pm.Type = "article"
|
|
}
|
|
pm.Title = t.Title
|
|
pm.Description = t.Description
|
|
pm.Aliases = t.Aliases
|
|
pm.Draft = t.Draft
|
|
pm.Reply = t.Reply
|
|
pm.Bookmark = t.Bookmark
|
|
pm.Recipe = t.Recipe
|
|
pm.PhotoPath = t.PhotoPath
|
|
|
|
possibleFormats := []string{
|
|
"2006-01-02",
|
|
time.Layout,
|
|
time.ANSIC,
|
|
time.UnixDate,
|
|
time.RubyDate,
|
|
time.RFC822,
|
|
time.RFC822Z,
|
|
time.RFC850,
|
|
time.RFC1123,
|
|
time.RFC1123Z,
|
|
time.RFC3339,
|
|
time.RFC3339Nano,
|
|
time.Stamp,
|
|
time.StampMilli,
|
|
time.StampMicro,
|
|
time.StampNano,
|
|
}
|
|
|
|
for _, format := range possibleFormats {
|
|
if t, err := time.Parse(format, s.Date); err == nil {
|
|
pm.Date = t
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func LoadContent(data []byte) string {
|
|
|
|
// trim yaml block
|
|
// TODO this can be done nicer
|
|
trimmedData := bytes.TrimSpace(data)
|
|
// ensure that data ends with a newline
|
|
trimmedData = append(trimmedData, []byte("\n")...)
|
|
// check first line is ---
|
|
if string(trimmedData[0:4]) == "---\n" {
|
|
trimmedData = trimmedData[4:]
|
|
// find --- end
|
|
end := bytes.Index(trimmedData, []byte("\n---\n"))
|
|
if end != -1 {
|
|
data = trimmedData[end+5:]
|
|
}
|
|
}
|
|
|
|
return string(data)
|
|
}
|
|
|
|
func LoadMeta(data []byte) (PostMeta, error) {
|
|
|
|
// get yaml metadata block
|
|
meta := PostMeta{}
|
|
trimmedData := bytes.TrimSpace(data)
|
|
// ensure that data ends with a newline
|
|
trimmedData = append(trimmedData, []byte("\n")...)
|
|
// check first line is ---
|
|
if string(trimmedData[0:4]) == "---\n" {
|
|
trimmedData = trimmedData[4:]
|
|
// find --- end
|
|
end := bytes.Index(trimmedData, []byte("---\n"))
|
|
if end != -1 {
|
|
metaData := trimmedData[:end]
|
|
err := yaml.Unmarshal(metaData, &meta)
|
|
if err != nil {
|
|
return PostMeta{}, err
|
|
}
|
|
}
|
|
}
|
|
|
|
return meta, nil
|
|
}
|
|
|
|
func AllUserPosts(userPath string) ([]Post, error) {
|
|
postFiles := listDir(path.Join(userPath, "public"))
|
|
posts := make([]Post, 0)
|
|
for _, id := range postFiles {
|
|
// if is a directory and has index.md, add to posts
|
|
if dirExists(path.Join(userPath, "public", id)) {
|
|
if fileExists(path.Join(userPath, "public", id, "index.md")) {
|
|
postData, err := os.ReadFile(path.Join(userPath, "public", id, "index.md"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
meta, err := LoadMeta(postData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
post := Post{
|
|
Id: id,
|
|
Content: LoadContent(postData),
|
|
Meta: meta,
|
|
}
|
|
posts = append(posts, post)
|
|
}
|
|
}
|
|
}
|
|
|
|
return posts, nil
|
|
}
|
|
|
|
func listDir(path string) []string {
|
|
dir, _ := os.Open(path)
|
|
defer dir.Close()
|
|
files, _ := dir.Readdirnames(-1)
|
|
return files
|
|
}
|
|
|
|
func dirExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil
|
|
}
|
|
|
|
func fileExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil
|
|
}
|