(ns dionysus.spotify (:require [clj-spotify.core :as spotify-api] [hato.client :as hc] [dotenv :as env] [overtone.at-at :as at]) (:import (java.util Date Calendar))) (def token (atom nil)) (defn search! [query] (spotify-api/search {:q query :type "track"} (:token @token))) (defn add-item-to-queue! [uri] ((spotify-api/api-post "me/player/queue" {:query-params [:uri]}) {:uri uri} (:token @token))) (defn get-current-track! [] (spotify-api/get-users-currently-playing-track {} (:token @token))) #_(:item (get-current-track!)) (defn get-track! [id] (spotify-api/get-a-track {:id id} (:token @token))) (defn get-artist! [id] (spotify-api/get-an-artist {:id id} (:token @token))) (defn parse-share-url [url] (when-let [parsed (->> url (re-seq #"https:\/\/open\.spotify\.com\/intl-de\/(track|artist)\/([0-9A-z]*)") first)] {:url (first parsed) :type (second parsed) :id (last parsed)})) (defn time-to-refresh-token? [] (when-let [t @token] (-> t :expires .getTime (- (.getTime (Date.))) (< 120000) ; Is token valid for under two minutes? ))) (def ^:private http-client (delay (hc/build-http-client {}))) (defn- update-token! [refresh-resp-body] (swap! token assoc :token (get refresh-resp-body "access_token")) (swap! token assoc :expires (let [calendar-instance (Calendar/getInstance)] (.setTime calendar-instance (Date.)) (.add calendar-instance Calendar/SECOND (get refresh-resp-body "expires_in")) (.getTime calendar-instance)))) (defn- request-new-token! [] (hc/post "https://accounts.spotify.com/api/token" {:http-client @http-client :throw-exceptions? false :content-type "application/x-www-form-urlencoded" :form-params {"grant_type" "refresh_token" "refresh_token" (:refresh-token @token)} :basic-auth {:user (env/env "SPOTIFY_CLIENT_ID") :pass (env/env "SPOTIFY_CLIENT_SECRET")} :as :json-string-keys})) (defn- refresh-token! [] (when (time-to-refresh-token?) (let [resp (request-new-token!)] (if (= (:status resp) 200) (do (update-token! (:body resp)) (println "refreshed token")) (println "refreshing token failed"))))) (def ^:private at-pool (at/mk-pool)) (defn start-token-watcher! [] (at/every 60000 refresh-token! at-pool))