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 fm.Date = strings.Split(fm.Date, "T")[0]
108
109 return fm.Title, fm.Subtitle, fm.Date, string(content)
110}
111
112// Get the read time of the post
113func getReadTime(content string) int {
114 wordCount := len(strings.Fields(content))
115 return wordCount / 200
116}
117
118// Get the site's title
119func getSiteTitle() string {
120 validConf := ""
121 confs := []string{"config.toml", "config.yaml", "config.yml"}
122 for _, conf := range confs {
123 if _, err := os.Stat(conf); os.IsNotExist(err) {
124 continue
125 }
126 validConf = conf
127 }
128 if validConf == "" {
129 fmt.Println("Error: No valid config file found")
130 os.Exit(1)
131 }
132
133 var t struct {
134 Title string `yaml:"title"`
135 }
136
137 f, err := os.Open(validConf)
138 if err != nil {
139 fmt.Println("Error: Could not open config file")
140 fmt.Println(err)
141 os.Exit(1)
142 }
143 defer f.Close()
144
145 decoder := yaml.NewDecoder(f)
146 err = decoder.Decode(&t)
147 if err != nil {
148 fmt.Println("Error: Could not parse config file")
149 fmt.Println(err)
150 os.Exit(1)
151 }
152
153 return t.Title
154}
155
156// Get the date the post was last edited
157func getGitDate(input string) string {
158 if _, err := os.Stat(input); os.IsNotExist(err) {
159 fmt.Println("Error: Input file does not exist")
160 os.Exit(1)
161 }
162
163 repo, err := git.PlainOpenWithOptions(".", &git.PlainOpenOptions{DetectDotGit: true})
164 if err != nil {
165 fmt.Println("Error: Could not open git repository")
166 fmt.Println(err)
167 os.Exit(1)
168 }
169
170 commitIter, err := repo.Log(&git.LogOptions{FileName: &input})
171 if err != nil {
172 fmt.Println("Error: Could not get git history")
173 fmt.Println(err)
174 os.Exit(1)
175 }
176
177 commit, err := commitIter.Next()
178 if err != nil {
179 fmt.Println("Error: Could not get git history")
180 fmt.Println(err)
181 os.Exit(1)
182 }
183
184 return commit.Committer.When.Format("2006-01-02")
185}