Last active
January 20, 2023 06:20
-
-
Save gkbrk/771852072ed5a6715882bfac734fdd36 to your computer and use it in GitHub Desktop.
Common lisp Mastodon bot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ql:quickload :drakma) | |
(ql:quickload :cl-json) | |
(ql:quickload :plump) | |
(ql:quickload :babel) | |
(ql:quickload :tooter) | |
(ql:quickload :split-sequence) | |
(defvar *feed-path* "https://lobste.rs/rss") | |
(setf drakma:*drakma-default-external-format* :UTF-8) | |
(defstruct lobsters-post | |
title | |
url | |
guid | |
) | |
(defun get-first-text (tag node) | |
"Search the XML node for the given tag name and return the text of the first one" | |
(plump:render-text (car (plump:get-elements-by-tag-name node tag))) | |
) | |
(defun parse-rss-item (item) | |
"Parse an RSS item into a lobsters-post" | |
(let* ((post (make-lobsters-post)) | |
) | |
(setf (lobsters-post-title post) (get-first-text "title" item)) | |
(setf (lobsters-post-url post) (get-first-text "link" item)) | |
(setf (lobsters-post-guid post) (get-first-text "guid" item)) | |
post | |
)) | |
(defun get-rss-feed () | |
"Gets rss feed of Lobste.rs" | |
(let* ((xml-text (babel:octets-to-string (drakma:http-request *feed-path*))) | |
(plump:*tag-dispatchers* plump:*xml-tags*) | |
(xml-tree (plump:parse xml-text)) | |
(items (plump:get-elements-by-tag-name xml-tree "item")) | |
) | |
(reverse (map 'list #'parse-rss-item items)) | |
)) | |
(defun get-mastodon-client () | |
(make-instance 'tooter:client | |
:base "https://botsin.space" | |
:name "lobsterbot" | |
:key "secret" | |
:secret "secret" | |
:access-token "secret") | |
) | |
(defun send-toot (item) | |
"Takes a lobsters-post and posts it on Mastodon" | |
(tooter:make-status (get-mastodon-client) (format nil "~a - ~a ~a" | |
(lobsters-post-title item) | |
(lobsters-post-guid item) | |
(lobsters-post-url item))) | |
) | |
(defun is-link-seen (item) | |
"Returns if we have processed a link before" | |
(with-open-file (stream "links.txt" | |
:if-does-not-exist :create) | |
(loop for line = (read-line stream nil) | |
while line | |
when (string= line (lobsters-post-guid item)) return t)) | |
) | |
(defun record-link-seen (item) | |
"Writes a link to the links file to keep track of it" | |
(with-open-file (stream "links.txt" | |
:direction :output | |
:if-exists :append | |
:if-does-not-exist :create) | |
(format stream "~a~%" (lobsters-post-guid item))) | |
) | |
(defun run-mastodon-bot () | |
(let* ((first-ten (subseq (get-rss-feed) 0 10)) | |
(new-links (remove-if #'is-link-seen first-ten)) | |
) | |
(loop for item in new-links do | |
(send-toot item) | |
(record-link-seen item)) | |
)) | |
(run-mastodon-bot) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@vindarel in this case isn't the subseq a list of posts? If so one can get up to 10 items from a list with
But in this case because they want to filter the stories it would make sense to move everything to the loop