Jump to content

Quick Start for Developers

A quick guide for developers working with VidPly. Detailed documentation can be found in the individual files.

VidPly TYPO3 Extension Logo

Installation

 
composer require mpc/mpc-vidply
 

Next:

  1. Database update → Admin tools → Maintenance → Analyse database structure
  2. Integrate site set → Site management → Sites → Your site → Sets → Add mpc/mpc-vidply
  3. Clear caches

Prerequisites: TYPO3 Core, Fluid and Extbase only — fluid_styled_content is not required. The extension has its own lib.mpcVidplyContentElement renderer and a standard layout (frame wrapper + tt_content header/subheader).

Optional customisation: If your site package or fluid_styled_content contains custom frame/header partials, you can link VidPly to them:

 
lib.mpcVidplyContentElement.layoutRootPaths.10 = {$styles.templates.layoutRootPath}
lib.mpcVidplyContentElement.partialRootPaths.10 = {$styles.templates.partialRootPath}
 

Directory structure

 
mpc_vidply/
├── Classes/
│   ├── Backend/
│   │   ├── Controller/           # MediaImportAjaxController (URL import)
│   │   ├── Form/Element/           # MediaUrlImportElement
│   │   └── Preview/              # VidPlyPreviewRenderer
│   ├── Form/FormDataProvider/    # MediaUrlImportFormDataProvider
│   ├── Service/                  # MediaFromUrlService, MediaUrlNormalizer
│   └── DataProcessing/           # VidPly, Listview, Detail processors
├── Configuration/
│   ├── Sets/mpc-vidply/          # Site Set (TYPO3 13.4+)
│   ├── TCA/
│   │   ├── tx_mpcvidply_media.php # Media record TCA
│   │   └── Overrides/
│   │       └── tt_content.php    # Content element TCA
│   ├── TypoScript/
│   │   └── Helper/ContentElement.typoscript  # lib.mpcVidplyContentElement
│   ├── ContentSecurityPolicies.php
│   ├── Icons.php
│   ├── JavaScriptModules.php
│   └── Services.yaml
├── Resources/
│   ├── Private/
│   │   ├── Language/             # XLF translations (en, de)
│   │   ├── Partials/VidPly/      # Modular template partials
│   │   ├── Layouts/              # Default content element layout
│   │   └── Templates/            # Main VidPly.html template
│   └── Public/
│       ├── Css/vidply.min.css
│       ├── Icons/
│       └── JavaScript/
│           ├── hls.min.js        # HLS streaming (loaded only when needed)
│           ├── dash.all.min.js   # DASH streaming (loaded only when needed)
│           ├── PlaylistInit.js   # Playlist logic
│           ├── PrivacyLayer.js   # GDPR consent (YouTube/Vimeo/SoundCloud)
│           └── vidply/           # Core player (compiled from TypeScript, ESM, code-split)
└── Documentation/
    ├── README.md                 # Documentation index (start here)
    ├── AssetLoading.md
    ├── Editors-Guide.md
    ├── HLS-Implementation.md
    ├── Integrations.md           # Vue/Swiper, CSP, mp-core JSON-LD
    ├── Listview.md
    ├── Partials.md
    ├── PrivacyLayer.md
    └── SettingsArchitecture.md
 

Website Pack

Activate in config/sites/<site>/config.yaml:

 
dependencies:
  - mpc/mpc-vidply
 

Or via the backend: Website Management → Websites → Sets → Add VidPly.

Database tables

tx_mpcvidply_media

Entries in the media library of the following types: video, audio, youtube, vimeo, soundcloud

Key columns:

ColumnTypeDescription
media_typeStringType identifier
media_fileFileFile references (video/audio, HLS/DASH, YouTube/Vimeo/SoundCloud via FAL Online Media Helper)
titleStringDisplay title
artistStringAuthor’s name
posterFileThumbnail
captionsFileWebVTT/SubRip subtitle files (SRT is automatically converted to VTT upon saving)
chaptersFileWebVTT/SubRip chapter files (SRT is automatically converted to VTT when saved)
audio_descriptionFileVideo file (MP4/WebM) to be used for the source exchange
audio_description_modeSelectauto, swapor vtt_speech — see audio description modes below
audio_description_durationintDuration of the captioned version in seconds (playlist user interface)
sign_languageFileSign language overlay
enable_transcriptboolShow transcript window

Audio description – Player option mapping

VidPlyProcessor Assigns media fields to VidPly data-vidply-options:

