🔌 The provider system#
sc-videos uses an extensible provider architecture based on Zope's component architecture.
Each video hosting service (YouTube, Vimeo, etc.) is a named utility that implements the IVideoMetadataProvider interface.
🧩 The IVideoMetadataProvider interface#
Module: sc.videos.interfaces
class IVideoMetadataProvider(Interface):
"""A utility that can resolve and fetch metadata for a video service."""
id = Attribute("Machine-readable service identifier")
name = Attribute("Human-readable display name")
url_pattern = Attribute("Compiled regex with a capture group for video ID")
def fetch_metadata(video_id: str) -> VideoMetadata:
"""Fetch metadata for a video by its provider-specific ID."""
Each provider carries a url_pattern. a compiled regular expression with a capture group that extracts the video ID from a URL.
This makes resolve_url() fully extensible: adding a new provider is just registering a new named utility.
🏭 Built-in providers#
YouTube#
Utility name: youtube
Module: sc.videos.integration.youtube
Matches these URL patterns:
youtube.com/watch?v=IDyoutu.be/IDyoutube.com/embed/IDyoutube.com/shorts/IDyoutube.com/live/ID
Has two HTTP clients:
Client |
Module |
API key required |
Data richness |
|---|---|---|---|
|
|
Yes |
Full (title, description, duration, tags, thumbnail) |
|
|
No |
Limited (title, thumbnail only) |
The provider selects the client based on the youtube_api_enabled setting in the ⚙️ Video Settings control panel.
Vimeo#
Utility name: vimeo
Module: sc.videos.integration.vimeo
Matches these URL patterns:
vimeo.com/IDplayer.vimeo.com/video/ID
Uses a single client:
Client |
Module |
API key required |
Data richness |
|---|---|---|---|
|
|
No |
Full (title, description, duration, thumbnail, channel) |
🔍 URL resolution flow#
When resolve_url(url) is called:
get_video_services()queries the component registry for allIVideoMetadataProviderutilities.For each provider, the URL is tested against
provider.url_pattern.The first match wins. the regex's capture group extracts the
video_id.Returns a
VideoReference(service=provider.id, video_id=video_id).
flowchart TD
A["resolve_url('https://youtu.be/abc123')"] --> B["get_video_services()"]
B --> C["YouTubeProvider.url_pattern.search()"]
C -->|match| D["VideoReference('youtube', 'abc123')"]
B --> E["VimeoProvider.url_pattern.search()"]
E -->|no match| F["skip"]
🔗 Dynamic vocabulary#
The sc.videos.vocabulary.video_services vocabulary is automatically generated from the registered providers.
It's used by the service field on the IRemoteVideo behavior.
Adding a new provider utility automatically adds it to the vocabulary. no extra registration needed.
🖥️ Frontend provider registry#
The frontend mirrors the backend's extensible pattern using @plone/registry utilities.
The VideoProvider interface#
Module: @simplesconsultoria/volto-videos/types/videoPlayer
export interface VideoProvider {
id: string; // matches backend IVideoMetadataProvider.id
name: string; // human-readable display name
urlPattern: RegExp; // regex with capture group for video ID
getDefaultThumbnail(videoId: string): string;
getEmbedUrl(videoId: string, autoplay: boolean): string;
}
Registration#
Providers are registered as videoProvider utilities in applyConfig:
import config from '@plone/registry';
config.registerUtility({
name: 'youtube',
type: 'videoProvider',
method: () => youtubeProvider,
});
Resolution#
The helpers in @simplesconsultoria/volto-videos/helpers/video query the registry at runtime:
getVideoProviders()callsconfig.getUtilities({ type: 'videoProvider' })and maps each result through itsmethod().resolveVideo(url)iterates all providers, testing the URL against eachurlPattern.getDefaultThumbnail(info)andgetEmbedUrl(info, autoplay)find the matching provider byid.
Third-party add-ons register new providers without patching any sc-videos module.
🧱 Class hierarchy#
Backend:
IVideoMetadataProvider (interface)
└── MetadataProvider (base class)
├── YouTubeMetadataProvider
└── VimeoMetadataProvider
BaseClient (HTTP wrapper)
├── YouTubeAPIClient
├── YouTubePublicClient
└── VimeoPublicClient
Frontend:
VideoProvider (interface)
├── youtubeProvider
└── vimeoProvider
MetadataProvider handles common logic (url_pattern matching, client instantiation).
BaseClient provides a shared get(path, params) method using httpx.
See also
🔌 Add a new video provider. Step-by-step guide to implementing a new provider.
🔄 The video metadata pipeline. How the provider fits into the overall metadata flow.
🌐 REST API. @video-metadata. The REST endpoint that invokes the provider.