pywidevine Python Widevine CDM implementation
Features
- 🚀 Seamless Installation via pip
- 🛡️ Robust Security with message signature verification
- 🙈 Privacy Mode with Service Certificates
- 🌐 Servable CDM API Server and Client with Authentication
- 📦 Custom provision serialization format (WVD v2)
- 🧰 Create, parse, or convert PSSH headers with ease
- 🗃️ User-friendly YAML configuration
- ❤️ Forever FOSS!
Installation
With pip
Since pip is pre-installed with Python, it is the most straight forward way to install pywidevine.
Simply run pip install pywidevine and it will be ready to use from the CLI or within scripts in a minute.
With uv
This is recommended for those who wish to install from the source code, are working on changes in the source code, or just simply prefer it’s many handy features.
Go to to the official website and get uv installed. Download or clone this repository, go inside it, and run uv run pywidevine --version. To run scripts, like a license.py that is importing pywidevine, do uv run license.py. Effectively, put uv run before calling whatever is using pywidevine. For other ways to run pywidevine with uv, see Running commands.
Usage
There are two ways to use pywidevine, through scripts, or the CLI (command-line interface). Most people would be using it through scripts due to complexities working with license server APIs.
Scripts
The following is a minimal example of using pywidevine in a script to get a License for Bitmovin’s Art of Motion Demo. This demo can be found on Bitmovin’s DRM Stream Test demo page.
from pywidevine.cdm import Cdm
from pywidevine.device import Device
from pywidevine.pssh import PSSH
import requests
# prepare pssh (usually inside the MPD/M3U8, an API response, the player page, or inside the pssh mp4 box)
pssh = PSSH("AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa"
"7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==")
# load device from a WVD file (your provision)
device = Device.load("C:/Path/To/A/Provision.wvd")
# load cdm (creating a CDM instance using that device)
cdm = Cdm.from_device(device)
# open cdm session (note that any one device should have a practical limit to amount of sessions open at any one time)
session_id = cdm.open()
# get license challenge (generate a license request message, signed using the device with the pssh)
challenge = cdm.get_license_challenge(session_id, pssh)