plugins/import.lisp (3012 bytes)
1 (eval-when (:compile-toplevel :load-toplevel) 2 (ql:quickload '(coleslaw cxml cl-ppcre local-time))) 3 4 (defpackage :coleslaw-import 5 (:use :cl :cxml) 6 (:export #:enable) 7 (:import-from :coleslaw #:slugify 8 #:load-config 9 #:*config* 10 #:repo 11 #:repo-dir 12 #:separator) 13 (:import-from :local-time #:+short-month-names+) 14 (:import-from :cl-ppcre #:regex-replace-all)) 15 16 (in-package :coleslaw-import) 17 18 (defun node-val (name post) 19 (flet ((value (node) 20 (let ((child (dom:last-child node))) 21 (when child (dom:data child))))) 22 (let ((nodes (dom:get-elements-by-tag-name post name))) 23 (if (string= "category" name) 24 (loop for node across nodes collecting (value node)) 25 (when (plusp (length nodes)) (value (elt nodes 0))))))) 26 27 (defun get-timestamp (post) 28 (destructuring-bind (day date month year time tz) 29 (cl-ppcre:split " " (node-val "pubDate" post)) 30 (format nil "~a-~2,'0d-~2,'0d ~a" year (position month +short-month-names+ 31 :test #'string=) date time))) 32 33 (defun import-post (post output &optional since) 34 (when (and (string= "publish" (node-val "wp:status" post)) ; is it public? 35 (string= "post" (node-val "wp:post_type" post)) ; is it a post? 36 (or (null since) (string>= (get-timestamp post) since))) 37 (let ((slug (slugify (node-val "title" post)))) 38 (when (string= "" slug) 39 (error "No valid slug-title for post ~a." (get-timestamp post))) 40 (export-post (node-val "title" post) (node-val "category" post) 41 (get-timestamp post) (node-val "content:encoded" post) 42 (format nil "~a.post" slug) output)))) 43 44 (defun export-post (title tags date content path output) 45 (with-open-file (out (merge-pathnames path (or output (repo-dir *config*))) 46 :direction :output 47 :if-exists :supersede 48 :if-does-not-exist :create 49 :external-format :utf-8) 50 ;; TODO: What other data/metadata should we write out? 51 (format out "~A~%" (separator *config*)) 52 (format out "title: ~A~%" title) 53 (format out "tags: ~A~%" (format nil "~{~A~^, ~}" tags)) 54 (format out "date: ~A~%" date) 55 (format out "format: html~%") ; post format: html, md, rst, etc 56 (format out "~A~%" (separator *config*)) 57 (format out "~A~%" (regex-replace-all (string #\Newline) content "<br>")))) 58 59 (defun import-posts (filepath output &optional since) 60 (when (probe-file filepath) 61 (ensure-directories-exist (or output (repo-dir *config*))) 62 (let* ((xml (cxml:parse-file filepath (cxml-dom:make-dom-builder))) 63 (posts (dom:get-elements-by-tag-name xml "item"))) 64 (loop for post across posts do (import-post post output since)) 65 (delete-file filepath)))) 66 67 (defun enable (&key filepath output) 68 (import-posts filepath output))