diff --git a/looptober.clj b/looptober.clj index 74fd5a6..3198e48 100644 --- a/looptober.clj +++ b/looptober.clj @@ -1,9 +1,9 @@ (ns looptober (:require [clojure.string :as str] - [org.httpkit.client :as http] - [org.httpkit.server :refer [run-server ]] + [clojure.data.xml :as xml] [cheshire.core :as json] - [clojure.data.xml :as xml])) + [org.httpkit.client :as http] + [org.httpkit.server :refer [run-server]])) (xml/alias-uri 'xspf "http://xspf.org/ns/0/") @@ -16,23 +16,25 @@ (def update-interval (* 1000 60 30)) ;; 30 min -(defn paginate! +(defn paginate "Fetch all mastodon statuses where `min-id` < status < `max-id`. Takes a `pred` to filter statuses, will stop if no status matches the pred." - ([url pred min-id] (paginate! url pred min-id nil)) - ([url pred min-id max-id] - (println "calling paginate! with" min-id max-id) - (let [req (http/get url {:query-params {:min_id min-id - :max_id max-id}}) + ([url token pred min-id] (paginate url token pred min-id nil)) + ([url token pred min-id max-id] + (println "calling paginate with" min-id max-id) + (let [opts (cond-> {:query-params {:min_id min-id + :max_id max-id}} + token (assoc :headers {"Authorization" (format "Bearer %s" token)})) + req (http/get url opts) result (filterv pred (json/parse-string (:body @req) true))] (concat result (when (seq result) - (paginate! url pred min-id (:id (last result)))))))) + (paginate url token pred min-id (:id (last result)))))))) (defn audio-attachment [status] (find-in #(= (:type %) "audio") (-> status :media_attachments))) -(defn fetch-loops! - ([instance-url] +(defn fetch-loops + ([instance-url token] ;; cache update logic (let [now (System/currentTimeMillis) [last-fetch statuses] (get @response-cache instance-url) @@ -41,10 +43,11 @@ (> (- now last-fetch) update-interval)) (let [updated (swap! response-cache assoc instance-url [now - (let [new-statuses (paginate! (format "%s/api/v1/timelines/tag/looptober" instance-url) + (let [new-statuses (paginate (format "%s/api/v1/timelines/tag/looptober" instance-url) + token (fn [status] (and (neg? (compare (:id max-status) (:id status))) - (neg? (compare (or (:created_at max-status) "2023-10-01T00:00:00.000Z") (:created_at status))))) + (neg? (compare (:created_at max-status "2023-10-01T00:00:00.000Z") (:created_at status))))) (:id max-status))] (concat (filterv audio-attachment new-statuses) statuses))]) [_ statuses] (get updated instance-url)] @@ -69,7 +72,7 @@ (:content status))] [::xspf/info (-> status :url)] [::xspf/duration (-> file :meta :original :duration (* 1000) int)] - [::xspf/location (:remote_url file)]])) statuses)]])) + [::xspf/location (:url file)]])) statuses)]])) (defn app [req] (let [instance-url (if (not= "/" (:uri req)) @@ -77,7 +80,8 @@ (-> (str/replace (:uri req) #"^/" "") (str/replace #".xspf$" ""))) "https://post.lurk.org") - statuses (fetch-loops! instance-url)] + token (some-> (:body req) (slurp) (json/parse-string true) :token) + statuses (fetch-loops instance-url token)] {:status 200 :headers {"Content-Type" "application/xspf+xml"} :body (xml/indent-str (->xspf statuses))}))