Media fieldPlayer option
audio_description (first file)audioDescriptionSrc
audio_description_modeaudioDescriptionMode (auto | swap | vtt_speech)
audio_description_durationaudioDescriptionDuration
Subtitles with tx_track_kind = descriptions<track kind="descriptions">

fallback hierarchy if audioDescriptionMode is auto:

  1. Description of the video switch when audio_description is set
  2. Otherwise, VTT language, if a VTT track with subtitles is available
  3. Otherwise, the AD button is hidden (no spoken AD)

The AD button is enabled if either a captioned video or a VTT track with descriptions is available.

SRT → WebVTT conversion

WebVTT is required for VidPly playback and transcripts. The extension accepts SubRip uploads (.srt) for subtitles, chapters and alternative audio description tracks (tx_desc_src_file).

TriggersBehaviour
Save tx_mpcvidply_media in the backendLinked .srt files are embedded directly in .vtt; editors display a flashing message
Upgrade Wizard (without shell)Admin Tools → Upgrade → Upgrade Assistants → VidPly: Convert SRT subtitle files to WebVTT
CLI (optional, DDEV/CI)vendor/bin/typo3 mpc-vidply:convert-srt-to-vtt [--dry-run] [--limit=N]

Implementation: SrtToVttConverter, SrtCaptionMigrationService, SrtCaptionConversionHook, ConvertSrtCaptionsUpgradeWizard.

tx_mpcvidply_content_media_mm

MM relationship between tt_content and tx_mpcvidply_media.

tx_mpcvidply_privacy_settings

Site-wide configuration of the privacy level for external services (YouTube, Vimeo, SoundCloud).

Key columns:

ColumnTypeDescription
youtube_headlinevarchar(255)Optional heading
youtube_intro_texttextIntroductory text before the link
youtube_outro_texttextClosing text after the link
youtube_policy_linkvarchar(255)URL of the privacy policy
youtube_link_textvarchar(255)Link text
youtube_button_labelvarchar(255)‘aria-label’ button
vimeo_*(same fields)Vimeo settings
soundcloud_*(same fields)SoundCloud settings
sys_language_uidintLanguage ID (multilingual)

Extension configuration

Global UI and security standards: Admin → Settings → Extension configuration → mpc_vidply (ext_conf_template.txt).

SettingPurpose
allowedVideoDomains / allowedAudioDomainsWhitelist for external MP4/WebM URLs
playIcon / playPosition / allowedPlayIconDomainsCustom icon for privacy/playback overlay
useCssIconsCSS-based icons in the control bar
theme / themeSyncEnabledSynchronisation of dark/light player and page designs

Full reference: SettingsArchitecture.md → Extension configuration.

Dynamic content and integrations

Vue, Swiper, CSP, mp-core JSON-LD merging, Theme API: integrations.

Fast API after PlaylistInit.js loading:

 
window.VidPlyInit.scan(rootElement);
window.VidPlyInit.pauseOutside(activeSlide);
document.dispatchEvent(new CustomEvent('mpc:dynamic-content:ready', { detail: { root } }));
 

Content element

CType: mpc_vidply

TCA fields:

FieldTypeDescription
tx_mpcvidply_media_itemsGroupSelection of media records (MM)
tx_mpcvidply_optionsCheckBit mask options
tx_mpcvidply_volumedecimalDefault volume (0–1)
tx_mpcvidply_playback_speeddecimalDefault speed (0.25–2.0)
tx_mpcvidply_languageSelectionForce UI language

Options bitmask

 
const AUTOPLAY        = 1;    // Auto-start playback
const LOOP            = 2;    // Loop content
const MUTED           = 4;    // Start muted
const CONTROLS        = 8;    // Show controls
const CAPTIONS_DEFAULT = 16;  // Captions on by default
const KEYBOARD        = 64;   // Enable keyboard shortcuts
const AUTO_ADVANCE    = 256;  // Auto-play next in playlist

// Default: 328 = CONTROLS + KEYBOARD + AUTO_ADVANCE
 

Notes:

  • Adaptive resizing is always enabled (no toggle button).
  • Transcription is controlled on a per-media-record basis (tx_mpcvidply_media.enable_transcript).

Enable option in ‘Fluid’:

 
<f:if condition="{data.tx_mpcvidply_options} % 16 >= 8">
    <!-- Controls enabled -->
</f:if>
 

Data processing

VidPlyProcessor

Processes media elements for front-end display.

TypoScript:

 
tt_content.mpc_vidply =< lib.mpcVidplyContentElement
tt_content.mpc_vidply {
    templateName = VidPly
    dataProcessing {
        10 = Mpc\MpcVidply\DataProcessing\VidPlyProcessor
    }
}
 

