aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Ángel Moreno <mail@migalmoreno.com>2024-11-05 00:02:10 +0100
committerMiguel Ángel Moreno <mail@migalmoreno.com>2024-11-05 01:18:11 +0100
commit01c3e19c6b0964a5947dad514533eb34a085dfb7 (patch)
treec5bf59a03408ad3f9b7358dada6848fd15908e46
parente3a01a35348e28469238b03717aa78cd2a4eedc2 (diff)
chore: apply formatting and linting
-rw-r--r--build.clj25
-rw-r--r--deps.edn52
-rw-r--r--src/backend/tubo/core.clj8
-rw-r--r--src/backend/tubo/downloader_impl.clj70
-rw-r--r--src/backend/tubo/handler.clj57
-rw-r--r--src/backend/tubo/http.clj9
-rw-r--r--src/backend/tubo/routes.clj32
-rw-r--r--src/frontend/tubo/api.cljs12
-rw-r--r--src/frontend/tubo/bookmarks/events.cljs168
-rw-r--r--src/frontend/tubo/bookmarks/modals.cljs11
-rw-r--r--src/frontend/tubo/bookmarks/views.cljs32
-rw-r--r--src/frontend/tubo/channel/events.cljs27
-rw-r--r--src/frontend/tubo/channel/views.cljs21
-rw-r--r--src/frontend/tubo/comments/events.cljs27
-rw-r--r--src/frontend/tubo/comments/views.cljs47
-rw-r--r--src/frontend/tubo/components/items.cljs88
-rw-r--r--src/frontend/tubo/components/layout.cljs75
-rw-r--r--src/frontend/tubo/components/navigation.cljs31
-rw-r--r--src/frontend/tubo/components/player.cljs149
-rw-r--r--src/frontend/tubo/core.cljs5
-rw-r--r--src/frontend/tubo/events.cljs78
-rw-r--r--src/frontend/tubo/kiosks/events.cljs85
-rw-r--r--src/frontend/tubo/kiosks/views.cljs24
-rw-r--r--src/frontend/tubo/modals/events.cljs21
-rw-r--r--src/frontend/tubo/modals/views.cljs2
-rw-r--r--src/frontend/tubo/notifications/events.cljs22
-rw-r--r--src/frontend/tubo/notifications/views.cljs6
-rw-r--r--src/frontend/tubo/player/events.cljs175
-rw-r--r--src/frontend/tubo/player/subs.cljs18
-rw-r--r--src/frontend/tubo/player/views.cljs106
-rw-r--r--src/frontend/tubo/playlist/events.cljs26
-rw-r--r--src/frontend/tubo/playlist/views.cljs14
-rw-r--r--src/frontend/tubo/queue/events.cljs48
-rw-r--r--src/frontend/tubo/queue/views.cljs69
-rw-r--r--src/frontend/tubo/routes.cljs91
-rw-r--r--src/frontend/tubo/search/events.cljs40
-rw-r--r--src/frontend/tubo/search/views.cljs16
-rw-r--r--src/frontend/tubo/services/events.cljs7
-rw-r--r--src/frontend/tubo/services/views.cljs12
-rw-r--r--src/frontend/tubo/settings/events.cljs49
-rw-r--r--src/frontend/tubo/settings/views.cljs17
-rw-r--r--src/frontend/tubo/stream/events.cljs28
-rw-r--r--src/frontend/tubo/stream/views.cljs31
-rw-r--r--src/frontend/tubo/subs.cljs2
-rw-r--r--src/frontend/tubo/utils.cljs16
-rw-r--r--src/frontend/tubo/views.cljs4
46 files changed, 1149 insertions, 804 deletions
diff --git a/build.clj b/build.clj
index 02ca14e..5535bc7 100644
--- a/build.clj
+++ b/build.clj
@@ -9,28 +9,31 @@
(def basis (b/create-basis {:project "deps.edn"}))
(def uber-file (format "target/%s-%s.jar" (name lib) version))
-(defn clean [_]
+(defn clean
+ [_]
(b/delete {:path "target"}))
-(defn aot-compile [_]
+(defn aot-compile
+ [_]
(println "Compiling AOT namespaces...")
- (b/compile-clj {:basis basis
- :src-dir ["src"]
- :class-dir class-dir
+ (b/compile-clj {:basis basis
+ :src-dir ["src"]
+ :class-dir class-dir
:ns-compile ['tubo.downloader-impl]})
(println "Compiled AOT namespaces"))
-(defn uberjar [_]
+(defn uberjar
+ [_]
(clean nil)
(aot-compile nil)
- (b/copy-dir {:src-dirs ["src/clj" "resources"]
+ (b/copy-dir {:src-dirs ["src/clj" "resources"]
:target-dir class-dir})
- (b/compile-clj {:basis basis
- :src-dir ["src"]
+ (b/compile-clj {:basis basis
+ :src-dir ["src"]
:class-dir class-dir})
(shadow/release :tubo)
(b/uber {:class-dir class-dir
:uber-file uber-file
- :basis basis
- :main 'tubo.core})
+ :basis basis
+ :main 'tubo.core})
(println "Uberjar: " uber-file))
diff --git a/deps.edn b/deps.edn
index ddd9f13..74a7ea3 100644
--- a/deps.edn
+++ b/deps.edn
@@ -1,34 +1,34 @@
{:deps {com.github.TeamNewPipe/NewpipeExtractor {:mvn/version "0.22.7"}
- com.squareup.okhttp3/okhttp {:mvn/version "4.10.0"}
- http-kit/http-kit {:mvn/version "2.7.0-alpha1"}
- metosin/reitit-core {:mvn/version "0.5.18"}
- metosin/reitit-ring {:mvn/version "0.5.18"}
- metosin/reitit-middleware {:mvn/version "0.5.18"}
- metosin/reitit-malli {:mvn/version "0.5.18"}
- ring/ring {:mvn/version "1.9.5"}
- ring/ring-json {:mvn/version "0.5.1"}
- org.clojure/java.data {:mvn/version "1.0.95"}
- hiccup/hiccup {:mvn/version "1.0.5"}
- ring-cors/ring-cors {:mvn/version "0.1.13"}}
+ com.squareup.okhttp3/okhttp {:mvn/version "4.10.0"}
+ http-kit/http-kit {:mvn/version "2.7.0-alpha1"}
+ metosin/reitit-core {:mvn/version "0.5.18"}
+ metosin/reitit-ring {:mvn/version "0.5.18"}
+ metosin/reitit-middleware {:mvn/version "0.5.18"}
+ metosin/reitit-malli {:mvn/version "0.5.18"}
+ ring/ring {:mvn/version "1.9.5"}
+ ring/ring-json {:mvn/version "0.5.1"}
+ org.clojure/java.data {:mvn/version "1.0.95"}
+ hiccup/hiccup {:mvn/version "1.0.5"}
+ ring-cors/ring-cors {:mvn/version "0.1.13"}}
:paths ["src/backend" "resources" "classes"]
:mvn/repos {"jitpack" {:url "https://jitpack.io"}}
:aliases
- {:build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.4"}}
+ {:build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.4"}}
:ns-default build}
:frontend
{:extra-paths ["src/frontend"]
- :extra-deps {thheller/shadow-cljs {:mvn/version "2.28.8"}
- cider/cider-nrepl {:mvn/version "0.28.4"}
- metosin/reitit-frontend {:mvn/version "0.5.18"}
- reagent/reagent {:mvn/version "1.1.1"}
- re-frame/re-frame {:mvn/version "1.3.0"}
- day8.re-frame/http-fx {:mvn/version "0.2.4"}
- cljs-ajax/cljs-ajax {:mvn/version "0.8.4"}
- akiroz.re-frame/storage {:mvn/version "0.1.4"}
- re-frame-utils/re-frame-utils {:mvn/version "0.1.0"}
- nano-id/nano-id {:mvn/version "1.1.0"}
- com.github.scopews/svgreq {:mvn/version "1.1.0"}
- funcool/promesa {:mvn/version "11.0.678"}
- re-promise/re-promise {:mvn/version "0.1.1"}}
- :main-opts ["-m" "shadow.cljs.devtools.cli"]}
+ :extra-deps {thheller/shadow-cljs {:mvn/version "2.28.8"}
+ cider/cider-nrepl {:mvn/version "0.28.4"}
+ metosin/reitit-frontend {:mvn/version "0.5.18"}
+ reagent/reagent {:mvn/version "1.1.1"}
+ re-frame/re-frame {:mvn/version "1.3.0"}
+ day8.re-frame/http-fx {:mvn/version "0.2.4"}
+ cljs-ajax/cljs-ajax {:mvn/version "0.8.4"}
+ akiroz.re-frame/storage {:mvn/version "0.1.4"}
+ re-frame-utils/re-frame-utils {:mvn/version "0.1.0"}
+ nano-id/nano-id {:mvn/version "1.1.0"}
+ com.github.scopews/svgreq {:mvn/version "1.1.0"}
+ funcool/promesa {:mvn/version "11.0.678"}
+ re-promise/re-promise {:mvn/version "0.1.1"}}
+ :main-opts ["-m" "shadow.cljs.devtools.cli"]}
:run {:main-opts ["-m" "tubo.core"]}}}
diff --git a/src/backend/tubo/core.clj b/src/backend/tubo/core.clj
index a587909..48a8897 100644
--- a/src/backend/tubo/core.clj
+++ b/src/backend/tubo/core.clj
@@ -3,10 +3,6 @@
(:require
[tubo.http :as http]))
-(defn -main
- [& _]
- (http/start-server!))
+(defn -main [& _] (http/start-server!))
-(defn reset
- []
- (http/stop-server!))
+(defn reset [] (http/stop-server!))
diff --git a/src/backend/tubo/downloader_impl.clj b/src/backend/tubo/downloader_impl.clj
index e22a2da..7cb0872 100644
--- a/src/backend/tubo/downloader_impl.clj
+++ b/src/backend/tubo/downloader_impl.clj
@@ -1,33 +1,36 @@
(ns tubo.downloader-impl
(:import
- [org.schabi.newpipe.extractor.downloader Response Request]
+ [org.schabi.newpipe.extractor.downloader Response]
[okhttp3 Request$Builder OkHttpClient$Builder RequestBody]))
(gen-class
- :name tubo.DownloaderImpl
+ :name tubo.DownloaderImpl
:constructors {[okhttp3.OkHttpClient$Builder] []}
- :extends org.schabi.newpipe.extractor.downloader.Downloader
- :init downloader-impl)
+ :extends org.schabi.newpipe.extractor.downloader.Downloader
+ :init downloader-impl)
(gen-class
- :name tubo.DownloaderImpl
+ :name tubo.DownloaderImpl
:constructors {[okhttp3.OkHttpClient$Builder] []}
- :extends org.schabi.newpipe.extractor.downloader.Downloader
- :prefix "-"
- :main false
- :state state
- :init downloader-impl
- :methods [#^{:static true} [init [] tubo.DownloaderImpl]
- #^{:static true} [getInstance [] tubo.DownloaderImpl]])
+ :extends org.schabi.newpipe.extractor.downloader.Downloader
+ :prefix "-"
+ :main false
+ :state state
+ :init downloader-impl
+ :methods [#^{:static true} [init [] tubo.DownloaderImpl]
+ #^{:static true} [getInstance [] tubo.DownloaderImpl]])
-(def user-agent "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0")
+(def user-agent
+ "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0")
(def instance (atom nil))
-(defn -downloader-impl [builder]
- [[] (atom {:client
- (.. builder
- (readTimeout 30 (java.util.concurrent.TimeUnit/SECONDS))
- (build))})])
+(defn -downloader-impl
+ [builder]
+ [[]
+ (atom {:client
+ (.. builder
+ (readTimeout 30 (java.util.concurrent.TimeUnit/SECONDS))
+ (build))})])
(defn -init
([]
@@ -35,33 +38,37 @@
([builder]
(reset! instance (tubo.DownloaderImpl. builder))))
-(defn -getInstance []
+(defn -getInstance
+ []
(or @instance (-init)))
-(defn -execute [this request]
- (let [http-method (.httpMethod request)
- url (.url request)
- headers (.headers request)
- data-to-send (.dataToSend request)
- request-body (and data-to-send (RequestBody/create nil data-to-send))
+(defn -execute
+ [this request]
+ (let [http-method (.httpMethod request)
+ url (.url request)
+ headers (.headers request)
+ data-to-send (.dataToSend request)
+ request-body (and data-to-send (RequestBody/create nil data-to-send))
request-builder (.. (Request$Builder.)
(method http-method request-body)
(url url)
(addHeader "User-Agent" user-agent))]
(doseq [pair (.entrySet headers)]
- (let [header-name (.getKey pair)
+ (let [header-name (.getKey pair)
header-value-list (.getValue pair)]
(if (> (.size header-value-list) 1)
(do
(.removeHeader request-builder header-name)
(doseq [header-value header-value-list]
(.addHeader request-builder header-name header-value)))
- (if (= (.size header-value-list) 1)
+ (when (= (.size header-value-list) 1)
(.header request-builder header-name (.get header-value-list 0))))))
- (let [response (.. (@(.state this) :client) (newCall (.build request-builder)) (execute))
- body (.body response)
+ (let [response (.. (@(.state this) :client)
+ (newCall (.build request-builder))
+ (execute))
+ body (.body response)
response-body-to-return (and body (.string body))
- latest-url (.. response (request) (url) (toString))]
+ latest-url (.. response (request) (url) (toString))]
(when (= (.code response) 429)
(.close response))
(Response. (.code response)
@@ -70,4 +77,5 @@
response-body-to-return
latest-url))))
-(comment (compile 'tubo.downloader-impl))
+(comment
+ (compile 'tubo.downloader-impl))
diff --git a/src/backend/tubo/handler.clj b/src/backend/tubo/handler.clj
index 4b37494..ab66d0f 100644
--- a/src/backend/tubo/handler.clj
+++ b/src/backend/tubo/handler.clj
@@ -3,11 +3,7 @@
[clojure.string :as str]
[hiccup.page :as hiccup]
[ring.util.response :refer [response]]
- [tubo.api.streams :as streams]
- [tubo.api.channels :as channels]
- [tubo.api.playlists :as playlists]
- [tubo.api.comments :as comments]
- [tubo.api.services :as services]))
+ [tubo.api :as api]))
(defn index
[_]
@@ -17,9 +13,10 @@
[:meta {:charset "UTF-8"}]
[:meta
{:name "viewport"
- :content "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"}]
+ :content
+ "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"}]
[:title "Tubo"]
- [:link {:rel "icon" :type "image/png" :href "/icons/tubo.svg"}]
+ [:link {:rel "icon" :type "image/svg+xml" :href "/icons/tubo.svg"}]
(hiccup/include-css "/styles/index.css")]
[:body
[:div#app]
@@ -28,46 +25,54 @@
(defn search
[{:keys [parameters] :as req}]
- (let [{:keys [service-id]} (:path parameters)
- {:keys [q]} (:query parameters)
+ (let [{:keys [service-id]} (:path parameters)
+ {:keys [q]} (:query parameters)
{:strs [contentFilters sortFilter nextPage]} (:query-params req)
- content-filters (and contentFilters (str/split contentFilters #","))]
+ content-filters (and contentFilters
+ (str/split
+ contentFilters
+ #","))]
(response (if nextPage
- (services/search service-id q contentFilters sortFilter nextPage)
- (services/search service-id q contentFilters sortFilter)))))
+ (api/get-search service-id q contentFilters sortFilter nextPage)
+ (api/get-search service-id q contentFilters sortFilter)))))
(defn channel
[{{:keys [url]} :path-params {:strs [nextPage]} :query-params}]
(response (if nextPage
- (channels/get-channel url nextPage)
- (channels/get-channel url))))
+ (api/get-channel url nextPage)
+ (api/get-channel url))))
(defn playlist
[{{:keys [url]} :path-params {:strs [nextPage]} :query-params}]
(response (if nextPage
- (playlists/get-playlist url nextPage)
- (playlists/get-playlist url))))
+ (api/get-playlist url nextPage)
+ (api/get-playlist url))))
(defn comments
[{{:keys [url]} :path-params {:strs [nextPage]} :query-params}]
(response (if nextPage
- (comments/get-comments url nextPage)
- (comments/get-comments url))))
+ (api/get-comments url nextPage)
+ (api/get-comments url))))
(defn services
[_]
- (response (services/get-services)))
+ (response (api/get-services)))
(defn kiosks
[{{{:keys [service-id]} :path} :parameters}]
- (response (services/get-kiosks service-id)))
+ (response (api/get-kiosks service-id)))
(defn kiosk
- [{{{:keys [kiosk-id service-id]} :path} :parameters {:strs [nextPage]} :query-params}]
+ [{{{:keys [kiosk-id service-id]} :path} :parameters
+ {:strs [nextPage]} :query-params}]
(response (cond
- (and kiosk-id service-id nextPage) (services/get-kiosk kiosk-id service-id nextPage)
- (and kiosk-id service-id) (services/get-kiosk kiosk-id service-id)
- :else (services/get-kiosk service-id))))
+ (and kiosk-id service-id nextPage) (api/get-kiosk kiosk-id
+ service-id
+ nextPage)
+ (and kiosk-id service-id) (api/get-kiosk kiosk-id
+ service-id)
+ :else (api/get-kiosk service-id))))
-(defn stream [{{:keys [url]} :path-params}]
- (response (streams/get-stream url)))
+(defn stream
+ [{{:keys [url]} :path-params}]
+ (response (api/get-stream url)))
diff --git a/src/backend/tubo/http.clj b/src/backend/tubo/http.clj
index 9ee87f3..200b52e 100644
--- a/src/backend/tubo/http.clj
+++ b/src/backend/tubo/http.clj
@@ -10,15 +10,10 @@
(defonce server (atom nil))
(defn start-server!
- ([]
- (start-server! 3000))
+ ([] (start-server! 3000))
([port]
(NewPipe/init (DownloaderImpl/init) (Localization. "en" "US"))
(reset! server (run-server #'routes/app {:port port}))
(println "Server running in port" port)))
-(defn stop-server!
- []
- (when @server
- (@server :timeout 100)
- (reset! server nil)))
+(defn stop-server! [] (when @server (@server :timeout 100) (reset! server nil)))
diff --git a/src/backend/tubo/routes.clj b/src/backend/tubo/routes.clj
index edf4876..7a3a456 100644
--- a/src/backend/tubo/routes.clj
+++ b/src/backend/tubo/routes.clj
@@ -1,14 +1,11 @@
(ns tubo.routes
(:require
- [malli.experimental.lite :as l]
[reitit.ring :as ring]
- [reitit.coercion :as coercion]
[reitit.ring.coercion :as rrc]
[reitit.coercion.malli]
[ring.middleware.reload :refer [wrap-reload]]
[ring.middleware.params :refer [wrap-params]]
[ring.middleware.json :refer [wrap-json-response]]
- [ring.middleware.cors :refer [wrap-cors]]
[tubo.handler :as handler]))
(def router
@@ -26,21 +23,24 @@
["/services"
["" {:get handler/services}]
["/:service-id/search"
- {:get {:coercion reitit.coercion.malli/coercion
- :parameters {:path {:service-id int?}
+ {:get {:coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int?}
:query {:q string?}}
- :handler handler/search}}]
+ :handler handler/search}}]
["/:service-id"
- ["/default-kiosk" {:get {:coercion reitit.coercion.malli/coercion
- :parameters {:path {:service-id int?}}
- :handler handler/kiosk}}]
+ ["/default-kiosk"
+ {:get {:coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int?}}
+ :handler handler/kiosk}}]
["/kiosks"
- ["" {:get {:coercion reitit.coercion.malli/coercion
- :parameters {:path {:service-id int?}}
- :handler handler/kiosks}}]
- ["/:kiosk-id" {:get {:coercion reitit.coercion.malli/coercion
- :parameters {:path {:service-id int? :kiosk-id string?}}
- :handler handler/kiosk}}]]]]
+ [""
+ {:get {:coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int?}}
+ :handler handler/kiosks}}]
+ ["/:kiosk-id"
+ {:get {:coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int? :kiosk-id string?}}
+ :handler handler/kiosk}}]]]]
["/streams/:url" {:get handler/stream}]
["/channels/:url" {:get handler/channel}]
["/playlists/:url" {:get handler/playlist}]
@@ -55,7 +55,7 @@
(ring/routes
(ring/create-resource-handler {:path "/"})
(ring/create-default-handler
- {:not-found (constantly {:status 404, :body "Not found"})}))
+ {:not-found (constantly {:status 404 :body "Not found"})}))
{:middleware [wrap-params
[wrap-json-response {:pretty true}]
wrap-reload]}))
diff --git a/src/frontend/tubo/api.cljs b/src/frontend/tubo/api.cljs
index 41ca410..fea688a 100644
--- a/src/frontend/tubo/api.cljs
+++ b/src/frontend/tubo/api.cljs
@@ -6,10 +6,10 @@
([uri on-success on-failure]
(get-request uri on-success on-failure {}))
([uri on-success on-failure params]
- {:http-xhrio {:method :get
- :uri (str "/api/v1" uri)
- :params params
- :format (ajax/json-request-format)
+ {:http-xhrio {:method :get
+ :uri (str "/api/v1" uri)
+ :params params
+ :format (ajax/json-request-format)
:response-format (ajax/json-response-format {:keywords? true})
- :on-success on-success
- :on-failure on-failure}}))
+ :on-success on-success
+ :on-failure on-failure}}))
diff --git a/src/frontend/tubo/bookmarks/events.cljs b/src/frontend/tubo/bookmarks/events.cljs
index e0f2f2b..decb107 100644
--- a/src/frontend/tubo/bookmarks/events.cljs
+++ b/src/frontend/tubo/bookmarks/events.cljs
@@ -2,14 +2,15 @@
(:require
[nano-id.core :refer [nano-id]]
[promesa.core :as p]
- [re-frame.core :as rf]
- [tubo.bookmarks.modals :as modals]))
+ [re-frame.core :as rf]))
(rf/reg-event-fx
:bookmarks/add
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ bookmark notify?]]
- (let [updated-db (update db :bookmarks conj
+ (let [updated-db (update db
+ :bookmarks
+ conj
(if (:id bookmark)
bookmark
(assoc bookmark :id (nano-id))))]
@@ -17,26 +18,31 @@
:store (assoc store :bookmarks (:bookmarks updated-db))
:fx [[:dispatch [:modals/close]]
(when notify?
- [:dispatch [:notifications/add
- {:status-text
- (str "Added playlist \"" (:name bookmark) "\"")
- :failure :success}]])]})))
+ [:dispatch
+ [:notifications/add
+ {:status-text
+ (str "Added playlist \"" (:name bookmark) "\"")
+ :failure :success}]])]})))
(rf/reg-event-fx
:bookmarks/remove
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ id notify?]]
(let [bookmark (first (filter #(= (:id %) id) (:bookmarks db)))
- updated-db (update db :bookmarks
- #(into [] (remove (fn [bookmark]
- (= (:id bookmark) id)) %)))]
+ updated-db (update db
+ :bookmarks
+ #(into []
+ (remove (fn [bookmark]
+ (= (:id bookmark) id))
+ %)))]
{:db updated-db
:store (assoc store :bookmarks (:bookmarks updated-db))
:fx (if notify?
- [[:dispatch [:notifications/add
- {:status-text
- (str "Removed playlist \"" (:name bookmark) "\"")
- :failure :success}]]]
+ [[:dispatch
+ [:notifications/add
+ {:status-text
+ (str "Removed playlist \"" (:name bookmark) "\"")
+ :failure :success}]]]
[])})))
(rf/reg-event-fx
@@ -49,63 +55,82 @@
(map (fn [item]
[:dispatch [:likes/remove item]])
(:items (first (:bookmarks db)))))
- [:dispatch [:notifications/add
- {:status-text "Cleared all playlists"
- :failure :success}]])}))
+ [:dispatch
+ [:notifications/add
+ {:status-text "Cleared all playlists"
+ :failure :success}]])}))
(rf/reg-event-fx
:likes/add-n
(fn [_ [_ items]]
{:fx (conj (map (fn [item]
- [:dispatch [:likes/add item]]) items)
- [:dispatch [:notifications/add
- {:status-text (str "Added " (count items)
- " items to likes")
- :failure :success}]])}))
+ [:dispatch [:likes/add item]])
+ items)
+ [:dispatch
+ [:notifications/add
+ {:status-text (str "Added "
+ (count items)
+ " items to likes")
+ :failure :success}]])}))
(rf/reg-event-fx
:likes/add
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ item notify?]]
(when-not (some #(= (:url %) (:url item))
- (-> db :bookmarks first :items))
- (let [updated-db (update-in db [:bookmarks 0 :items]
+ (-> db
+ :bookmarks
+ first
+ :items))
+ (let [updated-db (update-in db
+ [:bookmarks 0 :items]
#(into [] (conj (into [] %1) %2))
- (assoc item :bookmark-id
- (-> db :bookmarks first :id)))]
+ (assoc item
+ :bookmark-id
+ (-> db
+ :bookmarks
+ first
+ :id)))]
{:db updated-db
:store (assoc store :bookmarks (:bookmarks updated-db))
:fx (if notify?
- [[:dispatch [:notifications/add
- {:status-text "Added to favorites"
- :failure :success}]]]
+ [[:dispatch
+ [:notifications/add
+ {:status-text "Added to favorites"
+ :failure :success}]]]
[])}))))
(rf/reg-event-fx
:likes/remove
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ item notify?]]
- (let [updated-db (update-in db [:bookmarks 0 :items]
+ (let [updated-db (update-in db
+ [:bookmarks 0 :items]
(fn [items]
(remove #(= (:url %) (:url item)) items)))]
{:db updated-db
:store (assoc store :bookmarks (:bookmarks updated-db))
:fx (if notify?
- [[:dispatch [:notifications/add
- {:status-text "Removed from favorites"
- :failure :success}]]]
+ [[:dispatch
+ [:notifications/add
+ {:status-text "Removed from favorites"
+ :failure :success}]]]
[])})))
(rf/reg-event-fx
:bookmark/add-n
(fn [_ [_ bookmark items]]
{:fx (conj (map (fn [item]
- [:dispatch [:bookmark/add bookmark item]]) items)
- [:dispatch [:notifications/add
- {:status-text (str "Added " (count items)
- " items to playlist \""
- (:name bookmark) "\"")
- :failure :success}]])}))
+ [:dispatch [:bookmark/add bookmark item]])
+ items)
+ [:dispatch
+ [:notifications/add
+ {:status-text (str "Added "
+ (count items)
+ " items to playlist \""
+ (:name bookmark)
+ "\"")
+ :failure :success}]])}))
(rf/reg-event-fx
:bookmark/add
@@ -115,17 +140,20 @@
pos (.indexOf (:bookmarks db) selected)
updated-db (if (some #(= (:url %) (:url item)) (:items selected))
db
- (update-in db [:bookmarks pos :items]
+ (update-in db
+ [:bookmarks pos :items]
#(into [] (conj (into [] %1) %2))
(assoc item :bookmark-id (:id bookmark))))]
{:db updated-db
:store (assoc store :bookmarks (:bookmarks updated-db))
:fx [[:dispatch [:modals/close]]
(when notify?
- [:dispatch [:notifications/add
- {:status-text (str "Added to playlist \""
- (:name selected) "\"")
- :failure :success}]])]})))
+ [:dispatch
+ [:notifications/add
+ {:status-text (str "Added to playlist \""
+ (:name selected)
+ "\"")
+ :failure :success}]])]})))
(rf/reg-event-fx
:bookmark/remove
@@ -134,28 +162,32 @@
(let [selected (first (filter #(= (:id %) (:bookmark-id bookmark))
(:bookmarks db)))
pos (.indexOf (:bookmarks db) selected)
- updated-db (update-in db [:bookmarks pos :items]
+ updated-db (update-in db
+ [:bookmarks pos :items]
#(remove (fn [item]
(= (:url item) (:url bookmark)))
%))]
{:db updated-db
:store (assoc store :bookmarks (:bookmarks updated-db))
- :fx [[:dispatch [:notifications/add
- {:status-text (str "Removed from playlist \""
- (:name selected) "\"")
- :failure :success}]]]})))
+ :fx [[:dispatch
+ [:notifications/add
+ {:status-text (str "Removed from playlist \""
+ (:name selected)
+ "\"")
+ :failure :success}]]]})))
(rf/reg-event-fx
:bookmarks/add-imported
- (fn [{:keys [db]} [_ bookmarks]]
+ (fn [_ [_ bookmarks]]
{:fx (conj (map-indexed (fn [i bookmark]
(if (= i 0)
[:dispatch [:likes/add-n (:items bookmark)]]
[:dispatch [:bookmarks/add bookmark]]))
bookmarks)
- [:dispatch [:notifications/add
- {:status-text "Imported playlists successfully"
- :failure :success}]])}))
+ [:dispatch
+ [:notifications/add
+ {:status-text "Imported playlists successfully"
+ :failure :success}]])}))
(defn fetch-imported-bookmarks-items
[bookmarks]
@@ -172,17 +204,18 @@
(rf/reg-event-fx
:bookmarks/process-import
- (fn [{:keys [db]} [_ bookmarks]]
+ (fn [_ [_ bookmarks]]
{:promise
{:call #(-> (fetch-imported-bookmarks-items bookmarks)
(p/then (fn [res]
(js->clj res :keywordize-keys true))))
:on-success-n [[:notifications/clear]
[:bookmarks/add-imported]]}
- :fx [[:dispatch [:notifications/add
- {:status-text "Importing playlists..."
- :failure :success}
- false]]]}))
+ :fx [[:dispatch
+ [:notifications/add
+ {:status-text "Importing playlists..."
+ :failure :success}
+ false]]]}))
(rf/reg-fx
:bookmarks/import!
@@ -194,14 +227,14 @@
(rf/dispatch [:bookmarks/process-import (:playlists res)])
(throw (js/Error. "Format not supported")))))
(p/catch js/Error
- (fn [error]
- (rf/dispatch [:notifications/add
- {:status-text (.-message error)
- :failure :error}]))))))
+ (fn [error]
+ (rf/dispatch [:notifications/add
+ {:status-text (.-message error)
+ :failure :error}]))))))
(rf/reg-event-fx
:bookmarks/import
- (fn [{:keys [db]} [_ files]]
+ (fn [_ [_ files]]
{:fx (map (fn [file] [:bookmarks/import! file]) files)}))
(rf/reg-event-fx
@@ -212,16 +245,17 @@
:mime-type "application/json"
:data (.stringify
js/JSON
- (clj->js {:format "Tubo"
+ (clj->js {:format "Tubo"
:version 1
:playlists
(map (fn [bookmark]
{:name (:name bookmark)
:items (map :url (:items bookmark))})
(:bookmarks db))}))}
- :fx [[:dispatch [:notifications/add
- {:status-text "Exported playlists"
- :failure :success}]]]}))
+ :fx [[:dispatch
+ [:notifications/add
+ {:status-text "Exported playlists"
+ :failure :success}]]]}))
(rf/reg-event-fx
:bookmarks/fetch-page
diff --git a/src/frontend/tubo/bookmarks/modals.cljs b/src/frontend/tubo/bookmarks/modals.cljs
index 6edc1ce..f8a1738 100644
--- a/src/frontend/tubo/bookmarks/modals.cljs
+++ b/src/frontend/tubo/bookmarks/modals.cljs
@@ -2,16 +2,19 @@
(:require
[reagent.core :as r]
[re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
[tubo.components.layout :as layout]
[tubo.modals.views :as modals]))
(defn bookmark-item
- [{:keys [items id name] :as bookmark} item]
+ [{:keys [items name] :as bookmark} item]
[:div.flex.w-full.h-24.rounded.px-2.cursor-pointer.hover:bg-gray-100.dark:hover:bg-stone-800
- {:on-click #(rf/dispatch [(if (vector? item) :bookmark/add-n :bookmark/add) bookmark item])}
+ {:on-click #(rf/dispatch [(if (vector? item) :bookmark/add-n :bookmark/add)
+ bookmark item])}
[:div.w-24
- [layout/thumbnail (-> items first :thumbnail-url) nil name nil
+ [layout/thumbnail
+ (-> items
+ first
+ :thumbnail-url) nil name nil
:classes [:h-24 :py-2] :rounded? true]]
[:div.flex.flex-col.py-4.px-4
[:h1.line-clamp-1.font-bold {:title name} name]
diff --git a/src/frontend/tubo/bookmarks/views.cljs b/src/frontend/tubo/bookmarks/views.cljs
index c25a0b4..4bfd96e 100644
--- a/src/frontend/tubo/bookmarks/views.cljs
+++ b/src/frontend/tubo/bookmarks/views.cljs
@@ -11,14 +11,18 @@
[]
(let [!menu-active? (r/atom nil)]
(fn []
- (let [color @(rf/subscribe [:service-color])
- bookmarks @(rf/subscribe [:bookmarks])
+ (let [bookmarks @(rf/subscribe [:bookmarks])
items (map
#(assoc %
- :url (rfe/href :bookmark-page nil {:id (:id %)})
- :thumbnail-url (-> % :items first :thumbnail-url)
- :stream-count (count (:items %))
- :bookmark-id (:id %))
+ :stream-count (count (:items %))
+ :bookmark-id (:id %)
+ :url (rfe/href :bookmark-page
+ nil
+ {:id (:id %)})
+ :thumbnail-url (-> %
+ :items
+ first
+ :thumbnail-url))
bookmarks)]
[layout/content-container
[layout/content-header "Bookmarked Playlists"
@@ -32,10 +36,12 @@
:type "file"
:multiple "multiple"
:on-click #(reset! !menu-active? true)
- :on-change #(rf/dispatch [:bookmarks/import (.. % -target -files)])}]
+ :on-change #(rf/dispatch [:bookmarks/import
+ (.. % -target -files)])}]
[:label.whitespace-nowrap.cursor-pointer.w-full.h-full.absolute.right-0.top-0
{:for "file-selector"}]
- [:span.text-xs.w-10.min-w-4.w-4.flex.items-center [:i.fa-solid.fa-file-import]]
+ [:span.text-xs.w-10.min-w-4.w-4.flex.items-center
+ [:i.fa-solid.fa-file-import]]
[:span "Import"]]
{:label "Export"
:icon [:i.fa-solid.fa-file-export]
@@ -50,9 +56,9 @@
(let [!menu-active? (r/atom nil)]
(fn []
(let [bookmarks @(rf/subscribe [:bookmarks])
- service-color @(rf/subscribe [:service-color])
{{:keys [id]} :query-params} @(rf/subscribe [:current-match])
- {:keys [items name]} (first (filter #(= (:id %) id) bookmarks))]
+ {:keys [items name]} (first (filter #(= (:id %) id)
+ bookmarks))]
[layout/content-container
[layout/content-header name
(when-not (empty? items)
@@ -62,5 +68,7 @@
:on-click #(rf/dispatch [:queue/add-n items true])}
{:label "Add to playlist"
:icon [:i.fa-solid.fa-plus]
- :on-click #(rf/dispatch [:modals/open [modals/add-to-bookmark items]])}]])]
- [items/related-streams (map #(assoc % :type "stream" :bookmark-id id) items)]]))))
+ :on-click #(rf/dispatch [:modals/open
+ [modals/add-to-bookmark items]])}]])]
+ [items/related-streams
+ (map #(assoc % :type "stream" :bookmark-id id) items)]]))))
diff --git a/src/frontend/tubo/channel/events.cljs b/src/frontend/tubo/channel/events.cljs
index 5036e73..b8e5fb0 100644
--- a/src/frontend/tubo/channel/events.cljs
+++ b/src/frontend/tubo/channel/events.cljs
@@ -7,16 +7,18 @@
(rf/reg-event-fx
:channel/fetch
- (fn [{:keys [db]} [_ uri on-success on-error]]
+ (fn [_ [_ uri on-success on-error]]
(api/get-request
(str "/channels/" (js/encodeURIComponent uri))
- on-success on-error)))
+ on-success
+ on-error)))
(rf/reg-event-fx
:channel/load-page
(fn [{:keys [db]} [_ res]]
(let [channel-res (js->clj res :keywordize-keys true)]
- {:db (assoc db :channel channel-res
+ {:db (assoc db
+ :channel channel-res
:show-page-loading false)
:fx [[:dispatch [:services/fetch channel-res]]
[:document-title (:name channel-res)]]})))
@@ -24,15 +26,17 @@
(rf/reg-event-fx
:channel/bad-page-response
(fn [{:keys [db]} [_ uri res]]
- {:fx [[:dispatch [:change-view #(layout/error res [:channel/fetch-page uri])]]]
+ {:fx [[:dispatch
+ [:change-view #(layout/error res [:channel/fetch-page uri])]]]
:db (assoc db :show-page-loading false)}))
(rf/reg-event-fx
:channel/fetch-page
(fn [{:keys [db]} [_ uri]]
{:fx [[:dispatch [:change-view channel/channel]]
- [:dispatch [:channel/fetch uri [:channel/load-page]
- [:channel/bad-page-response uri]]]]
+ [:dispatch
+ [:channel/fetch uri [:channel/load-page]
+ [:channel/bad-page-response uri]]]]
:db (assoc db :show-page-loading true)}))
(rf/reg-event-db
@@ -44,7 +48,8 @@
(assoc-in [:channel :next-page] nil)
(assoc :show-pagination-loading false))
(-> db
- (update-in [:channel :related-streams] #(apply conj %1 %2)
+ (update-in [:channel :related-streams]
+ #(apply conj %1 %2)
(:related-streams channel-res))
(assoc-in [:channel :next-page] (:next-page channel-res))
(assoc :show-pagination-loading false))))))
@@ -62,7 +67,9 @@
{:db (assoc db :show-pagination-loading false)}
(assoc
(api/get-request
- (str "/channels/" (js/encodeURIComponent uri) )
- [:channel/load-paginated] [:channel/bad-paginated-response]
+ (str "/channels/" (js/encodeURIComponent uri))
+ [:channel/load-paginated]
+ [:channel/bad-paginated-response]
{:nextPage (js/encodeURIComponent next-page-url)})
- :db (assoc db :show-pagination-loading true)))))
+ :db
+ (assoc db :show-pagination-loading true)))))
diff --git a/src/frontend/tubo/channel/views.cljs b/src/frontend/tubo/channel/views.cljs
index 6994318..9986ca1 100644
--- a/src/frontend/tubo/channel/views.cljs
+++ b/src/frontend/tubo/channel/views.cljs
@@ -7,16 +7,16 @@
[tubo.components.layout :as layout]))
(defn channel
- [query-params]
- (let [!menu-active? (r/atom nil)
+ [_]
+ (let [!menu-active? (r/atom nil)
!show-description? (r/atom false)]
(fn [{{:keys [url]} :query-params}]
(let [{:keys [banner avatar name description subscriber-count next-page
- related-streams]} @(rf/subscribe [:channel])
- next-page-url (:url next-page)
- service-color @(rf/subscribe [:service-color])
- scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])
- page-loading? @(rf/subscribe [:show-page-loading])]
+ related-streams]}
+ @(rf/subscribe [:channel])
+ next-page-url (:url next-page)
+ scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])
+ page-loading? @(rf/subscribe [:show-page-loading])]
(when (and next-page-url scrolled-to-bottom?)
(rf/dispatch [:channel/fetch-paginated url next-page-url]))
[:<>
@@ -27,7 +27,8 @@
[layout/content-container
[:div.flex.items-center.justify-between
[:div.flex.items-center.my-4.mx-2
- [layout/uploader-avatar {:uploader-avatar avatar :uploader-name name}]
+ [layout/uploader-avatar
+ {:uploader-avatar avatar :uploader-name name}]
[:div.m-4
[:h1.text-2xl.line-clamp-1.font-semibold {:title name} name]
(when subscriber-count
@@ -41,7 +42,9 @@
:on-click #(rf/dispatch [:queue/add-n related-streams true])}
{:label "Add to playlist"
:icon [:i.fa-solid.fa-plus]
- :on-click #(rf/dispatch [:modals/open [modals/add-to-bookmark related-streams]])}]])]
+ :on-click #(rf/dispatch [:modals/open
+ [modals/add-to-bookmark
+ related-streams]])}]])]
(when-not (empty? description)
[layout/show-more-container @!show-description? description
#(reset! !show-description? (not @!show-description?))])
diff --git a/src/frontend/tubo/comments/events.cljs b/src/frontend/tubo/comments/events.cljs
index 1d78af3..f8122cd 100644
--- a/src/frontend/tubo/comments/events.cljs
+++ b/src/frontend/tubo/comments/events.cljs
@@ -5,9 +5,12 @@
(rf/reg-event-fx
:comments/fetch
- (fn [{:keys [db]} [_ url on-success on-error params]]
- (api/get-request (str "/comments/" (js/encodeURIComponent url))
- on-success on-error params)))
+ (fn [_ [_ url on-success on-error params]]
+ (api/get-request (str "/comments/"
+ (js/encodeURIComponent url))
+ on-success
+ on-error
+ params)))
(rf/reg-event-db
:comments/load-page
@@ -19,8 +22,9 @@
(rf/reg-event-fx
:comments/fetch-page
(fn [{:keys [db]} [_ url]]
- {:fx [[:dispatch [:comments/fetch url
- [:comments/load-page] [:bad-response]]]]
+ {:fx [[:dispatch
+ [:comments/fetch url
+ [:comments/load-page] [:bad-response]]]]
:db (-> db
(assoc-in [:stream :show-comments-loading] true)
(assoc-in [:stream :show-comments] true))}))
@@ -28,7 +32,8 @@
(rf/reg-event-db
:comments/toggle-replies
(fn [db [_ comment-id]]
- (update-in db [:stream :comments-page :comments]
+ (update-in db
+ [:stream :comments-page :comments]
(fn [comments]
(map #(if (= (:id %) comment-id)
(assoc % :show-replies (not (:show-replies %)))
@@ -39,7 +44,8 @@
:comments/load-paginated
(fn [db [_ res]]
(-> db
- (update-in [:stream :comments-page :comments] #(apply conj %1 %2)
+ (update-in [:stream :comments-page :comments]
+ #(apply conj %1 %2)
(:comments (js->clj res :keywordize-keys true)))
(assoc-in [:stream :comments-page :next-page]
(:next-page (js->clj res :keywordize-keys true)))
@@ -51,6 +57,7 @@
(if (empty? next-page-url)
{:db (assoc db :show-pagination-loading false)}
{:db (assoc db :show-pagination-loading true)
- :fx [[:dispatch [:comments/fetch url
- [:comments/load-paginated] [:bad-response]
- {:nextPage (js/encodeURIComponent next-page-url)}]]]})))
+ :fx [[:dispatch
+ [:comments/fetch url
+ [:comments/load-paginated] [:bad-response]
+ {:nextPage (js/encodeURIComponent next-page-url)}]]]})))
diff --git a/src/frontend/tubo/comments/views.cljs b/src/frontend/tubo/comments/views.cljs
index e9b5867..e1f6472 100644
--- a/src/frontend/tubo/comments/views.cljs
+++ b/src/frontend/tubo/comments/views.cljs
@@ -6,23 +6,28 @@
[tubo.utils :as utils]))
(defn comment-top-metadata
- [{:keys [pinned? uploader-name uploader-url uploader-verified? stream-position]}]
+ [{:keys [pinned? uploader-name uploader-url uploader-verified?
+ stream-position]}]
[:div.flex.items-center
(when pinned?
[:i.fa-solid.fa-thumbtack.mr-2.text-xs])
(when uploader-name
[:div.flex.items-stretch
- [:a {:href (rfe/href :channel-page nil {:url uploader-url})
- :title uploader-name}
- [:h1.text-neutral-800.dark:text-gray-300.font-bold.line-clamp-1 uploader-name]]
+ [:a
+ {:href (rfe/href :channel-page nil {:url uploader-url})
+ :title uploader-name}
+ [:h1.text-neutral-800.dark:text-gray-300.font-bold.line-clamp-1
+ uploader-name]]
(when stream-position
[:div.text-neutral-600.dark:text-neutral-300
- [:span.mx-2.text-xs.whitespace-nowrap (utils/format-duration stream-position)]])])
+ [:span.mx-2.text-xs.whitespace-nowrap
+ (utils/format-duration stream-position)]])])
(when uploader-verified?
[:i.fa-solid.fa-circle-check.ml-2])])
(defn comment-bottom-metadata
- [{:keys [upload-date like-count hearted-by-uploader? author-avatar author-name]}]
+ [{:keys [upload-date like-count hearted-by-uploader? author-avatar
+ author-name]}]
[:div.flex.items-center.my-2
[:div.mr-4
[:p (utils/format-date-ago upload-date)]]
@@ -34,8 +39,8 @@
[:div.relative.w-4.h-4.mx-2
[:i.fa-solid.fa-heart.absolute.-bottom-1.-right-1.text-xs.text-red-500]
[:img.rounded-full.object-covermax-w-full.min-h-full
- {:src author-avatar :title (str author-name " hearted this comment")}]])])
-
+ {:src author-avatar
+ :title (str author-name " hearted this comment")}]])])
(defn comment-item
[{:keys [id text replies reply-count show-replies] :as comment}]
@@ -44,7 +49,9 @@
[:div
[comment-top-metadata comment]
[:div.my-2
- [:p {:dangerouslySetInnerHTML {:__html text} :class "[overflow-wrap:anywhere]"}]]
+ [:p
+ {:dangerouslySetInnerHTML {:__html text}
+ :class "[overflow-wrap:anywhere]"}]]
[comment-bottom-metadata comment]
[:div.flex.items-center.cursor-pointer
{:on-click #(rf/dispatch [:comments/toggle-replies id])}
@@ -54,23 +61,33 @@
[:p.font-bold "Hide replies"]
[:i.fa-solid.fa-turn-up.mx-2.text-xs]]
[:<>
- [:p.font-bold (str reply-count (if (= reply-count 1) " reply" " replies"))]
+ [:p.font-bold
+ (str reply-count (if (= reply-count 1) " reply" " replies"))]
[:i.fa-solid.fa-turn-down.mx-2.text-xs]]))]]])
(defn comments
- [{:keys [comments next-page disabled?]} {:keys [uploader-name uploader-avatar url]}]
+ [{:keys [comments next-page]}
+ {:keys [uploader-name uploader-avatar url]}]
(let [pagination-loading? @(rf/subscribe [:show-pagination-loading])
- service-color @(rf/subscribe [:service-color])]
+ service-color @(rf/subscribe [:service-color])]
[:div.flex.flex-col
[:div
- (for [[i {:keys [replies show-replies] :as comment}] (map-indexed vector comments)]
+ (for [[i {:keys [replies show-replies] :as comment}]
+ (map-indexed vector comments)]
[:div.flex.flex-col {:key i}
[:div.flex
- [comment-item (assoc comment :author-name uploader-name :author-avatar uploader-avatar)]]
+ [comment-item
+ (assoc comment
+ :author-name uploader-name
+ :author-avatar uploader-avatar)]]
(when (and replies show-replies)
[:div {:style {:marginLeft "32px"}}
(for [[i reply] (map-indexed vector (:items replies))]
- ^{:key i} [comment-item (assoc reply :author-name uploader-name :author-avatar uploader-avatar)])])])]
+ ^{:key i}
+ [comment-item
+ (assoc reply
+ :author-name uploader-name
+ :author-avatar uploader-avatar)])])])]
(when (:url next-page)
(if pagination-loading?
[layout/loading-icon service-color]
diff --git a/src/frontend/tubo/components/items.cljs b/src/frontend/tubo/components/items.cljs
index e23b823..605169d 100644
--- a/src/frontend/tubo/components/items.cljs
+++ b/src/frontend/tubo/components/items.cljs
@@ -11,41 +11,58 @@
(defn item-popover
[_ _]
(let [!menu-active? (r/atom nil)]
- (fn [{:keys [service-id audio-streams video-streams type url bookmark-id uploader-url] :as item} bookmarks]
- (let [liked? (some #(= (:url %) url) (-> bookmarks first :items))
- items (if (or (= type "stream") audio-streams video-streams)
- [{:label "Add to queue"
- :icon [:i.fa-solid.fa-headphones]
- :on-click #(rf/dispatch [:player/switch-to-background item true])}
- {:label "Play radio"
- :icon [:i.fa-solid.fa-tower-cell]
- :on-click #(rf/dispatch [:player/start-radio item])}
- {:label (if liked? "Remove favorite" "Favorite")
- :icon [:i.fa-solid.fa-heart (when (and liked? service-id)
- {:style {:color (utils/get-service-color service-id)}})]
- :on-click #(rf/dispatch [(if liked? :likes/remove :likes/add) item true])}
- {:label "Add to playlist"
- :icon [:i.fa-solid.fa-plus]
- :on-click #(rf/dispatch [:modals/open [bookmarks/add-to-bookmark item]])}
- (when (some #(= (:url %) url) (:items (first (filter #(= (:id %) bookmark-id) bookmarks))))
- {:label "Remove from playlist"
- :icon [:i.fa-solid.fa-trash]
- :on-click #(rf/dispatch [:bookmark/remove item])})
- {:label "Show channel details"
- :icon [:i.fa-solid.fa-user]
- :on-click #(rf/dispatch [:navigate
- {:name :channel-page
- :params {}
- :query {:url uploader-url}}])}]
- [(when (and bookmarks (some #(= (:id %) bookmark-id) (rest bookmarks)))
- {:label "Remove playlist"
- :icon [:i.fa-solid.fa-trash]
- :on-click #(rf/dispatch [:bookmarks/remove bookmark-id true])})])]
+ (fn [{:keys [service-id audio-streams video-streams type url bookmark-id
+ uploader-url]
+ :as item} bookmarks]
+ (let [liked? (some #(= (:url %) url)
+ (-> bookmarks
+ first
+ :items))
+ items
+ (if (or (= type "stream") audio-streams video-streams)
+ [{:label "Add to queue"
+ :icon [:i.fa-solid.fa-headphones]
+ :on-click #(rf/dispatch [:player/switch-to-background item
+ true])}
+ {:label "Play radio"
+ :icon [:i.fa-solid.fa-tower-cell]
+ :on-click #(rf/dispatch [:player/start-radio item])}
+ {:label (if liked? "Remove favorite" "Favorite")
+ :icon [:i.fa-solid.fa-heart
+ (when (and liked? service-id)
+ {:style {:color (utils/get-service-color
+ service-id)}})]
+ :on-click #(rf/dispatch [(if liked? :likes/remove :likes/add)
+ item true])}
+ {:label "Add to playlist"
+ :icon [:i.fa-solid.fa-plus]
+ :on-click #(rf/dispatch [:modals/open
+ [bookmarks/add-to-bookmark item]])}
+ (when (some #(= (:url %) url)
+ (:items (first (filter #(= (:id %) bookmark-id)
+ bookmarks))))
+ {:label "Remove from playlist"
+ :icon [:i.fa-solid.fa-trash]
+ :on-click #(rf/dispatch [:bookmark/remove item])})
+ {:label "Show channel details"
+ :icon [:i.fa-solid.fa-user]
+ :on-click #(rf/dispatch [:navigate
+ {:name :channel-page
+ :params {}
+ :query {:url uploader-url}}])}]
+ [(when (and bookmarks
+ (some #(= (:id %) bookmark-id) (rest bookmarks)))
+ {:label "Remove playlist"
+ :icon [:i.fa-solid.fa-trash]
+ :on-click #(rf/dispatch [:bookmarks/remove bookmark-id
+ true])})])]
(when (not-empty (remove nil? items))
[layout/popover-menu !menu-active? items])))))
(defn item-content
- [{:keys [url name uploader-url uploader-name subscriber-count view-count stream-count verified?] :as item} route bookmarks]
+ [{:keys [url name uploader-url uploader-name subscriber-count view-count
+ stream-count verified?]
+ :as item} route bookmarks]
[:div
(when name
[:div.flex.items-center.my-2
@@ -57,9 +74,10 @@
[:div.flex.items-center.my-2
(conj
(when uploader-url
- [:a {:href (rfe/href :channel-page nil {:url uploader-url})
- :title uploader-name
- :key url}])
+ [:a
+ {:href (rfe/href :channel-page nil {:url uploader-url})
+ :title uploader-name
+ :key url}])
[:h1.text-neutral-800.dark:text-gray-300.font-semibold.pr-2.line-clamp-1.break-all
{:class "[overflow-wrap:anywhere]" :title uploader-name :key url}
uploader-name])
@@ -109,5 +127,5 @@
{:class "xs:grid-cols-[repeat(auto-fill,_minmax(165px,_1fr))]"}
(for [[i item] (map-indexed vector related-streams)]
^{:key i} [generic-item item bookmarks])])
- (when (and pagination-loading? (not (empty? next-page-url)))
+ (when (and pagination-loading? (seq next-page-url))
[layout/loading-icon service-color :text-md])]))
diff --git a/src/frontend/tubo/components/layout.cljs b/src/frontend/tubo/components/layout.cljs
index d0bed45..c542574 100644
--- a/src/frontend/tubo/components/layout.cljs
+++ b/src/frontend/tubo/components/layout.cljs
@@ -1,5 +1,6 @@
(ns tubo.components.layout
(:require
+ [clojure.string :as str]
[re-frame.core :as rf]
[reitit.frontend.easy :as rfe]
[reagent.core :as r]
@@ -12,11 +13,13 @@
[:div.relative.min-w-full
[:a.absolute.min-w-full.min-h-full.z-10 {:href route :title name}]
(if thumbnail-url
- [:img.object-cover.min-h-full.max-h-full.min-w-full {:src thumbnail-url :class (when rounded? :rounded)}]
+ [:img.object-cover.min-h-full.max-h-full.min-w-full
+ {:src thumbnail-url :class (when rounded? :rounded)}]
[:div.bg-gray-300.flex.min-h-full.min-w-full.justify-center.items-center.rounded
[:i.fa-solid.fa-image.text-3xl.text-white]])
(when duration
- [:div.rounded.p-2.absolute {:style {:bottom 5 :right 5 :background "rgba(0,0,0,.7)" :zIndex "0"}}
+ [:div.rounded.p-2.absolute
+ {:style {:bottom 5 :right 5 :background "rgba(0,0,0,.7)" :zIndex "0"}}
[:p.text-white.text-md
(if (= duration 0)
"LIVE"
@@ -66,14 +69,15 @@
(conj
(when uploader-url
[:a.flex-auto.flex.min-h-full.min-w-full.max-h-full.max-w-full
- {:href (rfe/href :channel-page nil {:url uploader-url})
+ {:href (rfe/href :channel-page nil {:url uploader-url})
:title uploader-name
- :key uploader-url}])
+ :key uploader-url}])
[:img.flex-auto.rounded-full.object-cover.max-w-full.min-h-full
{:src uploader-avatar :alt uploader-name :key uploader-name}])]))
(defn button
- [label on-click left-icon right-icon & {:keys [button-classes label-classes icon-classes]}]
+ [label on-click left-icon right-icon &
+ {:keys [button-classes label-classes icon-classes]}]
[:button.px-4.rounded-3xl.py-1.outline-none.focus:ring-transparent.whitespace-nowrap
{:on-click on-click :class button-classes}
(when left-icon
@@ -86,21 +90,24 @@
[label on-click left-icon right-icon]
[button label on-click left-icon right-icon
:button-classes ["bg-stone-800" "dark:bg-white"]
- :label-classes ["text-neutral-300" "dark:text-neutral-900"]])
+ :label-classes ["text-neutral-300" "dark:text-neutral-900"]])
(defn secondary-button
[label on-click left-icon right-icon]
[button label on-click left-icon right-icon
- :button-classes ["bg-neutral-100" "dark:bg-transparent" "border" "border-neutral-300" "dark:border-stone-700"]
+ :button-classes
+ ["bg-neutral-100" "dark:bg-transparent" "border" "border-neutral-300"
+ "dark:border-stone-700"]
:label-classes ["text-neutral-500" "dark:text-white"]])
-(defn generic-input [label & children]
+(defn generic-input
+ [label & children]
[:div.w-full.flex.justify-between.items-center.py-2.gap-x-4
[:label label]
(map-indexed #(with-meta %2 {:key %1}) children)])
(defn text-input
- [label key value on-change placeholder]
+ [label _key value on-change placeholder]
[generic-input label
[:input.text-black
{:type "text"
@@ -109,7 +116,7 @@
:placeholder placeholder}]])
(defn boolean-input
- [label key value on-change]
+ [label _key value on-change]
[generic-input label
[:input
{:type "checkbox"
@@ -118,27 +125,34 @@
:on-change on-change}]])
(defn select-input
- [label key value options on-change]
+ [label _key value options on-change]
[generic-input label
[:select.focus:ring-transparent.bg-transparent.font-bold
{:value value
:on-change on-change}
(for [[i option] (map-indexed vector options)]
- ^{:key i} [:option.dark:bg-neutral-900.border-none {:value option :key i} option])]])
+ ^{:key i}
+ [:option.dark:bg-neutral-900.border-none {:value option :key i}
+ option])]])
(defn menu-item
[{:keys [label icon on-click link] :as item}]
(let [content [:<>
- [:span.text-xs.min-w-4.w-4.flex.justify-center.items-center icon]
+ [:span.text-xs.min-w-4.w-4.flex.justify-center.items-center
+ icon]
[:span.whitespace-nowrap label]]
- classes ["relative" "flex" "items-center" "gap-x-3" "hover:bg-neutral-200"
+ classes ["relative" "flex" "items-center" "gap-x-3"
+ "hover:bg-neutral-200"
"dark:hover:bg-stone-800" "py-2" "px-3" "rounded"]]
(if link
- [:a {:href (:route link) :target (when (:external? link) "_blank")
- :class (clojure.string/join " " classes)}
+ [:a
+ {:href (:route link)
+ :target (when (:external? link) "_blank")
+ :class (str/join " " classes)}
content]
- [:li {:on-click on-click
- :class (clojure.string/join " " classes)}
+ [:li
+ {:on-click on-click
+ :class (str/join " " classes)}
(if (vector? item) item content)])))
(defn menu
@@ -176,7 +190,7 @@
(map-indexed #(with-meta %2 {:key %1}) content))])
(defn show-more-container
- [open? text on-open]
+ [_open? _text _on-open]
(let [!text-container (atom nil)
!resize-observer (atom nil)
text-clamped? (r/atom nil)]
@@ -186,11 +200,11 @@
(when @!text-container
(.observe
(reset! !resize-observer
- (js/ResizeObserver.
- #(let [target (.-target (first %))]
- (reset! text-clamped?
- (> (.-scrollHeight target)
- (.-clientHeight target))))))
+ (js/ResizeObserver.
+ #(let [target (.-target (first %))]
+ (reset! text-clamped?
+ (> (.-scrollHeight target)
+ (.-clientHeight target))))))
@!text-container)))
:component-will-unmount
#(when (and @!resize-observer @!text-container)
@@ -200,17 +214,20 @@
[:div.py-3.min-w-full
[:span.text-clip.pr-2
{:dangerouslySetInnerHTML {:__html text}
- :class (when-not open? "line-clamp-2")
- :ref #(reset! !text-container %)}]
+ :class (when-not open? "line-clamp-2")
+ :ref #(reset! !text-container %)}]
(when (or @text-clamped? open?)
- [:button.font-bold {:on-click on-open} (str "show " (if open? "less" "more"))])])})))
+ [:button.font-bold {:on-click on-open}
+ (str "show " (if open? "less" "more"))])])})))
-(defn error [{:keys [failure parse-error status status-text]} cb]
+(defn error
+ [{:keys [_failure parse-error status status-text]} cb]
[:div.flex.flex-auto.h-full.items-center.justify-center.p-5
[:div.flex.flex-col.gap-y-6.border-border-neutral-300.rounded.dark:border-stone-700.bg-neutral-300.dark:bg-neutral-800.p-5
[:div.flex.items-center.gap-2.text-xl
[:i.fa-solid.fa-circle-exclamation]
- [:h3.font-bold (str status (when (and status status-text) ": ") status-text)]]
+ [:h3.font-bold
+ (str status (when (and status status-text) ": ") status-text)]]
(when parse-error
[:span (:status-text parse-error)])
[:div.flex.justify-center.gap-x-3
diff --git a/src/frontend/tubo/components/navigation.cljs b/src/frontend/tubo/components/navigation.cljs
index 72f733f..c5e58ed 100644
--- a/src/frontend/tubo/components/navigation.cljs
+++ b/src/frontend/tubo/components/navigation.cljs
@@ -1,7 +1,6 @@
(ns tubo.components.navigation
(:require
[re-frame.core :as rf]
- [reagent.core :as r]
[reitit.frontend.easy :as rfe]
[tubo.components.layout :as layout]
[tubo.kiosks.views :as kiosks]
@@ -17,35 +16,43 @@
[:span {:class (when active? "font-bold")} label]]])
(defn mobile-nav
- [show-mobile-nav? service-color services available-kiosks & {:keys [service-id] :as kiosk-args}]
+ [show-mobile-nav? service-color services available-kiosks &
+ {:keys [service-id] :as kiosk-args}]
[:<>
[layout/focus-overlay #(rf/dispatch [:toggle-mobile-nav]) show-mobile-nav?]
[:div.fixed.overflow-x-hidden.min-h-screen.w-60.top-0.transition-all.ease-in-out.delay-75.bg-white.dark:bg-neutral-900.z-20
{:class [(if show-mobile-nav? "left-0" "left-[-245px]")]}
- [:div.flex.justify-center.py-4.items-center.text-white {:style {:background service-color}}
+ [:div.flex.justify-center.py-4.items-center.text-white
+ {:style {:background service-color}}
[layout/logo :height 75 :width 75]
[:h3.text-3xl.font-bold "Tubo"]]
[services/services-dropdown services service-id service-color]
[:div.relative.py-4
[:ul.flex.flex-col
(for [[i kiosk] (map-indexed vector available-kiosks)]
- ^{:key i} [mobile-nav-item
- (rfe/href :kiosk-page nil {:serviceId service-id :kioskId kiosk})
- [:i.fa-solid.fa-fire] kiosk
- :active? (kiosks/kiosk-active? (assoc kiosk-args :kiosk kiosk))])]]
+ ^{:key i}
+ [mobile-nav-item
+ (rfe/href :kiosk-page nil {:serviceId service-id :kioskId kiosk})
+ [:i.fa-solid.fa-fire] kiosk
+ :active? (kiosks/kiosk-active? (assoc kiosk-args :kiosk kiosk))])]]
[:div.relative.dark:border-neutral-800.border-gray-300.pt-4
{:class "border-t-[1px]"}
[:ul.flex.flex-col
- [mobile-nav-item (rfe/href :bookmarks-page) [:i.fa-solid.fa-bookmark] "Bookmarks"]
- [mobile-nav-item (rfe/href :settings-page) [:i.fa-solid.fa-cog] "Settings"]]]]])
+ [mobile-nav-item (rfe/href :bookmarks-page) [:i.fa-solid.fa-bookmark]
+ "Bookmarks"]
+ [mobile-nav-item (rfe/href :settings-page) [:i.fa-solid.fa-cog]
+ "Settings"]]]]])
(defn navbar
[{{:keys [kioskId]} :query-params path :path}]
(let [service-id @(rf/subscribe [:service-id])
- service-color @(rf/subscribe [:service-color])
+ service-color @(rf/subscribe
+ [:service-color])
services @(rf/subscribe [:services])
- show-mobile-nav? @(rf/subscribe [:show-mobile-nav])
- show-search-form? @(rf/subscribe [:show-search-form])
+ show-mobile-nav? @(rf/subscribe
+ [:show-mobile-nav])
+ show-search-form? @(rf/subscribe
+ [:show-search-form])
{:keys [default-service]} @(rf/subscribe [:settings])
{:keys [available-kiosks default-kiosk]} @(rf/subscribe [:kiosks])]
[:nav.sticky.flex.items-center.px-2.h-14.top-0.z-20
diff --git a/src/frontend/tubo/components/player.cljs b/src/frontend/tubo/components/player.cljs
index e59d3b5..0373c27 100644
--- a/src/frontend/tubo/components/player.cljs
+++ b/src/frontend/tubo/components/player.cljs
@@ -1,19 +1,22 @@
(ns tubo.components.player
(:require
+ [clojure.string :as str]
[reagent.core :as r]
[re-frame.core :as rf]
- [reagent.core :as r]
- [reagent.dom :as rdom]
["@vidstack/react" :refer (MediaPlayer MediaProvider Poster)]
- ["@vidstack/react/player/layouts/default" :refer (defaultLayoutIcons DefaultVideoLayout DefaultAudioLayout)]))
+ ["@vidstack/react/player/layouts/default" :refer
+ (defaultLayoutIcons DefaultVideoLayout DefaultAudioLayout)]))
(defn get-video-player-sources
[available-streams service-id]
(if available-streams
(if (= service-id 3)
- (map (fn [{:keys [content]}] {:src content :type "video/mp4"}) (reverse available-streams))
+ (map (fn [{:keys [content]}] {:src content :type "video/mp4"})
+ (reverse available-streams))
(->> available-streams
- (filter #(and (not= (:format %) "WEBMA_OPUS") (not= (:format %) "OPUS") (not= (:format %) "M4A")))
+ (filter #(and (not= (:format %) "WEBMA_OPUS")
+ (not= (:format %) "OPUS")
+ (not= (:format %) "M4A")))
(sort-by :bitrate)
(#(if (empty? (filter (fn [x] (= (:format x) "MP3")) %))
(reverse %)
@@ -23,28 +26,34 @@
[]))
(defn video-player
- [stream !player]
- (let [!elapsed-time @(rf/subscribe [:elapsed-time])
+ [_stream _!player]
+ (let [!elapsed-time @(rf/subscribe [:elapsed-time])
!main-player-first? (r/atom true)]
(r/create-class
{:component-will-unmount #(rf/dispatch [:main-player/ready false])
:reagent-render
- (fn [{:keys [name video-streams audio-streams thumbnail-url service-id]} !player]
+ (fn [{:keys [name video-streams audio-streams thumbnail-url service-id]}
+ !player]
(let [show-main-player? @(rf/subscribe [:main-player/show])]
[:> MediaPlayer
{:title name
- :src (get-video-player-sources (into video-streams audio-streams) service-id)
+ :src (get-video-player-sources (into video-streams
+ audio-streams)
+ service-id)
:poster thumbnail-url
:class "w-full xl:w-3/5 overflow-hidden"
:playsInline true
:ref #(reset! !player %)
- :loop (when show-main-player? (= @(rf/subscribe [:loop-playback]) :stream))
+ :loop (when show-main-player?
+ (= @(rf/subscribe [:loop-playback]) :stream))
:onSeeked (when show-main-player?
#(reset! !elapsed-time (.-currentTime @!player)))
:onTimeUpdate (when show-main-player?
#(reset! !elapsed-time (.-currentTime @!player)))
:onEnded #(when show-main-player?
- (rf/dispatch [:queue/change-pos (inc @(rf/subscribe [:queue-pos]))])
+ (rf/dispatch [:queue/change-pos
+ (inc @(rf/subscribe
+ [:queue-pos]))])
(reset! !elapsed-time 0))
:onLoadedData (fn []
(when show-main-player?
@@ -56,9 +65,10 @@
:onSourceChange #(when-not @!main-player-first?
(reset! !elapsed-time 0))}
[:> MediaProvider
- [:> Poster {:src thumbnail-url
- :alt name
- :class :vds-poster}]]
+ [:> Poster
+ {:src thumbnail-url
+ :alt name
+ :class :vds-poster}]]
[:> DefaultVideoLayout {:icons defaultLayoutIcons}]]))})))
(defn get-audio-player-sources
@@ -71,13 +81,13 @@
[]))
(defn audio-player
- [stream !player]
+ [_stream _!player]
(let [!elapsed-time @(rf/subscribe [:elapsed-time])
!bg-player-first? (r/atom nil)]
(r/create-class
- {:component-will-unmount #(rf/dispatch [:background-player/ready false])
+ {:component-will-unmount #(rf/dispatch [:bg-player/ready false])
:reagent-render
- (fn [{:keys [name audio-streams thumbnail-url]} !player]
+ (fn [{:keys [name audio-streams]} !player]
[:> MediaPlayer
{:title name
:class "invisible fixed"
@@ -86,19 +96,20 @@
:viewType "audio"
:ref #(reset! !player %)
:loop (= @(rf/subscribe [:loop-playback]) :stream)
- :onCanPlay #(rf/dispatch [:background-player/ready true])
+ :onCanPlay #(rf/dispatch [:bg-player/ready true])
:onSeeked #(reset! !elapsed-time (.-currentTime @!player))
:onTimeUpdate #(reset! !elapsed-time (.-currentTime @!player))
:onEnded (fn []
- (rf/dispatch [:queue/change-pos (inc @(rf/subscribe [:queue-pos]))])
+ (rf/dispatch [:queue/change-pos
+ (inc @(rf/subscribe [:queue-pos]))])
(reset! !elapsed-time 0))
- :onPlay #(rf/dispatch [:background-player/play])
+ :onPlay #(rf/dispatch [:bg-player/play])
:onReplay (fn []
- (rf/dispatch [:background-player/set-paused false])
+ (rf/dispatch [:bg-player/set-paused false])
(reset! !elapsed-time 0))
- :onPause #(rf/dispatch [:background-player/set-paused true])
+ :onPause #(rf/dispatch [:bg-player/set-paused true])
:onLoadedData (fn []
- (rf/dispatch [:background-player/start])
+ (rf/dispatch [:bg-player/start])
(when-not @!bg-player-first?
(reset! !bg-player-first? true)))
:onSourceChange #(when @!bg-player-first?
@@ -107,7 +118,8 @@
[:> DefaultAudioLayout {:icons defaultLayoutIcons}]])})))
(defonce base-slider-classes
- ["h-2" "cursor-pointer" "appearance-none" "bg-neutral-300" "dark:bg-neutral-600"
+ ["h-2" "cursor-pointer" "appearance-none" "bg-neutral-300"
+ "dark:bg-neutral-600"
"rounded-full" "overflow-hidden" "focus:outline-none"
"[&::-webkit-slider-thumb]:appearance-none"
"[&::-webkit-slider-thumb]:border-0"
@@ -124,34 +136,50 @@
(defn get-slider-shadow-classes
[service-color]
(case service-color
- "#cc0000" ["[&::-webkit-slider-thumb]:shadow-[#cc0000]" "[&::-moz-range-thumb]:shadow-[#cc0000]"]
- "#ff7700" ["[&::-webkit-slider-thumb]:shadow-[#ff7700]" "[&::-moz-range-thumb]:shadow-[#ff7700]"]
- "#333333" ["[&::-webkit-slider-thumb]:shadow-[#333333]" "[&::-moz-range-thumb]:shadow-[#333333]"]
- "#F2690D" ["[&::-webkit-slider-thumb]:shadow-[#F2690D]" "[&::-moz-range-thumb]:shadow-[#F2690D]"]
- "#629aa9" ["[&::-webkit-slider-thumb]:shadow-[#629aa9]" "[&::-moz-range-thumb]:shadow-[#629aa9]"]
- ["[&::-webkit-slider-thumb]:shadow-neutral-300" "[&::-moz-range-thumb]:shadow-neutral-300"]))
+ "#cc0000" ["[&::-webkit-slider-thumb]:shadow-[#cc0000]"
+ "[&::-moz-range-thumb]:shadow-[#cc0000]"]
+ "#ff7700" ["[&::-webkit-slider-thumb]:shadow-[#ff7700]"
+ "[&::-moz-range-thumb]:shadow-[#ff7700]"]
+ "#333333" ["[&::-webkit-slider-thumb]:shadow-[#333333]"
+ "[&::-moz-range-thumb]:shadow-[#333333]"]
+ "#F2690D" ["[&::-webkit-slider-thumb]:shadow-[#F2690D]"
+ "[&::-moz-range-thumb]:shadow-[#F2690D]"]
+ "#629aa9" ["[&::-webkit-slider-thumb]:shadow-[#629aa9]"
+ "[&::-moz-range-thumb]:shadow-[#629aa9]"]
+ ["[&::-webkit-slider-thumb]:shadow-neutral-300"
+ "[&::-moz-range-thumb]:shadow-neutral-300"]))
(defn get-slider-bg-classes
[service-color]
(case service-color
- "#cc0000" ["[&::-webkit-slider-thumb]:bg-[#cc0000]" "[&::-moz-range-thumb]:bg-[#cc0000]"]
- "#ff7700" ["[&::-webkit-slider-thumb]:bg-[#ff7700]" "[&::-moz-range-thumb]:bg-[#ff7700]"]
- "#333333" ["[&::-webkit-slider-thumb]:bg-[#333333]" "[&::-moz-range-thumb]:bg-[#333333]"]
- "#F2690D" ["[&::-webkit-slider-thumb]:bg-[#F2690D]" "[&::-moz-range-thumb]:bg-[#F2690D]"]
- "#629aa9" ["[&::-webkit-slider-thumb]:bg-[#629aa9]" "[&::-moz-range-thumb]:bg-[#629aa9]"]
- ["[&::-webkit-slider-thumb]:bg-neutral-300" "[&::-moz-range-thumb]:bg-neutral-300"]))
+ "#cc0000" ["[&::-webkit-slider-thumb]:bg-[#cc0000]"
+ "[&::-moz-range-thumb]:bg-[#cc0000]"]
+ "#ff7700" ["[&::-webkit-slider-thumb]:bg-[#ff7700]"
+ "[&::-moz-range-thumb]:bg-[#ff7700]"]
+ "#333333" ["[&::-webkit-slider-thumb]:bg-[#333333]"
+ "[&::-moz-range-thumb]:bg-[#333333]"]
+ "#F2690D" ["[&::-webkit-slider-thumb]:bg-[#F2690D]"
+ "[&::-moz-range-thumb]:bg-[#F2690D]"]
+ "#629aa9" ["[&::-webkit-slider-thumb]:bg-[#629aa9]"
+ "[&::-moz-range-thumb]:bg-[#629aa9]"]
+ ["[&::-webkit-slider-thumb]:bg-neutral-300"
+ "[&::-moz-range-thumb]:bg-neutral-300"]))
-(defn time-slider [!player !elapsed-time service-color]
- (let [styles (concat base-slider-classes
- (get-slider-bg-classes service-color)
- (get-slider-shadow-classes service-color))
- bg-player-ready? @(rf/subscribe [:background-player/ready])]
+(defn time-slider
+ [!player !elapsed-time service-color]
+ (let [styles (concat base-slider-classes
+ (get-slider-bg-classes service-color)
+ (get-slider-shadow-classes service-color))
+ bg-player-ready? @(rf/subscribe [:bg-player/ready])]
[:input.w-full
{:class styles
:type "range"
:on-input #(reset! !elapsed-time (.. % -target -value))
- :on-change #(when (and bg-player-ready? @!player) (set! (.-currentTime @!player) @!elapsed-time))
- :max (if (and bg-player-ready? @!player (not (js/isNaN (.-duration @!player))))
+ :on-change #(when (and bg-player-ready? @!player)
+ (set! (.-currentTime @!player) @!elapsed-time))
+ :max (if (and bg-player-ready?
+ @!player
+ (not (js/isNaN (.-duration @!player))))
(.floor js/Math (.-duration @!player))
100)
:value @!elapsed-time}]))
@@ -159,29 +187,30 @@
(defn button
[& {:keys [icon on-click disabled? show-on-mobile? extra-classes]}]
[:button.outline-none.focus:ring-transparent.px-2.pt-1
- {:class (into (into (when disabled? [:opacity-50 :cursor-auto])
- (when-not show-on-mobile? [:hidden :lg:block]))
- extra-classes)
+ {:class (into (into (when disabled? [:opacity-50 :cursor-auto])
+ (when-not show-on-mobile? [:hidden :lg:block]))
+ extra-classes)
:on-click on-click}
icon])
(defn loop-button
[loop-playback color show-on-mobile?]
[button
- :icon [:div.relative.flex.items-center
- [:i.fa-solid.fa-repeat
- {:style {:color (when loop-playback color)}}]
- (when (= loop-playback :stream)
- [:div.absolute.w-full.h-full.flex.justify-center.items-center.font-bold
- {:class "text-[6px]"
- :style {:color (when loop-playback color)}}
- "1"])]
+ :icon
+ [:div.relative.flex.items-center
+ [:i.fa-solid.fa-repeat
+ {:style {:color (when loop-playback color)}}]
+ (when (= loop-playback :stream)
+ [:div.absolute.w-full.h-full.flex.justify-center.items-center.font-bold
+ {:class "text-[6px]"
+ :style {:color (when loop-playback color)}}
+ "1"])]
:on-click #(rf/dispatch [:player/loop])
:extra-classes [:text-sm]
:show-on-mobile? show-on-mobile?])
(defn volume-slider
- [player volume-level muted? service-color]
+ [_player _volume-level _muted? _service-color]
(let [show-slider? (r/atom nil)]
(fn [player volume-level muted? service-color]
(let [styles (concat ["rotate-[270deg]"]
@@ -192,13 +221,15 @@
{:on-mouse-over #(reset! show-slider? true)
:on-mouse-out #(reset! show-slider? false)}
[button
- :icon (if muted? [:i.fa-solid.fa-volume-xmark] [:i.fa-solid.fa-volume-low])
- :on-click #(rf/dispatch [:background-player/mute (not muted?) player])
+ :icon
+ (if muted? [:i.fa-solid.fa-volume-xmark] [:i.fa-solid.fa-volume-low])
+ :on-click #(rf/dispatch [:bg-player/mute (not muted?) player])
:extra-classes [:pl-3 :pr-2]]
(when @show-slider?
[:input.absolute.w-24.ml-2.m-1.bottom-16
- {:class (clojure.string/join " " styles)
+ {:class (str/join " " styles)
:type "range"
- :on-input #(rf/dispatch [:player/change-volume (.. % -target -value) player])
+ :on-input #(rf/dispatch [:player/change-volume
+ (.. % -target -value) player])
:max 100
:value volume-level}])]))))
diff --git a/src/frontend/tubo/core.cljs b/src/frontend/tubo/core.cljs
index 2153e50..c9f7e7c 100644
--- a/src/frontend/tubo/core.cljs
+++ b/src/frontend/tubo/core.cljs
@@ -16,7 +16,4 @@
(routes/start-routes!)
(.render root (r/as-element [(fn [] views/app)])))
-(defn ^:export init
- []
- (rf/dispatch-sync [:initialize-db])
- (mount-root))
+(defn ^:export init [] (rf/dispatch-sync [:initialize-db]) (mount-root))
diff --git a/src/frontend/tubo/events.cljs b/src/frontend/tubo/events.cljs
index d9740f9..cfa5a78 100644
--- a/src/frontend/tubo/events.cljs
+++ b/src/frontend/tubo/events.cljs
@@ -30,26 +30,31 @@
(fn [{:keys [store]} _]
(let [if-nil #(if (nil? %1) %2 %1)]
{:db
- {:paused true
- :muted (:muted store)
- :queue (if-nil (:queue store) [])
- :service-id (if-nil (:service-id store) 0)
- :loop-playback (if-nil (:loop-playback store) :playlist)
- :queue-pos (if-nil (:queue-pos store) 0)
- :volume-level (if-nil (:volume-level store) 100)
- :background-player/show (:background-player/show store)
- :bookmarks
- (if-nil (:bookmarks store) [{:id (nano-id) :name "Liked Streams"}])
- :settings
- {:theme (if-nil (:theme store) "auto")
- :show-comments (if-nil (:show-comments store) true)
- :show-related (if-nil (:show-related store) true)
- :show-description (if-nil (:show-description store) true)
- :default-service (if-nil (:default-service store)
- {:service-id 0
- :id "YouTube"
- :default-kiosk "Trending"
- :available-kiosks ["Trending"]})}}})))
+ {:paused true
+ :muted (:muted store)
+ :queue (if-nil (:queue store) [])
+ :service-id (if-nil (:service-id store) 0)
+ :loop-playback (if-nil (:loop-playback store) :playlist)
+ :queue-pos (if-nil (:queue-pos store) 0)
+ :volume-level (if-nil (:volume-level store) 100)
+ :bg-player/show (:bg-player/show store)
+ :bookmarks (if-nil (:bookmarks store)
+ [{:id (nano-id) :name "Liked Streams"}])
+ :settings {:theme (if-nil (:theme store) "auto")
+ :show-comments (if-nil (:show-comments store)
+ true)
+ :show-related (if-nil (:show-related store)
+ true)
+ :show-description (if-nil (:show-description
+ store)
+ true)
+ :default-service (if-nil
+ (:default-service store)
+ {:service-id 0
+ :id "YouTube"
+ :default-kiosk "Trending"
+ :available-kiosks
+ ["Trending"]})}}})))
(rf/reg-fx
:scroll-to-top
@@ -74,7 +79,7 @@
(rf/reg-event-fx
:scroll-into-view
- (fn [{:keys [db]} [_ element]]
+ (fn [_ [_ element]]
{:scroll-into-view! element}))
(rf/reg-fx
@@ -118,10 +123,12 @@
:fx [(when (:main-player/show db)
[:dispatch [:player/switch-from-main]])
[:dispatch [:queue/show false]]
- [:dispatch [:services/fetch-all
- [:services/load] [:bad-response]]]
- [:dispatch [:kiosks/fetch-all (:service-id db)
- [:kiosks/load] [:bad-response]]]]})))
+ [:dispatch
+ [:services/fetch-all
+ [:services/load] [:bad-response]]]
+ [:dispatch
+ [:kiosks/fetch-all (:service-id db)
+ [:kiosks/load] [:bad-response]]]]})))
(defonce timeouts! (r/atom {}))
@@ -132,18 +139,20 @@
(js/clearTimeout existing)
(swap! timeouts! dissoc id))
(when (some? event)
- (swap! timeouts! assoc id
- (js/setTimeout #(rf/dispatch event) time)))))
+ (swap! timeouts! assoc
+ id
+ (js/setTimeout #(rf/dispatch event) time)))))
(rf/reg-event-fx
:bad-response
- (fn [{:keys [db]} [_ res]]
+ (fn [_ [_ res]]
{:fx [[:dispatch [:notifications/add res]]]}))
(rf/reg-fx
:file-download
(fn [{:keys [data name mime-type]}]
- (let [file (.createObjectURL js/URL (js/Blob. (array data) {:type mime-type}))
+ (let [file (.createObjectURL js/URL
+ (js/Blob. (array data) {:type mime-type}))
!link (.createElement js/document "a")]
(set! (.-href !link) file)
(set! (.-download !link) name)
@@ -155,15 +164,20 @@
(fn [{:keys [db]} [_ res]]
(let [updated-db (assoc db :services (js->clj res :keywordize-keys true))
service-id (:id (first
- (filter #(= (-> db :settings :default-service :id)
- (-> % :info :name))
+ (filter #(= (-> db
+ :settings
+ :default-service
+ :id)
+ (-> %
+ :info
+ :name))
(:services updated-db))))]
{:fx [[:dispatch [:kiosks/fetch-default-page service-id]]
[:dispatch [:services/change-id service-id]]]})))
(rf/reg-event-fx
:fetch-homepage
- (fn [{:keys [db]} _]
+ (fn [_ _]
{:fx [[:dispatch [:services/fetch-all [:load-homepage] [:bad-response]]]]}))
(rf/reg-event-fx
diff --git a/src/frontend/tubo/kiosks/events.cljs b/src/frontend/tubo/kiosks/events.cljs
index 5b0518b..720715e 100644
--- a/src/frontend/tubo/kiosks/events.cljs
+++ b/src/frontend/tubo/kiosks/events.cljs
@@ -11,28 +11,34 @@
(rf/reg-event-fx
:kiosks/fetch
- (fn [{:keys [db]} [_ service-id kiosk-id on-success on-error params]]
- (api/get-request (str "/services/" service-id "/kiosks/"
+ (fn [_ [_ service-id kiosk-id on-success on-error params]]
+ (api/get-request (str "/services/" service-id
+ "/kiosks/"
(js/encodeURIComponent kiosk-id))
- on-success on-error params)))
+ on-success
+ on-error
+ params)))
(rf/reg-event-fx
:kiosks/fetch-default
- (fn [{:keys [db]} [_ service-id on-success on-error]]
+ (fn [_ [_ service-id on-success on-error]]
(api/get-request (str "/services/" service-id "/default-kiosk")
- on-success on-error)))
+ on-success
+ on-error)))
(rf/reg-event-fx
:kiosks/fetch-all
- (fn [{:keys [db]} [_ id on-success on-error]]
+ (fn [_ [_ id on-success on-error]]
(api/get-request (str "/services/" id "/kiosks")
- on-success on-error)))
+ on-success
+ on-error)))
(rf/reg-event-fx
:kiosks/load-page
(fn [{:keys [db]} [_ res]]
(let [kiosk-res (js->clj res :keywordize-keys true)]
- {:db (assoc db :kiosk kiosk-res
+ {:db (assoc db
+ :kiosk kiosk-res
:show-page-loading false)
:fx [[:dispatch [:services/fetch kiosk-res]]
[:document-title (:id kiosk-res)]]})))
@@ -40,11 +46,13 @@
(rf/reg-event-fx
:kiosks/bad-page-response
(fn [{:keys [db]} [_ service-id kiosk-id res]]
- {:fx [[:dispatch [:change-view
- #(layout/error
- res (if kiosk-id
- [:kiosks/fetch-page service-id kiosk-id]
- [:kiosks/fetch-default-page service-id]))]]]
+ {:fx [[:dispatch
+ [:change-view
+ #(layout/error
+ res
+ (if kiosk-id
+ [:kiosks/fetch-page service-id kiosk-id]
+ [:kiosks/fetch-default-page service-id]))]]]
:db (assoc db :show-page-loading false)}))
(rf/reg-event-fx
@@ -52,38 +60,50 @@
(fn [{:keys [db]} [_ service-id kiosk-id]]
{:db (assoc db
:show-page-loading true
- :kiosk nil)
- :fx [[:dispatch (if kiosk-id
- [:kiosks/fetch service-id kiosk-id
- [:kiosks/load-page] [:kiosks/bad-page-response service-id kiosk-id]]
- [:kiosks/fetch-default-page service-id])]]}))
+ :kiosk nil)
+ :fx [[:dispatch
+ (if kiosk-id
+ [:kiosks/fetch service-id kiosk-id
+ [:kiosks/load-page]
+ [:kiosks/bad-page-response service-id kiosk-id]]
+ [:kiosks/fetch-default-page service-id])]]}))
(rf/reg-event-fx
:kiosks/fetch-default-page
(fn [{:keys [db]} [_ service-id]]
(let [default-kiosk-id
(when (= (js/parseInt service-id)
- (-> db :settings :default-service :service-id))
- (-> db :settings :default-service :default-kiosk))]
- {:fx [[:dispatch (if default-kiosk-id
- [:kiosks/fetch-page service-id default-kiosk-id]
- [:kiosks/fetch-default service-id
- [:kiosks/load-page] [:kiosks/bad-page-response service-id nil]])]]})))
+ (-> db
+ :settings
+ :default-service
+ :service-id))
+ (-> db
+ :settings
+ :default-service
+ :default-kiosk))]
+ {:fx [[:dispatch
+ (if default-kiosk-id
+ [:kiosks/fetch-page service-id default-kiosk-id]
+ [:kiosks/fetch-default service-id
+ [:kiosks/load-page]
+ [:kiosks/bad-page-response service-id nil]])]]})))
(rf/reg-event-fx
:kiosks/change-page
- (fn [{:keys [db]} [_ service-id]]
+ (fn [_ [_ service-id]]
{:fx [[:dispatch [:services/change-id service-id]]
[:dispatch
- [:navigate {:name :kiosk-page
- :params {}
- :query {:serviceId service-id}}]]]}))
+ [:navigate
+ {:name :kiosk-page
+ :params {}
+ :query {:serviceId service-id}}]]]}))
(rf/reg-event-db
:kiosks/load-paginated
(fn [db [_ res]]
(-> db
- (update-in [:kiosk :related-streams] #(into %1 %2)
+ (update-in [:kiosk :related-streams]
+ #(into %1 %2)
(:related-streams (js->clj res :keywordize-keys true)))
(assoc-in [:kiosk :next-page]
(:next-page (js->clj res :keywordize-keys true)))
@@ -95,6 +115,7 @@
(if (empty? next-page-url)
{:db (assoc db :show-pagination-loading false)}
{:db (assoc db :show-pagination-loading true)
- :fx [[:dispatch [:kiosks/fetch service-id kiosk-id
- [:kiosks/load-paginated] [:bad-response]
- {:nextPage (js/encodeURIComponent next-page-url)}]]]})))
+ :fx [[:dispatch
+ [:kiosks/fetch service-id kiosk-id
+ [:kiosks/load-paginated] [:bad-response]
+ {:nextPage (js/encodeURIComponent next-page-url)}]]]})))
diff --git a/src/frontend/tubo/kiosks/views.cljs b/src/frontend/tubo/kiosks/views.cljs
index 17e0e76..bd6c284 100644
--- a/src/frontend/tubo/kiosks/views.cljs
+++ b/src/frontend/tubo/kiosks/views.cljs
@@ -7,7 +7,7 @@
(defn kiosk-active?
[& {:keys [kiosk kiosk-id service-id default-service default-kiosk path]}]
- (or (and (= kiosk-id kiosk))
+ (or (= kiosk-id kiosk)
(and (= path "/kiosk")
(not kiosk-id)
(not= (js/parseInt service-id)
@@ -22,19 +22,21 @@
[:ul.flex.items-center.px-4.text-white
(for [kiosk kiosks]
[:li.px-3 {:key kiosk}
- [:a {:href (rfe/href :kiosk-page nil {:serviceId service-id
- :kioskId kiosk})
- :class (when (kiosk-active? (assoc kiosk-args :kiosk kiosk))
- :font-bold)}
+ [:a
+ {:href (rfe/href :kiosk-page
+ nil
+ {:serviceId service-id
+ :kioskId kiosk})
+ :class (when (kiosk-active? (assoc kiosk-args :kiosk kiosk))
+ :font-bold)}
kiosk]])])
(defn kiosk
- [{{:keys [serviceId kioskId]} :query-params}]
- (let [{:keys [id url related-streams
- next-page]} @(rf/subscribe [:kiosk])
- next-page-url (:url next-page)
- service-color @(rf/subscribe [:service-color])
- service-id (or @(rf/subscribe [:service-id]) serviceId)
+ [{{:keys [serviceId]} :query-params}]
+ (let [{:keys [id related-streams next-page]}
+ @(rf/subscribe [:kiosk])
+ next-page-url (:url next-page)
+ service-id (or @(rf/subscribe [:service-id]) serviceId)
scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])]
(when scrolled-to-bottom?
(rf/dispatch [:kiosks/fetch-paginated service-id id next-page-url]))
diff --git a/src/frontend/tubo/modals/events.cljs b/src/frontend/tubo/modals/events.cljs
index 4a88a5b..971fcac 100644
--- a/src/frontend/tubo/modals/events.cljs
+++ b/src/frontend/tubo/modals/events.cljs
@@ -16,21 +16,28 @@
(rf/reg-event-fx
:modals/hide
(fn [{:keys [db]} _]
- {:db (update db :modals
- #(map-indexed (fn [i modal]
- (if (= i (- (count %) 1))
- (assoc modal :show? false :child nil)))
- %))
+ {:db (update db
+ :modals
+ #(map-indexed
+ (fn [i modal]
+ (when (= i (- (count %) 1))
+ (assoc modal :show? false :child nil)))
+ %))
:body-overflow false}))
(rf/reg-event-fx
:modals/close
(fn [{:keys [db]} _]
- {:fx [[:dispatch [:modals/delete (-> (:modals db) last :id)]]]
+ {:fx [[:dispatch
+ [:modals/delete
+ (-> (:modals db)
+ last
+ :id)]]]
:body-overflow false}))
(rf/reg-event-fx
:modals/open
(fn [_ [_ child]]
- {:fx [[:dispatch [:modals/add {:show? true :child child :id (nano-id)}]]]
+ {:fx [[:dispatch
+ [:modals/add {:show? true :child child :id (nano-id)}]]]
:body-overflow true}))
diff --git a/src/frontend/tubo/modals/views.cljs b/src/frontend/tubo/modals/views.cljs
index e4c3aef..df59034 100644
--- a/src/frontend/tubo/modals/views.cljs
+++ b/src/frontend/tubo/modals/views.cljs
@@ -28,7 +28,7 @@
(defn modal
[]
(fn []
- (let [modals @(rf/subscribe [:modals])
+ (let [modals @(rf/subscribe [:modals])
visible-modal (last (filter :show? modals))]
(when visible-modal
[modal-panel visible-modal]))))
diff --git a/src/frontend/tubo/notifications/events.cljs b/src/frontend/tubo/notifications/events.cljs
index 2ecbf2e..120e896 100644
--- a/src/frontend/tubo/notifications/events.cljs
+++ b/src/frontend/tubo/notifications/events.cljs
@@ -6,21 +6,27 @@
(rf/reg-event-fx
:notifications/add
(fn [{:keys [db]} [_ data time]]
- (let [id (nano-id)
- updated-db (update db :notifications #(into [] (conj %1 %2))
+ (let [id (nano-id)
+ updated-db (update db
+ :notifications
+ #(into [] (conj %1 %2))
(assoc data :id id))]
{:db updated-db
:fx (if (false? time)
- []
- [[:timeout {:id id
- :event [:notifications/remove id]
- :time (or time 2000)}]])})))
+ []
+ [[:timeout
+ {:id id
+ :event [:notifications/remove id]
+ :time (or time 2000)}]])})))
(rf/reg-event-db
:notifications/remove
(fn [db [_ id]]
- (update db :notifications #(remove (fn [notification]
- (= (:id notification) id)) %))))
+ (update db
+ :notifications
+ #(remove (fn [notification]
+ (= (:id notification) id))
+ %))))
(rf/reg-event-db
:notifications/clear
diff --git a/src/frontend/tubo/notifications/views.cljs b/src/frontend/tubo/notifications/views.cljs
index 6c8a09a..7d0ba98 100644
--- a/src/frontend/tubo/notifications/views.cljs
+++ b/src/frontend/tubo/notifications/views.cljs
@@ -9,7 +9,8 @@
{:class (case failure
:success ["bg-green-600/90" :text-white]
:error ["bg-red-600/90" :text-white]
- ["dark:bg-stone-800" "dark:text-white" :bg-neutral-300 :text-neutral-800])}
+ ["dark:bg-stone-800" "dark:text-white" :bg-neutral-300
+ :text-neutral-800])}
[:div.flex.items-center.gap-x-4
(case failure
:success [:i.fa-solid.fa-circle-check]
@@ -20,7 +21,8 @@
{:on-click
#(rf/dispatch [:notifications/remove (:id notification)])}
[:i.fa-solid.fa-close]]
- [:span.font-bold (str status (when (and status status-text) ": ") status-text)]
+ [:span.font-bold
+ (str status (when (and status status-text) ": ") status-text)]
(when parse-error
[:span.line-clamp-1 (:status-text parse-error)])]]]))
diff --git a/src/frontend/tubo/player/events.cljs b/src/frontend/tubo/player/events.cljs
index f8476c3..375c055 100644
--- a/src/frontend/tubo/player/events.cljs
+++ b/src/frontend/tubo/player/events.cljs
@@ -1,7 +1,5 @@
(ns tubo.player.events
(:require
- [tubo.stream.views :as stream]
- [tubo.utils :as utils]
[goog.object :as gobj]
[re-frame.core :as rf]
[vimsical.re-frame.cofx.inject :as inject]))
@@ -20,7 +18,7 @@
(rf/reg-fx
:src
- (fn [{:keys [player src current-pos]}]
+ (fn [{:keys [player src]}]
(set! (.-source @player) (clj->js src))))
(rf/reg-fx
@@ -34,16 +32,16 @@
(set! (.-currentTime @player) time)))
(rf/reg-event-fx
- :background-player/seek
+ :bg-player/seek
[(rf/inject-cofx ::inject/sub [:player])]
(fn [{:keys [db player]} [_ time]]
- (when (:background-player/ready db)
+ (when (:bg-player/ready db)
{:current-time {:time time :player player}})))
(rf/reg-event-fx
:main-player/seek
[(rf/inject-cofx ::inject/sub [:main-player])]
- (fn [{:keys [db main-player]} [_ time]]
+ (fn [{:keys [main-player]} [_ time]]
{:current-time {:time time :player main-player}}))
(rf/reg-fx
@@ -53,14 +51,14 @@
(set! (.-paused @player) paused?))))
(rf/reg-event-db
- :background-player/set-paused
+ :bg-player/set-paused
(fn [db [_ val]]
(assoc db :paused val)))
(rf/reg-event-fx
- :background-player/pause
+ :bg-player/pause
[(rf/inject-cofx ::inject/sub [:player])]
- (fn [{:keys [db player]} [_ paused?]]
+ (fn [{:keys [player]} [_ paused?]]
{:pause! {:paused? paused?
:player player}}))
@@ -73,12 +71,12 @@
:player main-player}})))
(rf/reg-event-fx
- :background-player/play
+ :bg-player/play
[(rf/inject-cofx ::inject/sub [:elapsed-time])
(rf/inject-cofx ::inject/sub [:main-player])]
(fn [{:keys [db elapsed-time main-player]}]
- {:fx [[:dispatch [:background-player/set-paused false]]
- [:dispatch [:background-player/seek @elapsed-time]]
+ {:fx [[:dispatch [:bg-player/set-paused false]]
+ [:dispatch [:bg-player/seek @elapsed-time]]
(when (and (:main-player/ready db) @main-player)
[:dispatch [:main-player/pause true]])]}))
@@ -86,23 +84,23 @@
:main-player/play
[(rf/inject-cofx ::inject/sub [:elapsed-time])
(rf/inject-cofx ::inject/sub [:player])]
- (fn [{:keys [db elapsed-time player]}]
- {:fx [(when (and (:background-player/ready db) @player)
- [:dispatch [:background-player/pause true]])]}))
+ (fn [{:keys [db player]}]
+ {:fx [(when (and (:bg-player/ready db) @player)
+ [:dispatch [:bg-player/pause true]])]}))
(rf/reg-event-fx
- :background-player/stop
- (fn [{:keys [db]}]
- {:fx [[:dispatch [:background-player/pause true]]
- [:dispatch [:background-player/seek 0]]]}))
+ :bg-player/stop
+ (fn [_]
+ {:fx [[:dispatch [:bg-player/pause true]]
+ [:dispatch [:bg-player/seek 0]]]}))
(rf/reg-event-fx
- :background-player/start
+ :bg-player/start
[(rf/inject-cofx ::inject/sub [:player])
(rf/inject-cofx ::inject/sub [:elapsed-time])]
- (fn [{:keys [db player elapsed-time]} _]
- {:fx [[:dispatch [:background-player/set-paused true]]
- [:dispatch [:background-player/pause false]]
+ (fn [{:keys [db player]} _]
+ {:fx [[:dispatch [:bg-player/set-paused true]]
+ [:dispatch [:bg-player/pause false]]
[:dispatch [:player/change-volume (:volume-level db) player]]]}))
(rf/reg-event-fx
@@ -110,7 +108,7 @@
[(rf/inject-cofx ::inject/sub [:elapsed-time])]
(fn [{:keys [db elapsed-time]} _]
{:fx [[:dispatch [:main-player/pause false]]
- (when (and (:main-player/show db) (not (:background-player/ready db)))
+ (when (and (:main-player/show db) (not (:bg-player/ready db)))
[:dispatch [:main-player/seek @elapsed-time]])]}))
(rf/reg-fx
@@ -122,7 +120,7 @@
(rf/reg-fx
:media-session-handlers
- (fn [{:keys [current-pos player stream]}]
+ (fn [{:keys [current-pos player]}]
(when (gobj/containsKey js/navigator "mediaSession")
(let [current-time (and @player (.-currentTime @player))
update-position
@@ -136,11 +134,16 @@
"pause" #(.pause @player)
"previoustrack" #(rf/dispatch [:queue/change-pos (dec current-pos)])
"nexttrack" #(rf/dispatch [:queue/change-pos (inc current-pos)])
- "seekbackward" (fn [^js/navigator.MediaSessionActionDetails details]
- (seek (- current-time (or (.-seekOffset details) 10))))
- "seekforward" (fn [^js/navigator.MediaSessionActionDetails details]
- (seek (+ current-time (or (.-seekOffset details) 10))))
- "seekto" (fn [^js/navigator.MediaSessionActionDetails details]
+ "seekbackward" (fn [^js/navigator.MediaSessionActionDetails
+ details]
+ (seek (- current-time
+ (or (.-seekOffset details) 10))))
+ "seekforward" (fn [^js/navigator.MediaSessionActionDetails
+ details]
+ (seek (+ current-time
+ (or (.-seekOffset details) 10))))
+ "seekto" (fn [^js/navigator.MediaSessionActionDetails
+ details]
(seek (.-seekTime details)))
"stop" #(seek 0)}]
(doseq [[action cb] events]
@@ -155,7 +158,7 @@
:volume {:player player :volume value}}))
(rf/reg-event-fx
- :background-player/mute
+ :bg-player/mute
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ value player]]
{:db (assoc db :muted value)
@@ -163,11 +166,11 @@
:mute {:player player :muted? value}}))
(rf/reg-event-fx
- :background-player/hide
+ :bg-player/hide
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} _]
- {:db (assoc db :background-player/show false)
- :store (assoc store :background-player/show false)}))
+ {:db (assoc db :bg-player/show false)
+ :store (assoc store :bg-player/show false)}))
(rf/reg-event-fx
:player/loop
@@ -181,7 +184,7 @@
:store (assoc store :loop-playback loop-state)})))
(rf/reg-event-fx
- :background-player/dispose
+ :bg-player/dispose
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} _]
(let [remove-entries
@@ -191,14 +194,14 @@
(assoc :queue-pos 0)))]
{:db (remove-entries db)
:store (remove-entries store)
- :fx [[:dispatch [:background-player/pause true]]
- [:dispatch [:background-player/seek 0]]
- [:dispatch [:background-player/hide]]]})))
+ :fx [[:dispatch [:bg-player/pause true]]
+ [:dispatch [:bg-player/seek 0]]
+ [:dispatch [:bg-player/hide]]]})))
(rf/reg-event-db
- :background-player/ready
+ :bg-player/ready
(fn [db [_ ready]]
- (assoc db :background-player/ready ready)))
+ (assoc db :bg-player/ready ready)))
(rf/reg-event-db
:main-player/ready
@@ -213,38 +216,40 @@
idx (.indexOf (:queue updated-db) stream)]
{:db updated-db
:store (assoc store :queue (:queue updated-db))
- :fx [[:dispatch [:player/fetch-stream
- (:url stream) idx (= (count (:queue db)) 0)]]
+ :fx [[:dispatch
+ [:player/fetch-stream
+ (:url stream) idx (= (count (:queue db)) 0)]]
(when (and notify? (not (= (count (:queue db)) 0)))
- [:dispatch [:notifications/add
- {:status-text "Added stream to queue"
- :failure :info}]])]})))
+ [:dispatch
+ [:notifications/add
+ {:status-text "Added stream to queue"
+ :failure :info}]])]})))
(rf/reg-event-fx
:player/show-main-player
(fn [{:keys [db]} [_ val]]
- {:db (assoc db :main-player/show val)
+ {:db (assoc db :main-player/show val)
:body-overflow val}))
(rf/reg-event-fx
:player/switch-from-main
[(rf/inject-cofx ::inject/sub [:elapsed-time])]
- (fn [{:keys [db elapsed-time]} [_ stream]]
- {:db (assoc db :background-player/show true)
+ (fn [{:keys [db]} _]
+ {:db (assoc db :bg-player/show true)
:fx [[:dispatch [:player/show-main-player false]]
[:dispatch [:main-player/pause true]]]}))
(rf/reg-event-fx
:player/switch-to-main
[(rf/inject-cofx :store)]
- (fn [{:keys [db]} [_ stream]]
- {:fx [[:dispatch [:player/show-main-player true]]]
- :db (assoc db :background-player/show false)
+ (fn [{:keys [db]} _]
+ {:fx [[:dispatch [:player/show-main-player true]]]
+ :db (assoc db :bg-player/show false)
:scroll-to-top nil}))
(rf/reg-event-fx
:player/load-related-streams
- (fn [{:keys [db]} [_ res]]
+ (fn [_ [_ res]]
(let [{:keys [related-streams]} (js->clj res :keywordize-keys true)]
{:fx [[:dispatch [:queue/add-n related-streams]]]})))
@@ -254,45 +259,53 @@
(rf/inject-cofx ::inject/sub [:player])]
(fn [{:keys [db store player]} [_ idx play? res]]
(let [stream-res (js->clj res :keywordize-keys true)]
- {:db (assoc db
- :background-player/show (not (:main-player/show db))
- :background-player/loading false)
- :store (assoc store :background-player/show (not (:main-player/show db)))
- :fx (apply conj [(when play? [:dispatch [:queue/change-stream stream-res idx]])]
- (when (and (:background-player/ready db) play?)
- [[:media-session-metadata
- {:title (:name stream-res)
- :artist (:uploader-name stream-res)
- :artwork [{:src (:thumbnail-url stream-res)}]}]
- [:media-session-handlers
- {:current-pos idx
- :player player}]]))})))
+ {:db (assoc db
+ :bg-player/show (not (:main-player/show db))
+ :bg-player/loading false)
+ :store (assoc store :bg-player/show (not (:main-player/show db)))
+ :fx (apply conj
+ [(when play?
+ [:dispatch [:queue/change-stream stream-res idx]])]
+ (when (and (:bg-player/ready db) play?)
+ [[:media-session-metadata
+ {:title (:name stream-res)
+ :artist (:uploader-name stream-res)
+ :artwork [{:src (:thumbnail-url stream-res)}]}]
+ [:media-session-handlers
+ {:current-pos idx
+ :player player}]]))})))
(rf/reg-event-fx
:player/bad-response
(fn [{:keys [db]} [_ idx play? res]]
{:db (assoc db
- :background-player/loading false)
+ :bg-player/loading
+ false)
:fx [[:dispatch [:bad-response res]]
(when play?
- (if (> (-> db :queue count) 1)
+ (if (> (-> db
+ :queue
+ count)
+ 1)
[:dispatch [:queue/change-pos (inc idx)]]
- [:dispatch [:background-player/dispose]]))]}))
+ [:dispatch [:bg-player/dispose]]))]}))
(rf/reg-event-fx
:player/fetch-related-streams
(fn [{:keys [db]} [_ url]]
- {:fx [[:dispatch [:stream/fetch url
- [:player/load-related-streams]] [:bad-response]]]
- :db (assoc db :background-player/loading true)}))
+ {:fx [[:dispatch
+ [:stream/fetch url
+ [:player/load-related-streams]] [:bad-response]]]
+ :db (assoc db :bg-player/loading true)}))
(rf/reg-event-fx
:player/fetch-stream
(fn [{:keys [db]} [_ url idx play?]]
- {:fx [[:dispatch [:stream/fetch url
- [:player/load-stream idx play?]
- [:player/bad-response idx play?]]]]
- :db (assoc db :background-player/loading play?)}))
+ {:fx [[:dispatch
+ [:stream/fetch url
+ [:player/load-stream idx play?]
+ [:player/bad-response idx play?]]]]
+ :db (assoc db :bg-player/loading play?)}))
(rf/reg-event-fx
:player/start-radio
@@ -301,12 +314,14 @@
(when (not= (count (:queue db)) 0)
[:dispatch [:queue/change-pos (count (:queue db))]])
[:dispatch [:player/fetch-related-streams (:url stream)]]
- [:dispatch [:notifications/add
- {:status-text "Started stream radio"
- :failure :info}]]]}))
+ [:dispatch
+ [:notifications/add
+ {:status-text "Started stream radio"
+ :failure :info}]]]}))
(rf/reg-event-db
:main-player/toggle-layout
(fn [db [_ layout]]
- (assoc-in db [:queue (:queue-pos db) layout]
- (not (get-in db [:queue (:queue-pos db) layout])))))
+ (assoc-in db
+ [:queue (:queue-pos db) layout]
+ (not (get-in db [:queue (:queue-pos db) layout])))))
diff --git a/src/frontend/tubo/player/subs.cljs b/src/frontend/tubo/player/subs.cljs
index 0b0f93c..c61473a 100644
--- a/src/frontend/tubo/player/subs.cljs
+++ b/src/frontend/tubo/player/subs.cljs
@@ -9,18 +9,18 @@
(rf/reg-sub
:player
- (fn [db _]
+ (fn [_ _]
!player))
(rf/reg-sub
:main-player
- (fn [db _]
+ (fn [_ _]
!main-player))
(rf/reg-sub
- :background-player/ready
+ :bg-player/ready
(fn [db _]
- (:background-player/ready db)))
+ (:bg-player/ready db)))
(rf/reg-sub
:main-player/ready
@@ -28,14 +28,14 @@
(:main-player/ready db)))
(rf/reg-sub
- :background-player/show
+ :bg-player/show
(fn [db _]
- (:background-player/show db)))
+ (:bg-player/show db)))
(rf/reg-sub
- :background-player/loading
+ :bg-player/loading
(fn [db _]
- (:background-player/loading db)))
+ (:bg-player/loading db)))
(rf/reg-sub
:loop-playback
@@ -59,7 +59,7 @@
(rf/reg-sub
:elapsed-time
- (fn [db _]
+ (fn [_ _]
!elapsed-time))
(rf/reg-sub
diff --git a/src/frontend/tubo/player/views.cljs b/src/frontend/tubo/player/views.cljs
index e98a676..1cd8c86 100644
--- a/src/frontend/tubo/player/views.cljs
+++ b/src/frontend/tubo/player/views.cljs
@@ -8,8 +8,7 @@
[tubo.components.player :as player]
[tubo.queue.views :as queue]
[tubo.stream.views :as stream]
- [tubo.utils :as utils]
- ["@vidstack/react" :refer (useStore MediaPlayerInstance)]))
+ [tubo.utils :as utils]))
(defn stream-metadata
[{:keys [thumbnail-url url name uploader-url uploader-name]}]
@@ -29,15 +28,13 @@
(defn main-controls
[!player color]
- (let [queue @(rf/subscribe [:queue])
- queue-pos @(rf/subscribe [:queue-pos])
- loading? @(rf/subscribe [:background-player/loading])
- loop-playback @(rf/subscribe [:loop-playback])
- !main-player @(rf/subscribe [:main-player])
- bg-player-ready? @(rf/subscribe [:background-player/ready])
- main-player-ready? @(rf/subscribe [:main-player/ready])
- paused? @(rf/subscribe [:paused])
- !elapsed-time @(rf/subscribe [:elapsed-time])]
+ (let [queue @(rf/subscribe [:queue])
+ queue-pos @(rf/subscribe [:queue-pos])
+ loading? @(rf/subscribe [:bg-player/loading])
+ loop-playback @(rf/subscribe [:loop-playback])
+ bg-player-ready? @(rf/subscribe [:bg-player/ready])
+ paused? @(rf/subscribe [:paused])
+ !elapsed-time @(rf/subscribe [:elapsed-time])]
[:div.flex.flex-col.items-center.ml-auto
[:div.flex.justify-end
[player/loop-button loop-playback color]
@@ -47,33 +44,39 @@
:disabled? (not (and queue (not= queue-pos 0)))]
[player/button
:icon [:i.fa-solid.fa-backward]
- :on-click #(rf/dispatch [:background-player/seek (- @!elapsed-time 5)])]
+ :on-click #(rf/dispatch [:bg-player/seek (- @!elapsed-time 5)])]
[player/button
- :icon (if (and (not loading?) @!player)
- (if paused?
- [:i.fa-solid.fa-play]
- [:i.fa-solid.fa-pause])
- [layout/loading-icon color "lg:text-2xl"])
- :on-click #(rf/dispatch [:background-player/pause (not (.-paused @!player))])
+ :icon
+ (if (and (not loading?) @!player)
+ (if paused?
+ [:i.fa-solid.fa-play]
+ [:i.fa-solid.fa-pause])
+ [layout/loading-icon color "lg:text-2xl"])
+ :on-click
+ #(rf/dispatch [:bg-player/pause (not (.-paused @!player))])
:show-on-mobile? true
:extra-classes ["lg:text-2xl"]]
[player/button
:icon [:i.fa-solid.fa-forward]
- :on-click #(rf/dispatch [:background-player/seek (+ @!elapsed-time 5)])]
+ :on-click #(rf/dispatch [:bg-player/seek (+ @!elapsed-time 5)])]
[player/button
:icon [:i.fa-solid.fa-forward-step]
:on-click #(rf/dispatch [:queue/change-pos (inc queue-pos)])
:disabled? (not (and queue (< (inc queue-pos) (count queue))))]]
[:div.hidden.lg:flex.items-center.text-sm
[:span.mx-2
- (if (and bg-player-ready? @!player @!elapsed-time) (utils/format-duration @!elapsed-time) "--:--")]
+ (if (and bg-player-ready? @!player @!elapsed-time)
+ (utils/format-duration @!elapsed-time)
+ "--:--")]
[:div.w-20.lg:w-64.mx-2.flex.items-center
[player/time-slider !player !elapsed-time color]]
[:span.mx-2
- (if (and bg-player-ready? @!player) (utils/format-duration (.-duration @!player)) "--:--")]]]))
+ (if (and bg-player-ready? @!player)
+ (utils/format-duration (.-duration @!player))
+ "--:--")]]]))
(defn extra-controls
- [!player {:keys [url uploader-url] :as stream} color]
+ [_!player _stream _color]
(let [!menu-active? (r/atom nil)]
(fn [!player {:keys [url uploader-url] :as stream} color]
(let [muted? @(rf/subscribe [:muted])
@@ -81,7 +84,10 @@
queue @(rf/subscribe [:queue])
queue-pos @(rf/subscribe [:queue-pos])
bookmarks @(rf/subscribe [:bookmarks])
- liked? (some #(= (:url %) url) (-> bookmarks first :items))
+ liked? (some #(= (:url %) url)
+ (-> bookmarks
+ first
+ :items))
bookmark #(rf/dispatch [:modals/open [modals/add-to-bookmark %]])]
[:div.flex.lg:justify-end.lg:flex-1
[player/volume-slider !player volume muted? color]
@@ -92,8 +98,10 @@
:extra-classes [:!pl-4 :!pr-3]]
[layout/popover-menu !menu-active?
[{:label (if liked? "Remove favorite" "Favorite")
- :icon [:i.fa-solid.fa-heart (when liked? {:style {:color color}})]
- :on-click #(rf/dispatch [(if liked? :likes/remove :likes/add) stream])}
+ :icon [:i.fa-solid.fa-heart
+ (when liked? {:style {:color color}})]
+ :on-click #(rf/dispatch [(if liked? :likes/remove :likes/add)
+ stream])}
{:label "Play radio"
:icon [:i.fa-solid.fa-tower-cell]
:on-click #(rf/dispatch [:player/start-radio stream])}
@@ -117,22 +125,30 @@
:query {:url uploader-url}}])}
{:label "Close player"
:icon [:i.fa-solid.fa-close]
- :on-click #(rf/dispatch [:background-player/dispose])}]
+ :on-click #(rf/dispatch [:bg-player/dispose])}]
:menu-styles {:bottom "30px" :top nil :right "10px"}
:extra-classes [:pt-1 :!pl-4 :px-3]]]))))
(defn background-player
[]
- (let [!player @(rf/subscribe [:player])
- stream @(rf/subscribe [:queue-stream])
- show-queue? @(rf/subscribe [:show-queue])
- show-player? @(rf/subscribe [:background-player/show])
- dark-theme? @(rf/subscribe [:dark-theme])
- muted? @(rf/subscribe [:muted])
- loop-playback @(rf/subscribe [:loop-playback])
- color (-> stream :service-id utils/get-service-color)
- bg-color (str "rgba(" (if dark-theme? "23,23,23" "255,255,255") ",0.95)")
- bg-image (str "linear-gradient(" bg-color "," bg-color "),url(" (:thumbnail-url stream) ")")]
+ (let [!player @(rf/subscribe [:player])
+ stream @(rf/subscribe [:queue-stream])
+ show-queue? @(rf/subscribe [:show-queue])
+ show-player? @(rf/subscribe [:bg-player/show])
+ dark-theme? @(rf/subscribe [:dark-theme])
+ color (-> stream
+ :service-id
+ utils/get-service-color)
+ bg-color (str "rgba("
+ (if dark-theme? "23,23,23" "255,255,255")
+ ",0.95)")
+ bg-image (str "linear-gradient("
+ bg-color
+ ","
+ bg-color
+ "),url("
+ (:thumbnail-url stream)
+ ")")]
(when show-player?
[:div.sticky.absolute.left-0.bottom-0.z-10.p-3.transition-all.ease-in.relative
{:style
@@ -148,15 +164,17 @@
[main-controls !player color]
[extra-controls !player stream color]]])))
-(defn main-player []
- (let [queue @(rf/subscribe [:queue])
- queue-pos @(rf/subscribe [:queue-pos])
- bookmarks @(rf/subscribe [:bookmarks])
- !player @(rf/subscribe [:main-player])
- {:keys [service-id] :as stream} @(rf/subscribe [:queue-stream])
- show-player? @(rf/subscribe [:main-player/show])]
+(defn main-player
+ []
+ (let [queue @(rf/subscribe [:queue])
+ queue-pos @(rf/subscribe [:queue-pos])
+ bookmarks @(rf/subscribe [:bookmarks])
+ !player @(rf/subscribe [:main-player])
+ stream @(rf/subscribe [:queue-stream])
+ show-player? @(rf/subscribe [:main-player/show])]
[:div.fixed.w-full.bg-neutral-100.dark:bg-neutral-900.overflow-auto.z-10.transition-all.ease-in-out
- {:class ["h-[calc(100%-56px)]" (if show-player? "translate-y-0" "translate-y-full")]}
+ {:class ["h-[calc(100%-56px)]"
+ (if show-player? "translate-y-0" "translate-y-full")]}
[:div.sticky.z-10.right-0.top-0
[:button.absolute.text-white.m-8.text-2xl.z-10.right-0
{:on-click #(rf/dispatch [:player/switch-from-main nil])}
diff --git a/src/frontend/tubo/playlist/events.cljs b/src/frontend/tubo/playlist/events.cljs
index 5a96209..3451d2f 100644
--- a/src/frontend/tubo/playlist/events.cljs
+++ b/src/frontend/tubo/playlist/events.cljs
@@ -5,15 +5,18 @@
(rf/reg-event-fx
:playlist/fetch
- (fn [{:keys [db]} [_ url on-success on-error params]]
+ (fn [_ [_ url on-success on-error params]]
(api/get-request (str "/playlists/" (js/encodeURIComponent url))
- on-success on-error params)))
+ on-success
+ on-error
+ params)))
(rf/reg-event-db
:playlist/load-paginated
(fn [db [_ res]]
(-> db
- (update-in [:playlist :related-streams] #(apply conj %1 %2)
+ (update-in [:playlist :related-streams]
+ #(apply conj %1 %2)
(:related-streams (js->clj res :keywordize-keys true)))
(assoc-in [:playlist :next-page]
(:next-page (js->clj res :keywordize-keys true)))
@@ -24,16 +27,18 @@
(fn [{:keys [db]} [_ url next-page-url]]
(if (empty? next-page-url)
{:db (assoc db :show-pagination-loading false)}
- {:fx [[:dispatch [:playlist/fetch url
- [:playlist/load-paginated] [:bad-response]
- {:nextPage (js/encodeURIComponent next-page-url)}]]]
+ {:fx [[:dispatch
+ [:playlist/fetch url
+ [:playlist/load-paginated] [:bad-response]
+ {:nextPage (js/encodeURIComponent next-page-url)}]]]
:db (assoc db :show-pagination-loading true)})))
(rf/reg-event-fx
:playlist/load-page
(fn [{:keys [db]} [_ res]]
(let [playlist-res (js->clj res :keywordize-keys true)]
- {:db (assoc db :playlist playlist-res
+ {:db (assoc db
+ :playlist playlist-res
:show-page-loading false)
:fx [[:dispatch [:services/fetch playlist-res]]
[:document-title (:name playlist-res)]]})))
@@ -41,8 +46,9 @@
(rf/reg-event-fx
:playlist/fetch-page
(fn [{:keys [db]} [_ url]]
- {:fx [[:dispatch [:playlist/fetch url
- [:playlist/load-page] [:bad-response]]]]
+ {:fx [[:dispatch
+ [:playlist/fetch url
+ [:playlist/load-page] [:bad-response]]]]
:db (assoc db
:show-page-loading true
- :playlist nil)}))
+ :playlist nil)}))
diff --git a/src/frontend/tubo/playlist/views.cljs b/src/frontend/tubo/playlist/views.cljs
index 39adb88..c26bdd3 100644
--- a/src/frontend/tubo/playlist/views.cljs
+++ b/src/frontend/tubo/playlist/views.cljs
@@ -11,11 +11,11 @@
[{{:keys [url]} :query-params}]
(let [!menu-active? (r/atom nil)]
(fn []
- (let [{:keys [id name playlist-type thumbnail-url banner-url next-page
- uploader-name uploader-url related-streams
- stream-count]} @(rf/subscribe [:playlist])
- next-page-url (:url next-page)
- scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])]
+ (let [{:keys [name next-page uploader-name uploader-url related-streams
+ stream-count]}
+ @(rf/subscribe [:playlist])
+ next-page-url (:url next-page)
+ scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])]
(when scrolled-to-bottom?
(rf/dispatch [:playlist/fetch-paginated url next-page-url]))
[layout/content-container
@@ -28,7 +28,9 @@
:on-click #(rf/dispatch [:queue/add-n related-streams true])}
{:label "Add to playlist"
:icon [:i.fa-solid.fa-plus]
- :on-click #(rf/dispatch [:modals/open [modals/add-to-bookmark related-streams]])}]])]
+ :on-click #(rf/dispatch [:modals/open
+ [modals/add-to-bookmark
+ related-streams]])}]])]
[:div.flex.items-center.justify-between.my-4.gap-x-4
[:div.flex.items-center
[layout/uploader-avatar playlist]
diff --git a/src/frontend/tubo/queue/events.cljs b/src/frontend/tubo/queue/events.cljs
index 0154cef..a174623 100644
--- a/src/frontend/tubo/queue/events.cljs
+++ b/src/frontend/tubo/queue/events.cljs
@@ -16,29 +16,38 @@
{:db updated-db
:store (assoc store :queue (:queue updated-db))
:fx (if notify?
- [[:dispatch [:notifications/add
- {:status-text "Added stream to queue"
- :failure :info}]]]
+ [[:dispatch
+ [:notifications/add
+ {:status-text "Added stream to queue"
+ :failure :info}]]]
[])})))
(rf/reg-event-fx
:queue/add-n
[(rf/inject-cofx :store)]
- (fn [{:keys [db store]} [_ streams notify?]]
- {:fx (into (map (fn [stream] [:dispatch [:queue/add stream]]) streams)
- [[:dispatch [:player/fetch-stream (-> streams first :url)
- (count (:queue db)) (= (count (:queue db)) 0)]]
- (when notify?
- [:dispatch [:notifications/add
- {:status-text (str "Added " (count streams)
- " streams to queue")
- :failure :info}]])])}))
+ (fn [{:keys [db]} [_ streams notify?]]
+ {:fx (into (map (fn [stream] [:dispatch [:queue/add stream]]) streams)
+ [[:dispatch
+ [:player/fetch-stream
+ (-> streams
+ first
+ :url)
+ (count (:queue db)) (= (count (:queue db)) 0)]]
+ (when notify?
+ [:dispatch
+ [:notifications/add
+ {:status-text (str "Added "
+ (count streams)
+ " streams to queue")
+ :failure :info}]])])}))
(rf/reg-event-fx
:queue/remove
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ pos]]
- (let [updated-db (update db :queue #(into (subvec % 0 pos) (subvec % (inc pos))))
+ (let [updated-db (update db
+ :queue
+ #(into (subvec % 0 pos) (subvec % (inc pos))))
queue-pos (:queue-pos db)
queue-length (count (:queue updated-db))]
{:db updated-db
@@ -48,11 +57,12 @@
(or (< pos queue-pos)
(= pos queue-pos)
(= queue-pos queue-length)))
- [[:dispatch [:queue/change-pos
- (cond
- (= pos queue-length) 0
- (= pos queue-pos) pos
- :else (dec queue-pos))]]]
+ [[:dispatch
+ [:queue/change-pos
+ (cond
+ (= pos queue-length) 0
+ (= pos queue-pos) pos
+ :else (dec queue-pos))]]]
(= (count (:queue updated-db)) 0)
[[:dispatch [:player/dispose]]
[:dispatch [:queue/show false]]]
@@ -61,7 +71,7 @@
(rf/reg-event-fx
:queue/change-pos
[(rf/inject-cofx :store)]
- (fn [{:keys [db store]} [_ i]]
+ (fn [{:keys [db]} [_ i]]
(let [idx (if (< i (count (:queue db)))
i
(when (= (:loop-playback db) :playlist) 0))
diff --git a/src/frontend/tubo/queue/views.cljs b/src/frontend/tubo/queue/views.cljs
index c6326fe..eae40b2 100644
--- a/src/frontend/tubo/queue/views.cljs
+++ b/src/frontend/tubo/queue/views.cljs
@@ -4,7 +4,6 @@
[re-frame.core :as rf]
[reitit.frontend.easy :as rfe]
[tubo.bookmarks.modals :as modals]
- [tubo.components.items :as items]
[tubo.components.layout :as layout]
[tubo.components.player :as player]
[tubo.utils :as utils]))
@@ -29,11 +28,16 @@
(defn popover
[{:keys [url service-id uploader-url] :as item} i menu-active? bookmarks]
- (let [liked? (some #(= (:url %) url) (-> bookmarks first :items))]
+ (let [liked? (some #(= (:url %) url)
+ (-> bookmarks
+ first
+ :items))]
[:div.absolute.right-0.top-0.min-h-full.flex.items-center
[layout/popover-menu menu-active?
[{:label (if liked? "Remove favorite" "Favorite")
- :icon [:i.fa-solid.fa-heart (when liked? {:style {:color (utils/get-service-color service-id)}})]
+ :icon [:i.fa-solid.fa-heart
+ (when liked?
+ {:style {:color (utils/get-service-color service-id)}})]
:on-click #(rf/dispatch [(if liked? :likes/remove :likes/add) item])}
{:label "Play radio"
:icon [:i.fa-solid.fa-tower-cell]
@@ -54,12 +58,13 @@
:extra-classes [:px-7 :py-2]]]))
(defn queue-item
- [item queue queue-pos i bookmarks]
- (let [!menu-active? (r/atom false)
+ [_item _queue _queue-pos _i _bookmarks]
+ (let [!menu-active? (r/atom false)
show-main-player? @(rf/subscribe [:main-player/show])]
(fn [item queue queue-pos i bookmarks]
[:div.relative.w-full
- {:ref #(when (and queue (= queue-pos i) (not show-main-player?)) (rf/dispatch [:scroll-into-view %]))}
+ {:ref #(when (and queue (= queue-pos i) (not show-main-player?))
+ (rf/dispatch [:scroll-into-view %]))}
[item-metadata item queue-pos i]
[popover item i !menu-active? bookmarks]])))
@@ -76,24 +81,26 @@
uploader-name]])
(defn main-controls
- [{:keys [service-id]} queue queue-pos color]
- (let [loop-playback @(rf/subscribe [:loop-playback])
- !player @(rf/subscribe [:player])
- !main-player @(rf/subscribe [:main-player])
- loading? @(rf/subscribe [:background-player/loading])
- bg-player-ready? @(rf/subscribe [:background-player/ready])
- main-player-ready? @(rf/subscribe [:main-player/ready])
- paused? @(rf/subscribe [:paused])
- !elapsed-time @(rf/subscribe [:elapsed-time])
- queue @(rf/subscribe [:queue])
- queue-pos @(rf/subscribe [:queue-pos])]
+ [color]
+ (let [loop-playback @(rf/subscribe [:loop-playback])
+ !player @(rf/subscribe [:player])
+ loading? @(rf/subscribe [:bg-player/loading])
+ bg-player-ready? @(rf/subscribe [:bg-player/ready])
+ paused? @(rf/subscribe [:paused])
+ !elapsed-time @(rf/subscribe [:elapsed-time])
+ queue @(rf/subscribe [:queue])
+ queue-pos @(rf/subscribe [:queue-pos])]
[:<>
[:div.flex.flex-auto.py-2.w-full.items-center.text-sm
[:span.mr-4.whitespace-nowrap
- (if (and bg-player-ready? @!player @!elapsed-time) (utils/format-duration @!elapsed-time) "--:--")]
+ (if (and bg-player-ready? @!player @!elapsed-time)
+ (utils/format-duration @!elapsed-time)
+ "--:--")]
[player/time-slider !player !elapsed-time color]
[:span.ml-4.whitespace-nowrap
- (if (and bg-player-ready? @!player) (utils/format-duration (.-duration @!player)) "--:--")]]
+ (if (and bg-player-ready? @!player)
+ (utils/format-duration (.-duration @!player))
+ "--:--")]]
[:div.flex.justify-center.items-center
[player/loop-button loop-playback color true]
[player/button
@@ -104,21 +111,23 @@
:show-on-mobile? true]
[player/button
:icon [:i.fa-solid.fa-backward]
- :on-click #(rf/dispatch [:background-player/seek (- @!elapsed-time 5)])
+ :on-click #(rf/dispatch [:bg-player/seek (- @!elapsed-time 5)])
:extra-classes [:text-xl]
:show-on-mobile? true]
[player/button
- :icon (if (and (not loading?) @!player)
- (if paused?
- [:i.fa-solid.fa-play]
- [:i.fa-solid.fa-pause])
- [layout/loading-icon color :text-3xl])
- :on-click #(rf/dispatch [:background-player/pause (not (.-paused @!player))])
+ :icon
+ (if (and (not loading?) @!player)
+ (if paused?
+ [:i.fa-solid.fa-play]
+ [:i.fa-solid.fa-pause])
+ [layout/loading-icon color :text-3xl])
+ :on-click
+ #(rf/dispatch [:bg-player/pause (not (.-paused @!player))])
:show-on-mobile? true
:extra-classes [:text-3xl]]
[player/button
:icon [:i.fa-solid.fa-forward]
- :on-click #(rf/dispatch [:background-player/seek (+ @!elapsed-time 5)])
+ :on-click #(rf/dispatch [:bg-player/seek (+ @!elapsed-time 5)])
:extra-classes [:text-xl]
:show-on-mobile? true]
[player/button
@@ -140,7 +149,9 @@
bookmarks @(rf/subscribe [:bookmarks])
queue-pos @(rf/subscribe [:queue-pos])
queue @(rf/subscribe [:queue])
- color (-> stream :service-id utils/get-service-color)]
+ color (-> stream
+ :service-id
+ utils/get-service-color)]
[:div.fixed.flex.flex-col.items-center.min-w-full.w-full.z-10.backdrop-blur
{:class ["dark:bg-neutral-900/90" "bg-neutral-100/90"
"min-h-[calc(100dvh-56px)]" "h-[calc(100dvh-56px)]"
@@ -154,4 +165,4 @@
^{:key i} [queue-item item queue queue-pos i bookmarks])]
[:div.flex.flex-col.py-4.shrink-0.px-5
[queue-metadata stream]
- [main-controls stream queue queue-pos color]]]]))
+ [main-controls color]]]]))
diff --git a/src/frontend/tubo/routes.cljs b/src/frontend/tubo/routes.cljs
index d721429..67de20e 100644
--- a/src/frontend/tubo/routes.cljs
+++ b/src/frontend/tubo/routes.cljs
@@ -13,46 +13,57 @@
(def router
(ref/router
- [["/" {:view kiosk/kiosk
- :name :homepage
- :controllers [{:start #(rf/dispatch [:fetch-homepage])}]}]
- ["/search" {:view search/search
- :name :search-page
- :controllers [{:parameters {:query [:q :serviceId]}
- :start (fn [{{:keys [serviceId q]} :query}]
- (rf/dispatch [:search/fetch-page serviceId q]))
- :stop #(rf/dispatch [:search/show-form false])}]}]
- ["/stream" {:view stream/stream
- :name :stream-page
- :controllers [{:parameters {:query [:url]}
- :start (fn [{{:keys [url]} :query}]
- (rf/dispatch [:stream/fetch-page url]))}]}]
- ["/channel" {:view channel/channel
- :name :channel-page
- :controllers [{:parameters {:query [:url]}
- :start (fn [{{:keys [url]} :query}]
- (rf/dispatch [:channel/fetch-page url]))}]}]
- ["/playlist" {:view playlist/playlist
- :name :playlist-page
- :controllers [{:parameters {:query [:url]}
- :start (fn [{{:keys [url]} :query}]
- (rf/dispatch [:playlist/fetch-page url]))}]}]
- ["/kiosk" {:view kiosk/kiosk
- :name :kiosk-page
- :controllers [{:parameters {:query [:kioskId :serviceId]}
- :start (fn [{{:keys [serviceId kioskId]} :query}]
- (rf/dispatch [:kiosks/fetch-page serviceId kioskId]))}]}]
- ["/settings" {:view settings/settings
- :name :settings-page
- :controllers [{:start #(rf/dispatch [:settings/fetch-page])}]}]
- ["/bookmark" {:view bookmarks/bookmark
- :name :bookmark-page
- :controllers [{:parameters {:query [:id]}
- :start (fn [{{:keys [id]} :query}]
- (rf/dispatch [:bookmark/fetch-page id]))}]}]
- ["/bookmarks" {:view bookmarks/bookmarks
- :name :bookmarks-page
- :controllers [{:start #(rf/dispatch [:bookmarks/fetch-page])}]}]]))
+ [["/"
+ {:view kiosk/kiosk
+ :name :homepage
+ :controllers [{:start #(rf/dispatch [:fetch-homepage])}]}]
+ ["/search"
+ {:view search/search
+ :name :search-page
+ :controllers [{:parameters {:query [:q :serviceId]}
+ :start (fn [{{:keys [serviceId q]} :query}]
+ (rf/dispatch [:search/fetch-page serviceId
+ q]))
+ :stop #(rf/dispatch [:search/show-form false])}]}]
+ ["/stream"
+ {:view stream/stream
+ :name :stream-page
+ :controllers [{:parameters {:query [:url]}
+ :start (fn [{{:keys [url]} :query}]
+ (rf/dispatch [:stream/fetch-page url]))}]}]
+ ["/channel"
+ {:view channel/channel
+ :name :channel-page
+ :controllers [{:parameters {:query [:url]}
+ :start (fn [{{:keys [url]} :query}]
+ (rf/dispatch [:channel/fetch-page url]))}]}]
+ ["/playlist"
+ {:view playlist/playlist
+ :name :playlist-page
+ :controllers [{:parameters {:query [:url]}
+ :start (fn [{{:keys [url]} :query}]
+ (rf/dispatch [:playlist/fetch-page url]))}]}]
+ ["/kiosk"
+ {:view kiosk/kiosk
+ :name :kiosk-page
+ :controllers [{:parameters {:query [:kioskId :serviceId]}
+ :start (fn [{{:keys [serviceId kioskId]} :query}]
+ (rf/dispatch [:kiosks/fetch-page serviceId
+ kioskId]))}]}]
+ ["/settings"
+ {:view settings/settings
+ :name :settings-page
+ :controllers [{:start #(rf/dispatch [:settings/fetch-page])}]}]
+ ["/bookmark"
+ {:view bookmarks/bookmark
+ :name :bookmark-page
+ :controllers [{:parameters {:query [:id]}
+ :start (fn [{{:keys [id]} :query}]
+ (rf/dispatch [:bookmark/fetch-page id]))}]}]
+ ["/bookmarks"
+ {:view bookmarks/bookmarks
+ :name :bookmarks-page
+ :controllers [{:start #(rf/dispatch [:bookmarks/fetch-page])}]}]]))
(defn on-navigate
[new-match]
diff --git a/src/frontend/tubo/search/events.cljs b/src/frontend/tubo/search/events.cljs
index cfa3fe5..320e5ec 100644
--- a/src/frontend/tubo/search/events.cljs
+++ b/src/frontend/tubo/search/events.cljs
@@ -6,22 +6,27 @@
(rf/reg-event-fx
:search/fetch
- (fn [{:keys [db]} [_ service-id on-success on-error params]]
+ (fn [_ [_ service-id on-success on-error params]]
(api/get-request (str "/services/" service-id "/search")
- on-success on-error params)))
+ on-success
+ on-error
+ params)))
(rf/reg-event-fx
:search/load-page
(fn [{:keys [db]} [_ res]]
(let [search-res (js->clj res :keywordize-keys true)]
- {:db (assoc db :search-results search-res
+ {:db (assoc db
+ :search-results search-res
:show-page-loading false)
:fx [[:dispatch [:services/fetch search-res]]]})))
(rf/reg-event-fx
:search/bad-page-response
(fn [{:keys [db]} [_ service-id query res]]
- {:fx [[:dispatch [:change-view #(layout/error res [:search/fetch-page service-id query])]]]
+ {:fx [[:dispatch
+ [:change-view
+ #(layout/error res [:search/fetch-page service-id query])]]]
:db (assoc db :show-page-loading false)}))
(rf/reg-event-fx
@@ -29,10 +34,12 @@
(fn [{:keys [db]} [_ service-id query]]
{:db (assoc db
:show-page-loading true
- :show-search-form true
- :search-results nil)
- :fx [[:dispatch [:search/fetch service-id
- [:search/load-page] [:search/bad-page-response service-id query] {:q query}]]
+ :show-search-form true
+ :search-results nil)
+ :fx [[:dispatch
+ [:search/fetch service-id
+ [:search/load-page] [:search/bad-page-response service-id query]
+ {:q query}]]
[:document-title (str "Search for \"" query "\"")]]}))
(rf/reg-event-db
@@ -44,7 +51,8 @@
(assoc-in [:search-results :next-page] nil)
(assoc :show-pagination-loading false))
(-> db
- (update-in [:search-results :items] #(apply conj %1 %2)
+ (update-in [:search-results :items]
+ #(apply conj %1 %2)
(:items search-res))
(assoc-in [:search-results :next-page] (:next-page search-res))
(assoc :show-pagination-loading false))))))
@@ -54,16 +62,20 @@
(fn [{:keys [db]} [_ query id next-page-url]]
(if (empty? next-page-url)
{:db (assoc db :show-pagination-loading false)}
- {:fx [[:dispatch [:search/fetch id
- [:search/load-paginated] [:bad-response]
- {:q query
- :nextPage (js/encodeURIComponent next-page-url)}]]]
+ {:fx [[:dispatch
+ [:search/fetch id
+ [:search/load-paginated] [:bad-response]
+ {:q query
+ :nextPage (js/encodeURIComponent next-page-url)}]]]
:db (assoc db :show-pagination-loading true)})))
(rf/reg-event-db
:search/show-form
(fn [db [_ show?]]
- (when-not (= (-> db :current-match :path) "search")
+ (when-not (= (-> db
+ :current-match
+ :path)
+ "search")
(assoc db :show-search-form show?))))
(rf/reg-event-db
diff --git a/src/frontend/tubo/search/views.cljs b/src/frontend/tubo/search/views.cljs
index 58764f9..a121568 100644
--- a/src/frontend/tubo/search/views.cljs
+++ b/src/frontend/tubo/search/views.cljs
@@ -2,11 +2,11 @@
(:require
[re-frame.core :as rf]
[reagent.core :as r]
- [reitit.frontend.easy :as rfe]
[tubo.components.items :as items]
[tubo.components.layout :as layout]))
-(defn search-form []
+(defn search-form
+ []
(let [!query (r/atom "")
!input (r/atom nil)]
(fn []
@@ -14,7 +14,7 @@
show-search-form? @(rf/subscribe [:show-search-form])
service-id @(rf/subscribe [:service-id])]
[:form.relative.flex.items-center.text-white.ml-4
- {:class (when-not show-search-form? "hidden")
+ {:class (when-not show-search-form? "hidden")
:on-submit #(do (.preventDefault %)
(when-not (empty? @!query)
(rf/dispatch [:navigate
@@ -49,12 +49,10 @@
(defn search
[{{:keys [q serviceId]} :query-params}]
- (let [{:keys [items next-page]
- :as search-results} @(rf/subscribe [:search-results])
- next-page-url (:url next-page)
- services @(rf/subscribe [:services])
- service-id (or @(rf/subscribe [:service-id]) serviceId)
- scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])]
+ (let [{:keys [items next-page]} @(rf/subscribe [:search-results])
+ next-page-url (:url next-page)
+ service-id (or @(rf/subscribe [:service-id]) serviceId)
+ scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])]
(when scrolled-to-bottom?
(rf/dispatch [:search/fetch-paginated q service-id next-page-url]))
[layout/content-container
diff --git a/src/frontend/tubo/services/events.cljs b/src/frontend/tubo/services/events.cljs
index 7fb1789..922dd28 100644
--- a/src/frontend/tubo/services/events.cljs
+++ b/src/frontend/tubo/services/events.cljs
@@ -8,8 +8,9 @@
(fn [{:keys [db]} [_ {:keys [service-id]}]]
{:db db
:fx [[:dispatch [:services/change-id service-id]]
- [:dispatch [:kiosks/fetch-all service-id
- [:kiosks/load] [:bad-response]]]]}))
+ [:dispatch
+ [:kiosks/fetch-all service-id
+ [:kiosks/load] [:bad-response]]]]}))
(rf/reg-event-fx
:services/change-id
@@ -20,7 +21,7 @@
(rf/reg-event-fx
:services/fetch-all
- (fn [{:keys [db]} [_ on-success on-error]]
+ (fn [_ [_ on-success on-error]]
(api/get-request "/services" on-success on-error)))
(rf/reg-event-db
diff --git a/src/frontend/tubo/services/views.cljs b/src/frontend/tubo/services/views.cljs
index b27dca0..ceac017 100644
--- a/src/frontend/tubo/services/views.cljs
+++ b/src/frontend/tubo/services/views.cljs
@@ -8,13 +8,17 @@
{:style {:background service-color}}
[:div.w-full.box-border.z-10.lg:z-0
[:select.border-none.focus:ring-transparent.bg-blend-color-dodge.font-bold.w-full
- {:on-change #(rf/dispatch [:kiosks/change-page (js/parseInt (.. % -target -value))])
+ {:on-change #(rf/dispatch [:kiosks/change-page
+ (js/parseInt (.. % -target -value))])
:value service-id
:style {:background :transparent}}
(when services
(for [[i service] (map-indexed vector services)]
- ^{:key i} [:option.text-white.bg-neutral-900.border-none
- {:value (:id service)}
- (-> service :info :name)]))]]
+ ^{:key i}
+ [:option.text-white.bg-neutral-900.border-none
+ {:value (:id service)}
+ (-> service
+ :info
+ :name)]))]]
[:div.flex.items-center.justify-end.absolute.min-h-full.top-0.right-4.lg:right-0.z-0
[:i.fa-solid.fa-caret-down]]])
diff --git a/src/frontend/tubo/settings/events.cljs b/src/frontend/tubo/settings/events.cljs
index e2a5643..57e173f 100644
--- a/src/frontend/tubo/settings/events.cljs
+++ b/src/frontend/tubo/settings/events.cljs
@@ -15,27 +15,38 @@
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ service-name service-id res]]
(let [kiosks-res (js->clj res :keywordize-keys true)
- default-service-kiosk (-> db :settings :default-service :default-kiosk)
+ default-service-kiosk (-> db
+ :settings
+ :default-service
+ :default-kiosk)
default-kiosk (if (some #(= % default-service-kiosk)
(:available-kiosks kiosks-res))
default-service-kiosk
(:default-kiosk kiosks-res))]
- {:db (update-in db [:settings :default-service] assoc
- :id service-name
- :service-id service-id
+ {:db (update-in db
+ [:settings :default-service]
+ assoc
+ :id service-name
+ :service-id service-id
:available-kiosks (:available-kiosks kiosks-res)
- :default-kiosk default-kiosk)
- :store (update-in store [:default-service] assoc
- :id service-name
- :service-id service-id
+ :default-kiosk default-kiosk)
+ :store (update-in store
+ [:default-service]
+ assoc
+ :id service-name
+ :service-id service-id
:available-kiosks (:available-kiosks kiosks-res)
- :default-kiosk default-kiosk)})))
+ :default-kiosk default-kiosk)})))
(rf/reg-event-fx
:settings/change-service
[(rf/inject-cofx :store)]
- (fn [{:keys [db store]} [_ val]]
- (let [service-id (-> (filter #(= val (-> % :info :name)) (:services db))
+ (fn [{:keys [db]} [_ val]]
+ (let [service-id (-> (filter #(= val
+ (-> %
+ :info
+ :name))
+ (:services db))
first
:id)]
(api/get-request (str "/services/" service-id "/kiosks")
@@ -52,9 +63,17 @@
(rf/reg-event-fx
:settings/fetch-page
(fn [{:keys [db]} _]
- (let [id (-> db :settings :default-service :id)
- service-id (-> db :settings :default-service :service-id)]
+ (let [id (-> db
+ :settings
+ :default-service
+ :id)
+ service-id (-> db
+ :settings
+ :default-service
+ :service-id)]
(assoc
(api/get-request (str "/services/" service-id "/kiosks")
- [:settings/load-kiosks id service-id] [:bad-response])
- :document-title "Settings"))))
+ [:settings/load-kiosks id service-id]
+ [:bad-response])
+ :document-title
+ "Settings"))))
diff --git a/src/frontend/tubo/settings/views.cljs b/src/frontend/tubo/settings/views.cljs
index 207d125..0658bbb 100644
--- a/src/frontend/tubo/settings/views.cljs
+++ b/src/frontend/tubo/settings/views.cljs
@@ -16,20 +16,23 @@
(defn settings
[]
- (let [{:keys [theme themes show-comments show-related show-description
- default-service]} @(rf/subscribe [:settings])
- service-color @(rf/subscribe [:service-color])
- services @(rf/subscribe [:services])]
+ (let [{:keys [theme show-comments show-related show-description
+ default-service]}
+ @(rf/subscribe [:settings])
+ services @(rf/subscribe [:services])]
[layout/content-container
[layout/content-header "Settings"]
[:form.flex.flex-wrap.py-4
[select-input "Theme" :theme theme #{:auto :light :dark}]
[select-input "Default service" :default-service (:id default-service)
- (map #(-> % :info :name) services)
- #(rf/dispatch [:settings/change-service (.. % -target -value)])]
+ (map #(-> %
+ :info
+ :name)
+ services)
+ #(rf/dispatch [:settings/change-service (.. % -target -value)])]
[select-input "Default kiosk" :default-service
(:default-kiosk default-service) (:available-kiosks default-service)
- #(rf/dispatch [:settings/change-kiosk (.. % -target -value)])]
+ #(rf/dispatch [:settings/change-kiosk (.. % -target -value)])]
[boolean-input "Show description" :show-description show-description]
[boolean-input "Show comments" :show-comments show-comments]
[boolean-input "Show related videos" :show-related show-related]]]))
diff --git a/src/frontend/tubo/stream/events.cljs b/src/frontend/tubo/stream/events.cljs
index 6b4795a..7b55e7c 100644
--- a/src/frontend/tubo/stream/events.cljs
+++ b/src/frontend/tubo/stream/events.cljs
@@ -6,17 +6,21 @@
(rf/reg-event-fx
:stream/fetch
- (fn [{:keys [db]} [_ url on-success on-error]]
+ (fn [_ [_ url on-success on-error]]
(api/get-request (str "/streams/" (js/encodeURIComponent url))
- on-success on-error)))
+ on-success
+ on-error)))
(rf/reg-event-fx
:stream/load-page
(fn [{:keys [db]} [_ res]]
(let [stream-res (js->clj res :keywordize-keys true)]
- {:db (assoc db :stream stream-res
+ {:db (assoc db
+ :stream stream-res
:show-page-loading false)
- :fx [(when (and (-> db :settings :show-comments))
+ :fx [(when (-> db
+ :settings
+ :show-comments)
[:dispatch [:comments/fetch-page (:url stream-res)]])
[:dispatch [:services/fetch stream-res]]
[:document-title (:name stream-res)]]})))
@@ -24,19 +28,25 @@
(rf/reg-event-fx
:stream/bad-page-response
(fn [{:keys [db]} [_ url res]]
- {:fx [[:dispatch [:change-view #(layout/error res [:stream/fetch-page url])]]]
+ {:fx [[:dispatch
+ [:change-view #(layout/error res [:stream/fetch-page url])]]]
:db (assoc db :show-page-loading false)}))
(rf/reg-event-fx
:stream/fetch-page
(fn [{:keys [db]} [_ url]]
- {:fx [[:dispatch [:stream/fetch url
- [:stream/load-page] [:stream/bad-page-response url]]]]
+ {:fx [[:dispatch
+ [:stream/fetch url
+ [:stream/load-page] [:stream/bad-page-response url]]]]
:db (assoc db
:show-page-loading true
- :stream nil)}))
+ :stream nil)}))
(rf/reg-event-db
:stream/toggle-layout
(fn [db [_ layout]]
- (assoc-in db [:stream layout] (not (-> db :stream layout)))))
+ (assoc-in db
+ [:stream layout]
+ (not (-> db
+ :stream
+ layout)))))
diff --git a/src/frontend/tubo/stream/views.cljs b/src/frontend/tubo/stream/views.cljs
index 5c855e4..568563b 100644
--- a/src/frontend/tubo/stream/views.cljs
+++ b/src/frontend/tubo/stream/views.cljs
@@ -15,7 +15,10 @@
(let [!menu-active? (r/atom nil)]
(fn [{:keys [service-id url] :as stream}]
(let [bookmarks @(rf/subscribe [:bookmarks])
- liked? (some #(= (:url %) url) (-> bookmarks first :items))]
+ liked? (some #(= (:url %) url)
+ (-> bookmarks
+ first
+ :items))]
[layout/popover-menu !menu-active?
[{:label "Add to queue"
:icon [:i.fa-solid.fa-headphones]
@@ -28,13 +31,15 @@
[:i.fa-solid.fa-heart
{:style {:color (utils/get-service-color service-id)}}]
[:i.fa-solid.fa-heart])
- :on-click #(rf/dispatch [(if liked? :likes/remove :likes/add) stream true])}
+ :on-click #(rf/dispatch [(if liked? :likes/remove :likes/add) stream
+ true])}
{:label "Original"
:link {:route url :external? true}
:icon [:i.fa-solid.fa-external-link-alt]}
{:label "Add to playlist"
:icon [:i.fa-solid.fa-plus]
- :on-click #(rf/dispatch [:modals/open [modals/add-to-bookmark stream]])}]]))))
+ :on-click #(rf/dispatch [:modals/open
+ [modals/add-to-bookmark stream]])}]]))))
(defn metadata-uploader
[{:keys [uploader-url uploader-name subscriber-count] :as stream}]
@@ -84,7 +89,7 @@
(defn description
[{:keys [description show-description]}]
(let [show? (:show-description @(rf/subscribe [:settings]))]
- (when (and show? (not (empty? description)))
+ (when (and show? (seq description))
[layout/show-more-container show-description description
#(rf/dispatch [(if @(rf/subscribe [:main-player/show])
:main-player/toggle-layout
@@ -95,7 +100,7 @@
[{:keys [comments-page show-comments show-comments-loading url] :as stream}]
(let [show? (:show-comments @(rf/subscribe [:settings]))
service-color @(rf/subscribe [:service-color])]
- (when (and comments-page (not (empty? (:comments comments-page))) show?)
+ (when (and comments-page (seq (:comments comments-page)) show?)
[layout/accordeon
{:label "Comments"
:on-open #(if show-comments
@@ -115,27 +120,31 @@
(let [!menu-active? (r/atom nil)]
(fn [{:keys [related-streams show-related]}]
(let [show? (:show-related @(rf/subscribe [:settings]))]
- (when (and show? (not (empty? related-streams)))
+ (when (and show? (seq related-streams))
[layout/accordeon
{:label "Suggested"
:on-open #(rf/dispatch [(if @(rf/subscribe [:main-player/show])
:main-player/toggle-layout
- :stream/toggle-layout) :show-related])
+ :stream/toggle-layout)
+ :show-related])
:open? (not show-related)
:left-icon "fa-solid fa-list"
:right-button [layout/popover-menu !menu-active?
[{:label "Add to queue"
:icon [:i.fa-solid.fa-headphones]
- :on-click #(rf/dispatch [:queue/add-n related-streams true])}
+ :on-click #(rf/dispatch [:queue/add-n
+ related-streams true])}
{:label "Add to playlist"
:icon [:i.fa-solid.fa-plus]
- :on-click #(rf/dispatch [:modals/open [modals/add-to-bookmark related-streams]])}]]}
+ :on-click #(rf/dispatch [:modals/open
+ [modals/add-to-bookmark
+ related-streams]])}]]}
[items/related-streams related-streams nil]])))))
(defn stream
[]
- (let [{:keys [audio-streams video-streams name thumbnail-url] :as stream} @(rf/subscribe [:stream])
- !player @(rf/subscribe [:main-player])
+ (let [stream @(rf/subscribe [:stream])
+ !player @(rf/subscribe [:main-player])
page-loading? @(rf/subscribe [:show-page-loading])]
[:<>
(when-not page-loading?
diff --git a/src/frontend/tubo/subs.cljs b/src/frontend/tubo/subs.cljs
index 2dea707..a789ccb 100644
--- a/src/frontend/tubo/subs.cljs
+++ b/src/frontend/tubo/subs.cljs
@@ -2,7 +2,6 @@
(:require
[reagent.core :as r]
[re-frame.core :as rf]
- [tubo.utils :as utils]
[tubo.bookmarks.subs]
[tubo.channel.subs]
[tubo.kiosks.subs]
@@ -42,7 +41,6 @@
#(reset! theme (if (.-matches %) "dark" "light")))
theme))
-
(rf/reg-sub
:is-window-visible
(fn [_ _]
diff --git a/src/frontend/tubo/utils.cljs b/src/frontend/tubo/utils.cljs
index 4b4a45a..6d68219 100644
--- a/src/frontend/tubo/utils.cljs
+++ b/src/frontend/tubo/utils.cljs
@@ -31,7 +31,9 @@
(defn format-date-ago
[date]
- (if (-> date js/Date.parse js/isNaN)
+ (if (-> date
+ js/Date.parse
+ js/isNaN)
date
(timeago/format date)))
@@ -39,11 +41,17 @@
[num]
(.format
(js/Intl.NumberFormat
- "en-US" #js {"notation" "compact" "maximumFractionDigits" 1})
+ "en-US"
+ #js {"notation" "compact" "maximumFractionDigits" 1})
num))
(defn format-duration
[num]
(let [duration (and (not (js/isNaN num)) (js/Date. (* num 1000)))
- slice (and duration #(.slice % (if (>= (.getUTCHours duration) 1) 11 14) 19))]
- (if slice (-> duration (.toISOString) slice) "--:--")))
+ slice (and duration
+ #(.slice % (if (>= (.getUTCHours duration) 1) 11 14) 19))]
+ (if slice
+ (-> duration
+ (.toISOString)
+ slice)
+ "--:--")))
diff --git a/src/frontend/tubo/views.cljs b/src/frontend/tubo/views.cljs
index 124f3ce..3a68b65 100644
--- a/src/frontend/tubo/views.cljs
+++ b/src/frontend/tubo/views.cljs
@@ -15,7 +15,9 @@
[navigation/navbar current-match]
[notifications/notifications-panel]
[:div.flex.flex-col.flex-auto.justify-between.relative
- (when-let [view (-> current-match :data :view)]
+ (when-let [view (-> current-match
+ :data
+ :view)]
[view current-match])
[queue/queue]
[player/main-player]