mirror of
https://github.com/heyarne/airsonic-ui.git
synced 2026-05-06 18:33:38 +02:00
Add list of recent albums
This commit is contained in:
parent
6117b921a6
commit
8e799f651d
4 changed files with 85 additions and 28 deletions
|
|
@ -7,15 +7,14 @@
|
||||||
[airsonic-ui.db :as db]
|
[airsonic-ui.db :as db]
|
||||||
[clojure.string :as string]))
|
[clojure.string :as string]))
|
||||||
|
|
||||||
|
;; TODO:
|
||||||
;; TODO: Remove impurities
|
|
||||||
|
|
||||||
;; api related functions
|
;; api related functions
|
||||||
|
|
||||||
(defn ^:private uri-escape [s]
|
(defn ^:private uri-escape [s]
|
||||||
(js/encodeURIComponent s))
|
(js/encodeURIComponent s))
|
||||||
|
|
||||||
(defn api-url [endpoint params]
|
(defn ^:private api-url [endpoint params]
|
||||||
(let [query (->> (assoc params
|
(let [query (->> (assoc params
|
||||||
:f "json"
|
:f "json"
|
||||||
:c "airsonic-ui-cljs"
|
:c "airsonic-ui-cljs"
|
||||||
|
|
@ -25,13 +24,13 @@
|
||||||
(string/join "&"))]
|
(string/join "&"))]
|
||||||
(str config/server "/rest/" endpoint "?" query)))
|
(str config/server "/rest/" endpoint "?" query)))
|
||||||
|
|
||||||
(defn api-error?
|
(defn ^:private api-error?
|
||||||
"We need to look at the message body because the subsonic api always responds
|
"We need to look at the message body because the subsonic api always responds
|
||||||
with status 200"
|
with status 200"
|
||||||
[response]
|
[response]
|
||||||
(= "failed" (-> response :subsonic-response :status)))
|
(= "failed" (-> response :subsonic-response :status)))
|
||||||
|
|
||||||
(defn error-message
|
(defn ^:private error-message
|
||||||
[response]
|
[response]
|
||||||
(let [{:keys [code message]} (-> response :subsonic-response :error)]
|
(let [{:keys [code message]} (-> response :subsonic-response :error)]
|
||||||
(str "Code " code ": " message)))
|
(str "Code " code ": " message)))
|
||||||
|
|
@ -43,17 +42,38 @@
|
||||||
:http-xhrio {:method :get
|
:http-xhrio {:method :get
|
||||||
:uri (api-url "ping" {:u user :p pass})
|
:uri (api-url "ping" {:u user :p pass})
|
||||||
:response-format (ajax/json-response-format {:keywords? true})
|
:response-format (ajax/json-response-format {:keywords? true})
|
||||||
:on-success [::auth-successful user pass]
|
:on-success [::auth-success user pass]
|
||||||
:on-failure [::api-failure]}}))
|
:on-failure [::api-failure]}}))
|
||||||
|
|
||||||
|
;; TODO: Test that credentials are associated
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::auth-successful
|
::auth-success
|
||||||
(fn [{:keys [db]} [_ user pass response]]
|
(fn [{:keys [db]} [_ user pass response]]
|
||||||
;; TODO: Handle failures differently
|
;; TODO: Handle failures differently
|
||||||
(let [login {:u user :p pass}]
|
(let [login {:u user :p pass}]
|
||||||
{:navigate [login ::routes/main]
|
{:navigate [login ::routes/main]
|
||||||
:db (-> (update db :active-requests dec)
|
:db (-> (update db :active-requests #(max (dec %) 0))
|
||||||
(assoc :login login))})))
|
(assoc :login login))
|
||||||
|
:dispatch [::api-request "getAlbumList2" :albumList2 {:type "recent"}]})))
|
||||||
|
|
||||||
|
;; TODO: Test that credentials are actually taken
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::api-request
|
||||||
|
(fn [{:keys [db]} [_ endpoint k params]]
|
||||||
|
{:http-xhrio {:method :get
|
||||||
|
:uri (api-url endpoint (merge params (:login db)))
|
||||||
|
:response-format (ajax/json-response-format {:keywords? true})
|
||||||
|
:on-success [::api-success k]
|
||||||
|
:on-failure [::api-failure]}}))
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::api-success
|
||||||
|
(fn [db [_ k response]]
|
||||||
|
(println "api response" response)
|
||||||
|
;; we "unwrap" the responses
|
||||||
|
(assoc db :response (-> response :subsonic-response k))))
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::api-failure
|
::api-failure
|
||||||
|
|
@ -68,6 +88,7 @@
|
||||||
(fn [{:keys [db]} [_ route params query]]
|
(fn [{:keys [db]} [_ route params query]]
|
||||||
;; all the naviagation logic is in routes.cljs; all we need to do here
|
;; all the naviagation logic is in routes.cljs; all we need to do here
|
||||||
;; is say what actually happens once we've navigated succesfully
|
;; is say what actually happens once we've navigated succesfully
|
||||||
|
;; FIXME: This is really bad and wonky actually
|
||||||
{:navigate [(:login db) route params query]
|
{:navigate [(:login db) route params query]
|
||||||
:db (assoc db :current-route [route params query])}))
|
:db (assoc db :current-route [route params query])}))
|
||||||
|
|
||||||
|
|
@ -75,8 +96,8 @@
|
||||||
::routes/forbidden-route
|
::routes/forbidden-route
|
||||||
(fn [fx _]
|
(fn [fx _]
|
||||||
;; log out on 403
|
;; log out on 403
|
||||||
{:db db/default-db
|
{:navigate [nil routes/default-route]
|
||||||
:navigate [nil routes/default-route]}))
|
:db db/default-db}))
|
||||||
|
|
||||||
;; database reset / init
|
;; database reset / init
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,20 @@
|
||||||
|
|
||||||
(def default-route ::login)
|
(def default-route ::login)
|
||||||
|
|
||||||
(def routes
|
(def router
|
||||||
[["/" ::login]
|
(r/router [["/" ::login]
|
||||||
["/hello" ::main]])
|
["/hello" ::main]
|
||||||
|
["/album/:id" ::album-view]
|
||||||
|
["/artist/:id" ::artist-view]]))
|
||||||
|
|
||||||
(def protected-routes #{::main})
|
(def protected-routes #{::main ::album-view})
|
||||||
|
|
||||||
(defn is-authorized? [login route]
|
(defn is-authorized? [login route]
|
||||||
(or (not (protected-routes route)) login))
|
(or (not (protected-routes route)) login))
|
||||||
|
|
||||||
|
(defn url-for [k params]
|
||||||
|
(str "#" (r/resolve router k params)))
|
||||||
|
|
||||||
;; shouldn't need to change this
|
;; shouldn't need to change this
|
||||||
|
|
||||||
;; TODO: This is kind of ugly because at the moment r/navigate! is called twice.
|
;; TODO: This is kind of ugly because at the moment r/navigate! is called twice.
|
||||||
|
|
@ -22,7 +27,6 @@
|
||||||
"Registers a :navigate effect that can be used for navigation; opts will be
|
"Registers a :navigate effect that can be used for navigation; opts will be
|
||||||
passed to bide.core/start!"
|
passed to bide.core/start!"
|
||||||
[opts]
|
[opts]
|
||||||
(let [router (r/router routes)]
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:navigate
|
:navigate
|
||||||
(fn [[login route-id params query]]
|
(fn [[login route-id params query]]
|
||||||
|
|
@ -31,4 +35,4 @@
|
||||||
(do ;; 403 gets a special event
|
(do ;; 403 gets a special event
|
||||||
(println "Not authorized to navigate to " route-id)
|
(println "Not authorized to navigate to " route-id)
|
||||||
(re-frame/dispatch [::forbidden-route])))))
|
(re-frame/dispatch [::forbidden-route])))))
|
||||||
(r/start! router opts)))
|
(r/start! router opts))
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,17 @@
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(:login db)))
|
(:login db)))
|
||||||
|
|
||||||
;; ---
|
;; current hashbang
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
::current-route
|
::current-route
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(:current-route db)))
|
(:current-route db)))
|
||||||
|
|
||||||
|
;; ---
|
||||||
|
|
||||||
|
;; TODO: Make this nice and clean
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::current-album-list
|
||||||
|
(fn [db]
|
||||||
|
(-> db :response :album)))
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
[airsonic-ui.events :as events]
|
[airsonic-ui.events :as events]
|
||||||
[airsonic-ui.subs :as subs]))
|
[airsonic-ui.subs :as subs]))
|
||||||
|
|
||||||
|
;; login form
|
||||||
|
|
||||||
(defn login-form []
|
(defn login-form []
|
||||||
(let [user (r/atom "")
|
(let [user (r/atom "")
|
||||||
pass (r/atom "")]
|
pass (r/atom "")]
|
||||||
|
|
@ -21,10 +23,32 @@
|
||||||
[:div
|
[:div
|
||||||
[:button {:on-click #(re-frame/dispatch [::events/authenticate @user @pass])} "Submit"]]])))
|
[:button {:on-click #(re-frame/dispatch [::events/authenticate @user @pass])} "Submit"]]])))
|
||||||
|
|
||||||
(defn app [route]
|
;; album list
|
||||||
|
|
||||||
|
(defn album-item [album]
|
||||||
|
(let [{:keys [artist artistId name coverArt year id]} album]
|
||||||
|
[:div
|
||||||
|
;; link to artist page
|
||||||
|
[:a {:href (routes/url-for ::routes/artist-view {:id artistId})} artist]
|
||||||
|
" - "
|
||||||
|
;; link to album
|
||||||
|
[:a {:href (routes/url-for ::routes/album-view {:id id})} name] (when year (str " (" year ")"))]))
|
||||||
|
|
||||||
|
(defn album-list []
|
||||||
|
(let [albums @(re-frame/subscribe [::subs/current-album-list])]
|
||||||
|
[:ul
|
||||||
|
(map-indexed (fn [idx album]
|
||||||
|
[:li {:key idx} [album-item album]])
|
||||||
|
albums)]))
|
||||||
|
|
||||||
|
;; putting everything together
|
||||||
|
|
||||||
|
(defn app [route params query]
|
||||||
(let [login @(re-frame/subscribe [::subs/login])]
|
(let [login @(re-frame/subscribe [::subs/login])]
|
||||||
[:div
|
[:div
|
||||||
[:h2 (str "Currently logged in as " (:u login))]
|
[:h2 (str "Currently logged in as " (:u login))]
|
||||||
|
[:h3 (str "Recently played")]
|
||||||
|
[album-list]
|
||||||
[:a {:on-click #(re-frame/dispatch [::events/initialize-db]) :href "#"} "Logout"]]))
|
[:a {:on-click #(re-frame/dispatch [::events/initialize-db]) :href "#"} "Logout"]]))
|
||||||
|
|
||||||
(defn main-panel []
|
(defn main-panel []
|
||||||
|
|
@ -33,4 +57,4 @@
|
||||||
[:h1 "Airsonic"]
|
[:h1 "Airsonic"]
|
||||||
(case route
|
(case route
|
||||||
::routes/login [login-form]
|
::routes/login [login-form]
|
||||||
[app route])]))
|
[app route params query])]))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue