This repository has been archived on 2023-07-28. You can view files and clone it, but cannot push or open issues or pull requests.
mastodon-bot/mastodon-bot.cljs

149 lines
5.4 KiB
Text
Raw Normal View History

2018-03-11 21:05:25 +00:00
#!/usr/bin/env lumo
(ns mastodon-bot.core
(:require
[cljs.core :refer [*command-line-args*]]
[cljs.reader :as edn]
2018-03-15 05:01:53 +00:00
[clojure.set :refer [rename-keys]]
[clojure.string :as string]
2018-03-11 21:05:25 +00:00
["fs" :as fs]
2018-03-15 05:01:53 +00:00
["http" :as http]
2018-03-11 21:05:25 +00:00
["https" :as https]
["mastodon-api" :as mastodon]
2018-03-20 12:57:25 +00:00
["rss-parser" :as rss]
2018-03-15 05:01:53 +00:00
["tumblr" :as tumblr]
2018-03-11 21:05:25 +00:00
["twitter" :as twitter]))
2018-03-15 05:01:53 +00:00
(defn find-config []
(or (first *command-line-args*)
(-> js/process .-env .-MASTODON_BOT_CONFIG)
"config.edn"))
(def config (-> (find-config) fs/readFileSync str edn/read-string))
(def content-filter-regexes (mapv re-pattern (-> config :mastodon :content-filters)))
(defn blocked-content? [text]
(boolean (some #(re-matches % text) content-filter-regexes)))
2018-03-23 13:14:26 +00:00
(def max-post-length (or (-> config :mastodon :max-post-length) 300))
2018-03-15 05:01:53 +00:00
(def mastodon-client (or (some-> config :mastodon clj->js mastodon.)
(do
(js/console.error "missing Mastodon client configuration!")
(js/process.exit 1))))
2018-03-11 21:05:25 +00:00
(defn js->edn [data]
(js->clj data :keywordize-keys true))
2018-03-23 13:14:26 +00:00
(defn trim-text [text]
(if (> (count text) max-post-length)
(reduce
(fn [text word]
(if (> (+ (count text) (count word)) (- max-post-length 3))
(reduced (str text "..."))
(str text " " word)))
""
(clojure.string/split text #" "))
text))
2018-03-11 21:05:25 +00:00
(defn delete-status [status]
(.delete mastodon-client (str "statuses/" status) #js {}))
(defn post-status
([status-text]
(post-status status-text nil))
([status-text media-ids]
(.post mastodon-client "statuses"
2018-04-01 02:12:31 +00:00
(clj->js (merge {:status (if-let [signature (-> config :mastodon :signature)]
(str status-text "\n" signature)
status-text)}
2018-03-11 21:05:25 +00:00
(when media-ids {:media_ids media-ids}))))))
(defn post-image [image-stream description callback]
(-> (.post mastodon-client "media" #js {:file image-stream :description description})
(.then #(-> % .-data .-id callback))))
(defn post-status-with-images
([status-text urls]
(post-status-with-images status-text urls []))
([status-text [url & urls] ids]
(if url
2018-03-15 05:01:53 +00:00
(.get (if (string/starts-with? url "https://") https http) url
2018-03-11 21:05:25 +00:00
(fn [image-stream]
(post-image image-stream status-text #(post-status-with-images status-text urls (conj ids %)))))
(post-status status-text (not-empty ids)))))
(defn get-mastodon-timeline [callback]
(.then (.get mastodon-client "timelines/home" #js {}) #(-> % .-data js->edn callback)))
2018-03-15 05:01:53 +00:00
(defn post-items [last-post-time items]
(doseq [{:keys [text media-links]} (->> items
(remove #(blocked-content? (:text %)))
(filter #(> (:created-at %) last-post-time)))]
2018-03-15 05:01:53 +00:00
(if media-links
(post-status-with-images text media-links)
(post-status text))))
2018-03-11 21:05:25 +00:00
(defn parse-tweet [{created-at :created_at
text :text
{:keys [media]} :extended_entities
{:keys [screen_name]} :user :as tweet}]
{:created-at (js/Date. created-at)
:text (str text "\n - " screen_name)
:media-links (keep #(when (= (:type %) "photo") (:media_url_https %)) media)})
2018-03-15 05:01:53 +00:00
(defmulti parse-tumblr-post :type)
(defmethod parse-tumblr-post "text" [{:keys [body date short_url]}]
{:created-at (js/Date. date)
2018-03-23 13:14:26 +00:00
:text (str (trim-text body) "\n\n" short_url)})
2018-03-15 05:01:53 +00:00
(defmethod parse-tumblr-post "photo" [{:keys [caption date photos short_url] :as post}]
{:created-at (js/Date. date)
:text (string/join "\n" [(string/replace caption #"<[^>]*>" "") short_url])
:media-links (mapv #(-> % :original_size :url) photos)})
(defmethod parse-tumblr-post :default [post])
2018-03-15 05:01:53 +00:00
(defn post-tumblrs [last-post-time]
(fn [err response]
(->> response
js->edn
:posts
(mapv parse-tumblr-post)
(post-items last-post-time))))
2018-03-11 21:05:25 +00:00
(defn post-tweets [last-post-time]
(fn [error tweets response]
2018-03-15 05:01:53 +00:00
(->> (js->edn tweets)
(map parse-tweet)
(post-items last-post-time))))
2018-03-11 21:05:25 +00:00
2018-03-20 12:57:25 +00:00
(defn parse-feed [last-post-time parser [title url]]
(-> (.parseURL parser url)
(.then #(post-items
last-post-time
2018-03-23 13:14:26 +00:00
(for [{:keys [title isoDate pubDate content link]} (-> % js->edn :items)]
{:created-at (js/Date. (or isoDate pubDate))
:text (str (trim-text title) "\n\n" link)})))))
2018-03-20 12:57:25 +00:00
2018-03-11 21:05:25 +00:00
(get-mastodon-timeline
(fn [timeline]
2018-03-15 05:01:53 +00:00
(let [last-post-time (-> timeline first :created_at (js/Date.))]
2018-03-20 12:57:25 +00:00
;;post from Twitter
2018-03-15 05:01:53 +00:00
(when-let [twitter-client (some-> config :twitter :access-keys clj->js twitter.)]
(doseq [account (-> config :twitter :accounts)]
(.get twitter-client
"statuses/user_timeline"
#js {:screen_name account :include_rts false}
(post-tweets last-post-time))))
2018-03-20 12:57:25 +00:00
;;post from Tumblr
2018-03-15 05:01:53 +00:00
(when-let [tumblr-oauth (some-> config :tumblr :access-keys clj->js)]
(when-let [tumblr-client (some-> config :tumblr :accounts first (tumblr/Blog. tumblr-oauth))]
2018-03-20 12:57:25 +00:00
(.posts tumblr-client #js {:limit 5} (post-tumblrs last-post-time))))
;;post from RSS
(when-let [feeds (some-> config :rss)]
(let [parser (rss.)]
(doseq [feed feeds]
(parse-feed last-post-time parser feed)))))))