aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMiguel Ángel Moreno <mail@migalmoreno.com>2024-12-01 13:16:35 +0100
committerMiguel Ángel Moreno <mail@migalmoreno.com>2024-12-01 13:26:43 +0100
commitc6c5f094c41b0a024f052ce2350872490f60a73a (patch)
tree69514eb15bcc9f89f4c8e0ec564344121fe388a5 /src
parent3951173441bcb511c8f8ae383002e6992e6409a8 (diff)
feat: replace vidstack with Media Chrome
Diffstat (limited to 'src')
-rw-r--r--src/frontend/tubo/bg_player/events.cljs24
-rw-r--r--src/frontend/tubo/bg_player/views.cljs72
-rw-r--r--src/frontend/tubo/main_player/events.cljs2
-rw-r--r--src/frontend/tubo/player/events.cljs10
-rw-r--r--src/frontend/tubo/player/views.cljs161
-rw-r--r--src/frontend/tubo/queue/events.cljs18
6 files changed, 152 insertions, 135 deletions
diff --git a/src/frontend/tubo/bg_player/events.cljs b/src/frontend/tubo/bg_player/events.cljs
index 75f3a8c..7a0f22b 100644
--- a/src/frontend/tubo/bg_player/events.cljs
+++ b/src/frontend/tubo/bg_player/events.cljs
@@ -19,36 +19,20 @@
:bg-player/pause
[(rf/inject-cofx ::inject/sub [:bg-player])]
(fn [{:keys [bg-player]} [_ paused?]]
- {:player/pause {:paused? paused?
+ {:player/pause {:paused? (not paused?)
:player bg-player}}))
(rf/reg-event-fx
- :bg-player/play
- [(rf/inject-cofx ::inject/sub [:elapsed-time])
- (rf/inject-cofx ::inject/sub [:main-player])]
- (fn [{:keys [main-player db elapsed-time]}]
- {:fx [[:dispatch [:bg-player/set-paused false]]
- [:dispatch [:bg-player/seek @elapsed-time]]
- (when (and (:main-player/ready db) main-player @main-player)
- [:dispatch [:main-player/pause true]])]}))
-
-(rf/reg-event-fx
- :bg-player/stop
- (fn [_]
- {:fx [[:dispatch [:bg-player/pause true]]
- [:dispatch [:bg-player/seek 0]]]}))
-
-(rf/reg-event-fx
:bg-player/start
[(rf/inject-cofx ::inject/sub [:bg-player])
(rf/inject-cofx ::inject/sub [:elapsed-time])]
- (fn [{:keys [db bg-player]} _]
+ (fn [{:keys [db bg-player elapsed-time]} _]
{:fx [[:dispatch [:bg-player/set-paused true]]
+ [:dispatch [:bg-player/seek @elapsed-time]]
[:dispatch [:bg-player/pause false]]
[:dispatch
[:player/change-volume (:player/volume db)
- bg-player]]
- ]}))
+ bg-player]]]}))
(rf/reg-event-fx
:bg-player/mute
diff --git a/src/frontend/tubo/bg_player/views.cljs b/src/frontend/tubo/bg_player/views.cljs
index c5f336b..6be514e 100644
--- a/src/frontend/tubo/bg_player/views.cljs
+++ b/src/frontend/tubo/bg_player/views.cljs
@@ -2,14 +2,12 @@
(:require
[clojure.string :as str]
[re-frame.core :as rf]
+ [reagent.dom :as rdom]
[reagent.core :as r]
[reitit.frontend.easy :as rfe]
[tubo.bookmarks.modals :as modals]
[tubo.layout.views :as layout]
- [tubo.utils :as utils]
- ["@vidstack/react" :refer (MediaPlayer MediaProvider)]
- ["@vidstack/react/player/layouts/default" :refer
- (defaultLayoutIcons DefaultAudioLayout)]))
+ [tubo.utils :as utils]))
(defonce base-slider-classes
["h-2" "cursor-pointer" "appearance-none" "bg-neutral-300"
@@ -180,8 +178,7 @@
[: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))])
+ :on-click #(rf/dispatch [:bg-player/pause (not (.-paused @!player))])
:show-on-mobile? true
:extra-classes ["lg:text-2xl"]]
[button
@@ -258,52 +255,31 @@
:menu-styles {:bottom "30px" :top nil :right "10px"}
:extra-classes [:pt-1 :!pl-4 :px-3]]]))))
-(defn get-audio-player-sources
- [available-streams]
- (if available-streams
- (->> available-streams
- (filter #(not= (:format %) "OPUS"))
- (sort-by :bitrate)
- (map (fn [{:keys [content]}] {:src content :type "audio/mpeg"})))
- []))
-
(defn audio-player
- [_ _]
- (let [!elapsed-time @(rf/subscribe [:elapsed-time])
- !bg-player-first? (r/atom nil)]
+ [_]
+ (let [!elapsed-time @(rf/subscribe [:elapsed-time])
+ queue-pos @(rf/subscribe [:queue/position])
+ stream @(rf/subscribe [:queue/current])]
(r/create-class
{:component-will-unmount #(rf/dispatch [:bg-player/ready false])
+ :component-did-mount
+ (fn [this]
+ (set! (.-onended (rdom/dom-node this))
+ #(rf/dispatch [:queue/change-pos (inc queue-pos)]))
+ (when stream
+ (set! (.-src (rdom/dom-node this))
+ (:content (nth (:audio-streams stream) 0)))))
:reagent-render
- (fn [{:keys [name audio-streams]} !player]
- [:> MediaPlayer
- {:title name
- :class "invisible fixed"
- :controls []
- :src (get-audio-player-sources audio-streams)
- :viewType "audio"
- :ref #(reset! !player %)
+ (fn [!player]
+ [:audio
+ {:ref #(reset! !player %)
:loop (= @(rf/subscribe [:player/loop]) :stream)
- :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/position]))])
- (reset! !elapsed-time 0))
- :onPlay #(rf/dispatch [:bg-player/play])
- :onReplay (fn []
- (rf/dispatch [:bg-player/set-paused false])
- (reset! !elapsed-time 0))
- :onPause #(rf/dispatch [:bg-player/set-paused true])
- :onLoadedData (fn []
- (rf/dispatch [:bg-player/start])
- (when-not @!bg-player-first?
- (reset! !bg-player-first? true)))
- :onSourceChange #(when @!bg-player-first?
- (reset! !elapsed-time 0))}
- [:> MediaProvider]
- [:> DefaultAudioLayout {:icons defaultLayoutIcons}]])})))
+ :on-can-play #(rf/dispatch [:bg-player/ready true])
+ :on-seeked #(reset! !elapsed-time (.-currentTime @!player))
+ :on-time-update #(reset! !elapsed-time (.-currentTime @!player))
+ :on-play #(rf/dispatch [:bg-player/set-paused false])
+ :on-pause #(rf/dispatch [:bg-player/set-paused true])
+ :on-loaded-data #(rf/dispatch [:bg-player/start])}])})))
(defn player
[]
@@ -335,7 +311,7 @@
:background-position "center"
:background-repeat "no-repeat"}}
[:div.flex.items-center
- [audio-player stream !player]
+ [audio-player !player]
[metadata stream]
[main-controls !player color]
[extra-controls !player stream color]]])))
diff --git a/src/frontend/tubo/main_player/events.cljs b/src/frontend/tubo/main_player/events.cljs
index a5e8414..da9676e 100644
--- a/src/frontend/tubo/main_player/events.cljs
+++ b/src/frontend/tubo/main_player/events.cljs
@@ -14,7 +14,7 @@
[(rf/inject-cofx ::inject/sub [:main-player])]
(fn [{:keys [db main-player]} [_ paused?]]
(when (:main-player/ready db)
- {:player/pause {:paused? paused?
+ {:player/pause {:paused? (not paused?)
:player main-player}})))
(rf/reg-event-fx
diff --git a/src/frontend/tubo/player/events.cljs b/src/frontend/tubo/player/events.cljs
index 7246a7f..6350029 100644
--- a/src/frontend/tubo/player/events.cljs
+++ b/src/frontend/tubo/player/events.cljs
@@ -17,8 +17,10 @@
(rf/reg-fx
:player/src
- (fn [{:keys [player src]}]
- (set! (.-source @player) (clj->js src))))
+ (fn [{:keys [player src current-pos]}]
+ (set! (.-src @player) (clj->js src))
+ (set! (.-onended @player)
+ #(rf/dispatch [:queue/change-pos (inc current-pos)]))))
(rf/reg-fx
:player/loop
@@ -35,7 +37,9 @@
:player/pause
(fn [{:keys [paused? player]}]
(when (and player @player)
- (set! (.-paused @player) paused?))))
+ (if paused?
+ (.play @player)
+ (.pause @player)))))
(rf/reg-fx
:media-session-metadata
diff --git a/src/frontend/tubo/player/views.cljs b/src/frontend/tubo/player/views.cljs
index e1c5549..2a5e02c 100644
--- a/src/frontend/tubo/player/views.cljs
+++ b/src/frontend/tubo/player/views.cljs
@@ -2,27 +2,17 @@
(:require
[re-frame.core :as rf]
[reagent.core :as r]
- ["@vidstack/react" :refer (MediaPlayer MediaProvider Poster)]
- ["@vidstack/react/player/layouts/default" :refer
- (defaultLayoutIcons DefaultVideoLayout)]))
-
-(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))
- (->> available-streams
- (filter #(and (not= (:format %) "WEBMA_OPUS")
- (not= (:format %) "OPUS")
- (not= (:format %) "M4A")))
- (sort-by :bitrate)
- (#(if (empty? (filter (fn [x] (= (:format x) "MP3")) %))
- (reverse %)
- %))
- (map (fn [{:keys [content]}] {:src content :type "video/mp4"}))
- first))
- []))
+ ["media-chrome/dist/react" :refer
+ (MediaController
+ MediaControlBar
+ MediaTimeRange
+ MediaTimeDisplay
+ MediaVolumeRange
+ MediaFullscreenButton
+ MediaPipButton
+ MediaPlayButton
+ MediaPlaybackRateButton
+ MediaMuteButton)]))
(defn video-player
[_stream _!player]
@@ -31,41 +21,96 @@
(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]}
+ (fn [{:keys [video-streams audio-streams thumbnail-url]}
!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)
- :poster thumbnail-url
- :class "w-full xl:w-3/5 overflow-hidden"
- :playsInline true
- :ref #(reset! !player %)
- :loop (when show-main-player?
- (= @(rf/subscribe [:player/loop]) :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/position]))])
- (reset! !elapsed-time 0))
- :onLoadedData (fn []
- (when show-main-player?
- (rf/dispatch [:main-player/start]))
- (when (and @!main-player-first? show-main-player?)
- (reset! !main-player-first? false)))
- :onPlay #(rf/dispatch [:main-player/play])
- :onCanPlay #(rf/dispatch [:main-player/ready true])
- :onSourceChange #(when-not @!main-player-first?
- (reset! !elapsed-time 0))}
- [:> MediaProvider
- [:> Poster
- {:src thumbnail-url
- :alt name
- :class :vds-poster}]]
- [:> DefaultVideoLayout {:icons defaultLayoutIcons}]]))})))
+ (let [show-main-player? @(rf/subscribe [:main-player/show])
+ service-color @(rf/subscribe [:service-color])]
+ [:div
+ {:class "w-full h-80 md:h-[450px] lg:h-[600px]"}
+ [:> MediaController
+ {:style {"--media-secondary-color" "transparent"
+ "--media-primary-color" "white"
+ "aspectRatio" "16/9"
+ "height" "100%"
+ "width" "100%"}}
+ [:video
+ {:style {"max-height" "100%"
+ "min-height" "100%"
+ "min-width" "100%"
+ "max-width" "100%"}
+ :ref #(reset! !player %)
+ :poster thumbnail-url
+ :loop (when show-main-player?
+ (= @(rf/subscribe [:player/loop]) :stream))
+ :on-can-play #(rf/dispatch [:main-player/ready true])
+ :on-ended #(when show-main-player?
+ (rf/dispatch [:queue/change-pos
+ (inc @(rf/subscribe
+ [:queue/position]))])
+ (reset! !elapsed-time 0))
+ :on-play #(rf/dispatch [:main-player/play])
+ :on-loaded-data (fn []
+ (when show-main-player?
+ (rf/dispatch [:main-player/start]))
+ (when (and @!main-player-first?
+ show-main-player?)
+ (reset! !main-player-first? false)))
+ :on-time-update (when show-main-player?
+ #(reset! !elapsed-time (.-currentTime
+ @!player)))
+ :on-seeked (when show-main-player?
+ #(reset! !elapsed-time (.-currentTime
+ @!player)))
+ :slot "media"
+ :src (:content (nth (into video-streams audio-streams)
+ 0))
+ :preload "auto"
+ :muted @(rf/subscribe [:player/muted])
+ :crossOrigin ""}]
+ [:div.ytp-gradient-bottom.absolute.w-full.bottom-0.pointer-events-none.bg-bottom.bg-repeat-x
+ {:style
+ {"paddingTop" "37px"
+ "height" "170px"
+ "backgroundImage"
+ "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAACqCAYAAABsziWkAAAAAXNSR0IArs4c6QAAAQVJREFUOE9lyNdHBQAAhfHb3nvvuu2997jNe29TJJEkkkgSSSSJJJJEEkkiifRH5jsP56Xz8PM5gcC/xfDEmjhKxEOCSaREEiSbFEqkQppJpzJMJiWyINvkUCIX8kw+JQqg0BRRxaaEEqVQZsopUQGVpooS1VBjglStqaNEPTSYRko0QbNpoUQrtJl2qsN0UqILuk0PJXqhz/RTYgAGzRA1bEYoMQpjZpwSExAyk5SYgmkzQ82aOUqEIWKilJiHBbNIiSVYhhVYhTVYhw3YhC3Yhh3YhT3YhwM4hCM4hhM4hTM4hwu4hCu4hhu4hTu4hwd4hCd4hhd4hTd4hw/4hC/4hh/4/QM2/id28uIEJAAAAABJRU5ErkJggg==')"}}]
+ [:> MediaTimeRange
+ {:class "w-full h-[5px]"
+ :style
+ {"--media-control-hover-background" "transparent"
+ "--media-range-track-transition" "height 0.1s linear"
+ "--media-range-track-background" "rgba(255,255,255,.2)"
+ "--media-range-track-pointer-background" "rgba(255,255,255,.5)"
+ "--media-time-range-buffered-color" "rgba(255,255,255,.4)"
+ "--media-range-bar-color" service-color
+ "--media-range-thumb-border-radius" "13px"
+ "--media-range-thumb-background" service-color
+ "--media-range-thumb-transition" "transform 0.1s linear"
+ "--media-range-thumb-transform" "scale(0) translate(0%, 0%)"}}]
+ [:> MediaControlBar
+ {:class "relative pl-[10px] pr-[5px]"
+ :style
+ {"--media-control-hover-background" "transparent"
+ "--media-range-track-height" "3px"
+ "--media-range-thumb-height" "13px"
+ "--media-range-thumb-width" "13px"
+ "--media-range-thumb-border-radius" "13px"}}
+ [:> MediaPlayButton
+ {:class "py-[6px] px-[10px]"
+ :style
+ {"--media-button-icon-width" "30px"}}]
+ [:> MediaMuteButton
+ {:class "peer/mute"}]
+ [:> MediaVolumeRange
+ {:class
+ ["w-0" "overflow-hidden" "transition-[width]"
+ "transition-200" "ease-in" "peer-hover/mute:w-[70px]"
+ "peer-focus/mute:w-[70px]" "hover:w-[70px]" "focus:w-[70px]"]
+ :style
+ {"--media-range-track-background" "rgba(255,255,255,.2)"
+ "--media-range-bar-color" service-color
+ "--media-range-thumb-background" service-color}}]
+ [:> MediaTimeDisplay {:showDuration true}]
+ [:span.control-spacer.grow]
+ [:> MediaPlaybackRateButton]
+ [:> MediaPipButton]
+ [:> MediaFullscreenButton]]]]))})))
diff --git a/src/frontend/tubo/queue/events.cljs b/src/frontend/tubo/queue/events.cljs
index 04502fd..2765af2 100644
--- a/src/frontend/tubo/queue/events.cljs
+++ b/src/frontend/tubo/queue/events.cljs
@@ -1,6 +1,7 @@
(ns tubo.queue.events
(:require
- [re-frame.core :as rf]))
+ [re-frame.core :as rf]
+ [vimsical.re-frame.cofx.inject :as inject]))
(rf/reg-event-fx
:queue/show
@@ -104,8 +105,15 @@
(rf/reg-event-fx
:queue/change-stream
- [(rf/inject-cofx :store)]
- (fn [{:keys [db store]} [_ stream idx]]
+ [(rf/inject-cofx :store)
+ (rf/inject-cofx ::inject/sub [:bg-player])]
+ (fn [{:keys [db store bg-player]} [_ stream idx]]
(let [update-entry (fn [x] (update-in x [:queue idx] #(merge % stream)))]
- {:db (assoc (update-entry db) :queue/position idx)
- :store (assoc (update-entry store) :queue/position idx)})))
+ {:db (assoc (update-entry db) :queue/position idx)
+ :store (assoc (update-entry store) :queue/position idx)
+ :player/src {:player bg-player
+ :src (-> stream
+ :audio-streams
+ first
+ :content)
+ :current-pos idx}})))