Skip to content

DRM API

Auto-generated reference for the DRM systems: Widevine, PlayReady, ClearKey, and related helpers. For configuring DRM as a user, see DRM & CDM Setup.

ClearKey

ClearKey(key, iv=None)

AES-128 ClearKey (HLS) DRM system.

Give the IV where possible. If you do not give an IV, unshackle sets it to of the same bit-size as the content key.

warn_clear

warn_clear(reason)

Warn once per track that unshackle passed a segment through undecrypted.

decrypt

decrypt(path)

Decrypt a Track with AES-128 ClearKey (HLS) DRM.

from_m3u_key classmethod

from_m3u_key(m3u_key, session=None)

Load a ClearKey from an M3U(8) Playlist's EXT-X-KEY.

Parameters:

Name Type Description Default
m3u_key Key

A Key object parsed from a m3u(8) playlist using the m3u8 library.

required
session Optional[Session]

Optional HTTP session used to request external URIs with. Useful to set headers, proxies, cookies, and so forth.

None

ClearKeyCENC

ClearKeyCENC(kids, laurl=None, content_keys=None, **kwargs)

W3C EME ClearKey (org.w3.clearkey) DRM System over MPEG-CENC tracks.

Distinct from the HLS AES-128 ClearKey class: a license server gives the keys here as a JWK Set keyed by KID, and the media is standard CENC (decrypted with shaka-packager/mp4decrypt KID:KEY pairs, same as Widevine).

kid property

kid

Get first Key ID, if any.

Exceptions

KIDNotFound

Bases: Exception

KID (Encryption Key ID) was not found.

CEKNotFound

Bases: Exception

CEK (Content Encryption Key) for KID was not found in License.

EmptyLicense

Bases: Exception

License returned no Content Encryption Keys.

to_dict

to_dict()

Serialise this DRM instance for export/import (KIDs + license URL).

unshackle stores the content keys once at the export's track level, and does not duplicate them here.

get_license_challenge

get_license_challenge()

Assemble the W3C EME ClearKey JSON license request for the unkeyed KIDs.

get_content_keys

get_content_keys(*, licence, session=None)

Get Content Keys for this DRM Instance from a ClearKey license server.

The licence param is a function. unshackle gives it the W3C JSON license request as challenge. It may return the JWK Set license as a dict, JSON str, or bytes. If it returns None and the manifest gave a Laurl, unshackle POSTs the challenge there directly instead.

decrypt

decrypt(path)

Decrypt a Track with ClearKey DRM (standard CENC). Args: path: Path to the encrypted file to decrypt Raises: EnvironmentError if the required decryption executable could not be found. ValueError if unshackle has not yet downloaded the track. SubprocessError if the decryption process returned a non-zero exit code.

mp4decrypt_key_args

mp4decrypt_key_args()

Build the mp4decrypt --key arguments for every content key.

decrypt_with_mp4decrypt

decrypt_with_mp4decrypt(path)

Decrypt using mp4decrypt

decrypt_with_shaka_packager

decrypt_with_shaka_packager(path)

Decrypt with shaka-packager

MonaLisa

MonaLisa(ticket, device_path, tool_path=None, **kwargs)

MonaLisa DRM System.

Unlike Widevine/PlayReady, MonaLisa does not use a challenge/response flow with a license server. Instead, the service API gives the PSSH value (ticket) directly, and a WASM module extracts the content keys locally.

Initialise MonaLisa DRM.

Parameters:

Name Type Description Default
ticket Union[str, bytes]

PSSH value from service API (base64 string or raw bytes).

required
device_path Path

Path to the CDM device file (.mld).

required
tool_path Optional[Path]

Optional path to an external decryption binary.

None
**kwargs Any

Additional metadata stored in self.data.

{}

Raises:

Type Description
TicketNotFound

If ticket/PSSH is empty.

KeyExtractionFailed

If content key extraction fails.

kid property

kid

Get the Key ID.

key property

key

Get the content key as hex string.

pssh property

pssh

Get the raw PSSH/ticket value as a string.

Returns:

Type Description
str

The raw PSSH value as a base64 string.

content_id property

content_id

Extract the Content ID from the PSSH for display.

The PSSH contains an embedded Content ID at bytes 21-75 with format: H5DCID-V3-P1-YYYYMMDD-HHMMSS-MEDIAID-TIMESTAMP-SUFFIX

