Skip to content

Instantly share code, notes, and snippets.

@yogthos
Last active August 23, 2018 12:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yogthos/d8745f75fc930d5b255193f94e82d6f4 to your computer and use it in GitHub Desktop.
Save yogthos/d8745f75fc930d5b255193f94e82d6f4 to your computer and use it in GitHub Desktop.
Twitter to Markdown
{:access-keys
{:consumer_key "XXXX"
:consumer_secret "XXXX"
:access_token_key "XXXX"
:access_token_secret "XXXX"
:account "arstechnica"
:content-filters [".*badwords.*"]
:include-replies? true
:include-rts? true
:output-file "tweets.md"}
#!/usr/bin/env lumo
(ns twitter-to-md.core
(:require
[cljs.core :refer [*command-line-args*]]
[cljs.reader :as edn]
[clojure.set :refer [rename-keys]]
[clojure.string :as string]
["fs" :as fs]
["http" :as http]
["https" :as https]
["twitter" :as twitter]))
(defn exit-with-error [error]
(js/console.error error)
(js/process.exit 1))
(defn find-config []
(or (first *command-line-args*)
(-> js/process .-env .-TWITTER_BOT_CONFIG)
"config.edn"))
(def config (-> (find-config) (fs/readFileSync #js {:encoding "UTF-8"}) edn/read-string))
(def access-keys (or (:access-keys config clj->js)
(exit-with-error "missing Twitter client configuration!")))
(def content-filter-regexes (mapv re-pattern (:content-filters config)))
(defn blocked-content? [text]
(boolean (some #(re-find % text) content-filter-regexes)))
(defn js->edn [data]
(js->clj data :keywordize-keys true))
(defn format-date [date-str]
(.toLocaleDateString (js/Date. date-str) "en-US" #js {:year "numeric" :month "short" :day "numeric"}))
(defn format-links [links]
(string/join
(for [link (keep #(when (= (:type %) "photo") (:media_url_https %)) links)]
(str "\n![" link "](" link ")"))))
(defn parse-tweet [{created-at :created_at
text :text
{:keys [media]} :extended_entities
{:keys [screen_name]} :user :as tweet}]
(str "### " screen_name " - " (format-date created-at) "\n" text (format-links media)))
(defn post-items [items]
(.writeFileSync fs (:output-file config) (string/join "\n\n" items)))
(defn post-tweets []
(fn [error tweets response]
(->> (js->edn tweets)
(map parse-tweet)
(post-items))))
(defn twitter-client []
(try
(twitter. (clj->js access-keys))
(catch js/Error e
(exit-with-error
(str "failed to connect to Twitter: " (.-message e))))))
(let [{:keys [account include-replies? include-rts?]} config
client (twitter-client)]
(.get client
"statuses/user_timeline"
#js {:screen_name account
:include_rts (boolean include-replies?)
:exclude_replies (boolean include-rts?)}
(post-tweets)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment