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

  1. Use the official TF1/MYTF1 player for DRM content — youtube-dl cannot decrypt it.
  2. Check whether a non-DRM delivery exists for the same video (e.g. free replay vs premium version).
  3. 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

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.