diff --git a/src/cljs/airsonic_ui/api/helpers.cljs b/src/cljs/airsonic_ui/api/helpers.cljs index 6959015..8483861 100644 --- a/src/cljs/airsonic_ui/api/helpers.cljs +++ b/src/cljs/airsonic_ui/api/helpers.cljs @@ -6,16 +6,29 @@ :c "airsonic-ui-cljs" :v "1.15.0"}) +(defn- unroll-variadic-params + "Turns {:id [1 2 3], :foo :bar} into [[:id 1] [:id 2] [:id 3] [:foo :bar]]" + [params] + (->> + (map (fn [[k vs]] + (if (sequential? vs) + (map (fn [v] [k v]) vs) + [k vs])) params) + (flatten) + (partition 2))) + (def ^:private encode js/encodeURIComponent) (defn url "Returns an absolute url to an API endpoint" [credentials endpoint params] (let [server (:server credentials) - query (->> (merge default-params (select-keys credentials [:u :p]) params) + auth (select-keys credentials [:u :p]) + query (->> (merge default-params auth params) + (unroll-variadic-params) (map (fn [[k v]] (str (encode (name k)) "=" (encode v)))) (str/join "&"))] - (str server (when-not (str/ends-with? server "/") "/") "rest/" endpoint "?" query))) + (str (str/replace server #"/+$" "") "/rest/" endpoint "?" query))) (defn stream-url [credentials song-or-episode] ;; podcasts have a stream-id, normal songs just use their id @@ -63,4 +76,3 @@ #{:artistId :name :songCount :artist} :album #{:id :name :albumCount} :artist :unknown))) - diff --git a/test/cljs/airsonic_ui/api/helpers_test.cljs b/test/cljs/airsonic_ui/api/helpers_test.cljs index 3c50ab3..53ea60f 100644 --- a/test/cljs/airsonic_ui/api/helpers_test.cljs +++ b/test/cljs/airsonic_ui/api/helpers_test.cljs @@ -26,6 +26,17 @@ encoded-str (js/encodeURIComponent query)] (is (str/includes? (api/url {:server "http://localhost"} "search3" {:query query}) encoded-str))))) +(deftest variadic-parameters + (testing "Should append list-like parameters correctly" + (is (= (count (re-seq #"id=" (api/url {:server "http://localost"} "test" {:id []}))) 0)) + (is (= (count (re-seq #"id=" (api/url {:server "http://localost"} "test" {:id [1]}))) 1)) + (is (= (count (re-seq #"id=" (api/url {:server "http://localost"} "test" {:id (range 10)}))) 10))) + (testing "Should keep the non-lists" + (let [mixed (api/url {:server "http://localost"} "test" {:id (range 5) :foo "bar"})] + (is (some? (re-find #"u=user" (api/url {:server "http://localhost"} "test" {:u "user"})))) + (is (and (some? (re-find #"foo=bar" mixed)) + (= (count (re-seq #"id=" mixed)) 5)))))) + (deftest stream-urls (testing "Should construct the url based on a song's id" (let [stream-url (api/stream-url {:server "http://localhost"} fixtures/song)]