Liking cljdoc? Tell your friends :D

cljd-video-player

A reusable ClojureDart video player package with optional background audio service. Audio is handled by just_audio + audio_service, video display by video_player.

Installation

Clojars (recommended)

{:deps {org.clojars.ianffcs/cljd-video-player {:mvn/version "1.1"}}}

deps.edn

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 "..."}}}

pubspec.yaml

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

API

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

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})

Config keys

KeyRequiredDescription
::vpl/urlyesNetwork URL of the video/audio source
::vpl/titleyesMedia title
::vpl/albumyesAlbum name
::vpl/artistyesArtist name
::vpl/art-uriyesAlbum art URL
::vpl/builderyes(fn [initialized-video] -> Widget)
::vpl/background-audionofalse to skip audio service (default: true)

The initialized-video map

Your ::vpl/builder function receives a map with all config keys above, plus:

KeyTypeDescription
::vpl/audio-playerja/AudioPlayerManaged audio player instance
::vpl/video-controllervp/VideoPlayerControllerManaged video controller (muted)
::vpl/audio-service-handlerMyAudioHandler or nilLock screen handler (nil without bg)
::vpl/media-streamStream{:duration Duration :position Duration}
::vpl/playing-streamStream<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

Built-in widgets

All widgets accept the initialized-video map directly:

WidgetDescription
vpl/VideoLoaderShows video when initialized, loading spinner while buffering
vpl/BasicTitleReactive title from audio service, or static ::vpl/title
vpl/PlayerControlsRewind, play/pause, stop, fast-forward buttons
vpl/SeekBarDraggable slider with formatted time
vpl/PlayerStateText displaying current playing/paused state

Background audio

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:

  • No lock screen controls or media notifications
  • Controls talk directly to AudioPlayer instead of through the audio service handler
  • Rewind/fast-forward seek by 10 seconds on the player directly
  • ::vpl/audio-service-handler will be nil in the initialized-video map
  • BasicTitle falls back to the static ::vpl/title value

Examples

Using the default layout

(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})

Custom builder with extra widgets

(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"))))]))

Notes

  • Background audio behavior is driven by audio_service and may require platform-specific configuration.
  • The sample media is remote; network access is required.
  • IDE diagnostics (clj-kondo) show false warnings for ClojureDart interop types — compile warnings from clj -M:cljd flutter are the real signal.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close