takepart-media / vidiq
Statamic addon for 3q.video hosting platform integration
Requires
- php: ^8.3
- guzzlehttp/guzzle: ^7.0
- statamic/cms: ^5.0
Requires (Dev)
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0
README
A Statamic addon that integrates the 3q.video hosting platform into the Statamic Control Panel asset browser. Videos hosted on 3q appear as browsable, deletable assets with thumbnail previews. A Blade component is provided for embedding videos in frontend templates.
This addon has only been tested with Statamic 5 and 3Q's SDN API v2.
Features
- Asset browser integration — 3Q videos appear in Statamic's CP file browser with thumbnail previews and release-status colour strips (published / unpublished / draft)
- Asset editor player — opening a video in the CP asset editor replaces the default
<video>element with the 3Q player iframe - Fieldtype support — videos selected via an Assets fieldtype display thumbnails and status indicators in entry forms
- Read-only (for now) — browse videos directly from the CP; write operations (upload, delete, rename, move) are currently unsupported — manage content in 3Q's own dashboard. Full write support may be added in a future release.
- CP Cache Utility — manage the vidiq cache directly from the Statamic Control Panel (Utilities → vidiQ Cache) with Warm and Clear buttons
- Cache warm-up command —
vidiq:warm-cacheArtisan command pre-populates listing and embed-code caches during deployment - Flysystem v3 adapter — custom
ThreeQAdapterimplements the Flysystem interface backed by the 3Q SDN API - Embed codes — fetches the full
FileEmbedCodesarray per video via the 3Q playout API (cached) - Virtual meta files — generates
.meta/YAML on the fly so Statamic stores title, thumbnail URL, video ID and release status without writing to disk - Blade component —
<x-vidiq::embed>for embedding the 3Q player in frontend templates
Requirements
- PHP 8.3+
- Statamic 5.x
- GuzzleHTTP 7.x
- A 3q.video account with API access
Installation
Install the package via Composer:
composer require takepart-media/vidiq
Statamic will auto-discover the addon's service provider. No additional registration steps are needed.
Environment variables
Add the following to your .env file:
VIDIQ_API_TOKEN=your-api-token-here VIDIQ_PROJECT_ID=your-project-id-here # Optional — defaults shown VIDIQ_API_ENDPOINT=https://sdn.3qsdn.com/api VIDIQ_API_TIMEOUT=30
Asset container
Create content/assets/vidiq.yaml in your Statamic project:
title: '3Q Videos' disk: 3q allow_uploads: false allow_downloading: false allow_renaming: false allow_moving: false create_folders: false
Statamic will display this container as "3Q Videos" in the CP under Assets.
How It Works
Flysystem adapter (ThreeQAdapter)
The adapter connects to the 3Q SDN REST API and implements League\Flysystem\FilesystemAdapter:
| Operation | Behaviour |
|---|---|
listContents |
Fetches all files from GET /v2/projects/{id}/files and yields FileAttributes. Listing is cached for 1 hour by default (configurable via VIDIQ_CACHE_TTL). |
fileExists |
Resolved from the listing cache. |
read |
For .meta/ paths: returns generated YAML. Direct reads of asset paths are not supported and throw UnableToReadFile. |
readStream |
For .meta/ paths: streams the generated YAML. For asset paths: downloads the video thumbnail from 3Q for Statamic/Glide to cache. |
delete |
Accepted only for .meta/ paths (no-op, virtual files have no remote counterpart). All other paths throw UnableToDeleteFile. |
getUrl |
Calls GET /v2/projects/{id}/files/{fileId}/playouts/default/embed and returns the full FileEmbedCodes array (e.g. JavaScript, PlayerURL). Cached per file ID via VIDIQ_CACHE_TTL. |
write / writeStream |
Accepted only for .meta/ paths (Statamic metadata edits stored in Laravel cache). All other writes throw UnableToWriteFile. |
move, copy, createDirectory, deleteDirectory |
Not supported; throw the corresponding Flysystem exceptions. |
Path convention
Each video's path is its sanitized display title (e.g. My Interview.mp4). If two videos share the same title, the last
6 characters of the FileId are appended to avoid collisions. The FileId→path mapping is stored in the listing cache.
Virtual meta files
listContents also yields a virtual .meta/{path}.yaml entry for every video. This YAML contains:
size: 12345678 last_modified: 1700000000 mime_type: 'video/mp4' data: alt: 'Video title' thumbnail_url: 'https://...' video_id: '12345678' release_status: 'published'
Statamic reads this file automatically; because the file exists virtually, Statamic skips calling writeMeta() and
leaves the adapter's read-only behaviour intact.
CP JavaScript (thumbnail injection, status strips & player)
Statamic's asset browser only renders thumbnail images for assets where is_image: true. The addon registers an Axios
response interceptor (via Statamic.booted()) that enriches several CP views:
- Asset browser — intercepts folder listing responses for any 3Q-backed container, fetches the thumbnail & status
map from
GET /cp/vidiq/assets(once per page load), and injectsis_image: true+thumbnail: <url>into each asset object. A coloured left-edge strip is added to each thumbnail to indicate the release status (green = published, yellow = unpublished, grey = draft). - Asset editor — when a 3Q video is opened in the editor modal, the default
<video>element is replaced with a 3Q player iframe fetched fromGET /cp/vidiq/player-url. - Assets fieldtype — when an entry form contains an Assets field referencing a 3Q container, the interceptor injects thumbnails and status indicators into the fieldtype row display.
Blade Component
<x-vidiq::embed>
Embeds a 3Q video using one of three output methods. The method defaults to the config value
vidiq.embed_fallback_method (default: JavaScript).
{{-- Default method from config --}} <x-vidiq::embed :asset="$asset" /> {{-- Explicit method --}} <x-vidiq::embed :asset="$asset" method="iFrame" />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
asset |
Statamic\Assets\Asset|null |
null |
The asset object. Renders nothing if null or if no player URL can be resolved. |
method |
string|null |
config('vidiq.embed_fallback_method') |
Embed output method: JavaScript, iFrame, or PlayerURL. |
Methods
| Value | Output |
|---|---|
JavaScript |
Renders the JS embed snippet ({!! $embedCodes['JavaScript'] !!}) provided by 3Q. |
iFrame |
Renders an <iframe> with the PlayerURL as src and the video-embed CSS class. |
PlayerURL |
Outputs only the plain player URL string (useful for custom markup or JS integration). |
Configuration
config/vidiq.php (addon)
| Key | Env variable | Default | Description |
|---|---|---|---|
cache.ttl |
VIDIQ_CACHE_TTL |
3600 |
Cache TTL in seconds for listings and embed codes |
cache.permanent |
VIDIQ_CACHE_PERMANENT |
false |
When true, caches are stored forever (ignores TTL) |
cache.prefix |
— | vidiq |
Prefix for all cache keys (scoped per project ID) |
embed_fallback_method |
VIDIQ_FALLBACK_METHOD |
JavaScript |
Default embed method (JavaScript, iFrame, PlayerURL) |
config/vidiq-disk.php (addon)
Configures the 3q Laravel filesystem disk that is registered automatically by the ServiceProvider. The disk uses the
custom 3q driver backed by ThreeQAdapter.
| Key | Env variable | Default | Description |
|---|---|---|---|
api_token |
VIDIQ_API_TOKEN |
— | 3Q API token |
project_id |
VIDIQ_PROJECT_ID |
— | 3Q project identifier |
endpoint |
VIDIQ_API_ENDPOINT |
https://sdn.3qsdn.com/api |
3Q API base URL |
timeout |
VIDIQ_API_TIMEOUT |
30 |
HTTP timeout in seconds |
Multiple Projects
To connect a second 3Q project, add another disk entry in config/filesystems.php and a matching asset container YAML:
// config/filesystems.php '3q-project-b' => [ 'driver' => '3q', 'api_token' => env('VIDIQ_PROJECT_B_API_TOKEN', ''), // or use your default token VIDIQ_API_TOKEN 'project_id' => env('VIDIQ_PROJECT_B_PROJECT_ID', ''), 'endpoint' => env('VIDIQ_API_ENDPOINT', 'https://sdn.3qsdn.com/api'), 'timeout' => env('VIDIQ_API_TIMEOUT', 30), ],
# content/assets/vidiq-project-b.yaml title: '3Q Videos — Project B' disk: 3q-project-b allow_uploads: false allow_downloading: false allow_renaming: false allow_moving: false create_folders: false
After that update .env with the new credentials and clear or refresh caches:
php artisan cache:clear php artisan config:clear
Development
Clone the repository and install dependencies:
git clone https://github.com/takepart-media/vidiq.git
cd vidiq
composer install
npm install
Build CP assets
npm run dev # Vite dev server npm run build # Production build
Cache management
CP Utility
The addon registers a vidiQ Cache utility in the Statamic Control Panel under Utilities → vidiQ Cache. It displays the number of cached videos and the current cache mode (TTL or Permanent). Two actions are available:
- Warm — dispatches a background queue job (
WarmCacheJob) that flushes all vidiq caches, re-fetches the listing from the 3Q API, and pre-fetches embed codes for every video. - Clear — immediately flushes all vidiq-specific cache entries (listing, embed codes, meta edits).
Warm the cache (CLI)
Pre-populate the video listing cache (and optionally embed codes) so the first frontend request avoids an API round-trip:
php artisan vidiq:warm-cache # Warm listing cache only php artisan vidiq:warm-cache --embed # Also pre-fetch embed codes for every video
This is intended to run once during deployment (e.g. in a post-deploy script or CI pipeline).
Flush caches
php artisan cache:clear # Flush all Laravel caches (including vidiq) php artisan statamic:stache:clear # Clear Statamic file cache php artisan config:clear # Clear Laravel config cache
The vidiq:warm-cache command automatically flushes all vidiq-specific cache entries (listing, embed codes, meta edits) before re-populating.
License
The MIT License (MIT). Please see the LICENSE file for more information.