Visarc.Umbraco.Qencode 17.1.0

Visarc.Umbraco.Qencode

A Qencode video transcoding integration for Umbraco 17. Editors configure per-video processing options and trigger transcoding explicitly; the plugin pushes the upload to Qencode, captures the transcoded renditions, auto-generated thumbnails, and subtitles, and serves everything from CDN — with a ready-made responsive player and SEO structured data for the front end.

This is the package to install on an Umbraco website — it ships the backoffice UI and references Visarc.Umbraco.Qencode.Core for the backend models, services, migrations and rendering logic. If you only need the backend (e.g. a separate Models project in a multi-project solution), see that package's README instead.

Installation

dotnet add package Visarc.Umbraco.Qencode

The property editors, data types, and Video media-type properties self-install on first application start — no manual Settings → Data Types setup is required.

Add to appsettings.json under Visarc:Qencode — at minimum ApiKey and CallbackSecret:

{
  "Visarc": {
    "Qencode": {
      "ApiKey": "your-qencode-api-key",
      "CallbackSecret": "a-long-random-string"
    }
  }
}

See Visarc.Umbraco.Qencode.Core's README for the full configuration reference.

What it adds to the Video media type

Two visible tabs are added to the built-in Video media type:

"Video" tab (alongside Umbraco's own file/upload fields):

Sub-group Properties
Qencode qencodeModes — the Qencode Video Manager property editor (template picker, subtitle/thumbnail toggles, Process/Re-process button); qencodePoster — manual poster override with three named crops (1x1, 4x3, 16x9)
SEO Metadata videoName, videoDescription, videoUploadDate — feed the VideoObject JSON-LD; captionsFile — manual .vtt override

"Qencode" tab (internal/read-only, populated automatically once processing starts):

Property Purpose
qencodeStatus idle / transcoding / completed / failed
qencodeTaskToken Qencode task token, validates the completion callback
qencodePrimaryUrl Highest-resolution transcoded CDN URL
qencodeDuration Duration in seconds
qencodeCdnUrls JSON array of renditions and auto-generated thumbnails (QencodeCdnEntry[])
qencodeSubtitlesUrl Auto-generated VTT subtitles URL
qencodeHasAudio Whether the transcoded output retains audio — true/false, or unset for videos processed before this property existed / templates with no recognizable mp4 format entry
qencodeErrorMessage Why the last job failed, when qencodeStatus is failed — cleared automatically the next time processing starts
qencodeOutputsJson Raw JSON dump of any Qencode status fields not otherwise modelled

The Qencode Video Manager (on the Video media type)

Opened from a Video media item's own edit screen (qencodeModes property). An editor:

  1. Picks a transcoding template from a dropdown, populated live from your Qencode account (GET .../templates). A template must be selected before processing can start.
  2. Toggles Generate subtitles (VTT) on/off.
  3. Toggles Generate thumbnails on/off — when on, a slider sets the capture point as a percentage of the video's duration (default 50%).
  4. Clicks Process video (or Re-process video once already processed).

While transcoding, the editor sees a live pipeline view (Source → Transcoding → Ready) with real progress, polled every 5 seconds. Once complete, the transcoded duration is shown alongside the button.

If a job fails, the specific reason is shown in the pipeline (e.g. "Template unavailable", a Qencode error description, or "Qencode reported the job complete but returned no video URLs") rather than a generic failure message — sourced from qencodeErrorMessage.

The Qencode Video Picker (for your own content types)

The Qencode Video Picker property editor lets any content document type reference a video from the Media Library (filtered to Video-type items only) and toggle whether native playback controls show on the front end. Add it to a document type the same way you'd add any other custom data type — via Settings → Document Types — the plugin registers the data type but deliberately does not attach it to any content type for you.

In the backoffice, once a video is picked, the editor also sees at-a-glance status badges — Transcoded, Audio, Subtitles, Thumbnails — each yes / no / unknown, with a refresh button.

Its stored value is exposed as a strongly-typed QencodeVideoPickerValue (MediaKey, ShowControls), and is registered with a PropertyValueConverter so it comes back pre-converted from Value<T>:

@using Visarc.Umbraco.Qencode.Core.Extensions
@using Visarc.Umbraco.Qencode.Core.Models

@{
    var picker = Model.Value<QencodeVideoPickerValue>("qencodeFeaturedVideo");
    var video = picker?.MediaKey is { } key && Guid.TryParse(key, out var mediaKey)
        ? Umbraco.Media(mediaKey)
        : null;
}

@if (video is not null)
{
    @await Html.PartialAsync("QencodeVideoPlayer", new QencodeVideoPlayerModel
    {
        Media = video,
        ShowControls = picker!.ShowControls,
    })
}

The same value can also be read manually with content.GetQencodeVideoPicker("qencodeFeaturedVideo") if you're not using ModelsBuilder / the value converter for some reason — see the Core README.

The QencodeVideoPlayer partial

Ships from this package's RCL — no wiring beyond the snippet above. Given a QencodeVideoPlayerModel { Media, ShowControls }, it renders:

  • A responsive <video> built from the video's actual transcoded renditions — one <source media="(max-width: …)"> per breakpoint (ascending, largest as the catch-all fallback with no media attribute), so the browser picks the best rendition for the viewport
  • A poster from GetQencodePosterUrl() (manual override if set, else the best-matching auto-generated thumbnail) and an inline aspect-ratio matching the largest rendition, so there's no layout shift
  • A subtitles <track> (manual .vtt override if set, else auto-generated), with crossorigin="anonymous" added automatically whenever subtitles exist
  • The VideoObject JSON-LD <script> tag, appended right after the video

Playback behavior follows ShowControls:

ShowControls Behavior
true (default) preload="metadata", native controls, no autoplay
false preload="auto", autoplay muted loop, no native controls — background-video style

Renders nothing if the video hasn't finished transcoding yet, or if no renditions could be found — but in both cases it emits a console.warn(...) in the browser (e.g. [Qencode] Video player: "My Video" (media id ...) was not rendered — transcoding is not complete. qencodeStatus: transcoding.), so an unexpectedly-empty video slot is easy to spot in devtools instead of being a silent, unexplained gap.

.Url() never exposes the local file

Because Visarc.Umbraco.Qencode.Core registers a custom IMediaUrlProvider, calling Umbraco's own .Url() on any Video-type media item (content type alias contains "video") is intercepted — the local uploaded file path is never returned, even as a fallback:

<video src="@video.Url(Umbraco)" controls></video>
State What .Url() returns
Transcoding complete The Qencode CDN URL (qencodePrimaryUrl)
Not yet encoded / failed The literal string "error:qencode-video-not-yet-encoded"

This is deliberate: it prevents the raw, unoptimized local media file from ever leaking into markup by accident just because someone called .Url() before checking status. Always guard with IsTranscodingComplete() (or compare against QencodeMediaUrlProvider.NotEncodedUrl) before using the result — the QencodeVideoPlayer partial and the extension methods above already do this for you, so prefer those over calling .Url() directly.

Compatibility

Package Version
Umbraco CMS 17.x ([17.0.0,18.0.0))
.NET 10.0

Packages

Package Purpose
Visarc.Umbraco.Qencode Full plugin: backoffice UI + player view (install this)
Visarc.Umbraco.Qencode.Core Backend only: models, services, migrations, rendering helpers (referenced automatically)

No packages depend on Visarc.Umbraco.Qencode.

.NET 10.0

Version Downloads Last updated
17.1.2 1 7/28/2026
17.1.1 6 7/27/2026
17.1.0 1 7/27/2026
17.0.1 15 2/10/2026
17.0.0 7 2/9/2026
17.0.0-dev.9 6 2/9/2026