untrusted comment: verify with st.pub RWQTleDnDrmVqVdvd3FyfBzCpuHDQsj+wkAgx9X3fb1VzuwjFvMa1LqnrsgKorzL0SVcu3yas8TtbHGrTPJIfyZuy8npVC9dEQ0= (require :asdf) (require :alexandria) (require :tooter) ;; Do first: ;; Make a tooter client instance and make-load-form it into ;; client.sexp. super easy. Check tooter's doc/ (defvar *client* (with-open-file (in #p"client.sexp") (read in))) (defvar *ht* (make-hash-table :test 'equal)) (defun save-threads (&optional (filename #p"threads.sexp")) " Saves alist of *ht* to #p\"threads.sexp\" " (with-open-file (out filename :direction :output :if-exists :supersede) (let ((*print-pretty* t)) (prin1 (alexandria:hash-table-alist *ht*) out)))) (Defun load-threads (&optional (filename #p"threads.sexp")) (setq *ht* (alexandria:alist-hash-table (with-open-file (in filename) (read in)) :test 'equal))) (defun 2key.alist (status) (cons (tooter:id status) (list (cons 'utime (tooter:created-at status)) (multiple-value-bind (sec min hou day mon yea) (decode-universal-time (tooter:created-at status)) (cons 'd-time (format nil "~d of ~d ~d:~d" day mon hou min))) (cons 'account-name (tooter:account-name (tooter:account status))) (cons 'content (tooter:plain-format-html (tooter:content status))) (cons 'attachments (mapcar (lambda (x) (tooter:remote-url x)) (tooter:media-attachments status)))))) (defun sew-thread (status) (let* ((progenitor (or (car (tooter:ancestors (tooter:context *client* status))) status)) (orig-context (tooter:context *client* progenitor)) (protid (tooter:id progenitor))) (symbol-macrolet ((it (gethash protid *ht*))) (loop initially (setf it (or it (list (2key.alist progenitor)))) for d in (tooter:descendants orig-context) for key.alist = (2key.alist d) do (unless (assoc (car key.alist) it :test 'equal) (push key.alist (cdr it))) finally (setf it (sort it '< :key 'cdadr)) (return-from sew-thread it)))))