Available in the template:

 
{mediaItems}           <!-- Array of processed media -->
{isPlaylist}           <!-- true if 2+ items -->
{hasLocalMedia}        <!-- Has video/audio (including HLS/DASH sources) -->
{hasExternalService}   <!-- Has YouTube/Vimeo/SoundCloud -->
{playerOptions}        <!-- Decoded options array -->
{privacySettings}      <!-- Privacy layer settings per service -->
 

List view & detail view (CE in media library style)

  • ListviewProcessormpc_vidply_listview; created listview.rows with cards, pagination flags, sort settings, etc. See Documentation/Listview.md (Routing, i18n, editor fields).
  • DetailProcessormpc_vidply_detail; created detail.* and player data for the detail page. Template: Detail.html + Listview CSS, if shared. The associated shelf is only loaded if tt_content.tx_mpcvidply_show_related it is enabled (default 1); when deactivated, detail.related it is empty.

Templates / Sub-templates: Templates/Listview.html, Partials/Listview/*.

Template structure

Main template

Resources/Private/Templates/VidPly.html

Partials

PartialPurpose
VidPly/Assets.htmlConditional registration of assets
VidPly/VideoSources.html<source> Video elements
VidPly/AudioSources.html<source> Elements for audio
VidPly/Tracks.htmlSubtitles/Chapters <track> Elements
VidPly/MetadataScripts.htmlJSON-LD accessibility metadata
VidPly/PrivacyLayer.htmlGDPR consent overlay

Customisation

Override templates in your site package:

 
tt_content.mpc_vidply {
    templateRootPaths.20 = EXT:my_sitepackage/Resources/Private/Templates/
    partialRootPaths.20 = EXT:my_sitepackage/Resources/Private/Partials/
}
 

JavaScript architecture

Conditional Loading

VidPly only loads the JavaScript required for the current media types:

ScenarioLoaded assetsSize
YouTube/Vimeo/SoundCloud onlyPrivacyLayer.js~5 KB
Local video/audio filesvidply/vidply.esm.min.js (+ chunks) + PlaylistInit.js~180 KB
HLS streaming+ hls.min.js+60 KB
DASH streaming+ dash.all.min.js+200 KB
Playlist (2+ items)+ PlaylistInit.js+5 KB

Up to 97% reduction for external content only.

Files

FilePurpose
PrivacyLayer.jsGDPR consent for external services (YouTube / Vimeo / SoundCloud)
PlaylistInit.jsUser interface and navigation for playlists
hls.min.jshls.js 1.6.16 for adaptive HLS streaming (Chrome / Firefox / Edge / Desktop Safari)
dash.all.min.jsdash.js 5.2.0 (modern UMD) for MPEG-DASH streaming
vidply/*.jsCore player (compiled TypeScript → ESM, code split, includes SoundCloud renderer + buffer spinner + optional download button)

Initialisation of the player

 
// This is roughly what `PlaylistInit.js` does internally:
import { Player, PlaylistManager } from './vidply/vidply.esm.min.js';

const player = new Player('#my-player', {
    controls: true,
    keyboard: true,
    responsive: true,
});

// Optional: attach a playlist
const playlist = new PlaylistManager(player, { autoAdvance: true });
 

Data protection level

Implementation

External services (YouTube, Vimeo, SoundCloud) display a consent overlay:

  1. PrivacySettingsService Retrieves settings from tx_mpcvidply_privacy_settings table
  2. The template renders the poster and the play button (no iframe) using the settings from the database
  3. PrivacyLayer.js / PlaylistInit.js processes the click
  4. If consent is given: Creates an iframe, loads the service’s player
  5. No tracking until the user explicitly clicks ‘Play’

Privacy settings service

Classes/Service/PrivacySettingsService.php offers:

 
$privacySettings = $privacySettingsService->getSettingsForService('youtube', $languageId);
// Returns: ['headline', 'intro_text', 'outro_text', 'policy_link', 'link_text', 'button_label']
 

The settings use translations from the language file if the database fields are empty.

Customise the privacy policy

Recommended: Configure via the backend (List module → Privacy layer settings)

Or override the template: Partials/VidPly/PrivacyLayer.html

 
<div class="vidply-privacy-layer" 
     data-service="{service}" 
     data-embed-url="{embedUrl}">
    <f:if condition="{privacySettings.headline}">
        <h3>{privacySettings.headline}</h3>
    </f:if>
    <img src="{poster}" alt="{title}" />
    <button class="vidply-privacy-play">
        {privacySettings.button_label}
    </button>
    <p class="vidply-privacy-notice">
        {privacySettings.intro_text}
        <a href="{privacySettings.policy_link}">{privacySettings.link_text}</a>
        {privacySettings.outro_text}
    </p>
</div>
 

HLS and DASH streaming

HLS and DASH are not separate media types. Streaming sources (.m3u8 / .mpd) are added as files within the ‘Video’ or ‘Audio’ media type, together with progressive fallbacks.

How it works

HLS:

  1. Detects .m3u8 Source in media file references (by MIME type or file extension)
  2. Binds hls.min.js (only when required) – the VidPly bundle uses it in Chrome, Firefox, Edge and the desktop version of Safari to ensure full feature parity
  3. In Safari on iOS / iPadOS (where MSE is not available), VidPly automatically falls back to native HLS and integrates the TextTrack API into the VidPly menus for subtitles, transcripts and quality – no separate code path is required
  4. Provides a user interface for changing the quality
  5. Embedded subtitles from the HLS manifest are used by default; local VTT files take precedence
  6. The HLS renderer also responds to Hls.Events.SUBTITLE_FRAG_PROCESSED, ensuring that the interactive transcript remains synchronised when new subtitle fragments are loaded for long or live streams

DASH:

  1. Detects .mpd the source in media file references (by MIME type or file extension)
  2. Retrieves dash.all.min.js (only when required)
  3. Initialises dash.js for video/audio elements
  4. Provides support for adaptive quality as well as TTML and WebVTT subtitles
  5. By default, embedded subtitles from the DASH manifest are used; local VTT files take precedence

Source priority: DASH → HLS → progressive (MP4/WebM/MP3/OGG)

CSP configuration

Configuration/ContentSecurityPolicies.php Adds streaming domains and the schemas they use to the whitelist hls.js / dash.js.

Add custom domains:

 
return [
    'default-src' => ["'self'"],
    'media-src' => ["'self'", 'blob:', 'data:', 'https://your-cdn.com'],
    'connect-src' => ["'self'", 'https://your-cdn.com'],
];
 

blob: is required because hls.js / dash.js a blob: URL is <video>.src during playback. data: is required because some HLS variants embed init segments / subtitles inline as data URIs.

 

VidPly extension

Add a custom media type

  1. Extend TCA (Configuration/TCA/Overrides/tx_mpcvidply_media.php):
$GLOBALS['TCA']['tx_mpcvidply_media']['columns']['media_type']['config']['items'][] = [
    'label' => 'My Service',
    'value' => 'myservice',
];

$GLOBALS['TCA']['tx_mpcvidply_media']['types']['myservice'] = [
    'showitem' => '...',
];
  1. Update the DataProcessor to handle the new type

  2. Create a partial for the display

Custom player options

Add to tt_content.php:

 
$GLOBALS['TCA']['tt_content']['columns']['tx_mpcvidply_options']['config']['items'][] = [
    'label' => 'My Option',
    'value' => 512,  // Next power of 2
];
 

Debugging

Common problems

ProblemSolution
Media is not displayedCheck tx_mpcvidply_media whether the entry has been hidden
MM relationship interruptedCheck tx_mpcvidply_content_media_mm Table
JS is not loadingCheck the browser console; check TypoScript
HLS not workingCheck the CORS header in the .m3u8 file; ensure that the source file is included in the media record
DASH is not workingCheck the CORS headers in the .mpd file; ensure that the source file is included in the media record; ensure that dash.js is loaded
Privacy Layer is hangingClear caches; check ‘PrivacyLayer.js’

Useful queries

 
-- Check media records
SELECT uid, title, media_type, hidden FROM tx_mpcvidply_media;

-- Check MM relations
SELECT * FROM tx_mpcvidply_content_media_mm WHERE uid_local = [tt_content.uid];

-- Check file references
SELECT * FROM sys_file_reference WHERE tablenames = 'tx_mpcvidply_media';
 

Debug mode

Enable TYPO3 debug mode to display detailed errors:

 
$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] = true;
$GLOBALS['TYPO3_CONF_VARS']['FE']['debug'] = true;
 

Structured data (JSON-LD)

VidPly generates schema.org structured data for its media, so that pages are eligible for Google Rich Results for video/audio. The output is included on the page <head>, not in the template for the ‘content’ element.

  • What is output

    • Detail views and individual media pages: a VideoObject (or AudioObject for audio/soundcloud).
    • gallery pages with several different media items: one ItemList of the embedded VideoObject/AudioObject nodes. Inline mpc_vidply players (including playlists) and mpc_vidply_listview shelves are both taken into account and deduplicated based on their media UID in the default language.
    • Fields from the media record: name, description, duration (ISO 8601), thumbnailUrl, uploadDate, as well as contentUrl/embedUrl resolved depending on the media type.
  • contentUrl and adaptive streaming: HLS/DASH manifests are not progressive files; therefore, contentUrl outputted for pure HLS/DASH sources (the embedUrl still points to the playback page). Progressive MP4/WebM/MP3/OGG sources are used, where available.

  • Resolving the playback URL (in order of priority): the one displayed in a list view (tx_mpcvidply_detail_page), an mpc_vidply_detail element on the same page, then the site-wide first detail page; otherwise a #media-<uid> fragment on the current page.

  • With and without mp-core

    • Standalone: A separate <script type="application/ld+json"> is rendered, page.headerData rendered using a CSP nonce.
    • When mp_core loaded: The node is loaded into the mp-core @graph and WebPage.mainEntity, so that only a single JSON-LD script is output. If mp-core does not generate a usable @graph, VidPly falls back to a standalone document.
  • Disable: Set the website setting structuredDataEnabled to false to suppress all VidPly JSON-LD for this website (enabled by default). Add this to config/sites/<site>/config.yaml if your site set does not define this.

  • With mp-core: When mp-core outputs JSON-LD, VidPly includes it in its @graph. mp-core may also require seo.schema.enabled — both switches must be set to ‘true’ for the global structured data path to be used by mp-core. See Integrations.md → Structured Data.

Automated tests

The extension includes a PHPUnit suite that runs typo3/testing-framework:

  • unit tests (Tests/Unit/, configuration phpunit.xml.dist) – fast, without a database.
  • Functional tests (Tests/Functional/, configuration Build/FunctionalTests.xml) – test the database/FAL code (repository, services, processors) using a live database.

Set-up (one-off)

Install the extension’s development-specific dependencies in a standalone .Build/ directory tree (starting from the extension’s root directory – the directory containing the composer.json):

 
composer install --working-dir=vendor/mpc/mpc-vidply
# or, in a path-repo checkout:
composer install --working-dir=mpcore/packages/mpc-vidply
 

functional tests require authorisation to create temporary db_* files. Grant this authorisation once to the user “DDEV” db :

 
ddev exec 'mysql -uroot -proot -e "GRANT ALL ON \`db_%\`.* TO \`db\`@\`%\`; FLUSH PRIVILEGES;"'
 

Run

 
# Unit tests (replace EXT_ROOT with your checkout path)
ddev exec 'cd mpcore/packages/mpc-vidply && .Build/bin/phpunit -c phpunit.xml.dist'

# Functional tests (point typo3Database* at the DDEV `db` service)
ddev exec 'cd mpcore/packages/mpc-vidply && \
  typo3DatabaseDriver=mysqli typo3DatabaseHost=db typo3DatabaseName=db \
  typo3DatabaseUsername=db typo3DatabasePassword=db \
  .Build/bin/phpunit -c Build/FunctionalTests.xml'
 

Composer shortcuts are also defined: composer test:unit and composer test:functional (the functional one also requires the typo3Database* environment variables).

Coverage

Enable a coverage driver (ddev xdebug onor install pcov) and add a coverage flag:

 
ddev exec 'cd mpcore/packages/mpc-vidply && XDEBUG_MODE=coverage .Build/bin/phpunit -c phpunit.xml.dist --coverage-text --coverage-html .Build/coverage'
 

Further information

Target group-based navigation and the complete list of documents: Overview.

Quick guide

Install

 
composer require mpc/mpc-vidply
# → Database update → Include Site Set → Clear caches
 

Important files

WhatWhere
Media TCAConfiguration/TCA/tx_mpcvidply_media.php
Content TCAConfiguration/TCA/Overrides/tt_content.php
Data processorClasses/DataProcessing/VidPlyProcessor.php
Data protection serviceClasses/Service/PrivacySettingsService.php
Main templateResources/Private/Templates/VidPly.html
Data Protection JSResources/Public/JavaScript/PrivacyLayer.js
Data Protection CSSResources/Public/Css/privacy-layer.css

Database

 
-- Tables
tx_mpcvidply_media          -- Media library
tx_mpcvidply_content_media_mm -- Content-to-media relation
tx_mpcvidply_privacy_settings -- Privacy layer configuration
 

Version: 1.2.17 | TYPO3: 13.4+ / 14.x | PHP: ≥8.2

Share page