1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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)
}
|