diff --git a/modules/cdm.ts b/modules/cdm.ts index b8cab13..7aded8a 100644 --- a/modules/cdm.ts +++ b/modules/cdm.ts @@ -18,20 +18,44 @@ try { const files_prd = fs.readdirSync(path.join(workingDir, 'playready')); const bgroup_file_found = files_prd.find((f) => f === 'bgroupcert.dat'); const zgpriv_file_found = files_prd.find((f) => f === 'zgpriv.dat'); + const prd_file_found = files_prd.find((f) => f.endsWith('.prd')); try { - if (bgroup_file_found && zgpriv_file_found) { - const file_bgroup = path.join(workingDir, 'playready', bgroup_file_found); - const file_zgpriv = path.join(workingDir, 'playready', zgpriv_file_found); + const file_bgroup = path.join(workingDir, 'playready', 'bgroupcert.dat'); + const file_zgpriv = path.join(workingDir, 'playready', 'zgpriv.dat'); + if (bgroup_file_found && zgpriv_file_found) { const bgroup_stats = fs.statSync(file_bgroup); const zgpriv_stats = fs.statSync(file_zgpriv); + // Zgpriv is always 32 bytes long if (bgroup_stats.isFile() && zgpriv_stats.isFile() && zgpriv_stats.size === 32) { const bgroup = fs.readFileSync(file_bgroup); const zgpriv = fs.readFileSync(file_zgpriv); + // Init Playready Client prd_cdm = Playready.init(bgroup, zgpriv); } + } else if ((!bgroup_file_found || !zgpriv_file_found) && prd_file_found) { + const file_prd = path.join(workingDir, 'playready', prd_file_found); + + // Parse PRD file + const parsed = Playready.unpackV3PRD(fs.readFileSync(file_prd)); + + // Write bgroupcert.dat + fs.writeFileSync(file_bgroup, parsed.bgroupcert); + // Write zgpriv.dat + fs.writeFileSync(file_zgpriv, parsed.zgpriv); + + // Delete PRD file + try { + fs.rmSync(file_prd, { recursive: true, force: true }); + } catch (e) { + console.warn('Failed to delete unused .prd file.'); + } + + console.warn('Converted deprecated .prd file into bgroupcert.dat and zgpriv.dat.'); + + prd_cdm = Playready.init(parsed.bgroupcert, parsed.zgpriv); } } catch (e) { console.error('Error loading Playready CDM. For more informations read the readme.'); diff --git a/package.json b/package.json index 641791f..caa56e1 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "m3u8-parsed": "^2.0.0", "mpd-parser": "^1.3.1", "node-forge": "^1.3.1", - "node-playready": "^1.0.2", + "node-playready": "^1.0.4", "open": "^11.0.0", "protobufjs": "^7.5.4", "puppeteer-real-browser": "^1.4.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 95a2fd7..648e9ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,8 +48,8 @@ importers: specifier: ^1.3.1 version: 1.3.1 node-playready: - specifier: ^1.0.2 - version: 1.0.2 + specifier: ^1.0.4 + version: 1.0.4 open: specifier: ^11.0.0 version: 11.0.0 @@ -1271,6 +1271,10 @@ packages: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -1488,9 +1492,9 @@ packages: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} @@ -1579,8 +1583,8 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-playready@1.0.2: - resolution: {integrity: sha512-FJQsSXrqgv3cqDW80WW6bWy43rG745JG47XjrYa0BiqNrle9DJloARi0PKYOkK5jstIVPttUIiTWQuY8su2XqQ==} + node-playready@1.0.4: + resolution: {integrity: sha512-V9+Bf3zgGnQbm7idFs1yLzRdNPDKvsv5Pyydnvvm+wKB77Irypmh53aZ9EgfrBa+/+d5X6PbOJEBqmrtkKFjkQ==} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -2692,7 +2696,7 @@ snapshots: accepts@2.0.0: dependencies: - mime-types: 3.0.1 + mime-types: 3.0.2 negotiator: 1.0.0 acorn-jsx@5.3.2(acorn@8.15.0): @@ -2798,7 +2802,7 @@ snapshots: bytes: 3.1.2 content-type: 1.0.5 debug: 4.4.3 - http-errors: 2.0.0 + http-errors: 2.0.1 iconv-lite: 0.6.3 on-finished: 2.4.1 qs: 6.14.0 @@ -3141,9 +3145,9 @@ snapshots: etag: 1.8.1 finalhandler: 2.1.0 fresh: 2.0.0 - http-errors: 2.0.0 + http-errors: 2.0.1 merge-descriptors: 2.0.0 - mime-types: 3.0.1 + mime-types: 3.0.2 on-finished: 2.4.1 once: 1.4.0 parseurl: 1.3.3 @@ -3353,6 +3357,14 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -3541,7 +3553,7 @@ snapshots: mime-db@1.54.0: {} - mime-types@3.0.1: + mime-types@3.0.2: dependencies: mime-db: 1.54.0 @@ -3614,7 +3626,7 @@ snapshots: node-int64@0.4.0: {} - node-playready@1.0.2: + node-playready@1.0.4: dependencies: aes-cmac: 4.0.0 elliptic: 6.6.1 @@ -3897,8 +3909,8 @@ snapshots: escape-html: 1.0.3 etag: 1.8.1 fresh: 2.0.0 - http-errors: 2.0.0 - mime-types: 3.0.1 + http-errors: 2.0.1 + mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 @@ -4140,7 +4152,7 @@ snapshots: dependencies: content-type: 1.0.5 media-typer: 1.1.0 - mime-types: 3.0.1 + mime-types: 3.0.2 typed-query-selector@2.12.0: {}