1package main
2
3import (
4 _ "embed"
5 "fmt"
6 "os"
7 "strings"
8
9 "github.com/adrg/frontmatter"
10 "github.com/go-git/go-git/v5"
11 flag "github.com/spf13/pflag"
12 "gopkg.in/yaml.v3"
13)
14
15var (
16 flagHelp *bool = flag.BoolP("help", "h", false, "Show the help message")
17 flagInput *string = flag.StringP("input", "i", "", "Path to input Markdown")
18 flagOutput *string = flag.StringP("output", "o", "", "Path to output PNG")
19 flagMetaSize *int = flag.IntP("metasize", "m", 12, "Size of font for meta information")
20 flagPostTitleSize *int = flag.IntP("posttitlesize", "p", 14, "Size of font for post title")
21 flagSiteTitleSize *int = flag.IntP("sitetitlesize", "s", 10, "Size of font for site title")
22)
23
24//go:embed font.otf
25
26func main() {
27 flag.Parse()
28
29 if *flagHelp {
30 help()
31 os.Exit(0)
32 }
33
34 validateFlags()
35
36 postTitle, postSubtitle, postDate, postContent := getPostInfo(*flagInput)
37 postReadTime := getReadTime(postContent)
38 siteTitle := getSiteTitle()
39 dateEdited := getGitDate(*flagInput)
40
41 // TODO: Render information to image
42 fmt.Println(postTitle, postSubtitle, postDate, postReadTime, siteTitle, dateEdited)
43}
44
45// Print help message
46func help() {
47 fmt.Println("\nUsage: p2c [options]")
48 fmt.Println("\nOptions:")
49 flag.PrintDefaults()
50 fmt.Print(`
51example: p2c -i input.md -o output.png
52
53p2c is meant for use with Hugo.
54
55It looks at...
56- The Markdown file's frontmatter fields for
57 - title
58 - subtitle
59 - date
60- The site's config.{toml/yaml/yml} fields for
61 - title (site title)
62- The git history to determine the date the post was last edited.
63
64`)
65}
66
67// Validate flags
68func validateFlags() {
69 if *flagInput == "" {
70 fmt.Println("Error: No input file specified")
71 os.Exit(1)
72 }
73 if *flagOutput == "" {
74 fmt.Println("Error: No output file specified")
75 os.Exit(1)
76 }
77}
78
79// Get the post's title, subtitle, and date
80func getPostInfo(input string) (string, string, string, string) {
81 if _, err := os.Stat(input); os.IsNotExist(err) {
82 fmt.Println("Error: Input file does not exist")
83 fmt.Println(err)
84 os.Exit(1)
85 }
86
87 fileContents, err := os.ReadFile(input)
88 if err != nil {
89 fmt.Println("Error: Could not read input file")
90 fmt.Println(err)
91 os.Exit(1)
92 }
93
94 var fm struct {
95 Title string `yaml:"title"`
96 Subtitle string `yaml:"subtitle"`
97 Date string `yaml:"date"`
98 }
99
100 content, err := frontmatter.Parse(strings.NewReader(string(fileContents)), &fm)
101 if err != nil {
102 fmt.Println("Error: Could not parse frontmatter")
103 fmt.Println(err)
104 os.Exit(1)
105 }
106
107 return fm.Title, fm.Subtitle, fm.Date, string(content)
108}
109
110// Get the read time of the post
111func getReadTime(content string) int {
112 wordCount := len(strings.Fields(content))
113 return wordCount / 200
114}
115
116// Get the site's title
117func getSiteTitle() string {
118 validConf := ""
119 confs := []string{"config.toml", "config.yaml", "config.yml"}
120 for _, conf := range confs {
121 if _, err := os.Stat(conf); os.IsNotExist(err) {
122 continue
123 }
124 validConf = conf
125 }
126 if validConf == "" {
127 fmt.Println("Error: No valid config file found")
128 os.Exit(1)
129 }
130
131 var t struct {
132 Title string `yaml:"title"`
133 }
134
135 f, err := os.Open(validConf)
136 if err != nil {
137 fmt.Println("Error: Could not open config file")
138 fmt.Println(err)
139 os.Exit(1)
140 }
141 defer f.Close()
142
143 decoder := yaml.NewDecoder(f)
144 err = decoder.Decode(&t)
145 if err != nil {
146 fmt.Println("Error: Could not parse config file")
147 fmt.Println(err)
148 os.Exit(1)
149 }
150
151 return t.Title
152}
153
154// Get the date the post was last edited
155func getGitDate(input string) string {
156 if _, err := os.Stat(input); os.IsNotExist(err) {
157 fmt.Println("Error: Input file does not exist")
158 os.Exit(1)
159 }
160
161 repo, err := git.PlainOpenWithOptions(".", &git.PlainOpenOptions{DetectDotGit: true})
162 if err != nil {
163 fmt.Println("Error: Could not open git repository")
164 fmt.Println(err)
165 os.Exit(1)
166 }
167
168 commitIter, err := repo.Log(&git.LogOptions{FileName: &input})
169 if err != nil {
170 fmt.Println("Error: Could not get git history")
171 fmt.Println(err)
172 os.Exit(1)
173 }
174
175 commit, err := commitIter.Next()
176 if err != nil {
177 fmt.Println("Error: Could not get git history")
178 fmt.Println(err)
179 os.Exit(1)
180 }
181
182 return commit.Committer.When.Format("2006-01-02")
183}