🔌 Add a new video provider#
sc-videos is designed to be extensible. This guide walks you through adding support for a new video hosting service. from backend provider to frontend embed support.
We'll use Dailymotion as an example.
🔧 Backend: Implement the provider#
1. Create the client#
Create a module for your provider's HTTP client:
# src/my_addon/integration/dailymotion/public.py
from sc.videos.integration.base import BaseClient
from sc.videos.integration.base import VideoMetadata
class DailymotionPublicClient(BaseClient):
"""Fetch metadata from Dailymotion's oEmbed endpoint."""
BASE_URL = "https://www.dailymotion.com/services/oembed"
def fetch_metadata(self, video_id: str) -> VideoMetadata:
url = f"https://www.dailymotion.com/video/{video_id}"
data = self.get("", params={"url": url, "format": "json"})
return VideoMetadata(
video_id=video_id,
title=data.get("title", ""),
description=data.get("description", ""),
duration=int(data.get("duration", 0)),
thumbnail_url=data.get("thumbnail_url", ""),
channel=data.get("author_name", ""),
tags=[],
)
2. Create the provider#
# src/my_addon/integration/dailymotion/__init__.py
import re
from sc.videos.integration.base import MetadataProvider
from .public import DailymotionPublicClient
class DailymotionMetadataProvider(MetadataProvider):
"""Metadata provider for Dailymotion videos."""
id = "dailymotion"
name = "Dailymotion"
url_pattern = re.compile(
r"(?:dailymotion\.com/video/|dai\.ly/)([a-zA-Z0-9]+)"
)
def _get_client(self):
return DailymotionPublicClient(base_url=self.BASE_URL)
3. Register the utility#
<!-- configure.zcml -->
<utility
factory=".integration.dailymotion.DailymotionMetadataProvider"
provides="sc.videos.interfaces.IVideoMetadataProvider"
name="dailymotion"
/>
That's it for the backend.
The URL will now be recognized by resolve_url(), the vocabulary will include "dailymotion", and the @video-metadata service will fetch Dailymotion metadata.
🎨 Frontend: Register the provider#
The frontend uses @plone/registry utilities, so you don't need to modify any sc-videos source files.
4. Create the provider object#
In your add-on, create a provider that implements the VideoProvider interface:
// src/providers/dailymotion.ts
import type { VideoProvider } from '@simplesconsultoria/volto-videos/types/videoPlayer';
const dailymotionProvider: VideoProvider = {
id: 'dailymotion',
name: 'Dailymotion',
urlPattern: /(?:dailymotion\.com\/video\/|dai\.ly\/)([a-zA-Z0-9]+)/,
getDefaultThumbnail(videoId: string): string {
return `https://www.dailymotion.com/thumbnail/video/${videoId}`;
},
getEmbedUrl(videoId: string, autoplay: boolean): string {
const ap = autoplay ? 1 : 0;
return `https://www.dailymotion.com/embed/video/${videoId}?autoplay=${ap}`;
},
};
export default dailymotionProvider;
5. Register the provider utility#
In your add-on's applyConfig, register the provider:
// src/index.ts
import type { ConfigType } from '@plone/registry';
import dailymotionProvider from './providers/dailymotion';
function applyConfig(config: ConfigType) {
config.registerUtility({
name: 'dailymotion',
type: 'videoProvider',
method: () => dailymotionProvider,
});
return config;
}
export default applyConfig;
That's it. The resolveVideo(), getDefaultThumbnail(), and getEmbedUrl() helpers automatically discover your provider from the registry at runtime.
6. Add Storybook MSW handlers (optional)#
Add mock metadata for your provider in src/mocks/videoMetadata.ts so stories can exercise the new source without hitting the real API.
✅ Test#
Restart the backend (ZCML changes require a restart).
Create a Video and paste a Dailymotion URL.
Click the fetch button. metadata should populate.
Save. the player should embed the Dailymotion video.
See also
🔌 The provider system. Architecture of the provider system.
🌐 REST API. @video-metadata. The
@video-metadataendpoint.