ytdl-org/youtube-dl · error · ExtractorError
This video is DRM protected.
Error message
This video is DRM protected.
What it means
Raised by the 9c9media (CBC etc.) extractor when the content package's Constraints.Security.Type is truthy — the platform flags the package as DRM-protected. HLS/HDS/DASH manifests may still be fetched, but streams are encrypted, so the extractor refuses up front. Marked expected=True.
Source
Thrown at youtube_dl/extractor/ninecninemedia.py:38
_API_BASE_TEMPLATE = 'http://capi.9c9media.com/destinations/%s/platforms/desktop/contents/%s/'
def _real_extract(self, url):
destination_code, content_id = re.match(self._VALID_URL, url).groups()
api_base_url = self._API_BASE_TEMPLATE % (destination_code, content_id)
content = self._download_json(api_base_url, content_id, query={
'$include': '[Media.Name,Season,ContentPackages.Duration,ContentPackages.Id]',
})
title = content['Name']
content_package = content['ContentPackages'][0]
package_id = content_package['Id']
content_package_url = api_base_url + 'contentpackages/%s/' % package_id
content_package = self._download_json(
content_package_url, content_id, query={
'$include': '[HasClosedCaptions]',
})
if try_get(content_package, lambda x: x['Constraints']['Security']['Type']):
raise ExtractorError('This video is DRM protected.', expected=True)
manifest_base_url = content_package_url + 'manifest.'
formats = []
formats.extend(self._extract_m3u8_formats(
manifest_base_url + 'm3u8', content_id, 'mp4',
'm3u8_native', m3u8_id='hls', fatal=False))
formats.extend(self._extract_f4m_formats(
manifest_base_url + 'f4m', content_id,
f4m_id='hds', fatal=False))
formats.extend(self._extract_mpd_formats(
manifest_base_url + 'mpd', content_id,
mpd_id='dash', fatal=False))
self._sort_formats(formats)
thumbnails = []
for image in (content.get('Images') or []):
image_url = image.get('Url')
if not image_url:View on GitHub (pinned to 956b8c5855)
Solutions
- Accept it: DRM content cannot be downloaded with youtube-dl/yt-dlp; use the platform's official offline/app option if available.
- Look for a non-DRM on-demand replay of the same program (news clips are often unprotected while live streams are not).
- Do not retry with proxies/cookies — DRM is independent of region and session.
Defensive patterns
Strategy: try-catch
Validate before calling
import requests
pkg = requests.get(f'{api_base}contentpackages/{package_id}/', params={'$include': '[HasClosedCaptions]'}).json()
if (pkg.get('Constraints') or {}).get('Security', {}).get('Type'):
print('DRM protected — not downloadable') Try / catch
except ExtractorError as e:
if e.expected and 'DRM' in str(e):
give_up_permanently(url) # no proxy/cookie/retry will help
else:
raise Prevention
- Pre-check Constraints.Security.Type via the contentpackages API before batching.
- Never retry DRM failures — they are permanent by design.
- Use official apps/offline features for protected content instead.
When it happens
Trigger: Downloading any 9c9media-backed content whose contentpackages API response has Constraints.Security.Type set (e.g. Widevine/PlayReady-protected broadcasts).
Common situations: Premium or live CBC/GEM content; syndicated shows with DRM requirements; attempts to archive streaming platforms' protected catalogs — by design not downloadable by youtube-dl.
Related errors
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/c86585a1a9492d8d.
Report an issue: GitHub.