Installation
Requirements
- PHP 8.4 or higher, with the OpenSSL extension
- Laravel 13
- ffmpeg and ffprobe. Static builds work; tone mapping needs ffmpeg built with libzimg (
ffmpeg -filters | grep zscalechecks). league/flysystem-aws-s3-v3when you read from or write to S3 disks
Install the package
composer require foxws/laravel-media
Publish the config file to config/media.php:
php artisan vendor:publish --tag="media-config"
Point it at ffmpeg
Executables are resolved when they're first used, so only the tools you call need to be installed. A command name is looked up in the PATH and in the project root, so a static binary placed next to artisan is found too. Set an absolute path when they live elsewhere:
MEDIA_FFMPEG_PATH=/usr/local/bin/ffmpeg
MEDIA_FFPROBE_PATH=/usr/local/bin/ffprobe
Check what's found, with paths and versions:
php artisan media:info
php artisan about has a Media section too. A missing executable throws ExecutableNotFoundException, which names the variable to set.
Schedule the cleanup commands
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('media:clean')->hourly(); // temporary files left behind by crashed workers
Schedule::command('media:prune')->daily(); // segments cached for direct streaming
media:cleandeletes the package's own temporary directories that haven't been written to for longer than--older-thanminutes (by default the process timeout plus an hour). Temporary files are already deleted after every queue job and request, so this only catches what crashes, OOM kills or power loss leave behind.media:prunedeletes segments and converted subtitles that were packaged more than--older-thanminutes ago (a week by default) from the segment cache. They're packaged again when requested, so pruning is always safe.
Both take --dry-run.
Run a queue worker for streaming
Direct streams package the next segments ahead of the player's requests in a queued job. Run a worker for that queue, ideally a dedicated one:
MEDIA_DELIVERY_LOOK_AHEAD_QUEUE=media
php artisan queue:work --queue=media
Without a worker, set MEDIA_DELIVERY_LOOK_AHEAD_VIA=defer to package them in the same process after the response instead.
