A reusable ClojureDart video player package with optional background audio service.
Audio is handled by just_audio + audio_service, video display by video_player.
{:deps {org.clojars.ianffcs/cljd-video-player {:mvn/version "1.1"}}}
Add the package to your project's deps.edn:
{:deps {ianffcs/cljd-video-player {:git/url "https://github.com/ianffcs/cljd-video-player.git"
:sha "..."}}}
This is a pure ClojureDart source library — it does not include a pubspec.yaml.
You must add the required Flutter pub dependencies to your own pubspec.yaml:
dependencies:
audio_service: ^0.18.13
just_audio: ^0.9.38
video_player: ^2.9.1
rxdart: ^0.28.0
The public API lives in ianffcs.video-player (typically aliased as vpl).
(ns my-app
(:require [ianffcs.video-player :as vpl]
["package:flutter/material.dart" :as m]))
VideoPlayer is a lifecycle widget that manages AudioPlayer, VideoPlayerController,
and optionally the audio_service for lock screen controls. It requires a ::vpl/builder
function that receives the initialized-video map.
(vpl/VideoPlayer {::vpl/url "https://example.com/video.mp4"
::vpl/title "My Video"
::vpl/album "Album"
::vpl/artist "Artist"
::vpl/art-uri "https://example.com/art.jpg"
::vpl/builder my-view-fn})
| Key | Required | Description |
|---|---|---|
::vpl/url | yes | Network URL of the video/audio source |
::vpl/title | yes | Media title |
::vpl/album | yes | Album name |
::vpl/artist | yes | Artist name |
::vpl/art-uri | yes | Album art URL |
::vpl/builder | yes | (fn [initialized-video] -> Widget) |
::vpl/background-audio | no | false to skip audio service (default: true) |
Your ::vpl/builder function receives a map with all config keys above, plus:
| Key | Type | Description |
|---|---|---|
::vpl/audio-player | ja/AudioPlayer | Managed audio player instance |
::vpl/video-controller | vp/VideoPlayerController | Managed video controller (muted) |
::vpl/audio-service-handler | MyAudioHandler or nil | Lock screen handler (nil without bg) |
::vpl/media-stream | Stream | {:duration Duration :position Duration} |
::vpl/playing-stream | Stream<bool> | Reactive playing/paused state |
::vpl/on-seek | (fn [Duration]) | Seek to position |
::vpl/on-play | (fn []) | Start playback |
::vpl/on-pause | (fn []) | Pause playback |
::vpl/on-stop | (fn []) | Stop playback |
::vpl/on-rewind | (fn []) | Rewind 10 seconds |
::vpl/on-fast-forward | (fn []) | Fast-forward 10 seconds |
All widgets accept the initialized-video map directly:
| Widget | Description |
|---|---|
vpl/VideoLoader | Shows video when initialized, loading spinner while buffering |
vpl/BasicTitle | Reactive title from audio service, or static ::vpl/title |
vpl/PlayerControls | Rewind, play/pause, stop, fast-forward buttons |
vpl/SeekBar | Draggable slider with formatted time |
vpl/PlayerState | Text displaying current playing/paused state |
By default, VideoPlayer initializes audio_service for lock screen controls
and background playback. Pass ::vpl/background-audio false to skip it:
(vpl/VideoPlayer {::vpl/url "https://example.com/video.mp4"
::vpl/title "My Video"
::vpl/album "Album"
::vpl/artist "Artist"
::vpl/art-uri "https://example.com/art.jpg"
::vpl/background-audio false
::vpl/builder my-view-fn})
Without background audio:
AudioPlayer instead of through the audio service handler::vpl/audio-service-handler will be nil in the initialized-video mapBasicTitle falls back to the static ::vpl/title value(ns my-app
(:require [ianffcs.video-player :as vpl]
["package:flutter/material.dart" :as m]))
(defn default-layout [initialized-video]
[(vpl/VideoLoader initialized-video)
(m/SizedBox .height 20)
(vpl/BasicTitle initialized-video)
(m/SizedBox .height 10)
(vpl/PlayerControls initialized-video)
(m/SizedBox .height 10)
(vpl/SeekBar initialized-video)
(m/SizedBox .height 20)
(vpl/PlayerState initialized-video)])
(defn my-view [initialized-video]
(m/SingleChildScrollView
.child
(m/Padding
.padding (m/EdgeInsets.all 16.0)
.child
(m/Column
.crossAxisAlignment m/CrossAxisAlignment.stretch
.children (default-layout initialized-video)))))
;; Usage
(vpl/VideoPlayer {::vpl/url "..."
::vpl/title "..."
::vpl/album "..."
::vpl/artist "..."
::vpl/art-uri "..."
::vpl/builder my-view})
(defn custom-view
[{::vpl/keys [on-play on-pause playing-stream] :as iv}]
(m/Column
.children
[(vpl/VideoLoader iv)
(vpl/SeekBar iv)
;; Custom button using callbacks from the map
(f/widget
:watch [playing playing-stream]
(m/ElevatedButton
.onPressed (if playing on-pause on-play)
.child (m/Text (if playing "Pause" "Play"))))]))
audio_service and may require platform-specific configuration.clj -M:cljd flutter are the real signal.Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |