diff --git a/README.md b/README.md index b36df95..10dea30 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ If you get a [permission failure](https://github.com/anmonteiro/lumo/issues/206) with later timestamps to avoid duplicate posts. On the first run the timestamp will default to current time. ```clojure -#:mastodon-bot.core {;; add Twitter config to mirror Twitter accounts :twitter {:access-keys {:consumer_key "XXXX" @@ -52,39 +51,37 @@ with later timestamps to avoid duplicate posts. On the first run the timestamp w ;; add RSS config to follow feeds :rss {"Hacker News" "https://hnrss.org/newest" "r/Clojure" "https://www.reddit.com/r/clojure/.rss"} - :mastodon - #:mastodon-bot.mastodon-api -{:access_token "XXXX" - ;; account number you see when you log in and go to your profile - ;; e.g: https://mastodon.social/web/accounts/294795 - :account-id "XXXX" - :api_url "https://botsin.space/api/v1/" - ;; optional boolean to mark content as sensitive - :sensitive? true - ;; optional boolean defaults to false - ;; only sources containing media will be posted when set to true - :media-only? true - ;; optional visibility flag: direct, private, unlisted, public - ;; defaults to public - :visibility "unlisted" - ;; optional limit for the post length - :max-post-length 300 - ;; optional flag specifying wether the name of the account - ;; will be appended in the post, defaults to false - :append-screen-name? false - ;; optional signature for posts - :signature "#newsbot" - ;; optionally try to resolve URLs in posts to skip URL shorteners - ;; defaults to false - :resolve-urls? true - ;; optional content filter regexes - ;; any posts matching the regexes will be filtered out - :content-filters [".*bannedsite.*"] - ;; optional keyword filter regexes - ;; any posts not matching the regexes will be filtered out - :keyword-filters [".*clojure.*"] - ;; Replace Twitter links by Nitter - :nitter-urls? false}} + :mastodon {:access_token "XXXX" + ;; account number you see when you log in and go to your profile + ;; e.g: https://mastodon.social/web/accounts/294795 + :account-id "XXXX" + :api_url "https://botsin.space/api/v1/" + ;; optional boolean to mark content as sensitive + :sensitive? true + ;; optional boolean defaults to false + ;; only sources containing media will be posted when set to true + :media-only? true + ;; optional visibility flag: direct, private, unlisted, public + ;; defaults to public + :visibility "unlisted" + ;; optional limit for the post length + :max-post-length 300 + ;; optional flag specifying wether the name of the account + ;; will be appended in the post, defaults to false + :append-screen-name? false + ;; optional signature for posts + :signature "#newsbot" + ;; optionally try to resolve URLs in posts to skip URL shorteners + ;; defaults to false + :resolve-urls? true + ;; optional content filter regexes + ;; any posts matching the regexes will be filtered out + :content-filters [".*bannedsite.*"] + ;; optional keyword filter regexes + ;; any posts not matching the regexes will be filtered out + :keyword-filters [".*clojure.*"] + ;; Replace Twitter links by Nitter + :nitter-urls? false}} ``` * the bot looks for `config.edn` at its relative path by default, an alternative location can be specified either using the `MASTODON_BOT_CONFIG` environment variable or passing the path to config as an argument diff --git a/src/main/mastodon_bot/core.cljs b/src/main/mastodon_bot/core.cljs index 855ef3d..3a78cbc 100755 --- a/src/main/mastodon_bot/core.cljs +++ b/src/main/mastodon_bot/core.cljs @@ -6,9 +6,7 @@ [clojure.spec.test.alpha :as st] [orchestra.core :refer-macros [defn-spec]] [cljs.core :refer [*command-line-args*]] - [cljs.reader :as edn] [clojure.string :as string] - ["fs" :as fs] ["rss-parser" :as rss] ["tumblr" :as tumblr] ["twitter" :as twitter] @@ -20,23 +18,14 @@ (s/def ::tumblr map?) (s/def ::rss map?) -(def config? (s/keys :req [::mastodon-config] - :opt [::twitter ::tumblr ::rss])) +(def config? (s/keys :req-un [::mastodon-config] + :opt-un [::twitter ::tumblr ::rss])) -;this has to stay on top - only ns-keywords can be uses in spec (defn-spec mastodon-config ::mastodon-config [config config?] - (::mastodon-config config)) + (:mastodon-config config)) -(defn find-config [] - (let [config (or (first *command-line-args*) - (-> js/process .-env .-MASTODON_BOT_CONFIG) - "config.edn")] - (if (fs/existsSync config) - config - (infra/exit-with-error (str "failed to read config: " config))))) - -(def config (-> (find-config) (fs/readFileSync #js {:encoding "UTF-8"}) edn/read-string)) +(def config (infra/load-config)) (defn trim-text [text] (let [max-post-length (masto/max-post-length (mastodon-config config))] @@ -139,7 +128,7 @@ (fn [timeline] (let [last-post-time (-> timeline first :created_at (js/Date.))] ;;post from Twitter - (when-let [twitter-config (::twitter config)] + (when-let [twitter-config (:twitter config)] (let [{:keys [access-keys accounts include-replies? include-rts?]} twitter-config client (twitter-client access-keys)] (doseq [account accounts] diff --git a/src/main/mastodon_bot/mastodon_api.cljs b/src/main/mastodon_bot/mastodon_api.cljs index f56273f..9a8b839 100755 --- a/src/main/mastodon_bot/mastodon_api.cljs +++ b/src/main/mastodon_bot/mastodon_api.cljs @@ -29,33 +29,33 @@ (s/def ::content-filters (s/* ::content-filter)) (s/def ::keyword-filters (s/* ::keyword-filter)) -(s/def ::mastodon-js-config (s/keys :req [::access_token ::api_url])) -(s/def ::mastodon-clj-config (s/keys :req [::account-id ::content-filters ::keyword-filters - ::max-post-length ::signature ::visibility - ::append-screen-name? ::sensitive? ::resolve-urls? - ::nitter-urls? ::replacements])) +(s/def ::mastodon-js-config (s/keys :req-un [::access_token ::api_url])) +(s/def ::mastodon-clj-config (s/keys :req-un [::account-id ::content-filters ::keyword-filters + ::max-post-length ::signature ::visibility + ::append-screen-name? ::sensitive? ::resolve-urls? + ::nitter-urls? ::replacements])) (def mastodon-config? (s/merge ::mastodon-js-config ::mastodon-clj-config)) (defn-spec content-filter-regexes ::content-filters [mastodon-config mastodon-config?] - (mapv re-pattern (::content-filters mastodon-config))) + (mapv re-pattern (:content-filters mastodon-config))) (defn-spec keyword-filter-regexes ::keyword-filters [mastodon-config mastodon-config?] - (mapv re-pattern (::keyword-filters mastodon-config))) + (mapv re-pattern (:keyword-filters mastodon-config))) (defn-spec append-screen-name? ::append-screen-name? [mastodon-config mastodon-config?] - (boolean (::append-screen-name? mastodon-config))) + (boolean (:append-screen-name? mastodon-config))) (defn-spec max-post-length ::max-post-length [mastodon-config mastodon-config?] - (::max-post-length mastodon-config)) + (:max-post-length mastodon-config)) (defn-spec perform-replacements string? [mastodon-config mastodon-config? text string?] - (reduce-kv string/replace text (::replacements mastodon-config))) + (reduce-kv string/replace text (:replacements mastodon-config))) (defn-spec mastodon-client any? [mastodon-config mastodon-config?] @@ -94,15 +94,15 @@ [mastodon-config mastodon-config? text string?] (cond-> text - (::resolve-urls? mastodon-config) + (:resolve-urls? mastodon-config) (string/replace shortened-url-pattern resolve-url) - (::nitter-urls? mastodon-config) + (:nitter-urls? mastodon-config) (string/replace #"https://twitter.com" "https://nitter.net"))) (defn-spec set-signature string? [mastodon-config mastodon-config? text string?] - (if-let [signature (::signature mastodon-config )] + (if-let [signature (:signature mastodon-config )] (str text "\n" signature) text)) @@ -112,7 +112,7 @@ ([mastodon-config status-text media-ids] (post-status mastodon-config status-text media-ids print)) ([mastodon-config status-text media-ids callback] - (let [{:mastodon-bot.mastodon-api/keys [sensitive? signature visibility]} mastodon-config] + (let [{:keys [sensitive? signature visibility]} mastodon-config] (-> (.post (mastodon-client mastodon-config) "statuses" (clj->js (merge {:status (->> status-text (resolve-urls mastodon-config) @@ -134,22 +134,24 @@ (defn post-status-with-images ([mastodon-config status-text urls] - (post-status-with-images mastodon-config status-text urls [])) - ([mastodon-config status-text [url & urls] ids] + (post-status-with-images mastodon-config status-text urls [] print)) + ([mastodon-config status-text urls ids] + (post-status-with-images mastodon-config status-text urls ids print)) + ([mastodon-config status-text [url & urls] ids callback] (if url (-> request (.get url) (.on "response" (fn [image-stream] (post-image mastodon-config image-stream status-text - #(post-status-with-images status-text urls (conj ids %)))))) - (post-status mastodon-config status-text (not-empty ids))))) + #(post-status-with-images status-text urls (conj ids %) callback))))) + (post-status mastodon-config status-text (not-empty ids) callback)))) (defn-spec get-mastodon-timeline any? [mastodon-config mastodon-config? callback fn?] (.then (.get (mastodon-client mastodon-config) - (str "accounts/" (::account-id mastodon-config)"/statuses") #js {}) + (str "accounts/" (:account-id mastodon-config)"/statuses") #js {}) #(let [response (-> % .-data infra/js->edn)] (if-let [error (::error response)] (infra/exit-with-error error)