diff options
Diffstat (limited to 'scripts/extract_highlights.go')
| -rw-r--r-- | scripts/extract_highlights.go | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/scripts/extract_highlights.go b/scripts/extract_highlights.go new file mode 100644 index 00000000..c7253d5f --- /dev/null +++ b/scripts/extract_highlights.go @@ -0,0 +1,120 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/fs" + "net/url" + "os" + "path/filepath" + "regexp" + "strings" +) + +type HighlightLink struct { + Text string `json:"text"` + Link string `json:"link"` +} + +type Result struct { + Title string `json:"title"` + URL string `json:"url"` + Highlights []HighlightLink `json:"highlights"` +} + +func main() { + const contentDir = "content" + const outputFile = "data/highlights.json" + + highlightPattern := regexp.MustCompile(`==(.+?)==`) + titlePattern := regexp.MustCompile(`(?m)^title:\s*["']?(.+?)["']?\s*$`) + slugPattern := regexp.MustCompile(`(?m)^slug:\s*["']?(.+?)["']?\s*$`) + + var results []Result + + err := filepath.WalkDir(contentDir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() || !strings.HasSuffix(d.Name(), ".md") { + return nil + } + + contentBytes, err := os.ReadFile(path) + if err != nil { + return err + } + content := string(contentBytes) + + // Title + title := filepath.Base(path) + if m := titlePattern.FindStringSubmatch(content); len(m) > 1 { + title = m[1] + } + + // Slug and URL + urlPath := "" + if m := slugPattern.FindStringSubmatch(content); len(m) > 1 { + slug := strings.Trim(m[1], "/") + relDir, _ := filepath.Rel(contentDir, filepath.Dir(path)) + relDir = filepath.ToSlash(relDir) + if relDir != "." { + urlPath = fmt.Sprintf("/%s/%s/", relDir, slug) + } else { + urlPath = fmt.Sprintf("/%s/", slug) + } + } else { + rel, _ := filepath.Rel(contentDir, path) + rel = filepath.ToSlash(rel) + urlPath = "/" + strings.TrimSuffix(rel, ".md") + "/" + } + + // Highlights + matches := highlightPattern.FindAllStringSubmatch(content, -1) + if len(matches) == 0 { + return nil + } + + var highlightLinks []HighlightLink + for _, m := range matches { + if len(m) > 1 { + h := m[1] + encoded := url.QueryEscape(h) + link := fmt.Sprintf("%s#:~:text=%s", urlPath, encoded) + highlightLinks = append(highlightLinks, HighlightLink{Text: h, Link: link}) + } + } + + results = append(results, Result{ + Title: title, + URL: urlPath, + Highlights: highlightLinks, + }) + + return nil + }) + + if err != nil { + fmt.Println("❌ Error:", err) + return + } + + // Write JSON + if err := os.MkdirAll(filepath.Dir(outputFile), os.ModePerm); err != nil { + fmt.Println("❌ Error creating output directory:", err) + return + } + + jsonData, err := json.MarshalIndent(results, "", " ") + if err != nil { + fmt.Println("❌ Error encoding JSON:", err) + return + } + + if err := os.WriteFile(outputFile, jsonData, 0644); err != nil { + fmt.Println("❌ Error writing JSON file:", err) + return + } + + fmt.Printf("✔ 提取完成,共 %d 篇文章有高亮,已写入 %s\n", len(results), outputFile) +} |
