Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Statamic Video Tools Laravel Package

eminos/statamic-video-tools

Statamic Video Tools is an add-on for embedding and managing videos in your Statamic site. It provides video fieldtypes, responsive embed output, and handy template helpers for YouTube, Vimeo, and other sources, making video content easy to add and display.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Confirm the stack first. This is a Statamic addon, so you need Statamic 4/5 on Laravel 10/11, PHP 8.2+, and — critically — ffmpeg/ffprobe binaries on the server. whisper.cpp plus a model file is optional but required for transcription. Without ffmpeg the addon will appear installed and then fail at conversion time.

  • A real queue is mandatory. Encoding, poster extraction, and transcription are queued jobs. QUEUE_CONNECTION=sync will time out on any non-trivial video. Set up Redis/database queues and run a worker (ideally a dedicated one, see Gotchas).

  • Install order:

    1. composer require the package.
    2. Publish the config (vendor:publish — check DOCUMENTATION.md for the exact tag) and read config/video-tools.php end to end. This file is the package: presets, conditions, binaries, paths, and transcription settings all live here.
    3. Add the video fieldtype to the blueprint of the assets container you want to handle video (usually assets/videos.yaml → taxonomies/fields section). The CP status field with polling and re-run buttons only appears once the fieldtype is on the container.
    4. Restart the queue worker and upload one small MP4.
  • Where to look first: DOCUMENTATION.md for the tag/component API, then the presets array in the config, then the published fieldtype in your blueprint. Don't start with the source — the preset config tells you what actually happens to a file.

  • First use case to validate the whole pipeline: upload a short H.264 MP4 into the configured container, watch the CP status field go through its states, confirm the poster JPEG appears, then render it in a template with the self-closing tag:

    {{ video :src="video_file" preset="h264" }}
    

    If that renders a <video> element with a working poster and source, the install is sound. Everything else (HLS, AV1, transcription, alpha) is incremental.

Implementation Patterns

  • Self-closing vs pair mode. Self-closing renders the full <video> element for you — use it in Bard sets, listing pages, and anywhere you don't need control. Pair mode gives you the markup so you can add class, data-*, playsinline, poster, captions, and lazy-loading attributes yourself:

    {{ video :src="video_file" preset="hls" }}
        <video controls playsinline preload="metadata" poster="{{ poster }}">
            {{ sources }}
            {{ tracks }}
        </video>
    {{ /video }}
    

    Remember that in pair mode the alpha dual-source output and the VTT track are your responsibility to loop over — the tag won't inject them for you.

  • Prefer <x-video> in Blade-heavy projects. Mixing Antlers tags into Blade views works via the Statamic runtime, but the Blade component keeps prop typing, IDE completion, and @aware/slot semantics intact. Standardise on one of the two per project rather than mixing.

  • Treat presets as named contracts. Reference presets by name (preset="h264") and keep the name stable across environments even if the underlying ffmpeg args differ. Configure a ladder: h264 as the universal fallback, av1/webm for modern browsers, hevc where you control the client, and hls for anything over a couple of minutes. Order sources so the broadest-compatibility format sits last as the fallback.

  • Preset conditions are the main cost-control lever. Skipping AV1 for sources under 720p, or skipping HLS for clips under 60 seconds, saves enormous CPU. Conditions can key off resolution, duration, codec, pixel format, and alpha — put the cheap checks (duration, resolution) first and the probe-heavy ones later. Conditions are evaluated per asset per preset, so a misconfigured condition silently doubles your queue volume.

  • Alpha needs a strategy, not just a flag. Transparent sources generate dual output (HEVC/MP4 for Safari, AV1/WebM for Chrome/Firefox). In self-closing mode this is handled. In pair mode you must render both <source> elements in the right order, and you should document internally why there are two files per asset so nobody "cleans up" the duplicate.

  • Wire the events into your existing cache strategy. VideoAssetProcessed fires when the asset is ready; VideoConversionCompleted fires per conversion. Register listeners for:

    • Statamic static cache invalidation (StaticCache::flush() or a targeted clear) — otherwise your rendered tag points at a URL that changed after re-encode.
    • CDN purge / object-storage invalidation.
    • Downstream automation: notify editorial, push to a search index, attach the transcript to a CMS entry.

    Implement ShouldQueue on these listeners so a slow webhook doesn't stall the conversion worker.

  • Transcription as a content source, not just a caption file. Whisper output gives you VTT, SRT, TXT, formatted paragraphs, and word-level JSON. The practical pattern is: VTT into {{ tracks }} for captions, TXT/paragraphs into a hidden or collapsed transcript section for SEO and accessibility, and the word-level JSON into search indexing or chapter generation. Grab the transcript in the same event listener rather than re-reading files at render time.

  • Re-run buttons are an editorial workflow. The CP fieldtype's per-preset re-run is what you'll use after changing a preset's args — but it re-encodes in place. Pair it with your event listeners so caches clear automatically, and communicate to editors that re-running is safe but slow.

  • Environment-specific config. Publish the config and override per environment: local can use a single fast h264 preset with transcription disabled; production gets the full ladder. Never let local dev spin up AV1 encodes of a 4K upload.

