(var lfs (require :lfs)) (var fennel (require :fennel)) (global pp (fn [x] (print (fennel.view x)))) ; config variables (var gemini-baseurl "gemini://tilde.town/~nihilazo") (var html-baseurl "https://itwont.work") (var gemini-outdir "public_gemini") (var html-outdir "public_html") (var content-dir "content") ;; TODO header/footer files instead of variables? (var gemini-blog-header "# lipu pi jan Niko\n\n") (var gemini-footer "\n=> gemini://tilde.town/~nihilazo Go Home\n") (var html-blog-header "

lipu pi jan Niko

\n\n") (var html-header "lipu pi jan Niko
") (var html-footer "
") (var ass-feed-header "# Actually Simple Syndication - https://tilde.town/~dzwdz/ass/\n" ) (var rss-feed-header " lipu pi jan Niko jan Niko\n") ; working variables (var dirs []) (var files []) (var posts []) ; converts a gemini link line to a html link line, with the correct changes to function (fn html-link [line] (var url "") (let [(u name) (line:match "=> ([^%s]+) (.+)")] ; get the url and name (set url u) ; if the link isn't an offsite gemini link, change .gmi extensions to .html (if (and (string.match url ".%.gmi") (not (string.match url "gemini://.+"))) (set url (string.gsub url "%.gmi" ".html"))) (if (= (string.sub url 1 1) "/") ; if it's an absolute link, add the base url (string.format "%s
\n" html-baseurl url name) (string.format "%s
\n" url name)))) ; generates log roll page for gemini (fn generate-gemini-log [] (var gemini-index gemini-blog-header) (each [_ p (ipairs posts)] (let [{: date : title : path} p url (.. gemini-baseurl path)] (set gemini-index (.. gemini-index (string.format "=> %s %s %s\n" url date title))))) (set gemini-index (.. gemini-index gemini-footer)) (let [f (io.open (.. gemini-outdir "/log/index.gmi") :w+)] (f:write gemini-index) (f:close))) ; generate rss/atom feeds (fn generate-rss-feeds [] (var gemini-rss-feed (.. rss-feed-header "" gemini-baseurl "\n")) (var html-rss-feed (.. rss-feed-header "" html-baseurl "\n")) ; add last updated info to rss feeds (let [d (. posts 1 :date) ] (set gemini-rss-feed (.. gemini-rss-feed "" d "T12:00:00Z\n")) (set html-rss-feed (.. html-rss-feed "" d "T12:00:00Z\n"))) ; add posts to rss feeds (each [_ p (ipairs posts)] (let [ {: date : title : path} p entry "\n %s%s %s %sT12:00:00Z \n" ] (set html-rss-feed (.. html-rss-feed (entry:format html-baseurl (path:gsub ".gmi" ".html") title date (path:gsub ".gmi" ".html")))) (set gemini-rss-feed (.. gemini-rss-feed (entry:format gemini-baseurl path title date path))))) (set html-rss-feed (.. html-rss-feed "
")) (set gemini-rss-feed (.. gemini-rss-feed "")) ; write out rss feeds (let [f (io.open (.. gemini-outdir "/atom.xml") :w+)] (f:write gemini-rss-feed) (f:close)) (let [f (io.open (.. html-outdir "/atom.xml") :w+)] (f:write html-rss-feed) (f:close))) ; generate ass (https://tilde.town/~dzwdz/ass) feeds (fn generate-ass-feeds [] (var gemini-ass-feed ass-feed-header) (var html-ass-feed ass-feed-header) ; add posts to ass feeds (each [_ p (ipairs posts)] (let [ {: date : title : path} p] (set html-ass-feed (.. html-ass-feed (string.format "%s\t%s%s\t%s\n" date html-baseurl (path:gsub ".gmi" ".html") title))) (set gemini-ass-feed (.. gemini-ass-feed (string.format "%s\t%s%s\t%s\n" date gemini-baseurl path title))))) ; write out ass feeds (let [f (io.open (.. gemini-outdir "/feed.ass") :w+)] (f:write gemini-ass-feed) (f:close)) (let [f (io.open (.. html-outdir "/feed.ass") :w+)] (f:write html-ass-feed) (f:close))) ; generates log roll page for html (fn generate-html-log [] (var html-index (.. html-header html-blog-header :" html-footer)) (let [f (io.open (.. html-outdir "/log/index.html") :w+)] (f:write html-index) (f:close))) ; generate-log generates the log pages and feeds from the posts index (fn generate-logs [] (table.sort posts (fn [a b] (> (. a :date) (. b :date)))) (generate-gemini-log) (generate-html-log) (generate-ass-feeds) (generate-rss-feeds)) ; index-post adds a log post to the post index (fn index-post [f] (io.input (.. content-dir f)) ; open file (let [post {}] (tset post :path f) (let [line (io.read) ; read first line, match title title (line:match "^#%s*([^\n]+)%s*$")] (tset post :title title)) (let [line (io.read) ; read second line, match date date (line:match "^%s*(.+)%s*")] (tset post :date date)) (table.insert posts post)) (io.close)) ; HTML-escapes and trims a string (fn html-clean [l] (let [s (l:match "%s*(.+)%s*")] (-> s (string.gsub "&" "&") (string.gsub "<" "<") (string.gsub ">" ">") (string.gsub "\"" """) (string.gsub "''" "'")))) ; converts a gemtext line to an html line. This could probably be done far better. TODO am I overusing string matching here? Maybe could write an lpeg or something similar? (var state :normal) ; either :normal or :pre depending on the current position in the file. (var listing false) ; true if we are in a list, false otherwise (var blockquoting false) (fn to-html [line] (var prefix "") (if (and listing (not (line:match "^%*%s"))) (do (set listing false) (set prefix ""))) (if (and blockquoting (not (line:match "^>"))) (do (set blockquoting false) (set prefix ""))) (if (= state :pre) (if (line:match "^```") (do (set state :normal) "") line) (= state :normal) (if (line:match "^```") (do (set state :pre) (.. prefix "
")) ; open pre
          (line:match "^#[^#]")
          (.. prefix "

" (html-clean (line:match "^#([^#].+)")) "

") (line:match "^##[^#]") (.. prefix "

" (html-clean (line:match "^##([^#].+)")) "

") (line:match "^###[^#]") (.. prefix "

" (html-clean (line:match "^###([^#].+)")) "

") (line:match "^=>") (.. prefix (html-link line)) ; link (line:match "^%s*$") prefix ; blank line (line:match "^%*%s") (do (if (not listing) (do (set prefix "