Returns:

Type Description
Optional[str]

The Content ID string if extractable, None otherwise.

content_keys property

content_keys

Get content keys in the same format as Widevine/PlayReady.

Returns:

Type Description
dict[UUID, str]

Dictionary mapping KID to the content key hex string.

key_pair property

key_pair

The formatted KID:KEY for CLI decryptors (32hex:32hex).

Exceptions

TicketNotFound

Bases: Exception

Raised when the caller gives no PSSH/ticket data.

KeyExtractionFailed

Bases: Exception

Raised when content key extraction from the ticket fails.

extract_keys

extract_keys()

Extract keys from the ticket using the MonaLisa CDM.

from_ticket classmethod

from_ticket(ticket, device_path, tool_path=None)

Make a MonaLisa DRM instance from a PSSH/ticket.

Parameters:

Name Type Description Default
ticket Union[str, bytes]

PSSH value from service API.

required
device_path Path

Path to the CDM device file (.mld).

required
tool_path Optional[Path]

Optional path to an external decryption binary.

None

Returns:

Type Description
MonaLisa

MonaLisa DRM instance with extracted keys.

decrypt_segment

decrypt_segment(segment_path, output_path=None)

Decrypt an individual segment file using the configured CLI tool via subprocess.

Parameters:

Name Type Description Default
segment_path Path

Path to the segment file to decrypt.

required
output_path Optional[Path]

Optional path for the decrypted output segment.

None

decrypt

decrypt(path, output_path=None, *, is_segment=False)

Decrypt a media file (segment or track) using the configured CLI tool via subprocess.

Parameters:

Name Type Description Default
path Path

Path to the target file to decrypt.

required
output_path Optional[Path]

Optional path for the decrypted output file.

None
is_segment bool

Set True if this is an individual segment rather than a full track.

False

PlayReady

PlayReady(pssh, kid=None, pssh_b64=None, **kwargs)

PlayReady DRM System.

extract_kids_from_pssh_b64

extract_kids_from_pssh_b64(pssh_b64)

Extract all KIDs from base64-encoded PSSH data.

to_dict

to_dict()

Serialise this DRM instance for export/import (PSSH + KIDs).

unshackle stores the content keys once at the export's track level, and does not duplicate them here.

header_kids staticmethod

header_kids(header)

Return the KIDs one WRM header names, in header order.

absorb

absorb(*others)

Fold sibling PlayReady objects into this one so their headers and KIDs get licensed too.

A manifest can attach one PlayReady object per WRM header to the same track (ISM shares its Protection list across tracks; HLS emits one per EXT-X-KEY). The caller keeps this object's identity, which the decrypt path and drm_lock depend on.

distinct_headers

distinct_headers()

Return the WRM headers to license, deduplicated by the KID set each one names.

Two headers naming the same KIDs (a v4.0 header beside its v4.3 twin, or one PRH per rendition for one content key) cost one challenge. A header with no readable KID is kept: it may still be the only route to a content key nothing else names.

pro_b64_for staticmethod

pro_b64_for(header)

Build a base64 one-record PlayReady Object holding only this header.

Remote CDMs send the value given to set_pssh_b64 rather than the header passed to get_license_challenge, so a per-header challenge needs a per-header PRO.

extract_keys_from_cdm

extract_keys_from_cdm(cdm, session_id)

Extract keys from CDM session with cross-library compatibility.

Parameters:

Name Type Description Default
cdm Cdm

CDM instance

required
session_id bytes

Session identifier

required

Returns:

Type Description
dict

Dictionary mapping KID UUIDs to hex keys

get_content_keys

get_content_keys(cdm, certificate, licence)

License every distinct WRM header whose KIDs still lack a content key.

A v4.2+ header may list several KIDs and one response may stack several licences, so one challenge often covers everything. Content that ships several headers (ISM with one ProtectionHeader per track type, HLS with one PRH per playlist) gets one challenge per header that is not yet covered. Headers are sent as-is: Microsoft lets the server ignore the header, so a merged header could ask for keys it never grants.

A header that a round refused, or that yielded nothing, is not sent again by this object: every track of a title runs this method, and a repeat would only repeat the refusal.

detect_revocation staticmethod

detect_revocation(text)