Gotchas and Tips

  • ffmpeg not found is the #1 install failure. PHP-FPM's PATH differs from your shell's. Use absolute paths in the config and verify with the exact user the queue worker runs as.
  • ffmpeg build matters more than ffmpeg version. AV1 needs libsvtav1 or libaom-av1; HEVC may be absent or licence-restricted depending on your distro's build. Test each preset once manually with the same arguments before blaming the package.
  • Queue worker timeouts. A 4K AV1 encode can run for many minutes. Set --timeout above your slowest job and retry_after above timeout, or jobs get double-processed. Consider a dedicated queue connection for video with a single worker so encodes don't starvation-block mail and webhook jobs.
  • HLS needs web-server configuration. .m3u8 and .ts/.m4s segments must be served with correct MIME types and, for segments, byte-range support. If the player stalls at "loading" while the files clearly exist, it's almost always the server config, not the package.
  • Re-encodes change filenames/URLs. If output paths include a hash or timestamp, every re-run breaks cached HTML. Either keep output paths stable or make absolutely sure the event listeners flush the static cache — this is the most common "the video randomly disappeared" report.
  • Silent transcription failures. A missing whisper.cpp binary or model file typically means no transcript rather than a hard error. Check storage/logs and the failed-jobs table before assuming the feature is broken.
  • Whisper resource cost. Model size is a direct RAM/CPU tradeoff (tiny is fine for search indexing, medium/large for published captions). Running it on the same worker as ffmpeg will thrash — separate queues, or accept serialised processing.
  • Alpha detection is container-dependent. Some sources report alpha in the pixel format but are effectively opaque; others hide transparency in a way ffprobe misses. Spot-check the dual-source output on a known transparent file rather than trusting the condition.
  • Animated WebP thumbnails don't render in older Safari. The CP asset browser degrades gracefully, but don't rely on the animated thumbnail as a public-facing preview.
  • CP polling scales badly. Live status polling is per-asset in the CP; on a container with hundreds of videos, editors leaving tabs open generates steady background load. Keep the poll interval sane in config and scope the fieldtype to the video container only.
  • Event listeners fire per asset and per preset. Naive StaticCache::flush() in VideoConversionCompleted on a batch import will flush dozens of times in a minute. Debounce, or flush once on VideoAssetProcessed instead.
  • Don't hardcode preset names in templates. Presets are config, and config is per-environment. If a preset is missing in production the tag may render nothing — add a fallback source in the template.
  • Extension points: custom presets (raw ffmpeg args) are the intended escape hatch for anything the built-ins don't cover; published views under resources/views/vendor/ let you restyle the CP fieldtype and the component's markup without forking. Publish config and views rather than editing vendor code — the v1.0.0 surface is broad enough that you shouldn't need to patch the package itself.
  • Debugging a failed conversion: read the failed job's exception for the exact ffmpeg command line, then run that command by hand on the stored source file. That single step resolves the majority of "the package is broken" tickets — it's usually a codec, permission, or disk-space issue on your side.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log