ytdl-org/youtube-dl · error · ExtractorError
This video is DRM protected.
Error message
This video is DRM protected.
What it means
Raised by the Wat extractor when no formats were extracted from the delivery field AND the delivery object has drm truthy. It is the fallback path after extract_formats found nothing usable, indicating the stream exists only in a DRM-protected delivery.
Source
Thrown at youtube_dl/extractor/wat.py:90
def extract_formats(manifest_urls):
for f, f_url in manifest_urls.items():
if not f_url:
continue
if f in ('dash', 'mpd'):
formats.extend(self._extract_mpd_formats(
f_url.replace('://das-q1.tf1.fr/', '://das-q1-ssl.tf1.fr/'),
video_id, mpd_id='dash', fatal=False))
elif f == 'hls':
formats.extend(self._extract_m3u8_formats(
f_url, video_id, 'mp4',
'm3u8_native', m3u8_id='hls', fatal=False))
delivery = video_data.get('delivery') or {}
extract_formats({delivery.get('format'): delivery.get('url')})
if not formats:
if delivery.get('drm'):
raise ExtractorError('This video is DRM protected.', expected=True)
manifest_urls = self._download_json(
'http://www.wat.tv/get/webhtml/' + video_id, video_id, fatal=False)
if manifest_urls:
extract_formats(manifest_urls)
self._sort_formats(formats)
return {
'id': video_id,
'title': title,
'thumbnail': video_info.get('preview'),
'upload_date': unified_strdate(try_get(
video_data, lambda x: x['mediametrie']['chapters'][0]['estatS4'])),
'duration': int_or_none(video_info.get('duration')),
'formats': formats,
}
View on GitHub (pinned to 956b8c5855)
Solutions
- Use the official TF1/MYTF1 player for DRM content — youtube-dl cannot decrypt it.
- Check whether a non-DRM delivery exists for the same video (e.g. free replay vs premium version).
- If you believe the video is not DRM-protected, the manifest extraction may have silently failed (fatal=False) — report upstream with verbose output (-v).
Defensive patterns
Strategy: validation
Validate before calling
delivery = video_data.get('delivery') or {}
if not delivery.get('url') and delivery.get('drm'):
raise SystemExit(f'{video_id}: DRM-only delivery, skipping') Type guard
def is_drm_only_delivery(video_data: dict) -> bool:
delivery = video_data.get('delivery') or {}
return bool(delivery.get('drm')) and not delivery.get('url') Try / catch
try:
info = ydl.extract_info(url)
except ExtractorError as e:
if 'DRM protected' in str(e):
skip_drm(url)
else:
raise Prevention
- Prefer free/replay TF1 content over premium streams in automated queues.
- Inspect the mediainfo JSON's delivery.drm flag before extraction in custom clients.
- Run with -v to distinguish silent format-extraction failures from real DRM.
When it happens
Trigger: mediainfo.tf1.fr returns a delivery whose format/url produce no formats (empty url, or MPD/HLS extraction all failed with fatal=False) and delivery['drm'] is set; the fallback get/webhtml lookup then never runs.
Common situations: Premium TF1/wat.tv content only served under PlayReady/Widevine; partial delivery entries where the plain-media URL is absent because rights require DRM.
Related errors
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/48f91627ef075c6a.
Report an issue: GitHub.