Return the decoded error string if a revocation HRESULT is present, else None.

Reads the code from the raw SOAP body (0x8004C065) or from an exception message that carries it, so this method covers any service.

decrypt

decrypt(path)

Decrypt a Track with PlayReady DRM. Args: path: Path to the encrypted file to decrypt Raises: EnvironmentError if the required decryption executable could not be found. ValueError if unshackle has not yet downloaded the track. SubprocessError if the decryption process returned a non-zero exit code.

own_kids

own_kids()

Return the KIDs that identify this track's own content key.

The KID given to the constructor (from the manifest or the init segment) names the track exactly. A PSSH can name the KIDs of other renditions too.

mp4decrypt_key_args

mp4decrypt_key_args()

Build the mp4decrypt --key arguments for every content key and the zero-KID fallback.

decrypt_with_mp4decrypt

decrypt_with_mp4decrypt(path)

Decrypt using mp4decrypt

decrypt_with_shaka_packager

decrypt_with_shaka_packager(path)

Decrypt with shaka-packager (original method)

Widevine

Widevine(pssh, kid=None, **kwargs)

Widevine DRM System.

pssh property

pssh

Get Protection System Specific Header Box.

kid property

kid

Get first Key ID, if any.

kids property

kids

Get all Key IDs from PSSH, falling back to the externally provided KID.

Exceptions

PSSHNotFound

Bases: Exception

PSSH (Protection System Specific Header) was not found.

KIDNotFound

Bases: Exception

KID (Encryption Key ID) was not found.

CEKNotFound

Bases: Exception

CEK (Content Encryption Key) for KID was not found in License.

EmptyLicense

Bases: Exception

License returned no Content Encryption Keys.

from_track classmethod

from_track(track, session=None)

Get PSSH and KID from within the Initiation Segment of the Track Data. It also tries to get PSSH and KID from other track data like M3U8 data as well as through FFprobe.

Make a Widevine DRM System object from a track's information. Use this method only when a PSSH cannot be given directly. It is rare to need to use this.

You can give your own requests.Session to use custom headers and more.

Raises:

Type Description
PSSHNotFound

If the PSSH was not found within the data.

KIDNotFound

If the KID was not found within the data or PSSH.

from_init_data classmethod

from_init_data(init_data)

Get PSSH and KID from within Initialization Segment Data.

Use this method only when a PSSH cannot be given directly. It is rare to need to use this.

Raises:

Type Description
PSSHNotFound

If the PSSH was not found within the data.

KIDNotFound

If the KID was not found within the data or PSSH.

to_dict

to_dict()

Serialise this DRM instance for export/import (PSSH + KIDs).

unshackle stores the content keys once at the export's track level, and does not duplicate them here.

get_content_keys

get_content_keys(cdm, certificate, licence)

Make a CDM Session and get Content Keys for this DRM Instance. The certificate and license params are functions. unshackle gives them the challenge and the session ID.

decrypt

decrypt(path)

Decrypt a Track with Widevine DRM. Args: path: Path to the encrypted file to decrypt Raises: EnvironmentError if the required decryption executable could not be found. ValueError if unshackle has not yet downloaded the track. SubprocessError if the decryption process returned a non-zero exit code.

own_kids

own_kids()

Return the KIDs that identify this track's own content key.

The KID given to the constructor (from the manifest or the init segment) names the track exactly. A PSSH can name the KIDs of other renditions too.

mp4decrypt_key_args

mp4decrypt_key_args()

Build the mp4decrypt --key arguments for every content key and the zero-KID fallback.

decrypt_with_mp4decrypt

decrypt_with_mp4decrypt(path)

Decrypt using mp4decrypt

decrypt_with_shaka_packager

decrypt_with_shaka_packager(path)

Decrypt with shaka-packager (original method)

drm_from_dict

drm_from_dict(data)

Reconstruct a Widevine/PlayReady/ClearKeyCENC DRM instance from its to_dict() form.

Rebuilds the PSSH from the stored base64 (KIDs for ClearKey, which has no PSSH) and re-injects any saved content keys so the resulting object can decrypt without contacting a license server.

real_kids

real_kids(drm)

Return the KIDs a DRM object names, without the all-zero and test-pattern placeholders.

own_kids

own_kids(drm)

Return the real KIDs that identify the track's own content key, as the DRM object knows them.