summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authoreltrac <hi@eltr.ac>2026-04-07 14:46:20 +0800
committereltrac <hi@eltr.ac>2026-04-07 14:46:20 +0800
commitd733a7aede6421de9f3077b17d7011fadd598241 (patch)
tree6e65401fb82ff0425c7302a984044819a714a370 /scripts
chore: move templates from geek-death-project
Diffstat (limited to 'scripts')
-rw-r--r--scripts/extract_highlights.go120
-rw-r--r--scripts/get_external_link_rank.go77
-rw-r--r--scripts/get_internal_link_graph.go101
3 files changed, 298 insertions, 0 deletions
diff --git a/scripts/extract_highlights.go b/scripts/extract_highlights.go
new file mode 100644
index 0000000..c7253d5
--- /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)
+}
diff --git a/scripts/get_external_link_rank.go b/scripts/get_external_link_rank.go
new file mode 100644
index 0000000..4189c19
--- /dev/null
+++ b/scripts/get_external_link_rank.go
@@ -0,0 +1,77 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/fs"
+ "net/url"
+ "os"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strings"
+)
+
+func main() {
+ externalLinks := countExternalLinks("content")
+ writeJSON("data/externallinks.json", externalLinks)
+ fmt.Println("✅ External link rank data generated.")
+}
+
+// countExternalLinks scans markdown files and counts occurrences of each external domain.
+func countExternalLinks(root string) [][2]interface{} {
+ linkRegex := regexp.MustCompile(`https?://[^\s)>"']+`)
+ counts := make(map[string]int)
+
+ filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
+ if err != nil || d.IsDir() || !strings.HasSuffix(path, ".md") {
+ return nil
+ }
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil
+ }
+ matches := linkRegex.FindAllString(string(data), -1)
+ for _, match := range matches {
+ u, err := url.Parse(match)
+ if err == nil && u.Host != "" {
+ // skip my domains
+ if strings.HasSuffix(u.Host, "eltr.ac") || strings.HasSuffix(u.Host, "guhub.cn") {
+ continue
+ }
+ counts[u.Host]++
+ }
+ }
+ return nil
+ })
+
+ // convert map to sorted array (alphabetically by domain)
+ type kv struct {
+ Key string
+ Value int
+ }
+ var list []kv
+ for k, v := range counts {
+ list = append(list, kv{k, v})
+ }
+ sort.Slice(list, func(i, j int) bool { return list[i].Key < list[j].Key })
+
+ result := make([][2]interface{}, len(list))
+ for i, kv := range list {
+ result[i] = [2]interface{}{kv.Key, kv.Value}
+ }
+ return result
+}
+
+// writeJSON writes the result to file with indentation.
+func writeJSON(path string, data interface{}) {
+ file, err := os.Create(path)
+ if err != nil {
+ fmt.Println("Error:", err)
+ return
+ }
+ defer file.Close()
+ enc := json.NewEncoder(file)
+ enc.SetIndent("", " ")
+ enc.Encode(data)
+}
diff --git a/scripts/get_internal_link_graph.go b/scripts/get_internal_link_graph.go
new file mode 100644
index 0000000..8adf559
--- /dev/null
+++ b/scripts/get_internal_link_graph.go
@@ -0,0 +1,101 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strings"
+)
+
+type Node struct {
+ ID string `json:"id"`
+ Label string `json:"label"`
+ URL string `json:"url"`
+}
+
+type Edge struct {
+ From string `json:"from"`
+ To string `json:"to"`
+}
+
+func main() {
+ root := "content"
+
+ nodes := map[string]Node{}
+ edges := make([]Edge, 0) // non-nil so it becomes [] not null
+
+ err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
+ if err != nil || d.IsDir() || !strings.HasSuffix(strings.ToLower(path), ".md") {
+ return nil
+ }
+
+ rel, err := filepath.Rel(root, path)
+ if err != nil {
+ return nil
+ }
+ rel = filepath.ToSlash(rel)
+ urlPath := "/" + strings.TrimSuffix(rel, ".md") + "/"
+ label := strings.TrimSuffix(filepath.Base(path), ".md")
+
+ nodes[urlPath] = Node{ID: urlPath, Label: label, URL: urlPath}
+
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil
+ }
+ content := string(data)
+
+ linkPattern := regexp.MustCompile(`\[[^\]]*\]\((/[^)]+)\)`)
+ matches := linkPattern.FindAllStringSubmatch(content, -1)
+ for _, m := range matches {
+ link := strings.TrimSuffix(m[1], ".md")
+ if !strings.HasSuffix(link, "/") {
+ link += "/"
+ }
+ edges = append(edges, Edge{From: urlPath, To: link})
+ }
+
+ return nil
+ })
+
+ if err != nil {
+ fmt.Println("WalkDir error:", err)
+ return
+ }
+
+ nodeKeys := make([]string, 0, len(nodes))
+ for k := range nodes {
+ nodeKeys = append(nodeKeys, k)
+ }
+ sort.Strings(nodeKeys)
+ nodeList := make([]Node, 0, len(nodeKeys))
+ for _, k := range nodeKeys {
+ nodeList = append(nodeList, nodes[k])
+ }
+
+ os.MkdirAll("static", os.ModePerm)
+ output := map[string]interface{}{
+ "nodes": nodeList,
+ "edges": edges,
+ }
+
+ outfile := "static/link-graph.json"
+ f, err := os.Create(outfile)
+ if err != nil {
+ fmt.Println("create file error:", err)
+ return
+ }
+ defer f.Close()
+
+ enc := json.NewEncoder(f)
+ enc.SetIndent("", " ")
+ if err := enc.Encode(output); err != nil {
+ fmt.Println("json encode error:", err)
+ }
+
+ fmt.Printf("✅ Link graph written to %s (%d nodes, %d edges)\n", outfile, len(nodeList), len(edges))
+}