aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deps.edn4
-rw-r--r--src/backend/tubo/http.clj4
-rw-r--r--src/backend/tubo/router.clj84
-rw-r--r--src/backend/tubo/routes.clj64
-rw-r--r--src/frontend/tubo/core.cljs4
-rw-r--r--src/frontend/tubo/router.cljs93
-rw-r--r--src/frontend/tubo/routes.cljs76
-rw-r--r--src/shared/tubo/routes.cljc30
8 files changed, 214 insertions, 145 deletions
diff --git a/deps.edn b/deps.edn
index eb80f78..09e8f6c 100644
--- a/deps.edn
+++ b/deps.edn
@@ -5,12 +5,14 @@
metosin/reitit-ring {:mvn/version "0.5.18"}
metosin/reitit-middleware {:mvn/version "0.5.18"}
metosin/reitit-malli {:mvn/version "0.5.18"}
+ metosin/reitit-swagger {:mvn/version "0.5.18"}
+ metosin/reitit-swagger-ui {: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"]
+ :paths ["src/backend" "src/shared" "resources" "classes"]
:mvn/repos {"jitpack" {:url "https://jitpack.io"}}
:aliases
{:build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.4"}}
diff --git a/src/backend/tubo/http.clj b/src/backend/tubo/http.clj
index 200b52e..95913d6 100644
--- a/src/backend/tubo/http.clj
+++ b/src/backend/tubo/http.clj
@@ -1,7 +1,7 @@
(ns tubo.http
(:require
[org.httpkit.server :refer [run-server]]
- [tubo.routes :as routes])
+ [tubo.router :as router])
(:import
tubo.DownloaderImpl
org.schabi.newpipe.extractor.NewPipe
@@ -13,7 +13,7 @@
([] (start-server! 3000))
([port]
(NewPipe/init (DownloaderImpl/init) (Localization. "en" "US"))
- (reset! server (run-server #'routes/app {:port port}))
+ (reset! server (run-server #'router/app {:port port}))
(println "Server running in port" port)))
(defn stop-server! [] (when @server (@server :timeout 100) (reset! server nil)))
diff --git a/src/backend/tubo/router.clj b/src/backend/tubo/router.clj
new file mode 100644
index 0000000..8a031b5
--- /dev/null
+++ b/src/backend/tubo/router.clj
@@ -0,0 +1,84 @@
+(ns tubo.router
+ (:require
+ [reitit.core :as r]
+ [reitit.ring :as ring]
+ [reitit.ring.coercion :as rrc]
+ [reitit.coercion.malli]
+ [reitit.swagger :as swagger]
+ [reitit.swagger-ui :as swagger-ui]
+ [ring.middleware.reload :refer [wrap-reload]]
+ [ring.middleware.params :refer [wrap-params]]
+ [ring.middleware.json :refer [wrap-json-response]]
+ [tubo.handler :as handler]
+ [tubo.routes :as routes]))
+
+(defn expand-routes
+ [data opts]
+ (if (keyword? data)
+ (case data
+ :api/services {:get {:summary "returns all supported services"
+ :handler handler/services}}
+ :api/search {:get {:summary
+ "returns search results for a given service"
+ :coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int?}
+ :query {:q string?}}
+ :handler handler/search}}
+ :api/default-kiosk {:get
+ {:summary
+ "returns default kiosk entries for a given service"
+ :coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int?}}
+ :handler handler/kiosk}}
+ :api/all-kiosks {:get {:summary
+ "returns all kiosks supported by a given service"
+ :coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int?}}
+ :handler handler/kiosks}}
+ :api/kiosk {:get
+ {:summary
+ "returns kiosk entries for a given service and a kiosk ID"
+ :coercion reitit.coercion.malli/coercion
+ :parameters {:path {:service-id int? :kiosk-id string?}}
+ :handler handler/kiosk}}
+ :api/stream {:get {:summary "returns stream data for a given URL"
+ :handler handler/stream}}
+ :api/channel {:get {:summary "returns channel data for a given URL"
+ :handler handler/channel}}
+ :api/channel-tab {:get
+ {:summary
+ "returns channel tab data for a given URL and a tab ID"
+ :handler handler/channel-tabs}}
+ :api/playlist {:get {:summary "returns playlist data for a given URL"
+ :handler handler/playlist}}
+ :api/comments {:get {:summary "returns comments data for a given URL"
+ :handler handler/comments}}
+ :api/swagger-spec {:no-doc true
+ :get {:swagger {:info {:title "Tubo API"}
+ :basePath "/"}
+ :handler (swagger/create-swagger-handler)}}
+ :api/swagger-ui {:no-doc true
+ :get (swagger-ui/create-swagger-ui-handler)}
+ {:no-doc true
+ :handler handler/index})
+ (r/expand data opts)))
+
+(def router
+ (ring/router
+ routes/routes
+ {:expand expand-routes
+ :data {:middleware [rrc/coerce-request-middleware
+ rrc/coerce-response-middleware
+ rrc/coerce-exceptions-middleware]}}))
+
+(def app
+ (ring/ring-handler
+ router
+ (ring/routes
+ (ring/create-resource-handler {:path "/"})
+ (ring/redirect-trailing-slash-handler {:method :add})
+ (ring/create-default-handler
+ {:not-found (constantly {:status 404 :body "Not found"})}))
+ {:middleware [wrap-params
+ [wrap-json-response {:pretty true}]
+ wrap-reload]}))
diff --git a/src/backend/tubo/routes.clj b/src/backend/tubo/routes.clj
deleted file mode 100644
index e8dd536..0000000
--- a/src/backend/tubo/routes.clj
+++ /dev/null
@@ -1,64 +0,0 @@
-(ns tubo.routes
- (:require
- [reitit.ring :as ring]
- [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]]
- [tubo.handler :as handler]))
-
-(def router
- (ring/router
- [["/" handler/index]
- ["/search" handler/index]
- ["/stream" handler/index]
- ["/channel" handler/index]
- ["/playlist" handler/index]
- ["/kiosk" handler/index]
- ["/settings" handler/index]
- ["/bookmark" handler/index]
- ["/bookmarks" handler/index]
- ["/api/v1"
- ["/services"
- ["" {:get handler/services}]
- ["/:service-id/search"
- {:get {:coercion reitit.coercion.malli/coercion
- :parameters {:path {:service-id int?}
- :query {:q string?}}
- :handler handler/search}}]
- ["/:service-id"
- ["/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}}]]]]
- ["/streams/:url" {:get handler/stream}]
- ["/channels"
- ["/:url"
- ["" {:get handler/channel}]
- ["/tabs/:tab-id" {:get handler/channel-tabs}]]]
- ["/playlists/:url" {:get handler/playlist}]
- ["/comments/:url" {:get handler/comments}]]]
- {:data {:middleware [rrc/coerce-request-middleware
- rrc/coerce-response-middleware
- rrc/coerce-exceptions-middleware]}}))
-
-(def app
- (ring/ring-handler
- router
- (ring/routes
- (ring/create-resource-handler {:path "/"})
- (ring/create-default-handler
- {:not-found (constantly {:status 404 :body "Not found"})}))
- {:middleware [wrap-params
- [wrap-json-response {:pretty true}]
- wrap-reload]}))
diff --git a/src/frontend/tubo/core.cljs b/src/frontend/tubo/core.cljs
index c9f7e7c..4f8762f 100644
--- a/src/frontend/tubo/core.cljs
+++ b/src/frontend/tubo/core.cljs
@@ -4,7 +4,7 @@
[reagent.core :as r]
[re-frame.core :as rf]
[tubo.events]
- [tubo.routes :as routes]
+ [tubo.router :as router]
[tubo.subs]
[tubo.views :as views]))
@@ -13,7 +13,7 @@
(defn ^:dev/after-load mount-root
[]
(rf/clear-subscription-cache!)
- (routes/start-routes!)
+ (router/start-router!)
(.render root (r/as-element [(fn [] views/app)])))
(defn ^:export init [] (rf/dispatch-sync [:initialize-db]) (mount-root))
diff --git a/src/frontend/tubo/router.cljs b/src/frontend/tubo/router.cljs
new file mode 100644
index 0000000..3e51171
--- /dev/null
+++ b/src/frontend/tubo/router.cljs
@@ -0,0 +1,93 @@
+(ns tubo.router
+ (:require
+ [reitit.core :as r]
+ [reitit.frontend :as ref]
+ [reitit.frontend.easy :as rfe]
+ [re-frame.core :as rf]
+ [tubo.bookmarks.views :as bookmarks]
+ [tubo.channel.views :as channel]
+ [tubo.kiosks.views :as kiosk]
+ [tubo.playlist.views :as playlist]
+ [tubo.routes :as routes]
+ [tubo.search.views :as search]
+ [tubo.settings.views :as settings]
+ [tubo.stream.views :as stream]))
+
+(defn expand-routes
+ [data opts]
+ (if (keyword? data)
+ (case data
+ :web/homepage {:view kiosk/kiosk
+ :name :homepage
+ :controllers [{:start #(rf/dispatch [:fetch-homepage])}]}
+ :web/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])}]}
+ :web/stream {:view stream/stream
+ :name :stream-page
+ :controllers [{:parameters {:query [:url]}
+ :start (fn [{{:keys [url]} :query}]
+ (rf/dispatch
+ [:stream/fetch-page
+ url]))}]}
+ :web/channel {:view channel/channel
+ :name :channel-page
+ :controllers [{:parameters {:query [:url]}
+ :start (fn [{{:keys [url]} :query}]
+ (rf/dispatch
+ [:channel/fetch-page
+ url]))}]}
+ :web/playlist {:view playlist/playlist
+ :name :playlist-page
+ :controllers [{:parameters {:query [:url]}
+ :start (fn [{{:keys [url]} :query}]
+ (rf/dispatch
+ [:playlist/fetch-page
+ url]))}]}
+ :web/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]))}]}
+ :web/settings {:view settings/settings
+ :name :settings-page
+ :controllers [{:start #(rf/dispatch
+ [:settings/fetch-page])}]}
+ :web/bookmark {:view bookmarks/bookmark
+ :name :bookmark-page
+ :controllers [{:parameters {:query [:id]}
+ :start (fn [{{:keys [id]} :query}]
+ (rf/dispatch
+ [:bookmark/fetch-page
+ id]))}]}
+ :web/bookmarks {:view bookmarks/bookmarks
+ :name :bookmarks-page
+ :controllers [{:start #(rf/dispatch
+ [:bookmarks/fetch-page])}]}
+ nil)
+ (r/expand data opts)))
+
+(def router
+ (ref/router routes/routes {:expand expand-routes}))
+
+(defn on-navigate
+ [new-match]
+ (when new-match
+ (rf/dispatch [:navigation/navigated new-match])))
+
+(defn start-router!
+ []
+ (rfe/start! router on-navigate {:use-fragment false}))
diff --git a/src/frontend/tubo/routes.cljs b/src/frontend/tubo/routes.cljs
deleted file mode 100644
index 8e72d09..0000000
--- a/src/frontend/tubo/routes.cljs
+++ /dev/null
@@ -1,76 +0,0 @@
-(ns tubo.routes
- (:require
- [reitit.frontend :as ref]
- [reitit.frontend.easy :as rfe]
- [re-frame.core :as rf]
- [tubo.channel.views :as channel]
- [tubo.kiosks.views :as kiosk]
- [tubo.playlist.views :as playlist]
- [tubo.bookmarks.views :as bookmarks]
- [tubo.search.views :as search]
- [tubo.settings.views :as settings]
- [tubo.stream.views :as stream]))
-
-(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]))
- :stop #(rf/dispatch [:channel/reset])}]}]
- ["/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]
- (when new-match
- (rf/dispatch [:navigation/navigated new-match])))
-
-(defn start-routes!
- []
- (rfe/start! router on-navigate {:use-fragment false}))
diff --git a/src/shared/tubo/routes.cljc b/src/shared/tubo/routes.cljc
new file mode 100644
index 0000000..f67c547
--- /dev/null
+++ b/src/shared/tubo/routes.cljc
@@ -0,0 +1,30 @@
+(ns tubo.routes)
+
+(def routes
+ [["/" :web/homepage]
+ ["/search" :web/search]
+ ["/stream" :web/stream]
+ ["/channel" :web/channel]
+ ["/playlist" :web/playlist]
+ ["/kiosk" :web/kiosk]
+ ["/settings" :web/settings]
+ ["/bookmark" :web/bookmark]
+ ["/bookmarks" :web/bookmarks]
+ ["/swagger.json" :api/swagger-spec]
+ ["/api-docs/*" :api/swagger-ui]
+ ["/api/v1"
+ ["/services"
+ ["" :api/services]
+ ["/:service-id/search" :api/search]
+ ["/:service-id"
+ ["/default-kiosk" :api/default-kiosk]
+ ["/kiosks"
+ ["" :api/all-kiosks]
+ ["/:kiosk-id" :api/kiosk]]]]
+ ["/streams/:url" :api/stream]
+ ["/channels"
+ ["/:url"
+ ["" :api/channel]
+ ["/tabs/:tab-id" :api/channel-tab]]]
+ ["/playlists/:url" :api/playlist]
+ ["/comments/:url" :api/comments]]])