git.m455.casa

m455.casa

clone url: git://git.m455.casa/m455.casa


src/generate.scm

1 (module generate ()
2
3 (import scheme
4 utf8
5 srfi-1
6 (chicken base)
7 (chicken format)
8 (chicken time posix)
9 (chicken irregex)
10 (chicken pathname)
11 (chicken string)
12 (chicken file)
13 (chicken io)
14 (chicken port)
15 static
16 utils
17 parser)
18
19 ;; generate posts page ======================================================
20 (define (path-data->html-link path-data)
21 ;; remove "markup/" from links for a nicer URL
22 (let ((path (strip-markup-directory-from-start-of-path (alist-ref 'path path-data))))
23 (format " <li><a href=\"/~a\">~a</a></li>"
24 (pathname-replace-extension path "html")
25 (clean (alist-ref 'title path-data)))))
26
27 (define (create-posts-page paths-data)
28 (let* ((posts-list (map path-data->html-link paths-data))
29 ;; TODO: probably turn this into a template eventually
30 (html-contents (string-append
31 "<h1>posts</h1>\n"
32 "<p>here's a list of my blog posts. if you're looking for my older posts, then you\n"
33 "can find them in my <a href=\"/archive\">archive</a>.</p>\n"
34 "<ul>\n"
35 (string-intersperse posts-list "\n")
36 "\n</ul>")))
37 (string-populate
38 HTML-TEMPLATE
39 `((title . "m455's posts")
40 (contents . ,html-contents)))))
41
42 (define (generate-posts-page)
43 (let ((paths-data (paths->sorted-alists
44 (find-files
45 (make-pathname MARKUP-DIRECTORY
46 POSTS-DIRECTORY))))
47 (posts-build-path (make-pathname BUILD-DIRECTORY POSTS-DIRECTORY)))
48 (create-directory posts-build-path #t)
49 (file-write (make-pathname posts-build-path "index.html")
50 (create-posts-page paths-data))))
51
52 ;; generate html ============================================================
53 (define (markup-file->html file)
54 (let ((lines (file->lines file)))
55 (string-populate
56 HTML-TEMPLATE
57 `((title . ,(substring (car lines) (string-length TITLE-PREFIX)))
58 (contents . ,(parse-lines lines 'normal))))))
59
60 (define (generate-html)
61 (let* ((markup-files-and-directories (find-files MARKUP-DIRECTORY))
62 (markup-files (filter (lambda (path)
63 (not (directory-exists? path)))
64 markup-files-and-directories))
65 (markup-directories (filter (lambda (path)
66 (directory-exists? path))
67 markup-files-and-directories)))
68 (for-each
69 (lambda (path)
70 (create-directory
71 (make-pathname BUILD-DIRECTORY
72 (strip-markup-directory-from-start-of-path path))
73 #t))
74 markup-directories)
75
76 (for-each
77 (lambda (path)
78 (let ((stripped-path (strip-markup-directory-from-start-of-path path)))
79 (file-write (pathname-replace-extension
80 (make-pathname BUILD-DIRECTORY stripped-path)
81 "html")
82 (markup-file->html path))))
83 markup-files)))
84
85 ;; generate rss =============================================================
86
87 ;; this is mostly to fix the issue of rss readers opening relative links.
88 ;; this just takes links like "/path/to/thing.html" and changes them
89 ;; to "https://example.com/path/to/thing.html"
90 (define (relative-links->urls str)
91 (irregex-replace/all
92 (irregex "\\[(/[^\\[]*)\\|([^\\[]*)\\]" 's)
93 str
94 (lambda (m)
95 (format "[https://m455.casa~a|~a]"
96 (irregex-match-substring m 1) ;; link
97 (irregex-match-substring m 2))))) ;; title
98
99 (define (date->rss-date str)
100 (time->string
101 (string->time str "%Y-%m-%d %H:%M")
102 "%a, %d %b %Y %H:%M:%S %z"))
103
104 (define (post->rss-item path-data)
105 (let* ((content (with-input-from-file (alist-ref 'path path-data) read-string))
106 (content-links-fixed (relative-links->urls content))
107 (path (pathname-replace-extension (alist-ref 'path path-data) "html"))
108 (path-stripped (strip-markup-directory-from-start-of-path path)))
109 (string-populate
110 RSS-ITEM-TEMPLATE
111 `((post-title . ,(alist-ref 'title path-data))
112 (post-url . ,(string-append "https://m455.casa/" path-stripped))
113 (post-date . ,(date->rss-date (alist-ref 'date path-data)))
114 (post-contents . ,(parse-lines
115 (with-input-from-string content-links-fixed read-lines)
116 'normal))))))
117
118 (define (generate-rss)
119 (let* ((paths-data (paths->sorted-alists
120 (filter (lambda (path)
121 (not (directory-exists? path)))
122 (find-files (make-pathname MARKUP-DIRECTORY
123 POSTS-DIRECTORY)))))
124 (posts-as-rss-items (string-intersperse (map post->rss-item paths-data) "\n")))
125 (file-write
126 (make-pathname BUILD-DIRECTORY "feed.rss")
127 (string-populate RSS-CHANNEL-TEMPLATE `((items . ,posts-as-rss-items))))))
128
129 ;; do the stuff
130 (generate-posts-page)
131 (generate-html)
132 (generate-rss))