From 728b0993f5d343c9c5946ce5dc103253048a82e3 Mon Sep 17 00:00:00 2001 From: Miguel Ángel Moreno Date: Sun, 28 Jan 2024 03:09:31 +0100 Subject: feat(frontend): refine video player and tweak sources --- src/frontend/tubo/components/video_player.cljs | 46 ++++++++----- src/frontend/tubo/events.cljs | 18 ++--- src/frontend/tubo/subs.cljs | 5 -- src/frontend/tubo/views/stream.cljs | 94 +++++++++++++------------- 4 files changed, 79 insertions(+), 84 deletions(-) (limited to 'src/frontend') diff --git a/src/frontend/tubo/components/video_player.cljs b/src/frontend/tubo/components/video_player.cljs index c94579a..1825f50 100644 --- a/src/frontend/tubo/components/video_player.cljs +++ b/src/frontend/tubo/components/video_player.cljs @@ -1,27 +1,39 @@ (ns tubo.components.video-player (:require + [re-frame.core :as rf] [reagent.core :as r] [reagent.dom :as rdom] - ["video.js" :as videojs])) + ["video.js" :as videojs] + ["videojs-mobile-ui"] + ["@silvermine/videojs-quality-selector" :as VideojsQualitySelector])) (defn player - [options url] - (let [!player (atom nil)] + [options] + (let [!player (atom nil) + service-color @(rf/subscribe [:service-color]) + {:keys [theme]} @(rf/subscribe [:settings])] (r/create-class {:display-name "VideoPlayer" :component-did-mount - (fn [this] - (reset! !player (videojs (rdom/dom-node this) (clj->js options)))) - :component-did-update - (fn [this [_ prev-argv prev-more]] - (when (and @!player (not= prev-more (first (r/children this)))) - (.src @!player (apply array (map #(js-obj "type" % "src" (first (r/children this))) - (map #(get % "type") (get options "sources"))))) - (.ready @!player #(.play @!player)))) - :component-will-unmount - (fn [_] - (when @!player - (.dispose @!player))) + (fn [^videojs/VideoJsPlayer this] + (let [set-bg-color! #(set! (.. (.$ (.getChild ^videojs/VideoJsPlayer @!player "ControlBar") %) + -style + -background) + service-color)] + (VideojsQualitySelector videojs) + (reset! !player (videojs (rdom/dom-node this) (clj->js options))) + (set-bg-color! ".vjs-play-progress") + (set-bg-color! ".vjs-volume-level") + (set-bg-color! ".vjs-slider-bar") + (.ready @!player #(.mobileUi ^videojs/VideoJsPlayer @!player)) + (.on @!player "play" (fn [] + (.audioPosterMode + @!player + (clojure.string/includes? + (:label (first (filter #(= (:src %) (.src @!player)) + (:sources options)))) + "audio-only")))))) + :component-will-unmount #(when @!player (.dispose @!player)) :reagent-render - (fn [options url] - [:video-js.vjs-default-skin.vjs-big-play-centered.bottom-0.object-cover.min-h-full.max-h-full.min-w-full.focus:ring-transparent])}))) + (fn [options] + [:video-js.vjs-tubo.vjs-default-skin.vjs-big-play-centered.vjs-show-big-play-button-on-pause])}))) diff --git a/src/frontend/tubo/events.cljs b/src/frontend/tubo/events.cljs index 90282ed..a7d5269 100644 --- a/src/frontend/tubo/events.cljs +++ b/src/frontend/tubo/events.cljs @@ -621,20 +621,10 @@ (rf/reg-event-fx ::get-stream-page (fn [{:keys [db]} [_ uri]] - {:db (assoc db :show-page-loading true) - :fx [[:dispatch [::fetch-stream-page uri]]]})) - -(rf/reg-event-db - ::change-stream-format - (fn [{:keys [stream] :as db} [_ format-id]] - (let [{:keys [audio-streams video-streams]} stream] - (if format-id - (assoc db :stream-format - (first (filter #(= format-id (:id %)) - (apply conj audio-streams video-streams)))) - (assoc db :stream-format (if (empty? video-streams) - (first audio-streams) - (last video-streams))))))) + (assoc + (api/get-request (str "/api/streams/" (js/encodeURIComponent uri)) + [::load-stream-page] [::bad-response]) + :db (assoc db :show-page-loading true)))) (rf/reg-event-fx ::load-channel diff --git a/src/frontend/tubo/subs.cljs b/src/frontend/tubo/subs.cljs index 0ca48f0..d30d69c 100644 --- a/src/frontend/tubo/subs.cljs +++ b/src/frontend/tubo/subs.cljs @@ -70,11 +70,6 @@ (fn [db _] (:stream db))) -(rf/reg-sub - :stream-format - (fn [db _] - (:stream-format db))) - (rf/reg-sub :playlist (fn [db _] diff --git a/src/frontend/tubo/views/stream.cljs b/src/frontend/tubo/views/stream.cljs index b609511..3b97f42 100644 --- a/src/frontend/tubo/views/stream.cljs +++ b/src/frontend/tubo/views/stream.cljs @@ -17,59 +17,57 @@ uploader-url upload-date related-streams thumbnail-url show-comments-loading comments-page show-comments show-related show-description service-id] - :as stream} @(rf/subscribe [:stream]) - {show-comments? :show-comments show-related? :show-related - show-description? :show-description} @(rf/subscribe [:settings]) + :as stream} @(rf/subscribe [:stream]) + {show-comments? :show-comments + show-related? :show-related + show-description? :show-description} + @(rf/subscribe [:settings]) available-streams (apply conj audio-streams video-streams) - {:keys [content id] :as stream-format} @(rf/subscribe [:stream-format]) - page-loading? @(rf/subscribe [:show-page-loading]) - service-color @(rf/subscribe [:service-color]) - bookmarks @(rf/subscribe [:bookmarks])] + page-loading? @(rf/subscribe [:show-page-loading]) + service-color @(rf/subscribe [:service-color]) + bookmarks @(rf/subscribe [:bookmarks]) + sources (reverse (map (fn [{:keys [content format resolution averageBitrate]}] + {:src content + :type "video/mp4" + :label (str (or resolution "audio-only") " " + format + (when-not resolution + (str " " averageBitrate "kbit/s")))}) + available-streams)) + player-elements ["playToggle" "progressControl" + "volumePanel" "playbackRateMenuButton" + "QualitySelector" "fullscreenToggle"]] [layout/content-container [:div.flex.justify-center.relative {:class "h-[300px] md:h-[450px] lg:h-[600px]"} - (when stream-format - [player/player {"sources" [{"src" content "type" "video/mp4"} - {"src" content "type" "video/webm"}] - "poster" thumbnail-url - "controls" true - "responsive" true - "fill" true} - content])] - [:div.overflow-x-hidden - [:div.flex.flex.w-full.my-4.justify-center - [:button.sm:px-2.py-1.text-sm.sm:text-base.text-neutral-600.dark:text-neutral-300 - {:on-click #(rf/dispatch [::events/switch-to-audio-player stream service-color])} - [:i.fa-solid.fa-headphones] - [:span.mx-3 "Background"]] - (if (some #(= (:url %) url) bookmarks) - [:button.sm:px-2.py-1.text-sm.sm:text-base.text-neutral-600.dark:text-neutral-300 - {:on-click #(rf/dispatch [::events/remove-from-bookmarks stream])} - [:i.fa-solid.fa-bookmark] - [:span.mx-3 "Bookmarked"]] - [:button.sm:px-2.py-1.text-sm.sm:text-base.text-neutral-600.dark:text-neutral-300 - {:on-click #(rf/dispatch [::events/add-to-bookmarks stream])} - [:i.fa-regular.fa-bookmark] - [:span.mx-3 "Bookmark"]]) - [:button.sm:px-2.py-1.text-sm.sm:text-base.text-neutral-600.dark:text-neutral-300 - [:a.block.sm:inline-block {:href url} - [:i.fa-solid.fa-external-link-alt] - [:span.mx-3 "Original"]]] - (when stream-format - [:div.relative.flex.flex-col.items-center.justify-center.text-neutral-600.dark:text-neutral-300 - [:select.border-none.focus:ring-transparent.dark:bg-blend-color-dodge.pr-8.w-full.text-ellipsis.text-sm.sm:text-base - {:on-change #(rf/dispatch [::events/change-stream-format (.. % -target -value)]) - :value id - :style {:background "transparent"}} - (when available-streams - (for [[i {:keys [id format resolution averageBitrate]}] (map-indexed vector available-streams)] - [:option.dark:bg-neutral-900.border-none {:value id :key i} - (str (or resolution "audio-only") " " format (when-not resolution (str " " averageBitrate "kbit/s")))]))] - [:div.flex.absolute.min-h-full.top-0.right-4.items-center.justify-end - [:i.fa-solid.fa-caret-down]]])] + [player/player + {:sources sources + :poster thumbnail-url + :controls true + :controlBar {:children player-elements} + :preload "metadata" + :responsive true + :fill true + :playbackRates [0.5 1 1.5 2]}]] + [:div [:div.flex.flex-col - [:div.min-w-full.pb-3 - [:h1.text-2xl.font-extrabold.line-clamp-1 name]] + [:div.flex.items-center.justify-between.pt-4 + [:div.flex-auto + [:h1.text-lg.sm:text-2xl.font-extrabold.line-clamp-1 name]] + [:div.flex.flex-auto.justify-end.items-center.my-3.gap-x-5 + [:button + {:on-click #(rf/dispatch [::events/switch-to-audio-player stream service-color])} + [:i.fa-solid.fa-headphones]] + [:button + [:a.block.sm:inline-block {:href url :target "__blank"} + [:i.fa-solid.fa-external-link-alt]]] + (if (some #(= (:url %) url) bookmarks) + [:button + {:on-click #(rf/dispatch [::events/remove-from-bookmarks stream])} + [:i.fa-solid.fa-bookmark {:style {:color service-color}}]] + [:button + {:on-click #(rf/dispatch [::events/add-to-bookmarks stream])} + [:i.fa-regular.fa-bookmark]])]] [:div.flex.justify-between.py-2.flex-nowrap [:div.flex.items-center [layout/uploader-avatar uploader-avatar uploader-name -- cgit v1.2.3