@javagt/widevine
v1.9.0
Published
Pure TypeScript port of pywidevine — Widevine CDM protocol implementation (ported by DeepSeek V4 Flash)
Readme
@javagt/widevine
Version 1.9.0 — Pure TypeScript port of pywidevine v1.9.0, implemented by DeepSeek V4 Flash.
Version numbers are kept in sync with the original pywidevine releases.
Installation
npm install @javagt/widevineLibrary Usage
import { Device, Cdm, PSSH, Key, VERSION } from '@javagt/widevine';
// 1. Load a WVD device file
const device = Device.load('/path/to/device.wvd');
// 2. Create CDM instance from the device
const cdm = Cdm.fromDevice(device);
// 3. Open a session
const sessionId = cdm.open();
// 4. Parse the PSSH box from base64
const pssh = new PSSH('AAAAW3Bzc2g...');
// 5. Build a signed license challenge
const challenge = cdm.getLicenseChallenge(sessionId, pssh);
// 6. Send to license server (any HTTP client)
const response = await fetch(licenseUrl, {
method: 'POST',
body: challenge,
headers: { 'Content-Type': 'application/octet-stream' },
});
// 7. Parse the license response
cdm.parseLicense(sessionId, Buffer.from(await response.arrayBuffer()));
// 8. Extract decrypted content keys
const keys = cdm.getKeys(sessionId, 'CONTENT');
for (const key of keys) {
console.log(`${key.kid.toString('hex')}:${key.key.toString('hex')}`);
}
// 9. Clean up
cdm.close(sessionId);ESM Imports
All exports are available as named ESM imports:
import { Device, Cdm, PSSH, Key, Session } from '@javagt/widevine';
import { VERSION } from '@javagt/widevine';
import {
WidevineError, TooManySessions, InvalidSession,
InvalidInitData, InvalidLicenseType, InvalidLicenseMessage,
InvalidContext, SignatureMismatch, NoKeysLoaded,
} from '@javagt/widevine';API Reference
Device
| Method | Python equivalent | Status |
|--------|-------------------|--------|
| Device.load(path) | Device.load() | ✅ |
| Device.loads(data) | Device.loads() | ✅ |
| Device.dump(path) | Device.dump() | ✅ |
| Device.dumps() | Device.dumps() | ✅ |
| Device.migrate(data) | Device.migrate() | ✅ |
| .type / .securityLevel / .systemId / .privateKey / .clientId | same | ✅ |
Cdm
| Method | Python equivalent | Status |
|--------|-------------------|--------|
| Cdm.fromDevice(device) | Cdm.from_device() | ✅ |
| Cdm.open() | Cdm.open() | ✅ |
| Cdm.close(sessionId) | Cdm.close() | ✅ |
| Cdm.getLicenseChallenge(sessionId, pssh, ...) | Cdm.get_license_challenge() | ✅ |
| Cdm.parseLicense(sessionId, licenseMessage) | Cdm.parse_license() | ✅ |
| Cdm.getKeys(sessionId, type?) | Cdm.get_keys() | ✅ |
| Cdm.setServiceCertificate(sessionId, cert) | Cdm.set_service_certificate() | ✅ |
| Cdm.getServiceCertificate(sessionId) | Cdm.get_service_certificate() | ✅ |
| Cdm.uuid / Cdm.urn / Cdm.keyFormat | class attributes | ✅ |
| Cdm.MAX_NUM_OF_SESSIONS | class attribute | ✅ |
| Cdm.serviceCertificateChallenge | class attribute | ✅ |
| Static Cdm.encryptClientId() (private in TS) | Cdm.encrypt_client_id() | ⚠️ internal |
| Cdm.decrypt() (shaka-packager) | Cdm.decrypt() | ❌ |
PSSH
| Method | Python equivalent | Status |
|--------|-------------------|--------|
| new PSSH(data) | PSSH(data) | ✅ |
| .dump() / .dumps() | same | ✅ |
| .initData / .keyIds / .systemId / .version | same | ✅ |
| .contentId | (via WidevineCencHeader) | ✅ |
| .isWidevine | (via SystemId check) | ✅ |
| PSSH.new() factory | PSSH.new() classmethod | ❌ |
| .setKeyIds() | PSSH.set_key_ids() | ❌ |
| .toWidevine() / .toPlayready() | PSSH.to_widevine() / PSSH.to_playready() | ❌ |
Key
| Method | Python equivalent | Status |
|--------|-------------------|--------|
| Key.fromKeyContainer(kc, encKey) | Key.from_key_container() | ✅ |
| Key.kidToUuid(kid) | Key.kid_to_uuid() | ✅ |
| .type / .kid / .key / .permissions | same (kid is Buffer not UUID) | ✅ |
Module-level
| Export | Python equivalent | Status |
|--------|-------------------|--------|
| DeviceTypes enum | DeviceTypes | ✅ |
| Session class | Session | ✅ |
| VERSION constant | __version__ | ✅ (synced to v1.9.0) |
What's Missing vs pywidevine 1.9.0
| Feature | Reason |
|---------|--------|
| Cdm.decrypt() (shaka-packager) | Requires shaka-packager binary; not needed for key-only use |
| PSSH.new() / .setKeyIds() / .toWidevine() / .toPlayready() | Not used in practice for key extraction |
| RemoteCdm class | Network-based remote CDM; narrow use case |
| CLI (pywidevine commands) | Python CLI; unneeded in JS ecosystem |
| HTTP server (pywidevine serve) | Python aiohttp server; unneeded in JS ecosystem |
| Typed exception classes (10 types) | All errors throw Error with descriptive message |
| utils.get_binary_path() | Python-specific PATH utility |
Versioning
This library tracks pywidevine version numbers. Current release matches pywidevine v1.9.0.
License
MIT
Ported from pywidevine (MIT) by DeepSeek V4 Flash.
