From ec8ddd995a55f9fec381accb1380130678995fa7 Mon Sep 17 00:00:00 2001 From: widevinedump <96489252+widevinedump@users.noreply.github.com> Date: Sat, 25 Dec 2021 14:41:36 +0530 Subject: [PATCH] Main --- 1.- BLIM.cmd | 4 + 2.- HBO.cmd | 2 + KEYS/HBOMAX.txt | 542 +++ KEYS/PARAMOUNTPLUS.txt | 31 + ...METROS GENERALES_muestra como descarga.txt | 6 + README.md | 40 +- bad37.py | 128 + blimtv.py | 594 +++ cookies/cookies.txt | 0 hbomax.py | 949 +++++ parametros de descargas.txt | 84 + paramountplus.py | 788 ++++ paramountplus_original.py | 789 ++++ pywidevine/__init__.py | 0 pywidevine/cdm/__init__.py | 0 pywidevine/cdm/cdm.py | 364 ++ pywidevine/cdm/deviceconfig.py | 53 + .../android_generic/device_client_id_blob | Bin 0 -> 1651 bytes .../android_generic/device_private_key | 27 + pywidevine/cdm/formats/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 171 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 168 bytes .../__pycache__/wv_proto2_pb2.cpython-37.pyc | Bin 0 -> 44607 bytes .../__pycache__/wv_proto2_pb2.cpython-38.pyc | Bin 0 -> 48896 bytes pywidevine/cdm/formats/wv_proto2.proto | 466 +++ pywidevine/cdm/formats/wv_proto2_pb2.py | 3324 +++++++++++++++++ pywidevine/cdm/formats/wv_proto3.proto | 389 ++ pywidevine/cdm/formats/wv_proto3_pb2.py | 2686 +++++++++++++ pywidevine/cdm/key.py | 14 + pywidevine/cdm/session.py | 18 + pywidevine/cdm/vmp.py | 102 + .../blim/__pycache__/client.cpython-37.pyc | Bin 0 -> 1141 bytes .../blim/__pycache__/config.cpython-37.pyc | Bin 0 -> 2332 bytes .../__pycache__/downloader.cpython-37.pyc | Bin 0 -> 4681 bytes .../__pycache__/downloader_pr.cpython-37.pyc | Bin 0 -> 4684 bytes .../__pycache__/downloader_wv.cpython-37.pyc | Bin 0 -> 5625 bytes .../__pycache__/manifest_parse.cpython-37.pyc | Bin 0 -> 2699 bytes pywidevine/clients/blim/client.py | 27 + pywidevine/clients/blim/config.py | 59 + pywidevine/clients/blim/downloader_pr.py | 117 + pywidevine/clients/blim/downloader_wv.py | 155 + pywidevine/clients/blim/manifest_parse.py | 104 + pywidevine/clients/dictionary.py | 42 + .../__pycache__/authHelper.cpython-37.pyc | Bin 0 -> 1294 bytes .../__pycache__/authHelper.cpython-38.pyc | Bin 0 -> 1135 bytes .../hbomax/__pycache__/client.cpython-37.pyc | Bin 0 -> 3212 bytes .../hbomax/__pycache__/client.cpython-38.pyc | Bin 0 -> 2272 bytes .../hbomax/__pycache__/client_.cpython-37.pyc | Bin 0 -> 1625 bytes .../hbomax/__pycache__/config.cpython-37.pyc | Bin 0 -> 4332 bytes .../__pycache__/constants.cpython-37.pyc | Bin 0 -> 3051 bytes pywidevine/clients/hbomax/client.py | 106 + pywidevine/clients/hbomax/config.py | 125 + .../__pycache__/config.cpython-37.pyc | Bin 0 -> 1090 bytes .../__pycache__/downloader.cpython-37.pyc | Bin 0 -> 4510 bytes pywidevine/clients/paramountplus/config.py | 30 + .../clients/paramountplus/config_orignal.py | 9 + .../clients/paramountplus/downloader.py | 116 + .../paramountplus/downloader_oringal.py | 110 + .../clients/paramountplus/paramountplus.rar | Bin 0 -> 5420 bytes pywidevine/clients/proxy_config.py | 15 + pywidevine/decrypt/wvdecrypt.py | 55 + pywidevine/decrypt/wvdecryptcustom.py | 59 + pywidevine/downloader/__init__.py | 0 pywidevine/downloader/tracks.py | 72 + pywidevine/downloader/wvdownloader.py | 199 + pywidevine/downloader/wvdownloaderconfig.py | 14 + pywidevine/muxer/muxer.py | 271 ++ requeriments.txt | 28 + 68 files changed, 13111 insertions(+), 2 deletions(-) create mode 100644 1.- BLIM.cmd create mode 100644 2.- HBO.cmd create mode 100644 KEYS/HBOMAX.txt create mode 100644 KEYS/PARAMOUNTPLUS.txt create mode 100644 PARAMETROS GENERALES_muestra como descarga.txt create mode 100644 bad37.py create mode 100644 blimtv.py create mode 100644 cookies/cookies.txt create mode 100644 hbomax.py create mode 100644 parametros de descargas.txt create mode 100644 paramountplus.py create mode 100644 paramountplus_original.py create mode 100644 pywidevine/__init__.py create mode 100644 pywidevine/cdm/__init__.py create mode 100644 pywidevine/cdm/cdm.py create mode 100644 pywidevine/cdm/deviceconfig.py create mode 100644 pywidevine/cdm/devices/android_generic/device_client_id_blob create mode 100644 pywidevine/cdm/devices/android_generic/device_private_key create mode 100644 pywidevine/cdm/formats/__init__.py create mode 100644 pywidevine/cdm/formats/__pycache__/__init__.cpython-37.pyc create mode 100644 pywidevine/cdm/formats/__pycache__/__init__.cpython-38.pyc create mode 100644 pywidevine/cdm/formats/__pycache__/wv_proto2_pb2.cpython-37.pyc create mode 100644 pywidevine/cdm/formats/__pycache__/wv_proto2_pb2.cpython-38.pyc create mode 100644 pywidevine/cdm/formats/wv_proto2.proto create mode 100644 pywidevine/cdm/formats/wv_proto2_pb2.py create mode 100644 pywidevine/cdm/formats/wv_proto3.proto create mode 100644 pywidevine/cdm/formats/wv_proto3_pb2.py create mode 100644 pywidevine/cdm/key.py create mode 100644 pywidevine/cdm/session.py create mode 100644 pywidevine/cdm/vmp.py create mode 100644 pywidevine/clients/blim/__pycache__/client.cpython-37.pyc create mode 100644 pywidevine/clients/blim/__pycache__/config.cpython-37.pyc create mode 100644 pywidevine/clients/blim/__pycache__/downloader.cpython-37.pyc create mode 100644 pywidevine/clients/blim/__pycache__/downloader_pr.cpython-37.pyc create mode 100644 pywidevine/clients/blim/__pycache__/downloader_wv.cpython-37.pyc create mode 100644 pywidevine/clients/blim/__pycache__/manifest_parse.cpython-37.pyc create mode 100644 pywidevine/clients/blim/client.py create mode 100644 pywidevine/clients/blim/config.py create mode 100644 pywidevine/clients/blim/downloader_pr.py create mode 100644 pywidevine/clients/blim/downloader_wv.py create mode 100644 pywidevine/clients/blim/manifest_parse.py create mode 100644 pywidevine/clients/dictionary.py create mode 100644 pywidevine/clients/hbomax/__pycache__/authHelper.cpython-37.pyc create mode 100644 pywidevine/clients/hbomax/__pycache__/authHelper.cpython-38.pyc create mode 100644 pywidevine/clients/hbomax/__pycache__/client.cpython-37.pyc create mode 100644 pywidevine/clients/hbomax/__pycache__/client.cpython-38.pyc create mode 100644 pywidevine/clients/hbomax/__pycache__/client_.cpython-37.pyc create mode 100644 pywidevine/clients/hbomax/__pycache__/config.cpython-37.pyc create mode 100644 pywidevine/clients/hbomax/__pycache__/constants.cpython-37.pyc create mode 100644 pywidevine/clients/hbomax/client.py create mode 100644 pywidevine/clients/hbomax/config.py create mode 100644 pywidevine/clients/paramountplus/__pycache__/config.cpython-37.pyc create mode 100644 pywidevine/clients/paramountplus/__pycache__/downloader.cpython-37.pyc create mode 100644 pywidevine/clients/paramountplus/config.py create mode 100644 pywidevine/clients/paramountplus/config_orignal.py create mode 100644 pywidevine/clients/paramountplus/downloader.py create mode 100644 pywidevine/clients/paramountplus/downloader_oringal.py create mode 100644 pywidevine/clients/paramountplus/paramountplus.rar create mode 100644 pywidevine/clients/proxy_config.py create mode 100644 pywidevine/decrypt/wvdecrypt.py create mode 100644 pywidevine/decrypt/wvdecryptcustom.py create mode 100644 pywidevine/downloader/__init__.py create mode 100644 pywidevine/downloader/tracks.py create mode 100644 pywidevine/downloader/wvdownloader.py create mode 100644 pywidevine/downloader/wvdownloaderconfig.py create mode 100644 pywidevine/muxer/muxer.py create mode 100644 requeriments.txt diff --git a/1.- BLIM.cmd b/1.- BLIM.cmd new file mode 100644 index 0000000..574a68a --- /dev/null +++ b/1.- BLIM.cmd @@ -0,0 +1,4 @@ +python bad37.py --url https://www.blim.com/asset/10199 -c playready -s 7 -e 9 +python bad37.py --url https://www.blim.com/asset/24336 -c playready -s 7 -e 8 +python bad37.py --url https://www.blim.com/asset/24336 -c playready -s 7 -e 9 +pause \ No newline at end of file diff --git a/2.- HBO.cmd b/2.- HBO.cmd new file mode 100644 index 0000000..6f052bf --- /dev/null +++ b/2.- HBO.cmd @@ -0,0 +1,2 @@ +python bad37.py --url https://play.hbomax.com/page/urn:hbo:page:GYSAr8wiBN8IqpAEAAAAE:type:series --alang es-la en --slang en en-sdh es-la es-la-sdh --flang es-la-forced +pause \ No newline at end of file diff --git a/KEYS/HBOMAX.txt b/KEYS/HBOMAX.txt new file mode 100644 index 0000000..1a9a3f3 --- /dev/null +++ b/KEYS/HBOMAX.txt @@ -0,0 +1,542 @@ +##### One KEY per line. ##### +Sex and the City S01E01 - Sex and the City +010077f9feb0ab3feaa14533fad3db02:4680777ac43b9698b7ab0ab7e8dc215d +01051810dad40547af6417cd3923ad15:ffa4387c9044429d58c7173824e448e1 +0102a3562b2a4ca6f558e75d9e2e5a69:44742f93fa531725d1058900aa07cb5e +01018b9daf7dbcacdd3ed46c0a200375:d0bd3272ad478ee9d7c2dccd68ad73fc +MulherMaravilha 1984 (2020) +01004200311580d98790817b5e4bba85:f36e16ff4a972e47404ca57ffa4419f7 +010518ff7f06ac32c4600a4c3d58f47e:8331bb0fa3c544b5d7c5bb7c34f5a589 +010191111658e773667a025a991f4d8a:68f8ffaa759b0a2f76ab9f298ec91a3a +01039abe393e5a2c7fb219d2cb4709d7:2c4f6c7cf29e844145a4dd41fd612d64 +Game of Thrones S01E01 - Winter Is Coming +0100e34e7b880c7b9dde35f77c4bc1cb:593bf887f900ebfd6fea887fe4500ce4 +01055f0f6ff8175cf7722cdfa2b74d7f:5da0b5ebf4fe112aa0e567cd42f9a164 +010274d4c60b0c31d6f886c1f4f3e9ac:96087cbd0f95970ce414bac741b66fcd +0101c9735891941ecf7a306ca73727fe:f4a6f54a423f19e4954d5163f83acc48 +Game of Thrones S01E01 - Winter Is Coming +0100e34e7b880c7b9dde35f77c4bc1cb:593bf887f900ebfd6fea887fe4500ce4 +01055f0f6ff8175cf7722cdfa2b74d7f:5da0b5ebf4fe112aa0e567cd42f9a164 +010274d4c60b0c31d6f886c1f4f3e9ac:96087cbd0f95970ce414bac741b66fcd +0101c9735891941ecf7a306ca73727fe:f4a6f54a423f19e4954d5163f83acc48 +MulherMaravilha 1984 (2020) +01004200311580d98790817b5e4bba85:f36e16ff4a972e47404ca57ffa4419f7 +010518ff7f06ac32c4600a4c3d58f47e:8331bb0fa3c544b5d7c5bb7c34f5a589 +010191111658e773667a025a991f4d8a:68f8ffaa759b0a2f76ab9f298ec91a3a +01039abe393e5a2c7fb219d2cb4709d7:2c4f6c7cf29e844145a4dd41fd612d64 +MulherMaravilha 1984 (2020) +01004200311580d98790817b5e4bba85:f36e16ff4a972e47404ca57ffa4419f7 +010518ff7f06ac32c4600a4c3d58f47e:8331bb0fa3c544b5d7c5bb7c34f5a589 +010191111658e773667a025a991f4d8a:68f8ffaa759b0a2f76ab9f298ec91a3a +01039abe393e5a2c7fb219d2cb4709d7:2c4f6c7cf29e844145a4dd41fd612d64 +Fatale (2020) +0100100f83ba50be7f20cbe8095b422c:55dd470924f512b407ce2672c6751d9a +0105068f5057fe88847899662ecf452d:0a0bdb3381f733fca1ce94ef3be74a2f +010173ef657a0ecf2db35888f3b890cf:144877fc1cc4029711691e3dc002d262 +Fatale (2020) +0100100f83ba50be7f20cbe8095b422c:55dd470924f512b407ce2672c6751d9a +0105068f5057fe88847899662ecf452d:0a0bdb3381f733fca1ce94ef3be74a2f +010173ef657a0ecf2db35888f3b890cf:144877fc1cc4029711691e3dc002d262 +Young Rock S01E01 - Mantendo o Personagem +0100ddf2bc8a779a1f09c368c7eca060:e3fb2ac8d1d1fa1e11e0218593f93450 +01056abbb53e5805462797aeca5568bf:35edf555765b230b1e9d7a9658d0933e +0102c666058817aa543b63d1adfa904e:d1daa5eb5d51893aa6f9e9080800b136 +010193bbf7085e54cb9d573392abd865:9516e1c184cc999e64146e097b9bcab3 +Young Rock S01E02 - Na Estrada Novamente +010054d60dcaeb448e0c5b3b49059a46:1f7c10dc5271f1a9c46c778c7657fbe9 +0105af2e162b824e925309c3260b5ada:0c17e76e4df2153bb39f004c28b1d5ad +0102395832e1996319c8e03e3f63f0e7:261dc43e10427363a792e29ea72e47f2 +01015b51902146490c49e0faa2c8f5e1:fc53613bec2f69a2f4863665ff4b741e +Young Rock S01E03 - Para a Frente Juntos +01009d1877cfecb8779ef756af54f261:41ddba734a634ea37d9b892ae35aef3f +01056412baea7fcd45997fdfc8771469:965d3890435d8c40e557ab5d8d49f27d +01025e81393bb17ff3a3489fc50c7c46:053031f07db98f55187671c7cc16dfaf +010115fd9ecf07c2e3a285dd33bca839:276eec8ce47e55586df5c781de9848e6 +Young Rock S01E04 - Cuide da Mente +010007a3b2ebc6199cf73b41268aeb9a:5172f924aeb1877d90b6278349122a4c +0105fc4abfd949f28fe016e9ae7d4705:771c1eccd020d940e2cb84075d242f8e +01020d726386ce862f39738cdf54f6e0:5bcac6d1c1d5ae01573729c2f808cc42 +0101022b2d8f78a467289d744dd353b9:1ba2b246cda4daf91e22a0939f4a834c +Young Rock S01E05 - Nao Parta Meu Coracao +01008831029c6986c24f628cf885bdd4:a4d32c771e739fcb6d17e180d5c68080 +01058e6f1a11719c9aff718b10f72908:666b8a60b9651836c7d4787e9076e6cf +01028536b69cd182d50a48750c1de6a8:6e63166da194d1136a4d70ed05606b41 +010161db8c5f7cefb1e577cc203165f5:3cbde197496a08230b8b5600cceb40ea +Young Rock S01E06 - Meu Dia com Andre +01006934cd9d4691f1dac14d1588efed:d89cfd9560fdb02dfee41b1aa5623bae +0105681340b87f63875ed5afd9a0e458:ea4579a55ec782bf66e1727cb191ac86 +010240c33b9dd9053f77c44abc27b5d6:6238bc382509068fdc0833420cb34837 +01011e8893da248109987ac7c91b7b7d:eb07db5dde37d5653b6bf738f84c5a34 +Young Rock S01E07 - Johnson & Hopkins +01001147f7ddd528c77cd170638d587d:42afcdaaf53b96d9dd1e4bd2b04b1e1e +0105e3c0aec6474fca13d6802af9da30:462347dbfc08a64b4d92a8cff5f55e1f +0102e7fb80d82e6cfbf2120b2d4eba31:2d7c93942bcc0b948046bbab3674473b +0101b04ea21a8f9bfddb60d36d2b13b9:36a721f0dbd971913fe1b3d9125d5645 +Young Rock S01E08 - Meu Amor So Bebe do Bom +01000a6d4324864de7e290de76c1c067:7f9f618043e3e6cfb03716366f1701ea +01051631670ae66add688e3d06ecf1ed:19833d7a112bda41f308f830138386de +0102dfb48a5c39b890a78273f4f38d89:7e7788797f6085409b73cba34db9beff +0101f7462056c8453965361c27512236:ab27725060282d191763446df2bf735d +Young Rock S01E09 - Uma Moca Chamada Star Search +0100bec4cca40cd831dea8f8562543bf:cdb4be6be45890a2eaaed1b8b65d1fac +01053e113d278ce468b8a73d68aba62a:134a0f7242f9b334c036c2c4e4a01e55 +01021b615ea10a68711529293255eeae:8f4358e37f160d291e51e8498ca0b3aa +010121855d16b95c99be619cb4191a69:a23ebe421ef522f7fcef557989e17b7c +Young Rock S01E10 - Bom X Otimo +01003074cab5dba7a5d6f9941adadd22:56ca1b6eb1c12d806082d6e7926d26ea +0105830951b04527ec8addf62adecc58:08fe9afc6df88a9589b5affeef461bf1 +0102d84a6e425c9d9043f9ec3132fdcf:3ecad14b703a0e79204dc046b2cffb4c +0101cd0beb4e6daf0046655564d3758d:98f0b583564e05ab1d4567a1f836d248 +Young Rock S01E11 - Dia da Eleicao +01000b3f384a6c956873de8c0c009660:b21b2586f7ae3c90945d776387c52e10 +010546ef4e8ffb90ec97cf5bd64645e0:4f440e174ef3bbc21e39cd2de0201563 +01026dcd7e1fe32bdf8444e1fa3eba59:d96172bb34c4b8b7ec95a52fc4978617 +0101b932547501a932fac39db1295730:640e397bcf3be27ee2b8cee05d7e3790 +Trem Infinito S01E01 - O Vagao Quadriculado +0100a77dce692561487a5005f7575347:57b156f46b561b4def470eee03b13c5e +0105547b931ba9da5d9ab6a8fdbfd889:3a6748fc91f05df721106b23d25e0329 +010202a90117e06472004dbc8a80103a:14c7e92589036df2dd44ca95e2519c60 +0101ec922d17a4ad84ca1bb7799f2ae5:9faf3568d138ce4432da19a09b6c86f1 +Trem Infinito S01E02 - O Vagao Da Praia +0100f31da89cc5012fabe99622f791b6:e272cf736d9d15d5ef5920052dad7283 +0105bfc3f6d641726800af1885de4788:d2738c8b11bd0600cb7f09914d2b6ace +0102bff9aa6d56cb536145488ce8f50f:73c53f333ef7b588953e5bcfae1320ae +010117c7b84f8219057dcfd54a9a1225:bb6a7315adc4904daf7acbef2aa22e81 +Trem Infinito S01E03 - O Vagao Dos Corgis +010017051096026c8b6f5392c21348fa:0ae10a3c856d925d0afe0cb2e695ad14 +0105e8680f697fa79cd9cdd11041fb54:577235ff95e21fcfe54943a82488b0f2 +01025dd8b75ebbb2cc7d8607d8f37391:17630cb656ae82646fb99df8a4ef1ebf +01016a60ee89ff2797a08a492ddb701c:b25106fc8cd73268c7eeddf7fbd4983e +Trem Infinito S01E04 - O Vagao De Cristal +0100353052bae99ce777975a7ed8d154:50d3a6169f5c6bcf08771a805360dd83 +0105cf66d19e66efd2fc13179d826309:ff5d674d1af75240bfffe08b7a75e7dc +010225fdbcac74d1cc0a00b735a5eaff:e03454aea5f613b846f4f6ce7b74c0ba +0101c3c577164f0ff324ff45abe9d361:2c31beb7f600b2a92bedd789db906833 +Trem Infinito S01E05 - O Vagao Da Gata +01008a2a43298ea495606c95ecbcf051:269c70959604d6732ab9015e673a6394 +010525204496216c89154119f1a296fa:cb9983c0480616b7cbbe935cb8d0e6e5 +0102deaa3e89a1e494f8337de127c30f:86feec4fe39392186d8b57c63d8fc57f +01014b794bb65176fc3653ca830e74e6:3467d4bdb231cf3aaab4543e3b48e1f8 +Trem Infinito S01E06 - O Vagao Inacabado +01000226c535f9b8b32102d7d385508a:fbaf4aba3cb5f83f5426fdc62cbbe333 +01056221bc8de2e19d3884aa8a910f11:9d20db6955d7eec5712f013e8d412e1f +0102caa64ecb830002e7387bb2e62849:d5a5c77e2d547f3b0b993db3c079e899 +01016197bd7508424e470fc783490f25:5ceabff47db742c0f93d7946657f5787 +Trem Infinito S01E07 - O Vagao Cromado +01005be6bdcd2f9854ae56e1a089d3ce:9ef241bd6b028b55e43da5690c92a34b +010543c09f148951a86d4e6ed8af6ddd:fee9fd1c396e9e5d95c0394d308460d8 +01025b588cb1c2ca1ba60b398fc88b32:5d36ea74b93f1f56268176c4553653cc +01016c002ff53ca43c3261086abbc1c1:645a42f7debd2c214ca7b7a49f7410bf +Trem Infinito S01E08 - O Vagao Da Piscina De Bolinha +01003b7bcc03d8b69e5baad3031c70ff:9228dd4a52fe088cc49659a09ce0d4b6 +01055eceb5e2d3710422ccc34c312e90:a4563d84c953d524ce3518ce30e73545 +010264903a38e874b827e568ec124651:104d1fbe42ae1ff2aa1d04c00da9c997 +01019456ff260170b4f015ea9da9d784:58a2deb06f144ed9811eabb7a653209d +Trem Infinito S01E09 - O Vagao Do Passado +0100db06533c68827d006f368f208736:2ec9b461f67ae4dc3c8c46cda7b20f4e +0105fe417480ddbb404a2d95980880c6:06d1048a8d1b886d60adbae283d84cc2 +0102b6dc723d382dc21d1cd12a8ba60e:eed57ae5479ab01ba9c7e35d52a2814b +0101d5defb3393e8abc0b0362e857946:1696c981048bec66da4b0d371b56b580 +Trem Infinito S01E10 - O Motor +01006a7ac2b6dea3b0bb3974524e1f0a:1ce438bc6c63e3abccf414709a6f90f5 +0105e4d74df83d7bf31b294eb40ee8d5:b46f4c476d627b29ce811b45970ba158 +010259058d0738265a135144a4294975:86c5a4bdac322a1de44245f72e5f5676 +010141c5681e02b71a975a23fe6d7987:e18c666c0803946c2b048a6f86574e28 +Trem Infinito S02E01 - O Vagao Do Mercado Paralelo +01002dfa703eeaa6cb5e5ae5093d94c7:c2b3954c3fc65692d89d961cb42bbf12 +0105a1165f4c0124fb76e121d2144638:2d42412c29fad222d366166298eb007f +01029c9174ed36d7b6b72c389a3644a5:4d8769cf9e6a459701513d1945fb2e5b +01011dcd22e68d659c2d23f276096fd2:21865df21586af74d729b0483aecb657 +Trem Infinito S02E02 - O Vagao Da Arvore Genealogica +01002d58928076e7dea3900272147e79:0e39a701d95a378c9de92e7337463ebf +010535472acdf450593a023515944584:865210e56cd0908059ea248a738112d6 +010262b79da0386cb678214505bb6873:d58bd63f5cf80cdd745abe185aea4b0d +010102183d0dfbc01afa52892a0550f8:cdd3250250e140922c9299da953d5907 +Trem Infinito S02E03 - O Vagao Do Mapa +01004aeaaeb8bce805287772a47edb12:efdb877fbe4db39c5dbb4a51654794ad +0105a9b3efb90ea678a89aa75f34175f:78e807073c54fa54730d23d58c170bba +0102c8f406595c39afe8299f09c1b12c:5f10994e8555257bd508dfe9f92ce5c9 +01011a42102c2e0c31a93ab911798c59:39e05b417eca455c93f070908948b3f0 +Trem Infinito S02E04 - O Vagao Do Sapo +010021d75117232c1531b24c18c3122d:61c0b08791d579d6f097d149c1b0f98b +0105c6fe22256997a0158b97e2edf65f:f572dc2f62f0b909c48fb35a5decdfd8 +0102bc953b2b207b48682c6a86b9cf69:2017e4aa3045f4e49917d73dea36040f +0101e4542963aee71ba634c47e4e3ad2:d0ac221842b618756c19336a65c70bdb +Trem Infinito S02E05 - O Vagao Do Parasita +0100c5fa4542136889e6ced9d66e111a:4481fb0cb48a9d1b55d943c0616c21ba +010501421ebf739079fba48102efd643:625fee92af72edbf0e8e30db0c647318 +010282fa32ba05153dd193d313257690:d7dc5686161142a65776d281db2ab489 +0101630bb5df9827a68c5f937120514e:96094bf48358db542bcfcb36fa49646a +Trem Infinito S02E06 - O Vagao Da Gata Da Sorte +0100777b4c0c4c60cdf58293db9ff60f:aca59bdbaeb29a3a9e026cbe91de5d66 +01053823d2474187ce998a4649b98c6a:9b3c97891ec0562429a408525e908e3f +010283f3d55bdcdb99a066c62187f93b:be20d5d05bda12aefc7ad462db603098 +0101f39695f770603e7cd7233e718fff:305073711a17feccc2c3e2675fdead2b +Trem Infinito S02E07 - O Vagao Do Shopping +0100eebb18bda31f550616a663d70411:9a88c41b1e6154e419c71db608a04e53 +010565dc99b5a55c94af10a2f658d966:db26db5151d6c72c514038f37593503d +0102f0656816f9d96ca7d9cf561b7720:8389365e462ab1e76bbac4349b57324f +010186d41936f14c983a1a5781fbfe4e:14cc38f2c63f8cc104cfa64bd887deae +Trem Infinito S02E08 - O Terreno Baldio +01002cbbb07c5f0a59bb03fb1b5f2634:f2ec5c57801b81805a949b943e9f899e +01056718328b80acc408b3910e4c632d:79ffc596e2f2c33add5dff53f57c7a8d +01026c0d04247377689ec90fc46ba9cd:c307b0503666cc2b7e6374d90df9fd92 +0101896f0d5c7e8bf8240b9fca4aee8b:fa2d0fe28aadaea36774389d95a47e1e +Trem Infinito S02E09 - O Vagao Da Fita +0100ee249145422c84529aa22c15a851:789cb1df47813973702d683a0ceef6eb +0105f6ba2fbe04c0dfc5e679b8fa9ce7:0727567596ee8c592e620c6404bf1bbf +0102ea29eee03937b5a41acb01ed5f85:1a4ec821f2c6498ef9c2825eff5b01a2 +010184aa9fe7bb861e9db755d1a43dea:a0822e2bd15a90f6b7bdbdd18777ddd4 +Trem Infinito S02E10 - O Vagao Do Numero +01008dcd958a85c59a205f8447b27b51:4551fc782cb6fdc2b99786c157c8ec0d +01056532383cc4e8ffa067475a777c31:3b233156f07b72c99b2df3be3a96ac38 +010248b15295de961488e53707f8032e:42cf3ac0207b9bfff3f604a55411d6ac +01017a526e4dbeef40ef0d0e68ba29db:4deae4f4aa8300ce26e7f1cda2c016f6 +Fahrenheit 451 (2018) +0100189566132b2da3d324d04e84d757:1f38f71f9edbe5d0242c6205d64dd4c8 +0105067bd0dc8bd67598b206e0ac78c6:27a97050e2c22de05d61791d6d022943 +010277d957a83acb82845914bd603bf5:28aa523197bb9c44c989bd285d2b623e +0101c3a540d39664f59cc44006be6fab:8fe6dcdbb11158344f66acccf178892b +Roswell New Mexico S01E01 - Pilot +010009f9459677f87e91d91dfec31221:7a6a0b3f555dbfbb14690454ae1d6dda +0105a7bdb64bc304a4c5c0e4220c1c85:b3bf946609894e3143164b4f29a3ac2c +0102c99421c06470517caa1b2d8500b8:8841f7ec433dc436cb83b1cabbf94cf4 +010105371ec1c248d4f7347a92327330:5d3b50f6537f990e4ad15064fb042989 +Roswell New Mexico S01E02 - So Much For The Afterglow +0100c202620f26048584caa2790c67f6:99231c27dbc6958cbce31243de701a51 +0105091941943a3576a829da07d60f54:eac89d7b0edc8096fbf70f73999b4600 +010295b284ed83de4b5db7d7e767808d:f2094c7f0aa86b30206e4731be4b4032 +0101c6d44427b80c5feb165286a2f384:7fc62481b1e0977b64824c5aa826cd7b +Roswell New Mexico S01E03 - Tearin Up My Heart +0100732c14dcac70132458695a826dc7:61a36d4fcfd520143264f00853e9d066 +01050520af2782e19014630b1af9dfd7:4e824715a431bf47a0dfcd0f8413cde0 +01024fbdbdc97ffe5b38635540abfaa3:c800360caca6e40bd5ab4b4bf6aa2251 +0101d5c7a1d21b0f94d853a80b47ce19:b16dba1bd2df03cef6677b3445eafaac +Roswell New Mexico S01E04 - Where Have All The Cowboys Gone +0100cee62e1961f807c4795c926657a0:f0ad552ea5081fe544e21ee39c895d7d +010510a3efc687d07301794678dd3b8a:f719c0f1f1d6728f15f82b710e8dd188 +01029279f9c0c0f142c8b3d8129c66d8:b33c26bd3c5fa2c50c513dfe9a42a852 +01015f70674d18165d8244f996123849:67936765750aa5b0855611de7d360e9c +Roswell New Mexico S01E05 - Dont Speak +01009721246d2a52b6160b6f9e42fdb4:28aca89cafc55bd9ee739069b6a4b1d2 +01053286f3c8c35291605cdc2710e153:713c08c3b78bbc39dac51c0dae89a5b9 +0102d51ff0130b48b9e065e00db828dd:0872228085548c2f9a293d5ff47f6c73 +0101a1c965f2662ebc1f399a7bb5b333:c7bd6b01746b9579f6a552a8e5dd4f8a +Batwoman S01E01 - Pilot +0100390773530bf551cfae7f6c8ee52d:186ea907c5c0de6038cc742c9fcd3a44 +01052bbc9724dc441ce3d984bf56432a:47755fddfe9f998aa284bc888a15dd3c +0102ccf2dae2f4d80f8816fc3beff750:132f2f07be39786b01f4df0fe69863bc +010127ffab8a64c8ffb3960388dbb505:894aab24f219a9abcd0911c912aeedd3 +Batwoman S01E02 - The Rabbit Hole +0100804fbc7b6f49261c9a508d7baef8:d8026406cc8cb742ba811a10dc14435d +0105cfb4c89bb5e75c0d1572dd5f4aab:1219ec71cbdc695cbaf7ea6192bc6c5b +0102738070d60901250e0c4f534597a8:a8bbf3dde2a424b7a495c37868bf0d82 +0101f11b648c20a22985fdfb237184da:987e687746d81dc8f1e8fd533976c237 +Batwoman S01E03 - Down Down Down +01001ef87f6933c2526d88da2066ceea:ff92bf6e210dac502a36f69f561bc339 +01051581acf80d10802b57e01c13334a:0e54706121b12aeaf7da634befbfc20f +0102002b3307ed4720978bfa95217c59:bdd60deb40bc130141d24693b7275f7b +0101977f3a31d0a594728b47637d994b:4545d72c7fd25d725f8c804925dea370 +Batwoman S01E04 - Who Are You +0100249e976bca0d47f4355599227440:eacd7c594dd1e14439b4a2a316b9b3b8 +010532d3833836b5c8c22fdc92aa744b:d4ac953baff4587470b97e1db1b477e3 +01024b61a179615d2a98cd272f9fc7f3:333a5197f1ccc33d277e89d90919515a +01013e95d9feaa9e3d57e0a1339e003e:f9c89721192c53b48a13ebbe953c8943 +Batwoman S01E05 - Mine Is a Long and Sad Tale +0100a0e4aebe8d034cbbf28f2a8179f9:0fb674861e64570ebc6eec9ce32280cf +0105f44247ffa9b64002eff95af28c73:53bf76187a190337ad17767a4e698db2 +0102bcb91c6cff38cab1e465d9630ccb:2354d918be9e715906f12dad6903123b +01017a016043b17c55fa43b2c5c18f3e:2968f774c80e64a3c13bea2056e75f51 +Los Nobles Quando os Ricos Quebram a Cara (2013) +01000de616bcbccf4eb5600fb90ac44e:5d950c00ddc4c20b3e00d95e0e3a5079 +010583bbff43327262f4f2eb6e833c64:8ddf8340464b7a21c38383f4bf11ab74 +01023ec68c3630fd49a3dfe4603f9b45:f9da1c37e95e0977fcbb3b050d91cb1b +01016ba7aab5f1f5e7dbefb6bbc5f50f:2eadf2c51e1fd012fab77c6ade66ea02 +Academia de Vampiros O Beijo das Sombras (2014) +0100bbde78dacd6a020c71194a37ab69:28b79e31b93ffb2169b2df43b7273936 +01058880ae67aded89986d9b3fd791b8:4c290e959d61881e870d43be24114ff6 +01027cfd8a17e5ce73838197c9ade68d:11216a23f9eeb2656552a46a5f075830 +01018037f262cb1a342786b186debfe8:010353bfefc7f4137c52ae145c2a210a +Constantine (2005) +0100a28fc8e0342fa86e9069c71d38cf:c56618c167dab5c70394266af0fe1620 +0105cbc8989234e5aaff9d526152b0a1:bda3bb5e4f5258198dc81335d5f9cda2 +01019ad2190d5dc33d03abac524a18cd:7645205622d965e678cc215b7e95f89d +V De Vinganca (2006) +010096cb1ee693ccb48bd8bc490e9751:b96c4609105c2cef2f905a41906f1877 +0105520057217819b40d1936bc713ebf:76587f94092cdbde301ba0ebd81d5848 +01010666fe412705fa771636f89c0fc8:2dafcf73e2c62eeacd0f6df443d40327 +Roswell New Mexico S01E01 - Pilot +010009f9459677f87e91d91dfec31221:7a6a0b3f555dbfbb14690454ae1d6dda +0105a7bdb64bc304a4c5c0e4220c1c85:b3bf946609894e3143164b4f29a3ac2c +0102c99421c06470517caa1b2d8500b8:8841f7ec433dc436cb83b1cabbf94cf4 +010105371ec1c248d4f7347a92327330:5d3b50f6537f990e4ad15064fb042989 +Roswell New Mexico S01E06 - Smells Like Teen Spirit +010034443f4e7bc81b5a406b3a4b5163:926f97e2d93584efa27041fec0f549d1 +0105a746eaf16eaab8df5c4308a5d63b:0412fa441d6f1cd44ca92ea014f07a11 +0102323a46e8b950b01b534a43a3fbc5:fc8d9449d0fa3bb19a952443f6ce70fd +0101379f3ee6ceffbf11323803a81176:cca7ead90ee511ef0e38c2b59017804a +Roswell New Mexico S01E07 - I Saw The Sign +01007d4a6ea40d8c5be14b4cb37fa60a:94e005d1b0f02254f18cc8b3f6dcdb69 +0105b60a05f571c44553320aecbbae19:59ec4a87cba2fc2df042486c4e1501c9 +01020524d0e5a38ef18932e46d365969:eb71d5e0d4ce5667bc795e8e819e1330 +0101b918f70f4b6faa9f2f398d22f00d:e6e8bead456741b747e720bd57b9d6da +Roswell New Mexico S01E08 - Barely Breathing +0100782e5f39937f061d233438013591:9a65b3b177ba184180068511fa234174 +010564ea37554c7432227b31d2b8e405:04ef7d92f2c7c0fa3020f5763827e2b7 +0102002f74ffa263d7c9fc24e9774896:5fa1647d6dab73d65508b9bca11726be +010161303ce5b78c279f02846f2f4805:eeccb06b757604d50ad7c7c7fa58b4f8 +Roswell New Mexico S01E09 - Songs About Texas +0100b9738d03173c982180911b0b8950:387282e8cccd4955baa5d28166e84065 +0105612a51be75d205e5081c26a31898:77134361436e3d6759e856d249d6c173 +0102664f8ef4015db568a7dade8b9957:3b934aafcb07bc45ba1c6539f43e80fd +010103e49729c908b66086f1482ed1d2:1b72c8fda103607a20e8bf033588bbc8 +Roswell New Mexico S01E10 - I Dont Want To Miss A Thing +0100a2e059ca2ad0c9e97b3434ecaba0:aaa4a9285197d54b3889eea9bec4eb39 +01055c61e9b0afe4c4acb6e57feef77b:f8468d15eb82088ad0a927eaf19b1f2c +0102e5094f19e36fbdf79ebdd064b905:0e3b9badc03ec540c63e894c46cbc7ab +01019f2d0cae2be25cc2e7aa3a6b7c30:b5e0b5d687677a8706cd25ddcdab8840 +Roswell New Mexico S01E11 - Champagne Supernova +01005b94358a875f8d6617779bec40ac:ad37e726fac17480cb4a85a34046c752 +010523fb3e0e2bce86427b3a39738f96:4a49ad96a833ddb32d6ce863ea5e3300 +01029b07ecbcff2ffdd601a7f21e0594:5e020da6eb0b3787292e4fca71b638da +01011dbaddf66721ec26e83de8fc5a9a:dceebce554e274dd2f8f3db354e37997 +Roswell New Mexico S01E12 - Creep +0100cac8353d3c6787e054c2b488f2af:ba47001f333895161ecb15710228ec48 +0105800191f10bf4804198709e825e78:9992fb4023ac7c3232fea229eadb7247 +01029c8b7bbccc661a00965e5c3f9825:3bf0049865751ea48ade9b3d12512f2e +0101516d7b235ddcd0f6f09df2c9386f:fd7e04d4a74540213b98a072c671a4c1 +Roswell New Mexico S01E13 - Recovering the Satellites +0100f2351021ae7dd608b4cb49d89174:c8de71653719fb128a11f55384bcfc55 +010593faace129e34978202ed76f40a2:056130c72c5cbfa8861d6429c8e9ad3b +010245a904a8da7ae2e0dcaca3eada0e:867df482bc59b05edc184d7dc8230e64 +0101a5cfc82dee23ccb5f755690d02e7:37b8160904d675fed201ce6f28d9e58a +Roswell New Mexico S02E01 - Stay I Missed You +010055e93ba1d37f640ff15831420cb4:f1ffba9635c9ba8736e74d11664f3861 +010583d603a8ecc72c4ae5cd0b8df6d3:e8c9da174ea524f1d21e79170064c23c +010282ca77c5c6e9706850c5f9c4a935:33f5f604a36af1340a6c37ae0039c39a +0101042ea1a5c2ff8a01b865d468e29e:3a17fb9ef920f2dcb97c55791ba2ff54 +Roswell New Mexico S02E02 - Ladies and Gentlemen We Are Floating in Space +010000ac254ee1626d6784b34792b67e:5adecbefeb06305e2159d0227519b875 +0105bfa934bbf4977bce5ebb3e06e06c:1c693045499ace70660465480483f8a6 +010253d663e0b7bf99a9aa36c9618ab5:342709a8d38f5d465261b629df184aef +0101686551fb96dc2f3d85ef609c53c5:1edec050dfceaa348ad8b1086a5a8f18 +Roswell New Mexico S02E03 - Good Mother +01001d6f712eeae283179ab38e5603ab:783250752649649564daa266fed62211 +0105402438b79202cbb0684f3927c5b1:46be973eb922160f7bc3dffd58e7ffb7 +01023fe7621a1cd99b3630f07d98e187:ea65b608358103e9488fa1d031ad5319 +0101802d9b5715dd523dd73fea64292c:5043808db6b3dc251c7b43696a93065a +Roswell New Mexico S02E04 - What If God Was One Of Us +01009751d7168cde6f9e3dc3cadafe23:32f5a338462392131a89e163150e96ad +0105832d4f2d2d08211abeb798aa60a7:d287ef2a28616a9e03b176e8e5c9ffcd +01023650f1ea9b8505d7b25ff9ddd9ba:fa2ec0df5ea493e982b024e839a14d2f +0101a58a6c0cc0fe1d8b9eb79c75c84d:034775c84ef646caf593547bbd027160 +Roswell New Mexico S02E05 - Ill Stand By You +01003c170610acdc145705925c75dc8b:4e03ed142b3d3afd6ede3e8222469de0 +01053fa90075e56507d2f08d07418453:43a859f3a0c609909e3ef97836f6a089 +010247764dfd8b01bd94d35996268f2e:cef69b6a979225da5db5a6a9b004fa1c +01018a1da07eb10957df4f08badb212e:5f61c40d86ca117d1c000779c5fce26b +Roswell New Mexico S02E06 - Sex and Candy +0100c9859aa41447c281fbee144eb3ca:40b2ad310838bd37717d1dc0d6d2eca3 +010525ba85b6a8424e336f0be886c611:82f7e7b28558bed9fc40f9c8511a1e10 +0102d639e7b1f52df71d4f65825a7de6:8c20b5ff3ed796731ee921cd97542f08 +010182bce7a49e69c13b86cf9150d5ea:584a366522669f1d8e7659b6d6029fd3 +Roswell New Mexico S02E07 - Como La Flor +01001b413d2ccb50474f0d880745f3c4:d292e5f949d34d90fdb945ea00740098 +010529a8174856d7cad1a986209bb5c7:65b41e85079359df44d5d6ff718fddd4 +0102618670e1aa05e4c9c46b0d5f3fd9:43a21bcbd6f5eec2671c1d0fbadadeb5 +010157d4d2eb11cb63f7213e34f063ed:a5c9fe3cc669f3f5859101c2f1bf3307 +Roswell New Mexico S02E08 - Say It Aint So +0100bedd87f02e11a747c43ef356b72e:2503e4ab728e5cde26857e76d00365df +0105d127239b734a806f233384c6c9df:8f85088049d0f6bfa1f5198b37366136 +01027b32a815863e1e6fa75716275f9d:6a3c68b3128041e1ac1ebb755421c8d3 +010123fb1757ec91b45ed56957113074:6e5ced55be74e7e033d88e4a3a7534c6 +Roswell New Mexico S02E09 - The Diner +0100e1f297458d05a76eaed3cf707eb7:1ca521fa6dfb6fe1cb60f0747a37affe +0105ff7a4f71564cbc06f14dc1eb8449:e5a065a6c12461e2b07a6e9203946d60 +01027f165b3eea634c9133e0c9e0b393:277b885c14ea631fd257a9a411f2d66b +0101ad07886f6daa9b75e5529f2959bc:1857d8bcbeebc47fc205c8b93d08a404 +Roswell New Mexico S02E10 - American Woman +0100d36028910f5f9b24a643e1698fcd:1088bd62e153f23d8043d24a3509380a +0105c9dc1361ab8600255fba8af57296:68be26b8fc07a78e63a7d3debf810c64 +0102427c557dfcc23459d547a8a44d73:65c3e1667bb8508319e42af3851e6684 +0101b4daf13d1e085154921bc5337d59:ecfb22dbd453fe88b10d2eb55a170e6c +Roswell New Mexico S02E11 - Linger +010016090cfe549f0643884b39e3eee5:8f9ae671bf9386e77acbe911280cfc23 +01056e0953089b990bc39acca0232bcf:c3d86b7ca874e710444dec12d3cc5859 +0102bbe47be3edb9b89e21817f31a3a9:80e294ade70dfacf27276ea5dfdd902f +0101dd3d866e9543a4f8f85db766310b:c385ede674dc33e30ec640745ec9f843 +Roswell New Mexico S02E12 - Crash Into Me +0100012a101dc5708561a136b086d145:7ce8957327b017415fa40673deb088ee +01052ec32bc339314664e7b99ed2f5be:1bb4e43ccda18143ade33be872b4d311 +010251ac1b67c50cb4d7c95e083a09f7:2a893ffba30e18bb9327eb2977a1d3dc +01018cc4c476b5aa25290c03480933bc:372ede34c3519699f338c27a7088b19a +Roswell New Mexico S02E13 - Mr. Jones +0100e12f3fe7b6a545324f33d951caed:1afb8cb18d7874b3acece3c6c07df860 +0105d249d96c6fab93d1c3e313effcf0:459830b4933df00de270b92c5a883bdc +01024b21ea6e6ea711ace86d1a55e4f1:97977e8d89f138055aef5ccf86d09bf6 +01018e618a3607c17602f97fe730b053:13f6347051f503712b89bf4737f73532 +Batwoman S01E06 - Ill Be Judge Ill Be Jury +0100035d436fd3a38a4c67f52573795a:1070f9f940999f6668bf84ecd35bc25c +01051df4f69aa25f62357fa6ab29998a:564637292b4cb57a8ead1b82cb477962 +01021af52e84005c77165fa8f5d5dba2:1d20fa6ac6811bd928a63e7c61fd532f +01016d45285579f0b6e18f99c3cfe39c:32e8db3b1cf4c6e055efd19c089d7c1d +Batwoman S01E07 - Tell Me the Truth +0100d25d1d3f643e1375ba89566b6278:5d5fac6df13d4971d02df9abcefe7643 +0105e8ed57956430dbdf6c1e81cc294b:6ec6a00938e5b5e636bbb3539cb272ce +01027f276f8031e04ab0b4ec6428bb41:853f4d05533edbd3cd68a5e5895e2919 +01013a9c3e68630d14e4229f8390e780:41fc467d248521addd83c91f53694253 +Batwoman S01E08 - A Mad TeaParty +01009c66f4d085d088a2ab296a77e236:69d15a1be1d1af6ed8b59f9e9b070d2d +0105c96898605d53d193e3ccea19eb2c:ae7e989db4d7d3557b7b809faab52e47 +01029dfd6f8068ca2d5b9e59ef221d45:5f9c617ccc9b998c8286c8ce1301c84a +010134898d8d9e2ac6628fde4539e65a:3ffac8954cf5ceadfcb3b876eac90d6d +Batwoman S01E09 - Crisis on Infinite Earths Part Two +01004886cd5197e5cc90675b5d28b9fe:46ded550117402ce124db576452bb76c +01058f4e3f078e386b61f565a967b07a:44b226f2f5b8d473b9ff73674e1d3f57 +01029ab729da9b7830eadc016b508f13:293dd873bc8bae539982c502a6ba7ce7 +01011c4340d1e63b831278f3a4d2bba0:078c67fdee03973ec6a990dbcf7cc0fb +Batwoman S01E10 - How Queer Everything Is Today +01000a64cb11f470025f7861dfea245a:6d200458ea6e5c76d745cd5f0e829362 +01055d2a5362c6782c7ffd323486a09a:1e9b76a5767be9a3e0f2c80a40cfea20 +0102d86a5d895f8f2ba83d37b79a2091:1782f785676eeecacff742ed2b7f208b +01016c2da7936118823143f0326ecd02:fd262e5c19d05ee5b23b4e82069dfd4e +Batwoman S01E11 - An UnBirthday Present +01002ab23a6dc8570cee971720a9120d:22a4d9f94995210a6c91c200f042882c +010578fadc01321fc91ed35208ca320b:db1d7713b323aea2ebd251679a82f42a +010257259922aaa29c1a1b716ac3b639:213f968b7422156f264ee58ff7ece5a7 +010180a020a440a1bfd411119a29b287:f2d98d47a554dc590372c21c6104b0fa +Batwoman S01E12 - Take Your Choice +01000e9a1e5204c71cc677de16fd933f:cdb3b3ba7db9084fb878d90821d30f64 +01053f10dcb1eaad286c6532b422ddf8:57a5a7fd74fe851b20a4050f179bae67 +01025d50b1578f95e994b19582efd860:202007c453cae0148fa14ac0095b3af6 +01015d239cb82d487d3e5636bbfad079:629438e17c8671607fee73e8ede4ab22 +Batwoman S01E13 - Drink Me +0100884863936f6672128402a9acd8c5:8a453eeb7af6d8d51a8b7068ccfe6641 +010581ee86847d2e3c818d47fe1b30fe:7c052539028c5b6a74ceb06aa1f8ebb4 +01025805daff8af753dd39dc68ec1815:a1f0b35fbc5719243274d6e706e176f6 +0101b8adc416982e92eacee5a4b18f1f:37ef15b8d35efd9228905a7070bad093 +Batwoman S01E14 - Grinning From Ear to Ear +010008d0e901958c2082ff2ce6088099:86b5d84862abe0a0a3f572c5c46cc5a2 +01057f104e7198972975ba84b6b541b8:ddbfa02956875473a716475c571dae5d +010201e7e0ea9ed068fb3e0453184e35:37e23fb6384249d0697aae659ef0ed90 +0101cbf0440eb922dcf5fcccf0570767:4d47c2da04240526c5b25a196626c5c3 +Batwoman S01E15 - Off With Her Head +0100eea2f5e0a428730c95806f7249cd:e2e6db528dafac89b3e7962fab63908b +010535f25a3256ab232c5ddbeb81f012:41c2cb9451c329001c0a18b80c43d298 +010229edd2c096e619fa7f927caf97cf:ae3653fa959da30955ea6f8c83c403cc +0101e4f72b01eb1cb4715784f07ceece:2a76eb4a2c4236dcc98837f04066842a +Batwoman S01E16 - Through the LookingGlass +010027922226ebb00a92105c085f4c4d:5c05d0608c14e86b88da68892b427706 +0105544adf7cf66b8ad8e9fe8a702047:1726c1ae555e855b157cf0157881f499 +0102719b3c51b0326d5c30f5a8946416:ec9b8f2d4eebc2673a496cad0afd5439 +0101d6eb53f4e0347945fba8c9130d2d:a78547c8c6cb47f035cee5d56e00be63 +Batwoman S01E17 - A Narrow Escape +0100278fd6667cec4d1a631cdf796384:948d90a2e4dde44c954485f5b5ea80dc +0105bd0d61743eba7c3cf5b04fb7bcdc:2a8b0e496aa7ad94a3a4d1bdc98ab35f +0102830aad98fd995bbb9681f3a1f7d7:a8469b7875bd80a1ee7aef95279ede4b +0101d894d56bca027d036d1164af4126:062fb193e464618a7d7e6a4bd7080d83 +Batwoman S01E18 - If You Believe In Me Ill Believe In You +0100e7d1cc7d2f4fbc326ab64732c614:5dccf502aaa33bc9207e686df509f9ba +01053d5a7f6bcca4ec10ea3a7b98e10f:ef28d2f6c0e14331fe618ce0e800655b +0102fa83cf3a4825ba712cce81bacc41:5920b927611a8ed73ac62c7d7e5ba62a +0101c622ab93565ca301835ec0f2511b:7b0b5c4004620f45ab0f042763696e3c +Batwoman S01E19 - A Secret Kept From All the Rest +01009499add899323e56c93a3b6cacf4:b1adf953667c7f87722ef95002b3a7e7 +0105295e8784d92b43eba52bebce3925:2d6582ec207ef31d1449ac56eaba83bb +01029b257bd6d060d1f3a3e3de3aefe6:be4e0463eaa8ca6422b05290d77b6e53 +0101ea890c84392a4e54245cedab0c48:7ea76ac53dd68d01687e25c3f995659c +Batwoman S01E20 - O Mouse +01007f429a8a95178d08da9f0c2dee9b:5bf08eeb0fd96f063090f1ea1e2cd456 +0105eb376ad767a419ce1654a0a49e25:e196f8a0561331d57c6401877e10bcfd +0102e2eef8c3d3de5ba578df060159f3:bd0147fd33459dde65e0802a21271be1 +0101215a2e0e22edb5c1cdbedbcfde23:28e09a6d987a52ec5df8dd3bbfd786f3 +Batwoman S02E01 - Whatever Happened to Kate Kane +0100195fc40e55337ebe9e2c5c9f6b18:fdaecc6a251271b6421bed72c78b7d55 +0105c89526a76a69a36d8ec66a1184bd:a62bc8fedf13935496e284f5778a497d +0102f7735eef546b3ba225515caa1ed3:1a4f9e4054189570cbf99aa7762e9f4b +0101195a7385e588dd2455e36e8a5e3f:eab66efb9557ac3fdd85df45f437f989 +Batwoman S02E02 - Prior Criminal History +0100b4d9d53f3633b9cc9e7a21fbc556:ef5851feffe14998c2cc4bd0e0bc055d +010549a2945d735bba3dd43274939b8e:9872e4151ff3f95ece2a2067f5bb1caf +010275c53a546b20bf7647a73fe98494:37196cd33af243279ef2722b38b3f26c +0101b7694404a788549527493393762f:2f946a6f792be8529dd5f1db221937a6 +Batwoman S02E03 - Bat Girl Magic +0100a5706a179fee0f576bbc429c269f:8144bcc919ae18b34ae2e2177912a11b +01050d66178688aa7b254603127889ca:551a411ead678cfb7ffe7197a31aadb0 +01027d7a7dd4464bca3b4b4229a8a848:38e455dff11b4a340c25966ef8e94b59 +0101c978bb80268c723564c703c48eb2:af4a79ebf0b2fe7a8fa1d5ef4ed1b841 +Batwoman S02E04 - Fair Skin Blue Eyes +0100c9d92ae6eb9a8d054f5c64dbc7f3:0897f739796e0b3d8a5098a58804763b +0105a6d106a9caac09c7990cbe6922d4:ae8ed94d6a0dbfc2d87907fcbd208988 +01027727be2becb3801bb23ca5f82030:cd169d2316ae7c8cc1b5ace5105802f7 +0101c7e2f00526422737ecaec7cfbfd1:068ccaa9ba41121bdf9a671a6f6b76a2 +Batwoman S02E05 - Gore on Canvas +0100785a4a08f4670ea51d3a27e58cf9:769874aab85443e8f3f748d5df91a18f +01050c76675bb6ce29da708944bf6784:d75a72be1c65efc811473f5c5e2bdfb8 +010239a841c096e7bcdda365dacbb7b2:48445f8c87883bfcfef0fc36ae6534ab +010185d38aa8b1f82a91a0a23ffff890:3e914a141727f9711a1c7525a9b24552 +Batwoman S02E06 - Do Not Resuscitate +010067302a677a674b9be4be621102f0:ffd8ad6826e7f6d61850945a92d43632 +010566dee26f7208094d4733918fde49:72fcab9cfe718de35f1974a4a70c34cc +010249de755d9eeb5339dc587e366ff3:b46bf47aea22e546a3723fd6eed3c99b +0101f27f0727a7c31b71008c7675b7aa:0671dd811f889beaa942a56df1b1b406 +Batwoman S02E07 - Its Best You Stop Digging +01001ccca8ef2d5dbdb860c8f1ce5c61:75e69bda9b37058dcbda7da681c89c1f +0105b856318d8610a2e93852c4a06c2b:dfa1886f3e7806547f220626879ff261 +01027c26e9750fef7aa25d3210872d64:2f3870c689616032d949c9db19985d51 +0101cd39afdcbcc06956ab9ae342ac63:2ae5e2a56f53660c4a54b553c5b2d6a2 +Batwoman S02E08 - Survived Much Worse +010038429c900119a5837907df39e84c:56a45e9a47b31325f99f11278c59cf50 +010531e02e2f828a4e878ee57fe1aa36:ba75877b0c84eab324d9728853d7cf35 +0102dd204092dc81083e0ae685fbbbcb:b1ee9175b3e1f368c3900e3ff529b492 +010146121de7b4e8145707a9c1e4ca1a:f300e28d1808d53dc21695373e47b63b +Batwoman S02E09 - Rule 1 +010075d63eb37e1c8cefb01fe1480bc1:45de633f9841312698535cce35b89e69 +010544c8ef36126b4ef2d23691348687:22268c051049c705538ef008923c6fea +010212d6be72ea1061b0ecc51030d37c:13c731c1e293bfecd99d53f3f9365a12 +010137223021b950c1f0f6c9c490ba85:4c2abd22a6230d15959fedbcd6279bb6 +Batwoman S02E10 - Time Off for Good Behavior +010085342cff58ddfedaf55d11b5e7b3:b6b52880e492c945e876d873b66cf65e +010587e645752c67b65c55ed2edd2e9e:33975f1b9a5d240de589b405e6e5747d +01020d63aeee2f671edbe5095245f0f4:ae95ccaf09ecff58ee85b9bd0f7d0cdb +0101ce423176a0c35b8bf3ae2f3f5d23:25ddd879474fa73d33c60ce6737e5c29 +Batwoman S02E11 - Arrive Alive +01007f4ec4b3d8b75800804c17b592ea:668c05c2794fa19f0b04b1f892b7dc42 +0105802fecfb861e1d9737d131532114:9e3c7395dd581298526ebcb61a7c92fd +010239033eb000df46e69eb432549eb0:a08ee9f02ab8888f364d13e157f448ef +01015bb29f71f8ff1b7b144a8ab05bc0:8c99cdc981fe0e1f9f8e8a71bccffaff +Batwoman S02E12 - Initiate SelfDestruct +01004d5bbd5243775c78166fa0b89df6:16516f29315498b6f2e9560307fda7a1 +0105de80a6ff76c7eaef30a72d56cdc8:19a58cf6c3e652ee9bd48642c176d86e +010202d7403ad7de57669411bec8f6f1:3fc4d134442ebf69feb06df300b5d016 +010196bb776270cc0572ba965646d6b5:f7862b33719a782397e78b9f247aad4e +Batwoman S02E13 - Ill Give You a Clue +0100fb47d5ca8cdfb21bb659e262bee5:10f38081af0bda73c82443328cb49703 +0105af1b452522d5f5440768bfd0d56b:254be27bb967020e68c9a5d5d73e38d5 +0102ec412eefb75828dc9a72e583009c:da566dfaaeee1ece0af84f6d30f0edc4 +0101cb4d2d717d2253c43ee8d9b60a04:4d0076282cf7a9be56995a8c0f8d8bfe +Batwoman S02E14 - And Justice for All +01008877409569af4a2ead433f5af718:6ccaffc68f3a6aa2aaf98b8496b0ecbb +0105fa00a369032379aa208fb46fc303:99121febd1ae9cdf2c472a68cc1b8e5b +0102e3230f21c8bff8004740d89645cb:751687d4340d81c174d0f712d5dbcae0 +0101ebdbd11b670e91c268874c3109b0:7e4f10f5a0790c62ebe9dc4d5de9d33e +Batwoman S02E15 - Armed Suspect +01006ba0ea1f70084983e770c630bb36:c5f58a392516ac21ea1300ea04a669e5 +01055bd10b9f06d738e3d9a2b13edc7c:d492ed34fa7149844c7bf03c8ae47721 +0102b306556fb84582aa409ac4b6a584:281d9dd82d8843ca41f7092670d48800 +010152228cd2e39ea973f88d973dcd62:d93bdeb9dde3737e90a8fafc4df21427 +Batwoman S02E16 - Rebirth +010021bc64ac431f4df958583a483201:086f250bf075edd18a24e8fa6f8ed65b +01052ab94f1f64018300d1bb3077802d:91d163a8aacc0544e70f7eea763b3833 +0102089519e709cba16179a3ca398904:e0a082c1b0e34fd3cabc73265993ffd2 +010108362bd69113b4d27d7d986eb055:c683ed40543517865cdcf850c7ca5822 +Batwoman S02E17 - Kane Kate +0100e13e59e28292dfe6e08991c0e61e:24f3a32b3ef62df60777e75baf540cde +01056dce7c173e82c3eca7ed6f1d2b75:91ab12140d5c3ccaf4561fb3eab4213d +010246b98e624bf1bb31458f857c22a8:97f45fd8d9c60d1e6b6f5591abae8d1c +0101f682ea4a056ba5511f777c82fd0d:f6f9b45c4ad53548fafc97d1e309e5cc +Batwoman S02E18 - Power +0100c5624fc4fa47b5c771ba1f0879de:d5410e4831ba98d33ff18303aee40227 +0105eb5c07d078585c774abe909ca767:d3e9ddd1ec2bba81db00179c251571b5 +01028220ac9cd86cf7bbd47c6393b597:e329fc2c41fc6221a8eb84964c9f1c85 +0101b59a867c9c344c33bb9564a7812c:ff99c5cbca7e80dffedb4148bc21e5d5 diff --git a/KEYS/PARAMOUNTPLUS.txt b/KEYS/PARAMOUNTPLUS.txt new file mode 100644 index 0000000..d8f1be5 --- /dev/null +++ b/KEYS/PARAMOUNTPLUS.txt @@ -0,0 +1,31 @@ +##### One KEY per line. ##### +Un Lugar en Silencio (2018) +32c7ac2797ae4ca8990cdb917f418a28:9363b26f7c599512db7f33b2eda3eeae +Un Lugar en Silencio (2018) +32c7ac2797ae4ca8990cdb917f418a28:9363b26f7c599512db7f33b2eda3eeae +Sabrina the Teenage Witch - Piloto S01E01 - Piloto +540009bd9b0f4e1bb4655cf7c0a30ab6:bbbc41bb980fbf4134eec5d9288d676d +Sabrina the Teenage Witch - Viernes De Panque S01E02 - Viernes De Panque +78fa06031ee94c2f9b1a7feebefd9dd1:86d96275eb806d5f3156ca1a45c30251 +Sabrina the Teenage Witch - Viernes De Panque S01E02 - Viernes De Panque +78fa06031ee94c2f9b1a7feebefd9dd1:86d96275eb806d5f3156ca1a45c30251 +Sabrina the Teenage Witch - Viernes De Panque S01E02 - Viernes De Panque +78fa06031ee94c2f9b1a7feebefd9dd1:86d96275eb806d5f3156ca1a45c30251 +Familias De La Mafia S01E02 - Parte II +69e84b2e7fee46bc9630c7b4e8256d79:247b446e06c2d83d1ec70cb5cb2b50a2 +Familias De La Mafia S01E01 - Parte I +db6595d6f64444208e0e0cc2080f2d50:89ad3c24568875c667293edb841eb74b +Familias De La Mafia S01E01 - Parte I +db6595d6f64444208e0e0cc2080f2d50:89ad3c24568875c667293edb841eb74b +Los Padrinos Mágicos S05E01 - Día De Mudanzas Secreto De Familia +4805cc1c5c554ec7b009c5203f559e50:066732c2c49451ecc13c3e1a68c4a376 +Los Padrinos Mágicos S05E02 - Mi Hermano Mayor Qué Diferencia Hay +5634bd83530a4352a9eb05cbe3a17807:8ac3a06198dff4e5ec4155fd30b76841 +Los Padrinos Mágicos S05E03 - Un Ataque De Inteligencia La Academia Del Ocio +f204b48ccb08400e87c3ec1b76a4954e:6adabdf7f867be3a42b0690d4b390739 +iCarly! S01E101 - Un Nuevo Comienzo +41432623869945ee962c02bcac0109ea:baf729e875fb5431a2f2059189c54e60 +Acapulco Shore S08E14 - Invitadas Sorpresa +873043e2654246fd9fc51fea9833b0c5:fc6e03c6222a77d760dbeff5869960eb +Acapulco Shore S08E15 - La Fiesta Final +31a46457e5784ceba40fe333b093d758:d1cd078dd97676c2fc787976882c72ec diff --git a/PARAMETROS GENERALES_muestra como descarga.txt b/PARAMETROS GENERALES_muestra como descarga.txt new file mode 100644 index 0000000..87993ea --- /dev/null +++ b/PARAMETROS GENERALES_muestra como descarga.txt @@ -0,0 +1,6 @@ +python bad37.py --url httpsplay.hbomax.comfeatureurnhbofeatureGX9KHPw1OIMPCJgEAAAAD --alang es-la en --slang es-la en -q 1080p +pause + +para blim descargar la mejor calidad es el comando asi + +python bad37.py --url https://www.blim.com/asset/7607 -s 10 -c playready -e 1 \ No newline at end of file diff --git a/README.md b/README.md index 7f4c6b9..f141133 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,38 @@ -# HBO-MAX 4k Downloader - Download from HMAX + +
#HBO MAX- BlimTV -Paramount plus 4K Downloader +
+ +
Tool To download 4K HDR DV SDR from HBO MAX- BlimTV -Paramount plus +
+ +

+ +

+ +

Hello Fellow < Developers/ >!

+

+

+ + + +
Hi! My name is WVDUMP. I am Leaking the scripts to punish few idiots :smile: +
+ +

About Me

+ +Github + +- 🔭 I’m currently working on Java scripts + +- 🌱 I’m currently learning Python + +- 👯 Sharing is caring + + +- ⚡ CDM IS NOT INCLUDED BUY it from wvfuck@cyberfiends.net ⚡ + + +
+
+
+ diff --git a/bad37.py b/bad37.py new file mode 100644 index 0000000..9907b7c --- /dev/null +++ b/bad37.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +# Module: BAD Project +# Created on: 01-06-2021 +# Authors: JUNi +# Version: 1.0 + +import argparse +import os +import sys + + +parser = argparse.ArgumentParser() +#Common: +parser.add_argument("content", nargs="?", help="Content URL or ID") +parser.add_argument("--url", dest="url_season", help="If set, it will download all assets from the season provided.") +parser.add_argument("--tqdm", dest="tqmd_mode", help="If set, will download with threading", action="store_true") +parser.add_argument("--nv", "--no-video", dest="novideo", help="If set, don't download video", action="store_true") +parser.add_argument("--na", "--no-audio", dest="noaudio", help="If set, don't download audio", action="store_true") +parser.add_argument("--ns", "--no-subs", dest="nosubs", help="If set, don't download subs", action="store_true") +parser.add_argument("--all-season", dest="all_season", help="If set, active download mode.", action="store_true") +parser.add_argument("-e", "--episode", dest="episodeStart", help="If set, it will start downloading the season from that episode.") +parser.add_argument("-s", dest="season", help="If set, it will download all assets from the season provided.") +parser.add_argument("--tag", type=str, required=False, help="Release group tag to use for filenames") +parser.add_argument("-q", "--quality", dest="customquality", type=lambda x: [x.rstrip('p')], help="For configure quality of video.", default=[]) +parser.add_argument("-o", "--output", dest="output", default="downloads", help="If set, it will download all assets to directory provided.") +parser.add_argument("--keep", dest="keep", help="If set, it will list all formats available.", action="store_true") +parser.add_argument("--info", help="If set, it will print manifest infos and exit.", action="store_true") +parser.add_argument("--no-mux", dest="nomux", help="If set, dont mux.", action="store_true") +#parser.add_argument("--force-mux", dest="force_mux", nargs=1, help="If set, force mux.", default=[]) +#parser.add_argument("--langtag", dest="langtag", nargs=1, help="For configure language tag of MKV.", default=[]) +parser.add_argument("--only-2ch-audio", dest="only_2ch_audio", help="If set, no clean tag subtitles.", action="store_true") +parser.add_argument("--alang", "--audio-language", dest="audiolang", nargs="*", help="If set, download only selected audio languages", default=[]) +parser.add_argument("--slang", "--subtitle-language", dest="sublang", nargs="*", help="If set, download only selected subtitle languages", default=[]) +parser.add_argument("--flang", "--forced-language", dest="forcedlang", nargs="*", help="If set, download only selected forced subtitle languages", default=[]) +parser.add_argument("--no-cleansubs", dest="nocleansubs", help="If set, no clean tag subtitles.", action="store_true") +parser.add_argument("--hevc", dest="hevc", help="If set, it will return HEVC manifest", action="store_true") +parser.add_argument("--uhd", dest="uhd", help="If set, it will return UHD manifest", action="store_true") +parser.add_argument("--license", dest="license", help="Only print keys, don't download", action="store_true") +parser.add_argument("-licenses-as-json", help="Save the wv keys as json instead", action="store_true") +parser.add_argument("--debug", action="store_true", help="Enable debug logging") +parser.add_argument("--aformat-51ch", "--audio-format-51ch", dest="aformat_51ch", help="For configure format of audio.") +parser.add_argument("--nc", "--no-chapters", dest="nochpaters", help="If set, don't download chapters", action="store_true") +parser.add_argument("-c", "--codec", choices=["widevine", "playready"], help="Video type to download", default="widevine") + +parser.add_argument("--only-keys", dest="onlykeys", help="Only print keys, don't download", action="store_true") + +#HBOMAX +parser.add_argument("--atmos", dest="atmos", help="If set, it will return Atmos MPDs", action="store_true") +parser.add_argument("--ad", "--desc-audio", action="store_true", dest="desc_audio", help="Download descriptive audio instead of normal dialogue") +parser.add_argument("--hdr", dest="hdr", help="If set, it will return HDR manifest", action="store_true") +parser.add_argument("-r", "--region", choices=["la", "us"], help="HBO Max video region", default="la") +parser.add_argument("--vp", dest="videocodec", default="h264", choices=["h264", "hevc", "hdr"], help="video codec profile") + +#Clarovideo: +parser.add_argument("--m3u8", dest="m3u8mode", help="If set, it will return M3U8 manifest", action="store_true") +parser.add_argument("--file", dest="txtpath", help="If set, it will download links of an txt file") + +#DisneyPlus: +parser.add_argument("--tlang", "--title-language", dest="titlelang", nargs=1, help="If set, it will change title language", default="es-la") +parser.add_argument("--scenario", dest="scenario", help="Video API from DisneyPlus", default="chromecast-drm-cbcs") + +#PROXY: +parser.add_argument("--proxy", dest="proxy", help="Proxy URL to use for both fetching metadata and downloading") +#proxy format: http://email@email:password@host:port +args = parser.parse_args() + + +if args.debug: + import logging + logging.basicConfig(level=logging.DEBUG) + +currentFile = '__main__' +realPath = os.path.realpath(currentFile) +dirPath = os.path.dirname(realPath) +dirName = os.path.basename(dirPath) + +if __name__ == "__main__": + if args.content: + args.url_season = args.content + + if not args.url_season: + print('Please specify the URL of the content to download.') + sys.exit(1) + + if (args.url_season and 'hbomax' in args.url_season): + mode = 'hbomax' + import hbomax + hbomax.main(args) + elif (args.url_season and 'clarovideo' in args.url_season): + mode = 'clarovideo' + import clarovideo + clarovideo.main(args) + elif (args.url_season and 'blim' in args.url_season): + mode = 'blimtv' + import blimtv + blimtv.main(args) + elif (args.url_season and 'nowonline' in args.url_season): + mode = 'nowonline' + import nowonline + nowonline.main(args) + elif (args.url_season and 'globo' in args.url_season): + mode = 'globoplay' + import globoplay + globoplay.main(args) + elif (args.url_season and 'paramountplus.com' in args.url_season): + mode = 'paramountplus' + import paramountplus + paramountplus.main(args) + elif (args.url_season and 'disneyplus' in args.url_season): + mode = 'disneyplus' + import disneyplus + disneyplus.main(args) + elif (args.url_season and 'prende.tv' in args.url_season): + mode = 'prendetv' + import prendetv + prendetv.main(args) + elif (args.url_season and 'tv.apple.com' in args.url_season): + mode = 'appletv' + import appletv + appletv.main(args) + elif (args.url_season and 'wink' in args.url_season): + mode = 'wink' + import wink + wink.main(args) + + else: + print("Error! This url or mode is not recognized.") + sys.exit(0) diff --git a/blimtv.py b/blimtv.py new file mode 100644 index 0000000..bdc2010 --- /dev/null +++ b/blimtv.py @@ -0,0 +1,594 @@ +# -*- coding: utf-8 -*- +# Module: Blim Downloader +# Created on: 26-11-2020 +# Authors: JUNi +# Version: 3.5 + +import requests +import subprocess +import xmltodict +import ffmpy +import time, shutil +import glob, json +import sys, os, re +import isodate +import oauthlib +from oauthlib import oauth1 +from subprocess import Popen +from titlecase import titlecase +from unidecode import unidecode +from pymediainfo import MediaInfo +from os.path import isfile, join + +import pywidevine.clients.blim.manifest_parse as manifestParse +import pywidevine.clients.blim.client as blim_client +import pywidevine.clients.blim.config as blim_cfg +from pywidevine.clients.proxy_config import ProxyConfig +from pywidevine.muxer.muxer import Muxer + +from pywidevine.clients.blim.downloader_pr import PrDownloader +from pywidevine.clients.blim.downloader_wv import WvDownloader +from pywidevine.clients.blim.config import PrDownloaderConfig +from pywidevine.clients.blim.config import WvDownloaderConfig + +currentFile = 'blimtv' +realPath = os.path.realpath(currentFile) +dirPath = os.path.dirname(realPath) + +def main(args): + + SubtitleEditexe = shutil.which("subtitleedit") or shutil.which("SubtitleEdit") + + proxies = {} + proxy_meta = args.proxy + if proxy_meta == 'none': + proxies['meta'] = {'http': None, 'https': None} + elif proxy_meta: + proxies['meta'] = {'http': proxy_meta, 'https': proxy_meta} + SESSION = requests.Session() + SESSION.proxies = proxies.get('meta') + proxy_cfg = ProxyConfig(proxies) + + def alphanumericSort(l): + def convert(text): + if text.isdigit(): + return int(text) + else: + return text + + def alphanum_key(key): + return [convert(c) for c in re.split('([0-9]+)', key)] + + return sorted(l, key=alphanum_key) + + def convert_size(size_bytes): + if size_bytes == 0: + return '0bps' + else: + s = round(size_bytes / 1000, 0) + return '%ikbps' % s + + def get_size(size): + power = 1024 + n = 0 + Dic_powerN = {0:'', 1:'K', 2:'M', 3:'G', 4:'T'} + while size > power: + size /= power + n += 1 + return str(round(size, 2)) + Dic_powerN[n] + 'B' + + def find_str(s, char): + index = 0 + if char in s: + c = char[0] + for ch in s: + if ch == c: + if s[index:index + len(char)] == char: + return index + index += 1 + + return -1 + + def getKeyId(name): + mp4dump = subprocess.Popen([blim_cfg.MP4DUMP, name], stdout=(subprocess.PIPE)) + mp4dump = str(mp4dump.stdout.read()) + A = find_str(mp4dump, 'default_KID') + KEY_ID_ORI = '' + KEY_ID_ORI = mp4dump[A:A + 63].replace('default_KID = ', '').replace('[', '').replace(']', '').replace(' ', '') + if KEY_ID_ORI == '' or KEY_ID_ORI == "'": + KEY_ID_ORI = 'nothing' + return KEY_ID_ORI + + def replace_words(x): + x = re.sub(r'[]¡!"#$%\'()*+,:;<=>¿?@\\^_`{|}~[-]', '', x) + return unidecode(x) + + def downloadFile2(link, file_name): + with open(file_name, 'wb') as (f): + print('\nDownloading %s' % file_name) + response = requests.get(link, stream=True) + total_length = response.headers.get('content-length') + if total_length is None: + f.write(response.content) + else: + dl = 0 + total_length = int(total_length) + for data in response.iter_content(chunk_size=4096): + dl += len(data) + f.write(data) + done = int(50 * dl / total_length) + sys.stdout.write('\r[%s%s]' % ('=' * done, ' ' * (50 - done))) + sys.stdout.flush() + + global folderdownloader + if args.output: + if not os.path.exists(args.output): + os.makedirs(args.output) + os.chdir(args.output) + if ":" in str(args.output): + folderdownloader = str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath + str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath.replace('/','\\').replace('.\\','\\') + + def manifest_parse(manifest_url): + r = SESSION.get(url=manifest_url) + r.raise_for_status() + xml = xmltodict.parse(r.text) + manifest = json.loads(json.dumps(xml)) + if '.mpd' in manifest_url: + length, video_list, audio_list, subs_list = manifestParse.get_mpd_list(manifest) + base_url = manifest['MPD']['Period']['BaseURL'] + else: + length, video_list, audio_list, subs_list = manifestParse.get_ism_list(manifest) + base_url = manifest_url.split('Manifest')[0] + + video_list = sorted(video_list, key=(lambda k: int(k['Bandwidth']))) + height_all = [] + for x in video_list: + height_all.append(x['Height']) + + try: + while args.customquality != [] and int(video_list[(-1)]['Height']) > int(args.customquality[0]): + video_list.pop(-1) + except Exception: + video_list = [] + + if video_list == []: + video_list = video_list + args.novideo = True + + audio_list = sorted(audio_list, key=(lambda k: (int(k['Bandwidth']), str(k['Language']))), reverse=True) + BitrateList = [] + AudioLanguageList = [] + for x in audio_list: + BitrateList.append(x['Bandwidth']) + AudioLanguageList.append(x['Language']) + + BitrateList = alphanumericSort(list(set(BitrateList))) + AudioLanguageList = alphanumericSort(list(set(AudioLanguageList))) + audioList_new = [] + audio_Dict_new = {} + for y in AudioLanguageList: + counter = 0 + for x in audio_list: + if x['Language'] == y and counter == 0: + audio_Dict_new = { + 'Language':x['Language'], + 'Bandwidth':x['Bandwidth'], + 'ID':x['ID'], + 'Codec': x['Codec']} + audioList_new.append(audio_Dict_new) + counter = counter + 1 + + audioList = audioList_new + audio_list = sorted(audioList, key=(lambda k: (int(k['Bandwidth']), str(k['Language'])))) + + subs_list = [] + subsList_new = [] + if args.sublang: + for x in subs_list: + langAbbrev = x['Language'] + if langAbbrev in list(args.sublang): + subsList_new.append(x) + subs_list = subsList_new + + return base_url, length, video_list, audio_list, subs_list, manifest + + def get_episodes(ep_str, num_eps): + eps = ep_str.split(',') + eps_final = [] + + for ep in eps: + if '-' in ep: + (start, end) = ep.split('-') + start = int(start) + end = int(end or num_eps) + eps_final += list(range(start, end + 1)) + else: + eps_final.append(int(ep)) + + return eps_final + + tokenIsOk = False + os.makedirs(blim_cfg.COOKIES_FOLDER, exist_ok=True) + BLIMLOGINDATA_FILE = join(blim_cfg.COOKIES_FOLDER, 'blim_login_data.json') + SESSION, costumer_key, access_key_secret = blim_client.login(SESSION) + + def get_auth_header(api_url): + client = oauthlib.oauth1.Client(costumer_key, client_secret=access_key_secret) + uri, auth_header, body = client.sign(api_url) + return auth_header + + def get_season(blim_id): + season_req = requests.get(url=blim_cfg.ENDPOINTS['seasons'] + str(blim_id)).json()['data'] + + if 'episode' in season_req['category'] and args.season: + blim_id = season_req['parentShow']['id'] + season_req = requests.get(url=blim_cfg.ENDPOINTS['seasons'] + str(blim_id)).json()['data'] + + if not args.season: + args.season = 'all' + + seasons = [] + if args.season: + if args.season == 'all': + seasons = 'all' + elif ',' in args.season: + seasons = [int(x) for x in args.season.split(',')] + elif '-' in args.season: + (start, end) = args.season.split('-') + seasons = list(range(int(start), int(end) + 1)) + else: + seasons = [int(args.season)] + + if 'series' in season_req['category']: + if seasons == 'all': + seasons = [x['number'] for x in season_req['seasons']] + + for season_num in seasons: + episode_list = season_req['seasons'][int(season_num) - 1]['episodes'] + episodes_list_new = [] + for num, ep in enumerate(episode_list, start=1): + episodes_list_new.insert(num - 0, { + 'id': ep['id'], + 'episode_num': num + }) + episode_list = sorted(episodes_list_new, key=lambda x: x['episode_num']) + + if args.episodeStart: + eps = get_episodes(args.episodeStart, len(episode_list)) + episode_list = [x for x in episode_list if x['episode_num'] in eps] + + for episode in episode_list: + get_metadata(blim_id=episode['id']) + + else: + get_metadata(blim_id) + + def get_metadata(blim_id): + content_url = blim_cfg.ENDPOINTS['content'] + str(blim_id) + info_json = requests.get(url=content_url, headers=get_auth_header(content_url), proxies=proxy_cfg.get_proxy('meta')).json() + if 'episode' in info_json['data']['category']: + blimType = "show" + seriesTitles = info_json['data']['parentShow']['titleEditorial'] + seasonNumber = info_json['data']['parentSeason']['number'] + episodeNumber = info_json['data']['episodeNumber'] + episodeTitle = info_json['data']['titleEditorial'] + + if 'movie' in info_json['data']['category']: + blimType = "movie" + seriesTitles = info_json['data']['titleEditorial'] + releaseYearSearch = info_json['data']['airDate'] + releaseYear = re.search(r"^[0-9]{4}", releaseYearSearch) + + if blimType=="movie": + seriesName = replace_words(seriesTitles) + ' (' + releaseYear.group() + ')' + folderName = None + + if blimType=="show": + seriesName = f'{replace_words(seriesTitles)} S{seasonNumber:02}E{episodeNumber:02} - {replace_words(episodeTitle)}' + folderName = f'{replace_words(seriesTitles)} S{seasonNumber:02}' + + start_process(get_manifest_url(info_json), seriesName, folderName, blimType) + + codec = "mpd" if args.codec == "widevine" else "ss" + + def get_manifest_url(api_json): + video_json = api_json['data']['videos'][0]['files'] + for x in video_json: + if x['type'] == codec: + videoURL = x['path'].replace("AVOD.", "") + if 'ss_629d09c4372f297f2760c820711c4d4737b14f26c25c55e58f1147819005089e' in videoURL or "468842.mpd" in videoURL: + print("Lo sentimos, por el momento Blim no está disponible en tu país") + sys.exit(0) + break + return videoURL + + def get_drm_info(): # não está utilizando + resp = requests.get(url=blim_cfg.ENDPOINTS['config'], proxies=proxy_cfg.get_proxy('meta')).json() + wvlic = resp['widevineLicenseServer'] + wvcert = resp['widevineCertificateServer'] + return wvlic, wvcert + + def start_process(manifest_url, seriesName, folderName, blimType): + base_url, length, video_list, audio_list, subs_list, xml = manifest_parse(manifest_url) + video_bandwidth = dict(video_list[(-1)])['Bandwidth'] + video_height = str(dict(video_list[(-1)])['Height']) + video_width = str(dict(video_list[(-1)])['Width']) + video_codec = str(dict(video_list[(-1)])['Codec']) + video_format_id = str(dict(video_list[(-1)])['ID']) + if not args.novideo: + print('\nVIDEO - Bitrate: ' + convert_size(int(video_bandwidth)) + ' - Profile: ' + video_codec.split('=')[0] + ' - Size: ' + get_size(length * float(video_bandwidth) * 0.125) + ' - Dimensions: ' + video_width + 'x' + video_height) + print() + + if not args.noaudio: + if audio_list != []: + for x in audio_list: + audio_bandwidth = x['Bandwidth'] + audio_representation_id = str(x['Codec']) + audio_lang = x['Language'] + print('AUDIO - Bitrate: ' + convert_size(int(audio_bandwidth)) + ' - Profile: ' + audio_representation_id.split('=')[0] + ' - Size: ' + get_size(length * float(audio_bandwidth) * 0.125) + ' - Language: ' + audio_lang) + print() + + if not args.nosubs: + if subs_list != []: + for z in subs_list: + sub_lang = str(dict(z)['Language']) + print('SUBTITLE - Profile: Normal - Language: ' + sub_lang) + print() + + print('Name: ' + seriesName) + + if blimType == 'show': + CurrentName = seriesName + CurrentHeigh = str(video_height) + outputName = folderdownloader + '\\' + str(folderName) + str(CurrentName) + ' [' + str(CurrentHeigh) + 'p].mkv' + else: + CurrentName = seriesName + CurrentHeigh = str(video_height) + outputName = folderdownloader + str(CurrentName) + ' [' + str(CurrentHeigh) + 'p].mkv' + + if 'ism' in manifest_url: + if video_height == "1080": + init_url = blim_cfg.init_files["1080p"] + elif video_height == "480": + init_url = blim_cfg.init_files["480p"] + + if not os.path.isfile(outputName): + + if not args.novideo: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo): + print('\n' + inputVideo + '\nFile has already been successfully downloaded previously.\n') + else: + if args.codec == 'playready': + prdl_cfg = PrDownloaderConfig(xml, base_url, inputVideo, video_bandwidth, init_url, 'video') + downloader = PrDownloader(prdl_cfg) + else: + wvdl_cfg = WvDownloaderConfig(xml, base_url, inputVideo, video_format_id, 'video/mp4') + downloader = WvDownloader(wvdl_cfg) + downloader.run() + + if not args.noaudio: + for x in audio_list: + audio_lang = x['Language'] + inputAudio = seriesName + ' ' + '(' + audio_lang + ')' + '.mp4' + inputAudio_demuxed = seriesName + ' ' + '(' + audio_lang + ')' + '.m4a' + if os.path.isfile(inputAudio) or os.path.isfile(inputAudio_demuxed): + print('\n' + inputAudio + '\nFile has already been successfully downloaded previously.\n') + else: + if args.codec == 'playready': + prdl_cfg = PrDownloaderConfig(xml, base_url, inputAudio, x['Bandwidth'], blim_cfg.init_files["audio"], 'audio') + downloader = PrDownloader(prdl_cfg) + else: + wvdl_cfg = WvDownloaderConfig(xml, base_url, inputAudio, x['ID'], 'audio/mp4') + downloader = WvDownloader(wvdl_cfg) + downloader.run() + + if not args.nosubs: + if subs_list != []: + for z in subs_list: + langAbbrev = str(dict(z)['Language']) + inputSub = seriesName + " " + "(" + langAbbrev + ")" + if os.path.isfile(inputSub + ".vtt") or os.path.isfile(inputSub + ".srt"): + print("\n" + inputSub + "\nFile has already been successfully downloaded previously.\n") + else: + downloadFile2(str(dict(z)['File_URL']), inputSub + ".vtt") + print('\nConverting subtitles...') + SubtitleEdit_process = subprocess.Popen([SubtitleEditexe, "/convert", inputSub + ".vtt", "srt", "/fixcommonerrors", "/encoding:utf-8", "/RemoveLineBreaks"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait() + for f in glob.glob(inputSub + ".vtt"): + os.remove(f) + print("Done!") + else: + print ("\nNo subtitles available.") + + CorrectDecryptVideo = False + if not args.novideo: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo): + CorrectDecryptVideo = DecryptVideo(inputVideo=inputVideo, keys_video=blim_cfg.protection_keys) + else: + CorrectDecryptVideo = True + + CorrectDecryptAudio = False + if not args.noaudio: + for x in audio_list: + audio_lang = x['Language'] + inputAudio = seriesName + ' ' + '(' + audio_lang + ')' + '.mp4' + if os.path.isfile(inputAudio): + CorrectDecryptAudio = DecryptAudio(inputAudio=inputAudio, keys_audio=blim_cfg.protection_keys) + else: + CorrectDecryptAudio = True + + if not args.nomux: + if not args.novideo: + if not args.noaudio: + if CorrectDecryptVideo == True: + if CorrectDecryptAudio == True: + print('\nMuxing...') + + if blimType=="show": + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=folderName, + CurrentHeigh=CurrentHeigh, + Type=blimType, + mkvmergeexe=blim_cfg.MKVMERGE) + + else: + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=None, + CurrentHeigh=CurrentHeigh, + Type=blimType, + mkvmergeexe=blim_cfg.MKVMERGE) + + MKV_Muxer.mkvmerge_muxer(lang="English") + + if args.tag: + inputName = CurrentName + ' [' + CurrentHeigh + 'p].mkv' + release_group(base_filename=inputName, + default_filename=CurrentName, + folder_name=folderName, + type=blimType, + video_height=CurrentHeigh) + + if not args.keep: + for f in os.listdir(): + if re.fullmatch(re.escape(CurrentName) + r'.*\.(mp4|m4a|h264|h265|eac3|srt|txt|avs|lwi|mpd)', f): + os.remove(f) + print("Done!") + else: + print("\nFile '" + str(outputName) + "' already exists.") + + def release_group(base_filename, default_filename, folder_name, type, video_height): + if type=='show': + video_mkv = os.path.join(folder_name, base_filename) + else: + video_mkv = base_filename + + mediainfo = MediaInfo.parse(video_mkv) + video_info = next(x for x in mediainfo.tracks if x.track_type == "Video") + video_format = video_info.format + + video_codec = '' + if video_format == "AVC": + video_codec = 'H.264' + elif video_format == "HEVC": + video_codec = 'H.265' + + audio_info = next(x for x in mediainfo.tracks if x.track_type == "Audio") + codec_name = audio_info.format + channels_number = int(audio_info.other_channel_positions[0].split('/')[0]) + + audio_codec = '' + audio_channels = '' + if codec_name == "AAC": + audio_codec = "AAC" + elif codec_name == "AC-3": + audio_codec = "DD" + elif codec_name == "E-AC-3": + audio_codec = "DDP" + elif codec_name == "E-AC-3 JOC": + audio_codec = "ATMOS" + + if channels_number == "2": + audio_channels = "2.0" + elif channels_number == "6": + audio_channels = "5.1" + + audio_ = audio_codec + audio_channels + + # renomear arquivo + default_filename = default_filename.replace('&', '.and.') + default_filename = re.sub(r'[]!"#$%\'()*+,:;<=>?@\\^_`{|}~[-]', '', default_filename) + default_filename = default_filename.replace(' ', '.') + default_filename = re.sub(r'\.{2,}', '.', default_filename) + default_filename = unidecode(default_filename) + + output_name = '{}.{}p.BLIM.WEB-DL.{}.{}-{}'.format(default_filename, video_height, audio_, video_codec, args.tag) + if type=='show': + outputName = os.path.join(folder_name, output_name + '.mkv') + else: + outputName = output_name + '.mkv' + + os.rename(video_mkv, outputName) + print("{} -> {}".format(base_filename, output_name)) + + def DecryptAudio(inputAudio, keys_audio): + key_audio_id_original = getKeyId(inputAudio) + outputAudioTemp = inputAudio.replace(".mp4", "_dec.mp4") + if key_audio_id_original != "nothing": + for key in keys_audio: + key_id=key[0:32] + if key_id == key_audio_id_original: + print("\nDecrypting audio...") + print ("Using KEY: " + key) + wvdecrypt_process = subprocess.Popen([blim_cfg.MP4DECRYPT, "--show-progress", "--key", key, inputAudio, outputAudioTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + time.sleep (50.0/1000.0) + os.remove(inputAudio) + print("\nDemuxing audio...") + mediainfo = MediaInfo.parse(outputAudioTemp) + audio_info = next(x for x in mediainfo.tracks if x.track_type == "Audio") + codec_name = audio_info.format + + ext = '' + if codec_name == "AAC": + ext = '.m4a' + elif codec_name == "E-AC-3": + ext = ".eac3" + elif codec_name == "AC-3": + ext = ".ac3" + outputAudio = outputAudioTemp.replace("_dec.mp4", ext) + print("{} -> {}".format(outputAudioTemp, outputAudio)) + ff = ffmpy.FFmpeg(executable=blim_cfg.FFMPEG, inputs={outputAudioTemp: None}, outputs={outputAudio: '-c copy'}, global_options="-y -hide_banner -loglevel warning") + ff.run() + time.sleep (50.0/1000.0) + os.remove(outputAudioTemp) + print("Done!") + return True + + elif key_audio_id_original == "nothing": + return True + + def DecryptVideo(inputVideo, keys_video): + key_video_id_original = getKeyId(inputVideo) + inputVideo = inputVideo + outputVideoTemp = inputVideo.replace('.mp4', '_dec.mp4') + outputVideo = inputVideo + if key_video_id_original != 'nothing': + for key in keys_video: + key_id = key[0:32] + if key_id == key_video_id_original: + print('\nDecrypting video...') + print('Using KEY: ' + key) + wvdecrypt_process = subprocess.Popen([blim_cfg.MP4DECRYPT, '--show-progress', '--key', key, inputVideo, outputVideoTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + print('\nRemuxing video...') + ff = ffmpy.FFmpeg(executable=blim_cfg.FFMPEG, inputs={outputVideoTemp: None}, outputs={outputVideo: '-c copy'}, global_options='-y -hide_banner -loglevel warning') + ff.run() + time.sleep(0.05) + os.remove(outputVideoTemp) + print('Done!') + return True + + elif key_video_id_original == 'nothing': + return True + + def id_parse(x): + if 'player' in args.url_season: + id_ = args.url_season.split('/')[-2] + else: + id_ = args.url_season.split('/')[-1] + return id_ + + blim_id = id_parse(args.url_season) + + if 'player' in args.url_season: + get_metadata(blim_id) + else: + get_season(blim_id) + diff --git a/cookies/cookies.txt b/cookies/cookies.txt new file mode 100644 index 0000000..e69de29 diff --git a/hbomax.py b/hbomax.py new file mode 100644 index 0000000..d436d69 --- /dev/null +++ b/hbomax.py @@ -0,0 +1,949 @@ +# -*- coding: utf-8 -*- +# Module: HBO Max Downloader +# Created on: 04-11-2020 +# Version: 3.5 + +import sys, os +import subprocess, re, base64, requests +import xmltodict, isodate +import time, glob, uuid, ffmpy, json +import shutil, urllib.parse + +from unidecode import unidecode + +import pywidevine.clients.hbomax.config as HMAXConfig +import pywidevine.clients.hbomax.client as HMAXClient + +from pywidevine.clients.hbomax.config import HMAXRegion +from pywidevine.clients.proxy_config import ProxyConfig +from pywidevine.muxer.muxer import Muxer +from os.path import join, isfile + +currentFile = 'hbomax' +realPath = os.path.realpath(currentFile) +dirPath = os.path.dirname(realPath) +SESSION = requests.session() +USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36" + +def main(args): + + proxies = {} + proxy_meta = args.proxy + if proxy_meta == 'none': + proxies['meta'] = {'http': None, 'https': None} + elif proxy_meta: + proxies['meta'] = {'http': proxy_meta, 'https': proxy_meta} + SESSION.proxies = proxies.get('meta') + proxy_cfg = ProxyConfig(proxies) + + if not os.path.exists(dirPath + '/KEYS'): + os.makedirs(dirPath + '/KEYS') + else: + keys_file = dirPath + '/KEYS/HBOMAX.txt' + try: + keys_file_hbomax = open(keys_file, 'r', encoding='utf8') + keys_file_txt = keys_file_hbomax.readlines() + except Exception: + with open(keys_file, 'a', encoding='utf8') as (file): + file.write('##### One KEY per line. #####\n') + keys_file_hbomax = open(keys_file, 'r', encoding='utf8') + keys_file_txt = keys_file_hbomax.readlines() + + global folderdownloader + if args.output: + if not os.path.exists(args.output): + os.makedirs(args.output) + os.chdir(args.output) + if ":" in str(args.output): + folderdownloader = str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath + '\\' + str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath.replace('/','\\').replace('.\\','\\') + + def downloadFile(aria2c_infile): + aria2c_opts = [ + HMAXConfig.ARIA2C, + '--allow-overwrite=true', + '--download-result=hide', + '--console-log-level=warn', + '--enable-color=false', + '-x16', '-s16', '-j16', + '-i', aria2c_infile] + subprocess.run(aria2c_opts, check=True) + + def downloadFile2(link, file_name): + with open(file_name, 'wb') as (f): + print(file_name) + response = SESSION.get(link, stream=True) + total_length = response.headers.get('content-length') + if total_length is None: + f.write(response.content) + else: + dl = 0 + total_length = int(total_length) + for data in response.iter_content(chunk_size=4096): + dl += len(data) + f.write(data) + + def find_str(s, char): + index = 0 + + if char in s: + c = char[0] + for ch in s: + if ch == c: + if s[index:index+len(char)] == char: + return index + + index += 1 + + return -1 + + def getKeyId(name): + mp4dump = subprocess.Popen([HMAXConfig.MP4DUMP, name], stdout=subprocess.PIPE) + mp4dump = str(mp4dump.stdout.read()) + A=find_str(mp4dump, "default_KID") + KEY_ID_ORI=mp4dump[A:A+63].replace("default_KID = ", "").replace("[", "").replace("]", "").replace(" ", "") + if KEY_ID_ORI == "": + KEY_ID_ORI = "nothing" + return KEY_ID_ORI + + def mediainfo_(file): + mediainfo_output = subprocess.Popen([HMAXConfig.MEDIAINFO, '--Output=JSON', '-f', file], stdout=subprocess.PIPE) + mediainfo_json = json.load(mediainfo_output.stdout) + return mediainfo_json + + def replace_words(x): + x = re.sub(r'[]¡!"#$%\'()*+,:;<=>¿?@\\^_`{|}~[-]', '', x) + x = x.replace('\\', '').replace('/', ' & ') + return unidecode(x) + + def ReplaceCodeLanguages(X): + X = X.lower() + X = X.replace('_subtitle_dialog_0', '').replace('_narrative_dialog_0', '').replace('_caption_dialog_0', '').replace('_dialog_0', '').replace('_descriptive_0', '_descriptive').replace('_descriptive', '_descriptive').replace('_sdh', '-sdh').replace('es-es', 'es').replace('SPA', 'es').replace('en-es', 'es').replace('kn-in', 'kn').replace('gu-in', 'gu').replace('ja-jp', 'ja').replace('mni-in', 'mni').replace('si-in', 'si').replace('as-in', 'as').replace('ml-in', 'ml').replace('sv-se', 'sv').replace('hy-hy', 'hy').replace('sv-sv', 'sv').replace('da-da', 'da').replace('fi-fi', 'fi').replace('nb-nb', 'nb').replace('is-is', 'is').replace('uk-uk', 'uk').replace('hu-hu', 'hu').replace('bg-bg', 'bg').replace('hr-hr', 'hr').replace('lt-lt', 'lt').replace('et-et', 'et').replace('el-el', 'el').replace('he-he', 'he').replace('ar-ar', 'ar').replace('fa-fa', 'fa').replace('ENG', 'en').replace('ro-ro', 'ro').replace('sr-sr', 'sr').replace('cs-cs', 'cs').replace('sk-sk', 'sk').replace('mk-mk', 'mk').replace('hi-hi', 'hi').replace('bn-bn', 'bn').replace('ur-ur', 'ur').replace('pa-pa', 'pa').replace('ta-ta', 'ta').replace('te-te', 'te').replace('mr-mr', 'mr').replace('kn-kn', 'kn').replace('gu-gu', 'gu').replace('ml-ml', 'ml').replace('si-si', 'si').replace('as-as', 'as').replace('mni-mni', 'mni').replace('tl-tl', 'tl').replace('id-id', 'id').replace('ms-ms', 'ms').replace('vi-vi', 'vi').replace('th-th', 'th').replace('km-km', 'km').replace('ko-ko', 'ko').replace('zh-zh', 'zh').replace('ja-ja', 'ja').replace('ru-ru', 'ru').replace('tr-tr', 'tr').replace('it-it', 'it').replace('es-mx', 'es-la').replace('ar-sa', 'ar').replace('zh-cn', 'zh').replace('nl-nl', 'nl').replace('pl-pl', 'pl').replace('pt-pt', 'pt').replace('hi-in', 'hi').replace('mr-in', 'mr').replace('bn-in', 'bn').replace('te-in', 'te').replace('POR', 'pt').replace('cmn-hans', 'zh-hans').replace('cmn-hant', 'zh-hant').replace('ko-kr', 'ko').replace('en-au', 'en').replace('es-419', 'es-la').replace('es-us', 'es-la').replace('en-us', 'en').replace('en-gb', 'en').replace('fr-fr', 'fr').replace('de-de', 'de').replace('las-419', 'es-la').replace('ar-ae', 'ar').replace('da-dk', 'da').replace('yue-hant', 'yue').replace('bn-in', 'bn').replace('ur-in', 'ur').replace('ta-in', 'ta').replace('sl-si', 'sl').replace('cs-cz', 'cs').replace('hi-jp', 'hi').replace('-001', '').replace('en-US', 'en').replace('deu', 'de').replace('eng', 'en').replace('ca-es', 'cat').replace('fil-ph', 'fil').replace('en-ca', 'en').replace('eu-es', 'eu').replace('ar-eg', 'ar').replace('he-il', 'he').replace('el-gr', 'he').replace('nb-no', 'nb').replace('es-ar', 'es-la').replace('en-ph', 'en').replace('sq-al', 'sq').replace('bs-ba', 'bs') + return X + + def alphanumericSort(l): + def convert(text): + if text.isdigit(): + return int(text) + else: + return text + + def alphanum_key(key): + return [convert(c) for c in re.split('([0-9]+)', key)] + + return sorted(l, key=alphanum_key) + + def convert_size(size_bytes): + if size_bytes == 0: + return '0bps' + else: + s = round(size_bytes / 1000, 0) + return '%ikbps' % s + + def get_size(size): + power = 1024 + n = 0 + Dic_powerN = {0:'', 1:'K', 2:'M', 3:'G', 4:'T'} + while size > power: + size /= power + n += 1 + return str(round(size, 2)) + Dic_powerN[n] + 'B' + + global auth_url, content_url, license_wv + + if args.region == "la": + auth_url, content_url, license_wv = HMAXRegion.configHBOMaxLatam() + + if args.region == "us": + auth_url, content_url, license_wv = HMAXRegion.configHBOMaxUS() + + def get_authorization_header(TOKEN): + headers = HMAXConfig.get_user_headers()['headers'] + + headers = { + "accept": "application/vnd.hbo.v9.full+json", + "accept-encoding": "gzip, deflate, br", + "accept-language": str(args.titlelang), + "Authorization": f"Bearer {TOKEN}", + "user-agent": HMAXConfig.UA, + "x-hbo-client-version": "Hadron/50.40.0.111 desktop (DESKTOP)", + "x-hbo-device-name": "desktop", + "x-hbo-device-os-version": "undefined" + } + return headers + + os.makedirs(HMAXConfig.COOKIES_FOLDER, exist_ok=True) + HMAXTOKEN_FILE = join(HMAXConfig.COOKIES_FOLDER, 'hmax_login_data.json') + if not isfile(HMAXTOKEN_FILE): + access_token = HMAXClient.login(SESSION, auth_url, content_url) + + def refresh_token(): + content = None + TOKEN = False + with open(HMAXTOKEN_FILE,'rb') as f: + content = f.read().decode('utf-8') + jso = json.loads(content) + token_exp = int(time.time()) - jso["EXPIRATION_TIME"] + if int(token_exp/60) > 15: + TOKEN = False + elif int(token_exp/60) < 15: + TOKEN = True + + if TOKEN: + access_token = jso['ACCESS_TOKEN'] + + if not TOKEN: + access_token = HMAXClient.login(SESSION, auth_url, content_url) + return get_authorization_header(access_token) + + def mpd_parse(mpd_url): + if args.atmos: + mpd_url = mpd_url.replace('_noatmos', '') + base_url = mpd_url.rsplit('/', 1)[0] + '/' + r = SESSION.get(url=mpd_url) + xml = xmltodict.parse(r.text, force_list={ + 'Period', 'AdaptationSet', 'ContentProtection' + }) + mpd = json.loads(json.dumps(xml)) + period = mpd['MPD']['Period'] + tracks = [] + for pb in period: + tracks = tracks + pb['AdaptationSet'] + + def get_height(width, height): + if width == '1920': + return '1080' + elif width in ('1280', '1248'): + return '720' + else: + return height + + def force_instance(x): + if isinstance(x['Representation'], list): + X = x['Representation'] + else: + X = [x['Representation']] + return X + + def get_pssh(track): + pssh = '' + for t in track.get('ContentProtection', {}): + if (t['@schemeIdUri'].lower() == 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed' + and t.get('pssh', {}).get('#text')): + pssh = t.get('pssh', {}).get('#text') + return pssh + + video_list = [] + for video_tracks in tracks: + if video_tracks['@contentType'] == 'video': + for x in video_tracks['Representation']: + videoDict = { + 'Height':get_height(x['@width'], x['@height']), + 'Width':x['@width'], + 'Bandwidth':x['@bandwidth'], + 'ID':x['@id'], + 'Codec':x['@codecs'], + 'File_URL':x['BaseURL']} + video_list.append(videoDict) + video_list = sorted(video_list, key=(lambda k: int(k['Bandwidth']))) + + if args.videocodec: + if args.videocodec == 'h264': + codec_s = 'avc1' + if args.videocodec == 'hevc': + codec_s = 'hvc1' + if args.videocodec == 'hdr': + codec_s = 'dvh1' + + video_list_tmp = [] + for x in video_list: + if codec_s in x['Codec']: + video_list_tmp.append(x) + video_list = video_list_tmp + + while args.customquality != [] and int(video_list[(-1)]['Height']) > int(args.customquality[0]): + video_list.pop(-1) + + + audio_list = [] + for audio_tracks in tracks: + if audio_tracks['@contentType'] == 'audio': + isAD = False + pssh = get_pssh(audio_tracks) + try: + if audio_tracks['Role']['@value']: + isAD = True + except KeyError: + isAD = False + + if isAD: + lang_id = ReplaceCodeLanguages(audio_tracks["@lang"]) + '-ad' + else: + lang_id = ReplaceCodeLanguages(audio_tracks["@lang"]) + + for x in force_instance(audio_tracks): + audio_dict = { + 'Bandwidth':x['@bandwidth'], + 'ID':x['@id'], + 'Language':lang_id, + 'Codec':x['@codecs'], + 'Channels':x['AudioChannelConfiguration']['@value'], + 'File_URL':x['BaseURL'], + 'isAD':isAD} + audio_list.append(audio_dict) + + audio_list = sorted(audio_list, key=(lambda k: (int(k['Bandwidth']), str(k['Language']))), reverse=True) + + if args.only_2ch_audio: + c = 0 + while c != len(audio_list): + if '-3' in audio_list[c]['Codec'].split('=')[0]: + audio_list.remove(audio_list[c]) + else: + c += 1 + + if args.desc_audio: + c = 0 + while c != len(audio_list): + if not audio_list[c]['isAD']: + audio_list.remove(audio_list[c]) + else: + c += 1 + else: + c = 0 + while c != len(audio_list): + if audio_list[c]['isAD']: + audio_list.remove(audio_list[c]) + else: + c += 1 + + BitrateList = [] + AudioLanguageList = [] + for x in audio_list: + BitrateList.append(x['Bandwidth']) + AudioLanguageList.append(x['Language']) + + BitrateList = alphanumericSort(list(set(BitrateList))) + AudioLanguageList = alphanumericSort(list(set(AudioLanguageList))) + audioList_new = [] + audio_Dict_new = {} + for y in AudioLanguageList: + counter = 0 + for x in audio_list: + if x['Language'] == y and counter == 0: + audio_Dict_new = { + 'Language':x['Language'], + 'Bandwidth':x['Bandwidth'], + 'Codec': x['Codec'], + 'Channels': x['Channels'], + 'File_URL':x['File_URL'], + 'isAD':x['isAD'] + } + audioList_new.append(audio_Dict_new) + counter = counter + 1 + + audioList = audioList_new + audio_list = sorted(audioList, key=(lambda k: (int(k['Bandwidth']), str(k['Language'])))) + + audioList_new = [] + if args.audiolang: + for x in audio_list: + langAbbrev = x['Language'] + if langAbbrev in list(args.audiolang): + audioList_new.append(x) + audio_list = audioList_new + + return (video_list, audio_list, pssh, base_url) + + def get_episodes(ep_str, num_eps): + eps = ep_str.split(',') + eps_final = [] + + for ep in eps: + if '-' in ep: + (start, end) = ep.split('-') + start = int(start) + end = int(end or num_eps) + eps_final += list(range(start, end + 1)) + else: + eps_final.append(int(ep)) + + return eps_final + + def get_season(series_id): + seasons = [] + if args.season: + if args.season == 'all': + seasons = 'all' + elif ',' in args.season: + seasons = [int(x) for x in args.season.split(',')] + elif '-' in args.season: + (start, end) = args.season.split('-') + seasons = list(range(int(start), int(end) + 1)) + else: + seasons = [int(args.season)] + + season_req = SESSION.post(url=content_url, headers=refresh_token(), json=[{"id":series_id}], proxies=proxy_cfg.get_proxy('meta')).json()[0]['body'] + try: + if seasons == 'all': + seasons = [num for num, season in enumerate(season_req['references']['seasons'], start=1)] + except KeyError: + pass + + for season_num in seasons: + if args.all_season: + episode_list = season_req['references']['episodes'] + else: + try: + season_id = season_req['references']['seasons'][int(season_num)-1] + episode_req = SESSION.post(url=content_url, headers=refresh_token(), json=[{"id":season_id}], proxies=proxy_cfg.get_proxy('meta')).json()[0]['body'] + episode_list = episode_req['references']['episodes'] + except KeyError: + episode_list = season_req['references']['episodes'] + + episodes_list_new = [] + for num, ep in enumerate(episode_list, start=1): + episodes_list_new.insert(num - 0, { + 'id': ep, + 'episode_num': num}) + episode_list = sorted(episodes_list_new, key=lambda x: x['episode_num']) + + if args.episodeStart: + eps = get_episodes(args.episodeStart, len(episode_list)) + episode_list = [x for x in episode_list if x['episode_num'] in eps] + + for episode in episode_list: + get_metadata(content_id=episode['id']) + + def get_video_id(content_id): + video_id = 'preview' + while 'preview' in video_id: + video_resp = SESSION.post(url=content_url, headers=refresh_token(), json=HMAXClient.get_video_payload(content_id)).json() + if video_resp[0]["statusCode"] > 200: + print(video_resp[0]['body']['message']) + exit(1) + video_id = [item['body']['references']['video'] for (i, item) in enumerate(video_resp) if 'video' in item['body']['references']][0] + mpd_url, length, subs_list, chapters = get_infos(video_id) + return video_resp[0]['body'], mpd_url, length, subs_list, chapters + + def get_infos(video_id): + video_json = SESSION.post(url=content_url, headers=refresh_token(), json=HMAXClient.get_video_payload(video_id)).json()[0]['body'] + try: + mpd_url = video_json['fallbackManifest'] + except KeyError: + mpd_url = video_json['manifest'] + for x in video_json['videos']: + if x['type'] == 'urn:video:main': + length = float(x['duration']) + return mpd_url, length, get_subtitles(video_json), get_chapters(video_json) + + def get_chapters(video_json): + chapters = [] + for x in video_json['videos']: + if 'annotations' in x: + for (i, chapter) in enumerate(x['annotations']): + secs, ms = divmod(chapter['start'], 1) + mins, secs = divmod(secs, 60) + hours, mins = divmod(mins, 60) + ms = ms * 10000; + chapter_time = '%02d:%02d:%02d.%04d' % (hours, mins, secs, ms) + chapters.append({'TEXT':chapter['secondaryType'], 'TIME': chapter_time}) + return chapters + + def get_subtitles(video_json): + subs_list = [] + for x in video_json['videos']: + if x['type'] == 'urn:video:main': + if 'textTracks' in x: + for sub in x['textTracks']: + + isCC = False + if 'ClosedCaptions' in sub["type"]: + isCC = True + isNormal = False + if isCC: + lang_id = ReplaceCodeLanguages(sub['language']) + '-sdh' + trackType = 'SDH' + else: + lang_id = ReplaceCodeLanguages(sub['language']) + isNormal = True + trackType = 'NORMAL' + isForced = False + if sub["type"] == "Forced": + isForced = True + isNormal = False + trackType = 'FORCED' + lang_id = ReplaceCodeLanguages(sub['language']) + '-forced' + subsDict = { + 'Language':lang_id, + 'URL':sub['url'], + 'isCC':isCC, + 'isForced':isForced, + 'isNormal':isNormal, + 'Type':trackType} + subs_list.append(subsDict) + + subs_list_new = [] + subs_for_list_new = [] + for subs in subs_list: + isForced = subs['isForced'] + if isForced: + subs_for_list_new.append(subs) + else: + subs_list_new.append(subs) + + subs_for_list = [] + for subs in subs_for_list_new: + lang = subs['Language'] + if args.forcedlang: + if lang in args.forcedlang: + subs_for_list.append(subs) + else: + subs_for_list.append(subs) + + subs_list = [] + for subs in subs_list_new: + lang = subs['Language'] + if args.sublang: + if lang in args.sublang: + subs_list.append(subs) + else: + subs_list.append(subs) + + subs_list_new = [] + subs_list_new = subs_list + subs_for_list + subs_list = subs_list_new + + return subs_list + + def get_metadata(content_id): + meta_resp, mpd_url, length, subs_list, chapters = get_video_id(content_id) + + if 'feature' in args.url_season: + hbomaxType = "movie" + releaseYear = meta_resp['releaseYear'] + seriesTitles = meta_resp['titles']['full'] + episodeTitle = meta_resp['titles']['full'] + + if 'numberInSeries' in meta_resp: + hbomaxType = "show" + numberInSeries = meta_resp['numberInSeries'] + seriesTitles = meta_resp['seriesTitles']['full'] + episodeTitle = meta_resp['titles']['full'] + + if 'numberInSeason' in meta_resp: + hbomaxType = "show" + seriesTitles = meta_resp['seriesTitles']['full'] + seasonNumber = meta_resp['seasonNumber'] + episodeNumber = meta_resp['numberInSeason'] + episodeTitle = meta_resp['titles']['full'] + + if hbomaxType=="movie": + seriesName = f'{replace_words(episodeTitle)} ({releaseYear})' + folderName = None + + if hbomaxType=="show": + try: + seriesName = f'{replace_words(seriesTitles)} S{seasonNumber:02}E{episodeNumber:02} - {replace_words(episodeTitle)}' + folderName = f'{replace_words(seriesTitles)} S{seasonNumber:02}' + except UnboundLocalError: + seriesName = f'{replace_words(seriesTitles)} E{numberInSeries:02} - {replace_words(episodeTitle)}' + folderName = f'{replace_words(seriesTitles)}' + + start_process(seriesName, folderName, subs_list, mpd_url, length, chapters, hbomaxType) + + def start_process(seriesName, folderName, subs_list, mpd_url, length, chapters, hbomaxType): + video_list, audio_list, pssh, base_url = mpd_parse(mpd_url) + video_bandwidth = dict(video_list[(-1)])['Bandwidth'] + video_height = str(dict(video_list[(-1)])['Height']) + video_width = str(dict(video_list[(-1)])['Width']) + video_codec = str(dict(video_list[(-1)])['Codec']) + if not args.license: + if not args.novideo: + print('\nVIDEO - Bitrate: ' + convert_size(int(video_bandwidth)) + ' - Profile: ' + video_codec.split('=')[0] + ' - Size: ' + get_size(length * float(video_bandwidth) * 0.125) + ' - Dimensions: ' + video_width + 'x' + video_height) + print() + if not args.noaudio: + if audio_list != []: + for x in audio_list: + audio_bandwidth = x['Bandwidth'] + audio_representation_id = str(x['Codec']) + audio_lang = x['Language'] + print('AUDIO - Bitrate: ' + convert_size(int(audio_bandwidth)) + ' - Profile: ' + audio_representation_id.split('=')[0] + ' - Size: ' + get_size(length * float(audio_bandwidth) * 0.125) + ' - Language: ' + audio_lang) + print() + if not args.nosubs: + if subs_list != []: + for z in subs_list: + sub_lang = str(dict(z)['Language']) + sub_profile = str(dict(z)['Type']) + print('SUBTITLE - Profile: '+ sub_profile +' - Language: ' + sub_lang) + print() + print('Name: ' + seriesName + '\n') + + if args.license: + format_mpd = "" + if 'hvc1' in video_codec: + format_mpd = "HEVC KEYS" + keys_all = get_keys(pssh) + with open(keys_file, 'a', encoding='utf8') as (file): + file.write(seriesName + format_mpd + '\n') + for key in keys_all: + with open(keys_file, 'a', encoding='utf8') as (file): + file.write(key + '\n') + print('\n' + seriesName + ' ' + format_mpd + '\n' + key) + + else: + ''' + if args.tag: + from pywidevine.clients.dictionary import get_release_tag + for x in audio_list: + isDual = False + audio_total = len(audio_list) + if audio_total > 1: + isDual = True + seriesName = get_release_tag(seriesName, video_codec, video_height, x['Codec'], x['Channels'], x['Bandwidth'], 'HMAX', str(args.tag), isDual) + ''' + + if hbomaxType == 'show': + CurrentName = seriesName + CurrentHeigh = str(video_height) + if 'hvc1' in video_codec: + VideoOutputName = folderdownloader + '\\' + str(folderName) + str(CurrentName) + ' [' + str(CurrentHeigh) + 'p] [HEVC].mkv' + if 'dvh1' in video_codec: + VideoOutputName = folderdownloader + '\\' + str(folderName) + str(CurrentName) + ' [' + str(CurrentHeigh) + 'p] [HDR].mkv' + else: + VideoOutputName = folderdownloader + '\\' + str(folderName) + str(CurrentName) + ' [' + str(CurrentHeigh) + 'p].mkv' + + else: + CurrentName = seriesName + CurrentHeigh = str(video_height) + if 'hvc1' in video_codec: + VideoOutputName = str(CurrentName) + ' [' + str(CurrentHeigh) + 'p] [HEVC].mkv' + if 'dvh1' in video_codec: + VideoOutputName = str(CurrentName) + ' [' + str(CurrentHeigh) + 'p] [HDR].mkv' + else: + VideoOutputName = str(CurrentName) + ' [' + str(CurrentHeigh) + 'p].mkv' + + if not args.novideo or (not args.noaudio): + print("Getting KEYS...") + keys_all = get_keys(pssh) + if not keys_all: + print('License request failed, using keys from txt') + keys_all = keys_file_txt + if args.licenses_as_json: + with open(keys_file, "a", encoding="utf8") as file: + file.write(seriesName + "\n") + for key in keys_all: + with open(keys_file, "a", encoding="utf8") as file: + file.write(key + "\n") + print("Done!\n") + + if not os.path.isfile(VideoOutputName): + + print('Downloading video & audio') + aria2c_input = '' + if not args.novideo: + if 'hvc1' in video_codec: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p] [HEVC].mp4' + if 'dvh1' in video_codec: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p] [HDR].mp4' + else: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo) and not os.path.isfile(inputVideo + '.aria2'): + print('\n' + inputVideo + '\nFile has already been successfully downloaded previously.\n') + else: + url = urllib.parse.urljoin(base_url, video_list[(-1)]['File_URL']) + aria2c_input += f'{url}\n' + aria2c_input += f'\tdir={folderdownloader}\n' + aria2c_input += f'\tout={inputVideo}\n' + + #downloadFile(base_url + video_list[(-1)]['File_URL'], inputVideo) + + if not args.noaudio: + for x in audio_list: + langAbbrev = x['Language'] + inputAudio = seriesName + ' ' + '(' + langAbbrev + ')' + '.mp4' + inputAudio_ac3 = seriesName + ' ' + '(' + langAbbrev + ')' + '.ac3' + inputAudio_eac3 = seriesName + ' ' + '(' + langAbbrev + ')' + '.eac3' + inputAudio_m4a = seriesName + ' ' + '(' + langAbbrev + ')' + '.m4a' + if os.path.isfile(inputAudio) and not os.path.isfile(inputAudio + '.aria2') or os.path.isfile(inputAudio_ac3) or os.path.isfile(inputAudio_m4a) or os.path.isfile(inputAudio_eac3): + print('\n' + inputAudio + '\nFile has already been successfully downloaded previously.\n') + else: + url = urllib.parse.urljoin(base_url, x['File_URL']) + aria2c_input += f'{url}\n' + aria2c_input += f'\tdir={folderdownloader}\n' + aria2c_input += f'\tout={inputAudio}\n' + + aria2c_infile = os.path.join(folderdownloader, 'aria2c_infile.txt') + with open(aria2c_infile, 'w') as fd: + fd.write(aria2c_input) + aria2c_opts = [ + HMAXConfig.ARIA2C, + '--allow-overwrite=true', + '--download-result=hide', + '--console-log-level=warn', + '-x16', '-s16', '-j16', + '-i', aria2c_infile] + subprocess.run(aria2c_opts, check=True) + + if not args.nosubs: + if subs_list != []: + for z in subs_list: + langAbbrev = str(dict(z)['Language']) + inputSubtitle = seriesName + " " + "(" + langAbbrev + ")" + if os.path.isfile(inputSubtitle + ".xml") or os.path.isfile(inputSubtitle + ".srt"): + print("\n" + inputSubtitle + "\nFile has already been successfully downloaded previously.\n") + else: + downloadFile2(str(dict(z)['URL']), inputSubtitle + ".xml") + SubtitleEdit_process = subprocess.Popen([HMAXConfig.SUBTITLE_EDIT, "/convert", inputSubtitle + ".xml", "srt", "/fixcommonerrors", "/encoding:utf-8", "/RemoveLineBreaks"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait() + for f in glob.glob(inputSubtitle + ".xml"): + os.remove(f) + print("Done!\n") + else: + print ("\nNo subtitles available.") + + if not args.nochpaters: + if chapters != []: + print('\nGenerating chapters file...') + if os.path.isfile(seriesName + ' Chapters.txt'): + print(seriesName + " Chapters.txt" + " has already been successfully downloaded previously.") + else: + counter = 1 + with open(seriesName + ' Chapters.txt', 'a', encoding='utf-8') as f: + for x in chapters: + f.write("CHAPTER" + f'{counter:02}' + "=" + x["TIME"] + "\n" + "CHAPTER" + f'{counter:02}' + "NAME=" + x["TEXT"] + "\n") + counter = counter + 1 + print('Done!\n') + else: + print("\nNo chapters available.") + + #~NOTE: aqui faz de tudo! Extrai as keys, faz decrypt e muxa os arquivos + + CorrectDecryptVideo = False + if not args.novideo: + if 'hvc1' in video_codec: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p] [HEVC].mp4' + if 'dvh1' in video_codec: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p] [HDR].mp4' + else: + inputVideo = seriesName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo): + CorrectDecryptVideo = DecryptVideo(inputVideo=inputVideo, keys_video=keys_all) + else: + CorrectDecryptVideo = True + + CorrectDecryptAudio = False + if not args.noaudio: + for x in audio_list: + langAbbrev = x['Language'] + inputAudio = seriesName + ' ' + '(' + langAbbrev + ')' + '.mp4' + if os.path.isfile(inputAudio): + CorrectDecryptAudio = DecryptAudio(inputAudio=inputAudio, keys_audio=keys_all) + else: + CorrectDecryptAudio = True + + if not args.nomux: + if not args.novideo: + if not args.noaudio: + if CorrectDecryptVideo == True: + if CorrectDecryptAudio == True: + print('\nMuxing...') + + if hbomaxType=="show": + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=folderName, + CurrentHeigh=CurrentHeigh, + Type=hbomaxType, + mkvmergeexe=HMAXConfig.MKVMERGE) + + else: + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=None, + CurrentHeigh=CurrentHeigh, + Type=hbomaxType, + mkvmergeexe=HMAXConfig.MKVMERGE) + + MKV_Muxer.mkvmerge_muxer(lang="English") + + if args.tag: + if 'hvc1' in video_codec: + inputName = CurrentName + ' [' + CurrentHeigh + 'p] [HEVC].mkv' + if 'dvh1' in video_codec: + inputName = seriesName + ' [' + str(CurrentHeigh) + 'p] [HDR].mkv' + else: + inputName = CurrentName + ' [' + CurrentHeigh + 'p].mkv' + + release_group(base_filename=inputName, + default_filename=CurrentName, + folder_name=folderName, + type=hbomaxType, + video_height=CurrentHeigh) + + if not args.keep: + for f in os.listdir(): + if re.fullmatch(re.escape(CurrentName) + r'.*\.(mp4|m4a|h264|h265|eac3|ac3|srt|txt|avs|lwi|mpd)', f): + os.remove(f) + print('Done!') + else: + print("File '" + str(VideoOutputName) + "' already exists.") + + def title_parse(x): + m = re.match(r'https?://(play\.hbomax\.com/|(?:www\.)hbomax\.com/)(?:page|feature|series|episode)/(urn?:hbo?:(?:feature|series|page|episode):.+?$)', x) + if m: + if 'type' in m[2] and 'series' in m[2]: + m = 'urn:hbo:series:{}'.format(m[2].split(':')[-3]) + elif 'type' in m[2] and 'feature' in m[2]: + m = 'urn:hbo:feature:{}'.format(m[2].split(':')[-3]) + elif 'type' in m[2] and 'episode' in m[2]: + m = 'urn:hbo:episode:{}'.format(m[2].split(':')[-3]) + else: + m = m[2] + return m + + from pywidevine.decrypt.wvdecryptcustom import WvDecrypt + from pywidevine.cdm import cdm, deviceconfig + + def get_keys(pssh): + device = deviceconfig.device_android_generic + wvdecrypt = WvDecrypt(init_data_b64=bytes(pssh.encode()), cert_data_b64=None, device=device) + + license_req = SESSION.post(url=license_wv, headers=refresh_token(), data=wvdecrypt.get_challenge()).content + license_b64 = base64.b64encode(license_req) + + wvdecrypt.update_license(license_b64) + status, keys = wvdecrypt.start_process() + return keys + + def release_group(base_filename, default_filename, folder_name, type, video_height): + if type=='show': + video_mkv = os.path.join(folder_name, base_filename) + else: + video_mkv = base_filename + + mediainfo = mediainfo_(video_mkv) + for v in mediainfo['media']['track']: # mediainfo do video + if v['@type'] == 'Video': + video_format = v['Format'] + + video_codec = '' + if video_format == "AVC": + video_codec = 'H.264' + elif video_format == "HEVC": + video_codec = 'H.265' + + for m in mediainfo['media']['track']: # mediainfo do audio + if m['@type'] == 'Audio': + codec_name = m['Format'] + channels_number = m['Channels'] + + audio_codec = '' + audio_channels = '' + if codec_name == "AAC": + audio_codec = 'AAC' + elif codec_name == "AC-3": + audio_codec = "DD" + elif codec_name == "E-AC-3": + audio_codec = "DDP" + elif codec_name == "E-AC-3 JOC": + audio_codec = "Atmos" + + if channels_number == "2": + audio_channels = "2.0" + elif channels_number == "6": + audio_channels = "5.1" + + audio_ = audio_codec + audio_channels + + # renomear arquivo + default_filename = default_filename.replace('&', '.and.') + default_filename = re.sub(r'[]!"#$%\'()*+,:;<=>?@\\^_`{|}~[-]', '', default_filename) + default_filename = default_filename.replace(' ', '.') + default_filename = re.sub(r'\.{2,}', '.', default_filename) + + output_name = '{}.{}p.HMAX.WEB-DL.{}.{}-{}'.format(default_filename, video_height, audio_, video_codec, args.tag) + if type=='show': + outputName = os.path.join(folder_name, output_name + '.mkv') + else: + outputName = output_name + '.mkv' + + os.rename(video_mkv, outputName) + print("{} -> {}".format(base_filename, output_name)) + + def DecryptAudio(inputAudio, keys_audio): + key_audio_id_original = getKeyId(inputAudio) + outputAudioTemp = inputAudio.replace('.mp4', '_dec.mp4') + if key_audio_id_original != 'nothing': + for key in keys_audio: + key_id = key[0:32] + if key_id == key_audio_id_original: + print('\nDecrypting audio...') + print('Using KEY: ' + key) + wvdecrypt_process = subprocess.Popen([HMAXConfig.MP4DECRYPT, '--show-progress', '--key', key, inputAudio, outputAudioTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + time.sleep(0.05) + os.remove(inputAudio) + print('\nDemuxing audio...') + mediainfo = mediainfo_(outputAudioTemp) + for m in mediainfo['media']['track']: + if m['@type'] == 'Audio': + codec_name = m['Format'] + try: + codec_tag_string = m['Format_Commercial_IfAny'] + except Exception: + codec_tag_string = '' + ext = '' + if codec_name == "AAC": + ext = '.m4a' + elif codec_name == "E-AC-3": + ext = ".eac3" + elif codec_name == "AC-3": + ext = ".ac3" + outputAudio = outputAudioTemp.replace("_dec.mp4", ext) + print("{} -> {}".format(outputAudioTemp, outputAudio)) + ff = ffmpy.FFmpeg(executable=HMAXConfig.FFMPEG, inputs={outputAudioTemp: None}, outputs={outputAudio: '-c copy'}, global_options="-y -hide_banner -loglevel warning") + ff.run() + time.sleep (50.0/1000.0) + os.remove(outputAudioTemp) + print("Done!") + return True + + elif key_audio_id_original == "nothing": + return True + + def DecryptVideo(inputVideo, keys_video): + key_video_id_original = getKeyId(inputVideo) + inputVideo = inputVideo + outputVideoTemp = inputVideo.replace('.mp4', '_dec.mp4') + outputVideo = inputVideo + if key_video_id_original != 'nothing': + for key in keys_video: + key_id = key[0:32] + if key_id == key_video_id_original: + print('\nDecrypting video...') + print('Using KEY: ' + key) + wvdecrypt_process = subprocess.Popen([HMAXConfig.MP4DECRYPT, '--show-progress', '--key', key, inputVideo, outputVideoTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + print('\nRemuxing video...') + ff = ffmpy.FFmpeg(executable=HMAXConfig.FFMPEG, inputs={outputVideoTemp: None}, outputs={outputVideo: '-c copy'}, global_options='-y -hide_banner -loglevel warning') + ff.run() + time.sleep(0.05) + os.remove(outputVideoTemp) + print('Done!') + return True + + elif key_video_id_original == 'nothing': + return True + + global content_id + content_id = title_parse(args.url_season) + + if 'series' in args.url_season: + if not args.season: + args.season = 'all' + get_season(content_id) + elif 'feature' or 'episode': + get_metadata(content_id=content_id) diff --git a/parametros de descargas.txt b/parametros de descargas.txt new file mode 100644 index 0000000..58be986 --- /dev/null +++ b/parametros de descargas.txt @@ -0,0 +1,84 @@ +-h, --help show this help message and exit + -t TITLE, --title TITLE + title id + -wids [WATCH_IDS [WATCH_IDS ...]], --watch-ids [WATCH_IDS [WATCH_IDS ...]] + episode / watch id, extract it straight from an + episode/extra url + --trailers download trailers for the specified title + -o [OUTPUTFILE], --outputfile [OUTPUTFILE] + output filename (no extension) + -q {sd,sd-baseline,sd-main,720p,1080p,2160p,best}, --quality {sd,sd-baseline,sd-main,720p,1080p,2160p,best} + video resolution + -a AUDIOLANG, --audiolang AUDIOLANG + audio language + -c CODEC, --codec CODEC + video type to download + -k, --skip-cleanup skip cleanup step + -dm, --dont-mux move unmuxed tracks instead of muxing + -i, --info print track information and exit + -d, --debug print debug statements + -n {once,every,off}, --notify {once,every,off} + choose notification mode + -S, --subs-only download subtitles and exit + -sl SUB_LANG, --sub-lang SUB_LANG + subtitle languages to download + -st {dfxp,vtt,none}, --sub-type {dfxp,vtt,none} + subtitle format to download + -sc {srt,ass,none}, --sub-convert {srt,ass,none} + subtitle format to convert to + -A, --audio-only download audio and exit + -sA, --skip-audio do NOT download any audio tracks + -ad, --audio-description + download audio description tracks instead of regular + ones + -at, --all-tracks download and merge ALL tracks + -s SEASON, --season SEASON + lookup and download season from title id + -E EPISODE, --episode EPISODE + rip only specified episode(s) in season mode + -e EPISODE_START, --episode_start EPISODE_START + Recursively rip season number that provided viewable + ID belongs to, starting at the episode provided + --skip SKIP skip episodes in season mode + --web-login + --no-web-login use web login method instead of Android API login + method + --license do license request and print decryption keys only + --licenses-as-json, -laj + save the licenses as json instead + --licenses-json-name LICENSES_JSON_NAME, -ljn LICENSES_JSON_NAME + save the licenses-json to a specific name (will be + "keys{name}.json") + --licenses-json-overwrite, -ljo + always overwrite keys.json if it exists (dangerous) + --create-dl-info-json, -dij + Create a JSON file with all metadata + track URLs + (IIRC expire after 24 hours) + working VPN address (if + any found in proxydata.json) + --dl-info-json-name, -ijn + Name of the json stored when using --create-dl-info- + json/-dij + -m, --store-meta store the metadata of the movies (json) + --proxy PROXY proxy URL to use for both fetching metadata and + downloading + --proxy-meta PROXY_META + proxy URL to use for fetching metadata + --proxy-dl PROXY_DL proxy URL to use for downloading + + -r us donde us es la region para estados unidos + + + +[-h] [--url URL_SEASON] [--tqdm] [--nv] [--na] [--ns] + [--all-season] [-e EPISODESTART] [-s SEASON] [--tag TAG] + [-q CUSTOMQUALITY] [-o OUTPUT] [--keep] [--no-mux] + [--only-2ch-audio] [--alang [AUDIOLANG [AUDIOLANG ...]]] + [--slang [SUBLANG [SUBLANG ...]]] + [--flang [FORCEDLANG [FORCEDLANG ...]]] [--hevc] [--uhd] + [--only-keys] [--debug] [--aformat-51ch AFORMAT_51CH] [--nc] + [-c {widevine,playready}] [--atmos] [--ad] [--hdr] + [-r {la,us}] [--m3u8] [--file TXTPATH] [--tlang TITLELANG] + [--scenario SCENARIO] [--proxy PROXY] + [content] + + diff --git a/paramountplus.py b/paramountplus.py new file mode 100644 index 0000000..fa4cfb6 --- /dev/null +++ b/paramountplus.py @@ -0,0 +1,788 @@ +# -*- coding: utf-8 -*- +# Module: Paramount Plus Downloader +# Created on: 19-02-2021 +# Authors: JUNi +# Version: 2.0 + +import urllib.parse +import re, base64, requests, sys, os +import subprocess, shutil +import xmltodict, isodate +import json, ffmpy +import http, html, time + +from unidecode import unidecode +from http.cookiejar import MozillaCookieJar +from titlecase import titlecase +from pymediainfo import MediaInfo + +import pywidevine.clients.paramountplus.config as pmnp_cfg +from pywidevine.clients.proxy_config import ProxyConfig +from pywidevine.muxer.muxer import Muxer + +from pywidevine.clients.paramountplus.downloader import WvDownloader +from pywidevine.clients.paramountplus.config import WvDownloaderConfig + + +currentFile = 'paramountplus' +realPath = os.path.realpath(currentFile) +dirPath = os.path.dirname(realPath) +USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36' +SESSION = requests.Session() + +def main(args): + global _id + + proxies = {} + proxy_meta = args.proxy + if proxy_meta == 'none': + proxies['meta'] = {'http': None, 'https': None} + elif proxy_meta: + proxies['meta'] = {'http': proxy_meta, 'https': proxy_meta} + SESSION.proxies = proxies.get('meta') + proxy_cfg = ProxyConfig(proxies) + + if not os.path.exists(dirPath + '/KEYS'): + os.makedirs(dirPath + '/KEYS') + else: + keys_file = dirPath + '/KEYS/PARAMOUNTPLUS.txt' + try: + keys_file_pmnp = open(keys_file, 'r') + keys_file_txt = keys_file_pmnp.readlines() + except Exception: + with open(keys_file, 'a', encoding='utf8') as (file): + file.write('##### One KEY per line. #####\n') + keys_file_pmnp = open(keys_file, 'r', encoding='utf8') + keys_file_txt = keys_file_pmnp.readlines() + + def alphanumericSort(l): + def convert(text): + if text.isdigit(): + return int(text) + else: + return text + + def alphanum_key(key): + return [convert(c) for c in re.split('([0-9]+)', key)] + + return sorted(l, key=alphanum_key) + + def convert_size(size_bytes): + if size_bytes == 0: + return '0bps' + else: + s = round(size_bytes / 1000, 0) + return '%ikbps' % s + + def get_size(size): + power = 1024 + n = 0 + Dic_powerN = {0:'', 1:'K', 2:'M', 3:'G', 4:'T'} + while size > power: + size /= power + n += 1 + return str(round(size, 2)) + Dic_powerN[n] + 'B' + + def getKeyId(name): + mp4dump = subprocess.Popen([pmnp_cfg.MP4DUMP, name], stdout=(subprocess.PIPE)) + mp4dump = str(mp4dump.stdout.read()) + A = find_str(mp4dump, 'default_KID') + KEY_ID_ORI = '' + KEY_ID_ORI = mp4dump[A:A + 63].replace('default_KID = ', '').replace('[', '').replace(']', '').replace(' ', '') + if KEY_ID_ORI == '' or KEY_ID_ORI == "'": + KEY_ID_ORI = 'nothing' + return KEY_ID_ORI + + def find_str(s, char): + index = 0 + if char in s: + c = char[0] + for ch in s: + if ch == c: + if s[index:index + len(char)] == char: + return index + index += 1 + + return -1 + + def mediainfo_(file): + mediainfo_output = subprocess.Popen([MediaInfo_exe, '--Output=JSON', '-f', file], stdout=(subprocess.PIPE)) + mediainfo_json = json.load(mediainfo_output.stdout) + return mediainfo_json + + def ReplaceDontLikeWord(X): + try: + X = X.replace(" : ", " - ").replace(": ", " - ").replace(":", " - ").replace("&", "and").replace("+", "").replace(";", "").replace("ó", "o").\ + replace("[", "").replace("'", "").replace("]", "").replace("/", "").replace("//", "").\ + replace("’", "'").replace("*", "x").replace("<", "").replace(">", "").replace("|", "").\ + replace("~", "").replace("#", "").replace("%", "").replace("{", "").replace("}", "").replace(",", "").\ + replace("?","").replace("¿","") + except Exception: + X = X.replace(" : ", " - ").replace(": ", " - ").replace(":", " - ").replace("&", "and").replace("+", "").replace(";", "").\ + replace("ó", "o").replace("[", "").replace("'", "").replace("]", "").replace("/", "").\ + replace("//", "").replace("’", "'").replace("*", "x").replace("<", "").replace(">", "").replace("|", "").\ + replace("~", "").replace("#", "").replace("%", "").replace("{", "").replace("}", "").replace(",", "").\ + replace("?","").replace("¿","") + + return titlecase(X) + + def replace_code_lang(X): + X = X.lower() + X = X.replace('es-mx', 'es-la').replace('pt-BR', 'pt-br').replace('dolby digital', 'en').replace('dd+', 'en') + return X + + def get_cookies(file_path): + try: + cj = http.cookiejar.MozillaCookieJar(file_path) + cj.load() + except Exception: + print('\nCookies not found! Please dump the cookies with the Chrome extension https://chrome.google.com/webstore/detail/cookiestxt/njabckikapfpffapmjgojcnbfjonfjfg and place the generated file in ' + file_path) + print('\nWarning, do not click on "download all cookies", you have to click on "click here".\n') + sys.exit(0) + + cookies = str() + for cookie in cj: + cookie.value = urllib.parse.unquote(html.unescape(cookie.value)) + cookies = cookies + cookie.name + '=' + cookie.value + ';' + + cookies = list(cookies) + del cookies[-1] + cookies = ''.join(cookies) + return cookies + + cookies_file = 'cookies_pmnp.txt' + cookies = get_cookies(dirPath + '/cookies/' + cookies_file) + pmnp_headers = { + 'Accept':'application/json, text/plain, */*', + 'Access-Control-Allow-Origin':'*', + 'cookie':cookies, + 'User-Agent':USER_AGENT + } + + def mpd_parsing(mpd_url): + base_url = mpd_url.split('stream.mpd')[0] + r = SESSION.get(url=mpd_url) + r.raise_for_status() + xml = xmltodict.parse(r.text) + mpdf = json.loads(json.dumps(xml)) + length = isodate.parse_duration(mpdf['MPD']['@mediaPresentationDuration']).total_seconds() + tracks = mpdf['MPD']['Period']['AdaptationSet'] + + def get_pssh(track): + pssh = '' + for t in track["ContentProtection"]: + if t['@schemeIdUri'].lower() == 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed': + pssh = t["cenc:pssh"] + return pssh + + def force_instance(x): + if isinstance(x['Representation'], list): + X = x['Representation'] + else: + X = [x['Representation']] + return X + + video_list = [] + for video_tracks in tracks: + if video_tracks['@contentType'] == 'video': + pssh = get_pssh(video_tracks) + for x in force_instance(video_tracks): + try: + codecs = x['@codecs'] + except (KeyError, TypeError): + codecs = video_tracks['@codecs'] + video_dict = { + 'Height':x['@height'], + 'Width':x['@width'], + 'Bandwidth':x['@bandwidth'], + 'ID':x['@id'], + 'TID':video_tracks['@id'], + 'Codec':codecs} + video_list.append(video_dict) + + video_list = sorted(video_list, key=(lambda k: int(k['Bandwidth']))) + + while args.customquality != [] and int(video_list[(-1)]['Height']) > int(args.customquality[0]): + video_list.pop(-1) + + audio_list = [] + for audio_tracks in tracks: + if audio_tracks['@contentType'] == 'audio': + for x in force_instance(audio_tracks): + try: + codecs = x['@codecs'] + except (KeyError, TypeError): + codecs = audio_tracks['@codecs'] + audio_dict = { + 'Bandwidth':x['@bandwidth'], + 'ID':x['@id'], + 'TID':audio_tracks['@id'], + 'Language':replace_code_lang(audio_tracks['@lang']), + 'Codec':codecs} + audio_list.append(audio_dict) + + audio_list = sorted(audio_list, key=(lambda k: (int(k['Bandwidth']), str(k['Language']))), reverse=True) + if args.only_2ch_audio: + c = 0 + while c != len(audio_list): + if '-3' in audio_list[c]['Codec'].split('=')[0]: + audio_list.remove(audio_list[c]) + else: + c += 1 + + BitrateList = [] + AudioLanguageList = [] + for x in audio_list: + BitrateList.append(x['Bandwidth']) + AudioLanguageList.append(x['Language']) + + BitrateList = alphanumericSort(list(set(BitrateList))) + AudioLanguageList = alphanumericSort(list(set(AudioLanguageList))) + audioList_new = [] + audio_Dict_new = {} + for y in AudioLanguageList: + counter = 0 + for x in audio_list: + if x['Language'] == y and counter == 0: + audio_Dict_new = { + 'Language':x['Language'], + 'Bandwidth':x['Bandwidth'], + 'Codec': x['Codec'], + 'TID':x['TID'], + 'ID':x['ID']} + audioList_new.append(audio_Dict_new) + counter = counter + 1 + + audioList = audioList_new + audio_list = sorted(audioList, key=(lambda k: (int(k['Bandwidth']), str(k['Language'])))) + + audioList_new = [] + if args.audiolang: + for x in audio_list: + langAbbrev = x['Language'] + if langAbbrev in list(args.audiolang): + audioList_new.append(x) + audio_list = audioList_new + + return base_url, length, video_list, audio_list, [], pssh, mpdf + + def get_episodes(ep_str, num_eps): + eps = ep_str.split(',') + eps_final = [] + + for ep in eps: + if '-' in ep: + (start, end) = ep.split('-') + start = int(start) + end = int(end or num_eps) + eps_final += list(range(start, end + 1)) + else: + eps_final.append(int(ep)) + + return eps_final + + _id = args.url_season.split('/')[-2] + if '/video/' in args.url_season: + content_regex = r'(\/shows\/)([\w-]+)(\/video\/)([\w-]+)' + url_match = re.search(content_regex, args.url_season) + _id = url_match[2] + + def get_content_info(): + if 'shows' in args.url_season: + pmnp_season_url = 'https://www.paramountplus.com/shows/{}/xhr/episodes/page/0/size/100/xs/0/season/{}/'.format(_id, '') + season_req = requests.get(url=pmnp_season_url, headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + + if not args.season: + args.season = 'all' + + seasons = [] + if args.season: + if args.season == 'all': + seasons = 'all' + elif ',' in args.season: + seasons = [int(x) for x in args.season.split(',')] + elif '-' in args.season: + (start, end) = args.season.split('-') + seasons = list(range(int(start), int(end) + 1)) + else: + seasons = [int(args.season)] + + if seasons == 'all': + seasons_list = [x['season_number'] for x in season_req.json()['result']['data']] + seasons = sorted(set(seasons_list)) + + for season_num in seasons: + pmnp_season_url = 'https://www.paramountplus.com/shows/{}/xhr/episodes/page/0/size/500/xs/0/season/{}/'.format(_id, season_num) + season_req = requests.get(url=pmnp_season_url, headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + if season_req.json()['result']['total'] < 1: + print('This season doesnt exist!') + exit() + + for num, ep in enumerate(season_req.json()['result']['data'], start=1): + episodeNumber = ep['episode_number'] + seasonNumber = ep['season_number'] + seriesTitle = ReplaceDontLikeWord(ep['series_title']) + episodeTitle = ReplaceDontLikeWord(ep['label']) + seriesName = f'{seriesTitle} S{seasonNumber:0>2}E{episodeNumber:0>2} - {episodeTitle}' + folderName = f'{seriesTitle} S{seasonNumber:0>2}' + raw_url = urllib.parse.urljoin('https://www.paramountplus.com', ep['metaData']['contentUrl']) + + episodes_list_new = [] + episodes_dict = { + 'id': ep['content_id'], + 'raw_url': raw_url, + 'pid':ep['metaData']['pid'], + 'seriesName':seriesName, + 'folderName':folderName, + 'episodeNumber': num, + 'seasonNumber':seasonNumber, + 'pmnpType': 'show'} + episodes_list_new.append(episodes_dict) + episodes_list = [] + for x in episodes_list_new: + episodes_list.append(x) + #episodes_list = sorted(episodes_list, key=lambda x: x['episodeNumber']) + + if args.episodeStart: + eps = get_episodes(args.episodeStart, len(episodes_list)) + episodes_list = [x for x in episodes_list if x['episodeNumber'] in eps] + + if 'video' in args.url_season: + episodes_list = [x for x in episodes_list if x['id'] in url_match.group(4)] + + for content_json in episodes_list: + start_process(content_json) + + if 'movies' in args.url_season: + while 1: + resp = requests.get(url=args.url_season + '/', headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + if resp.ok: + break + + html_data = resp + html_data = html_data.text.replace('\r\n', '').replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '') + html_data_list = re.split('()(?i)', html_data) + json_web = [] + for div in html_data_list: + if 'player.paramsVO.adCallParams' in div: + print() + rg = re.compile('(player.metaData = )(.*)(;player.tms_program_id)') + m = rg.search(div) + if m: + json_web = m.group(2) + json_web = json.loads(json_web) + + content_dict = {} + episodes_list = [] + year_regex = r'(\d{4})' + movieTitle = ReplaceDontLikeWord(json_web['seriesTitle']) + try: + r = re.search(year_regex, json_web['airdate']) + except KeyError: + r = re.search(year_regex, json_web['airdate_tv']) + seriesName = f'{movieTitle} ({r.group(0)})' + + content_dict = { + 'id':json_web['contentId'], + 'raw_url': str(args.url_season), + 'pid': json_web['pid'], + 'seriesName':seriesName, + 'folderName':None, + 'episodeNumber':1, + 'seasonNumber':1, + 'pmnpType': 'movie'} + episodes_list.append(content_dict) + + for content_json in episodes_list: + start_process(content_json) + + def get_license(id_json): + while 1: + resp = requests.get(url=id_json['raw_url'], headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + if resp.ok: + break + + html_data = resp + html_data = html_data.text.replace('\r\n', '').replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '') + html_data_list = re.split('()(?i)', html_data) + json_web = [] + for div in html_data_list: + if '(!window.CBS.Registry.drmPromise) {' in div: + rg = re.compile('(player.drm = )(.*)(;}player.enableCP)') + m = rg.search(div) + if m: + json_web = m.group(2) + json_web = json.loads(json_web) + + lic_url = json_web['widevine']['url'] + header_auth = json_web['widevine']['header']['Authorization'] + if not lic_url: + print('Too many requests...') + return lic_url, header_auth + + global folderdownloader + if args.output: + if not os.path.exists(args.output): + os.makedirs(args.output) + os.chdir(args.output) + if ":" in str(args.output): + folderdownloader = str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath + str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath.replace('/','\\').replace('.\\','\\') + + def get_manifest(id_json): + api_manifest = 'https://link.theplatform.com/s/dJ5BDC/{}?format=SMIL&manifest=m3u&Tracking=true&mbr=true'.format(id_json['pid']) + r = requests.get(url=api_manifest, headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + xmls = xmltodict.parse(r.text) + smil = json.loads(json.dumps(xmls)) + videoSrc = [] + try: + for x in smil['smil']['body']['seq']['switch']: + videoSrc = x['video']['@src'] + except Exception: + videoSrc = smil['smil']['body']['seq']['switch']['video']['@src'] + lic_url, header_auth = get_license(id_json) + return {'mpd_url': videoSrc, 'license': lic_url, 'lic_header': header_auth} + + def start_process(content_info): + drm_info = get_manifest(content_info) + base_url, length, video_list, audio_list, subs_list, pssh, xml = mpd_parsing(drm_info['mpd_url']) + video_bandwidth = dict(video_list[(-1)])['Bandwidth'] + video_height = str(dict(video_list[(-1)])['Height']) + video_width = str(dict(video_list[(-1)])['Width']) + video_codec = str(dict(video_list[(-1)])['Codec']) + video_format_id = str(dict(video_list[(-1)])['ID']) + video_track_id = str(dict(video_list[(-1)])['TID']) + if not args.onlykeys: + if not args.novideo: + print('\nVIDEO - Bitrate: ' + convert_size(int(video_bandwidth)) + ' - Profile: ' + video_codec.split('=')[0] + ' - Size: ' + get_size(length * float(video_bandwidth) * 0.125) + ' - Dimensions: ' + video_width + 'x' + video_height) + print() + + if not args.noaudio: + if audio_list != []: + for x in audio_list: + audio_bandwidth = x['Bandwidth'] + audio_representation_id = str(x['Codec']) + audio_lang = x['Language'] + print('AUDIO - Bitrate: ' + convert_size(int(audio_bandwidth)) + ' - Profile: ' + audio_representation_id.split('=')[0] + ' - Size: ' + get_size(length * float(audio_bandwidth) * 0.125) + ' - Language: ' + audio_lang) + print() + + if not args.nosubs: + if subs_list != []: + for z in subs_list: + sub_lang = z['Language'] + print('SUBTITLE - Profile: Normal - Language: ' + sub_lang) + print() + + print('Name: ' + content_info['seriesName']) + + if content_info['pmnpType'] == 'show': + CurrentName = content_info['seriesName'] + CurrentHeigh = str(video_height) + VideoOutputName = folderdownloader + '\\' + str(content_info['folderName']) + '\\' + str(CurrentName) + ' [' + str(CurrentHeigh) + 'p].mkv' + else: + CurrentName = content_info['seriesName'] + CurrentHeigh = str(video_height) + VideoOutputName = folderdownloader + '\\' + str(CurrentName) + '\\' + ' [' + str(CurrentHeigh) + 'p].mkv' + + if args.onlykeys: + keys_all = get_keys(drm_info, pssh) + with open(keys_file, 'a', encoding='utf8') as (file): + file.write(CurrentName + '\n') + print('\n' + CurrentName) + for key in keys_all: + with open(keys_file, 'a', encoding='utf8') as (file): + file.write(key + '\n') + print(key) + + else: + + if not args.novideo or (not args.noaudio): + print("\nGetting KEYS...") + + try: + keys_all = get_keys(drm_info, pssh) + except KeyError: + print('License request failed, using keys from txt') + keys_all = keys_file_txt + else: + with open(keys_file, "a", encoding="utf8") as file: + file.write(CurrentName + "\n") + for key in keys_all: + with open(keys_file, "a", encoding="utf8") as file: + file.write(key + "\n") + print("Done!") + + if not os.path.isfile(VideoOutputName): + + if not args.novideo: + inputVideo = CurrentName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo): + print('\n' + inputVideo + '\nFile has already been successfully downloaded previously.\n') + else: + wvdl_cfg = WvDownloaderConfig(xml, base_url, inputVideo, video_track_id, video_format_id) + wvdownloader = WvDownloader(wvdl_cfg) + wvdownloader.run() + + if not args.noaudio: + for x in audio_list: + langAbbrev = x['Language'] + format_id = x['ID'] + inputAudio = CurrentName + ' ' + '(' + langAbbrev + ').mp4' + inputAudio_demuxed = CurrentName + ' ' + '(' + langAbbrev + ')' + '.m4a' + if os.path.isfile(inputAudio) or os.path.isfile(inputAudio_demuxed): + print('\n' + inputAudio + '\nFile has already been successfully downloaded previously.\n') + else: + wvdl_cfg = WvDownloaderConfig(xml, base_url, inputAudio, x['TID'], x['ID']) + wvdownloader = WvDownloader(wvdl_cfg) + wvdownloader.run() + + CorrectDecryptVideo = False + if not args.novideo: + inputVideo = CurrentName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo): + CorrectDecryptVideo = DecryptVideo(inputVideo=inputVideo, keys_video=keys_all) + else: + CorrectDecryptVideo = True + + CorrectDecryptAudio = False + if not args.noaudio: + for x in audio_list: + langAbbrev = x['Language'] + inputAudio = CurrentName + ' ' + '(' + langAbbrev + ')' + '.mp4' + if os.path.isfile(inputAudio): + CorrectDecryptAudio = DecryptAudio(inputAudio=inputAudio, keys_audio=keys_all) + else: + CorrectDecryptAudio = True + + if not args.nomux: + if not args.novideo: + if not args.noaudio: + if CorrectDecryptVideo == True: + if CorrectDecryptAudio == True: + print('\nMuxing...') + + pmnpType = content_info['pmnpType'] + folderName = content_info['folderName'] + + if pmnpType=="show": + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=folderName, + CurrentHeigh=CurrentHeigh, + Type=pmnpType, + mkvmergeexe=pmnp_cfg.MKVMERGE) + + else: + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=None, + CurrentHeigh=CurrentHeigh, + Type=pmnpType, + mkvmergeexe=pmnp_cfg.MKVMERGE) + + MKV_Muxer.mkvmerge_muxer(lang="English") + + if args.tag: + inputName = CurrentName + ' [' + CurrentHeigh + 'p].mkv' + release_group(base_filename=inputName, + default_filename=CurrentName, + folder_name=folderName, + type=pmnpType, + video_height=CurrentHeigh) + + if not args.keep: + for f in os.listdir(): + if re.fullmatch(re.escape(CurrentName) + r'.*\.(mp4|m4a|h264|h265|eac3|srt|txt|avs|lwi|mpd)', f): + os.remove(f) + print("Done!") + else: + print("\nFile '" + str(VideoOutputName) + "' already exists.") + + def release_group(base_filename, default_filename, folder_name, type, video_height): + if type=='show': + video_mkv = os.path.join(folder_name, base_filename) + else: + video_mkv = base_filename + + mediainfo = mediainfo_(video_mkv) + for v in mediainfo['media']['track']: # mediainfo do video + if v['@type'] == 'Video': + video_format = v['Format'] + + video_codec = '' + if video_format == "AVC": + video_codec = 'H.264' + elif video_format == "HEVC": + video_codec = 'H.265' + + for m in mediainfo['media']['track']: # mediainfo do audio + if m['@type'] == 'Audio': + codec_name = m['Format'] + channels_number = m['Channels'] + + audio_codec = '' + audio_channels = '' + if codec_name == "AAC": + audio_codec = 'AAC' + elif codec_name == "AC-3": + audio_codec = "DD" + elif codec_name == "E-AC-3": + audio_codec = "DDP" + elif codec_name == "E-AC-3 JOC": + audio_codec = "ATMOS" + + if channels_number == "2": + audio_channels = "2.0" + elif channels_number == "6": + audio_channels = "5.1" + + audio_ = audio_codec + audio_channels + + # renomear arquivo + default_filename = default_filename.replace('&', '.and.') + default_filename = re.sub(r'[]!"#$%\'()*+,:;<=>?@\\^_`{|}~[-]', '', default_filename) + default_filename = default_filename.replace(' ', '.') + default_filename = re.sub(r'\.{2,}', '.', default_filename) + default_filename = unidecode(default_filename) + + output_name = '{}.{}p.PMNP.WEB-DL.{}.{}-{}'.format(default_filename, video_height, audio_, video_codec, args.tag) + if type=='show': + outputName = os.path.join(folder_name, output_name + '.mkv') + else: + outputName = output_name + '.mkv' + + os.rename(video_mkv, outputName) + print("{} -> {}".format(base_filename, output_name)) + + from pywidevine.decrypt.wvdecryptcustom import WvDecrypt + from pywidevine.cdm import cdm, deviceconfig + + def do_decrypt(init_data_b64, cert_data_b64, device, licurl, licheader): + wvdecrypt = WvDecrypt(init_data_b64=init_data_b64, cert_data_b64=cert_data_b64, device=deviceconfig.device_android_generic) + chal = wvdecrypt.get_challenge() + headers = { + 'authorization': licheader + } + + try: + license_res = requests.Session().post(url=licurl, data=chal, headers=headers, proxies=proxy_cfg.get_proxy('meta')) + license_base64 = base64.b64encode(license_res.content) + except Exception: + print(license_res.text) + license_base64 = "Error" + return license_base64 + if license_base64 != 'Error': + wvdecrypt.update_license(license_base64) + wvdecrypt.start_process() + Correct, keyswvdecrypt = wvdecrypt.start_process() + return Correct, keyswvdecrypt + else: + keyswvdecrypt = [] + Correct = True + return Correct, keyswvdecrypt + + def get_keys(lic_info, pssh): + Correct = False + keys_new = [] + device = deviceconfig.DeviceConfig(deviceconfig.device_android_generic) + while Correct is False: + Correct, keys_new = do_decrypt(init_data_b64=bytes(pssh.encode()), cert_data_b64=None, device=device, licurl=lic_info['license'], licheader=lic_info['lic_header']) + return keys_new + + def DecryptAudio(inputAudio, keys_audio): + key_audio_id_original = getKeyId(inputAudio) + outputAudioTemp = inputAudio.replace(".mp4", "_dec.mp4") + if key_audio_id_original != "nothing": + for key in keys_audio: + key_id=key[0:32] + if key_id == key_audio_id_original: + print("\nDecrypting audio...") + print ("Using KEY: " + key) + wvdecrypt_process = subprocess.Popen([pmnp_cfg.MP4DECRYPT, "--show-progress", "--key", key, inputAudio, outputAudioTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + time.sleep (50.0/1000.0) + os.remove(inputAudio) + print("\nDemuxing audio...") + mediainfo = MediaInfo.parse(outputAudioTemp) + audio_info = next(x for x in mediainfo.tracks if x.track_type == "Audio") + codec_name = audio_info.format + + ext = '' + if codec_name == "AAC": + ext = '.m4a' + elif codec_name == "E-AC-3": + ext = ".eac3" + elif codec_name == "AC-3": + ext = ".ac3" + outputAudio = outputAudioTemp.replace("_dec.mp4", ext) + print("{} -> {}".format(outputAudioTemp, outputAudio)) + ff = ffmpy.FFmpeg(executable=pmnp_cfg.FFMPEG, inputs={outputAudioTemp: None}, outputs={outputAudio: '-c copy'}, global_options="-y -hide_banner -loglevel warning") + ff.run() + time.sleep (50.0/1000.0) + os.remove(outputAudioTemp) + print("Done!") + return True + + elif key_audio_id_original == "nothing": + return True + + def DecryptVideo(inputVideo, keys_video): + key_video_id_original = getKeyId(inputVideo) + inputVideo = inputVideo + outputVideoTemp = inputVideo.replace('.mp4', '_dec.mp4') + outputVideo = inputVideo + if key_video_id_original != 'nothing': + for key in keys_video: + key_id = key[0:32] + if key_id == key_video_id_original: + print('\nDecrypting video...') + print('Using KEY: ' + key) + wvdecrypt_process = subprocess.Popen([pmnp_cfg.MP4DECRYPT, '--show-progress', '--key', key, inputVideo, outputVideoTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + print('\nRemuxing video...') + ff = ffmpy.FFmpeg(executable=pmnp_cfg.FFMPEG, inputs={outputVideoTemp: None}, outputs={outputVideo: '-c copy'}, global_options='-y -hide_banner -loglevel warning') + ff.run() + time.sleep(0.05) + os.remove(outputVideoTemp) + print('Done!') + return True + + elif key_video_id_original == 'nothing': + return True + + def DemuxAudio(inputAudio): + if os.path.isfile(inputAudio): + print('\nDemuxing audio...') + mediainfo = mediainfo_(inputAudio) + for m in mediainfo['media']['track']: + if m['@type'] == 'Audio': + codec_name = m['Format'] + try: + codec_tag_string = m['Format_Commercial_IfAny'] + except Exception: + codec_tag_string = '' + + ext = '' + if codec_name == 'AAC': + ext = '.m4a' + else: + if codec_name == 'E-AC-3': + ext = '.eac3' + else: + if codec_name == 'AC-3': + ext = '.ac3' + outputAudio = inputAudio.replace('.mp4', ext) + print('{} -> {}'.format(inputAudio, outputAudio)) + ff = ffmpy.FFmpeg(executable=pmnp_cfg.FFMPEG, + inputs={inputAudio: None}, + outputs={outputAudio: '-c copy'}, + global_options='-y -hide_banner -loglevel warning') + ff.run() + time.sleep(0.05) + os.remove(inputAudio) + print('Done!') + + get_content_info() diff --git a/paramountplus_original.py b/paramountplus_original.py new file mode 100644 index 0000000..24423aa --- /dev/null +++ b/paramountplus_original.py @@ -0,0 +1,789 @@ +# -*- coding: utf-8 -*- +# Module: Paramount Plus Downloader +# Created on: 19-02-2021 +# Authors: JUNi +# Version: 2.0 + +import urllib.parse +import re, base64, requests, sys, os +import subprocess, shutil +import xmltodict, isodate +import json, ffmpy +import http, html, time + +from unidecode import unidecode +from http.cookiejar import MozillaCookieJar +from titlecase import titlecase + +from pywidevine.clients.proxy_config import ProxyConfig +from pywidevine.muxer.muxer import Muxer + +from pywidevine.clients.paramountplus.downloader import WvDownloader +from pywidevine.clients.paramountplus.config import WvDownloaderConfig + + +currentFile = 'paramountplus' +realPath = os.path.realpath(currentFile) +dirPath = os.path.dirname(realPath) +USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36' +SESSION = requests.Session() + +def main(args): + global _id + + mp4decryptexe = "mp4decrypt" + mp4dumptexe = "mp4dump" + ffmpegpath = "ffmpeg" + mkvmergeexe = "mkvmerge" + MediaInfo_exe = shutil.which("mediainfo") or shutil.which("MediaInfo") + + proxies = {} + proxy_meta = args.proxy + if proxy_meta == 'none': + proxies['meta'] = {'http': None, 'https': None} + elif proxy_meta: + proxies['meta'] = {'http': proxy_meta, 'https': proxy_meta} + SESSION.proxies = proxies.get('meta') + proxy_cfg = ProxyConfig(proxies) + + if not os.path.exists(dirPath + '/KEYS'): + os.makedirs(dirPath + '/KEYS') + else: + keys_file = dirPath + '/KEYS/PARAMOUNTPLUS.txt' + try: + keys_file_pmnp = open(keys_file, 'r') + keys_file_txt = keys_file_pmnp.readlines() + except Exception: + with open(keys_file, 'a', encoding='utf8') as (file): + file.write('##### One KEY per line. #####\n') + keys_file_pmnp = open(keys_file, 'r', encoding='utf8') + keys_file_txt = keys_file_pmnp.readlines() + + def alphanumericSort(l): + def convert(text): + if text.isdigit(): + return int(text) + else: + return text + + def alphanum_key(key): + return [convert(c) for c in re.split('([0-9]+)', key)] + + return sorted(l, key=alphanum_key) + + def convert_size(size_bytes): + if size_bytes == 0: + return '0bps' + else: + s = round(size_bytes / 1000, 0) + return '%ikbps' % s + + def get_size(size): + power = 1024 + n = 0 + Dic_powerN = {0:'', 1:'K', 2:'M', 3:'G', 4:'T'} + while size > power: + size /= power + n += 1 + return str(round(size, 2)) + Dic_powerN[n] + 'B' + + def getKeyId(name): + mp4dump = subprocess.Popen([mp4dumptexe, name], stdout=(subprocess.PIPE)) + mp4dump = str(mp4dump.stdout.read()) + A = find_str(mp4dump, 'default_KID') + KEY_ID_ORI = '' + KEY_ID_ORI = mp4dump[A:A + 63].replace('default_KID = ', '').replace('[', '').replace(']', '').replace(' ', '') + if KEY_ID_ORI == '' or KEY_ID_ORI == "'": + KEY_ID_ORI = 'nothing' + return KEY_ID_ORI + + def find_str(s, char): + index = 0 + if char in s: + c = char[0] + for ch in s: + if ch == c: + if s[index:index + len(char)] == char: + return index + index += 1 + + return -1 + + def mediainfo_(file): + mediainfo_output = subprocess.Popen([MediaInfo_exe, '--Output=JSON', '-f', file], stdout=(subprocess.PIPE)) + mediainfo_json = json.load(mediainfo_output.stdout) + return mediainfo_json + + def ReplaceDontLikeWord(X): + try: + X = X.replace(" : ", " - ").replace(": ", " - ").replace(":", " - ").replace("&", "and").replace("+", "").replace(";", "").replace("ó", "o").\ + replace("[", "").replace("'", "").replace("]", "").replace("/", "").replace("//", "").\ + replace("’", "'").replace("*", "x").replace("<", "").replace(">", "").replace("|", "").\ + replace("~", "").replace("#", "").replace("%", "").replace("{", "").replace("}", "").replace(",", "").\ + replace("?","").replace("¿","") + except Exception: + X = X.replace(" : ", " - ").replace(": ", " - ").replace(":", " - ").replace("&", "and").replace("+", "").replace(";", "").\ + replace("ó", "o").replace("[", "").replace("'", "").replace("]", "").replace("/", "").\ + replace("//", "").replace("’", "'").replace("*", "x").replace("<", "").replace(">", "").replace("|", "").\ + replace("~", "").replace("#", "").replace("%", "").replace("{", "").replace("}", "").replace(",", "").\ + replace("?","").replace("¿","") + + return titlecase(X) + + def replace_code_lang(X): + X = X.lower() + X = X.replace('es-mx', 'es-la').replace('pt-BR', 'pt-br').replace('dolby digital', 'en').replace('dd+', 'en') + return X + + def get_cookies(file_path): + try: + cj = http.cookiejar.MozillaCookieJar(file_path) + cj.load() + except Exception: + print('\nCookies not found! Please dump the cookies with the Chrome extension https://chrome.google.com/webstore/detail/cookiestxt/njabckikapfpffapmjgojcnbfjonfjfg and place the generated file in ' + file_path) + print('\nWarning, do not click on "download all cookies", you have to click on "click here".\n') + sys.exit(0) + + cookies = str() + for cookie in cj: + cookie.value = urllib.parse.unquote(html.unescape(cookie.value)) + cookies = cookies + cookie.name + '=' + cookie.value + ';' + + cookies = list(cookies) + del cookies[-1] + cookies = ''.join(cookies) + return cookies + + cookies_file = 'cookies_pmnp.txt' + cookies = get_cookies(dirPath + '/cookies/' + cookies_file) + pmnp_headers = { + 'Accept':'application/json, text/plain, */*', + 'Access-Control-Allow-Origin':'*', + 'cookie':cookies, + 'User-Agent':USER_AGENT + } + + def mpd_parsing(mpd_url): + base_url = mpd_url.split('stream.mpd')[0] + r = SESSION.get(url=mpd_url) + r.raise_for_status() + xml = xmltodict.parse(r.text) + mpdf = json.loads(json.dumps(xml)) + length = isodate.parse_duration(mpdf['MPD']['@mediaPresentationDuration']).total_seconds() + tracks = mpdf['MPD']['Period']['AdaptationSet'] + + def get_pssh(track): + pssh = '' + for t in track["ContentProtection"]: + if t['@schemeIdUri'].lower() == 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed': + pssh = t["cenc:pssh"] + return pssh + + def force_instance(x): + if isinstance(x['Representation'], list): + X = x['Representation'] + else: + X = [x['Representation']] + return X + + video_list = [] + for video_tracks in tracks: + if video_tracks['@contentType'] == 'video': + pssh = get_pssh(video_tracks) + for x in force_instance(video_tracks): + try: + codecs = x['@codecs'] + except (KeyError, TypeError): + codecs = video_tracks['@codecs'] + video_dict = { + 'Height':x['@height'], + 'Width':x['@width'], + 'Bandwidth':x['@bandwidth'], + 'ID':x['@id'], + 'TID':video_tracks['@id'], + 'Codec':codecs} + video_list.append(video_dict) + + video_list = sorted(video_list, key=(lambda k: int(k['Bandwidth']))) + + while args.customquality != [] and int(video_list[(-1)]['Height']) > int(args.customquality[0]): + video_list.pop(-1) + + audio_list = [] + for audio_tracks in tracks: + if audio_tracks['@contentType'] == 'audio': + for x in force_instance(audio_tracks): + try: + codecs = x['@codecs'] + except (KeyError, TypeError): + codecs = audio_tracks['@codecs'] + audio_dict = { + 'Bandwidth':x['@bandwidth'], + 'ID':audio_tracks['@id'], + 'TID':audio_tracks['@id'], + 'Language':replace_code_lang(audio_tracks['@lang']), + 'Codec':codecs} + audio_list.append(audio_dict) + + audio_list = sorted(audio_list, key=(lambda k: (int(k['Bandwidth']), str(k['Language']))), reverse=True) + if args.only_2ch_audio: + c = 0 + while c != len(audio_list): + if '-3' in audio_list[c]['Codec'].split('=')[0]: + audio_list.remove(audio_list[c]) + else: + c += 1 + + BitrateList = [] + AudioLanguageList = [] + for x in audio_list: + BitrateList.append(x['Bandwidth']) + AudioLanguageList.append(x['Language']) + + BitrateList = alphanumericSort(list(set(BitrateList))) + AudioLanguageList = alphanumericSort(list(set(AudioLanguageList))) + audioList_new = [] + audio_Dict_new = {} + for y in AudioLanguageList: + counter = 0 + for x in audio_list: + if x['Language'] == y and counter == 0: + audio_Dict_new = { + 'Language':x['Language'], + 'Bandwidth':x['Bandwidth'], + 'Codec': x['Codec'], + 'TID':x['TID'], + 'ID':x['ID']} + audioList_new.append(audio_Dict_new) + counter = counter + 1 + + audioList = audioList_new + audio_list = sorted(audioList, key=(lambda k: (int(k['Bandwidth']), str(k['Language'])))) + + audioList_new = [] + if args.audiolang: + for x in audio_list: + langAbbrev = x['Language'] + if langAbbrev in list(args.audiolang): + audioList_new.append(x) + audio_list = audioList_new + + return base_url, length, video_list, audio_list, pssh, xml + + def get_episodes(ep_str, num_eps): + eps = ep_str.split(',') + eps_final = [] + + for ep in eps: + if '-' in ep: + (start, end) = ep.split('-') + start = int(start) + end = int(end or num_eps) + eps_final += list(range(start, end + 1)) + else: + eps_final.append(int(ep)) + + return eps_final + + _id = args.url_season.split('/')[-2] + if '/video/' in args.url_season: + content_regex = r'(\/shows\/)([\w-]+)(\/video\/)([\w-]+)' + url_match = re.search(content_regex, args.url_season) + _id = url_match[2] + + def get_content_info(): + if 'shows' in args.url_season: + pmnp_season_url = 'https://www.paramountplus.com/shows/{}/xhr/episodes/page/0/size/100/xs/0/season/{}/'.format(_id, '') + season_req = requests.get(url=pmnp_season_url, headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + + if not args.season: + args.season = 'all' + + seasons = [] + if args.season: + if args.season == 'all': + seasons = 'all' + elif ',' in args.season: + seasons = [int(x) for x in args.season.split(',')] + elif '-' in args.season: + (start, end) = args.season.split('-') + seasons = list(range(int(start), int(end) + 1)) + else: + seasons = [int(args.season)] + + if seasons == 'all': + seasons_list = [x['season_number'] for x in season_req.json()['result']['data']] + seasons = sorted(set(seasons_list)) + + for season_num in seasons: + pmnp_season_url = 'https://www.paramountplus.com/shows/{}/xhr/episodes/page/0/size/500/xs/0/season/{}/'.format(_id, season_num) + season_req = requests.get(url=pmnp_season_url, headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + if season_req.json()['result']['total'] < 1: + print('This season doesnt exist!') + exit() + + for num, ep in enumerate(season_req.json()['result']['data'], start=1): + episodeNumber = ep['episode_number'] + seasonNumber = ep['season_number'] + seriesTitle = ReplaceDontLikeWord(ep['series_title']) + episodeTitle = ReplaceDontLikeWord(ep['label']) + seriesName = f'{seriesTitle} S{seasonNumber:0>2}E{episodeNumber:0>2} - {episodeTitle}' + folderName = f'{seriesTitle} S{seasonNumber:0>2}' + raw_url = urllib.parse.urljoin('https://www.paramountplus.com', ep['metaData']['contentUrl']) + + episodes_list_new = [] + episodes_dict = { + 'id': ep['content_id'], + 'raw_url': raw_url, + 'pid':ep['metaData']['pid'], + 'seriesName':seriesName, + 'folderName':folderName, + 'episodeNumber': num, + 'seasonNumber':seasonNumber, + 'pmnpType': 'show'} + episodes_list_new.append(episodes_dict) + episodes_list = [] + for x in episodes_list_new: + episodes_list.append(x) + #episodes_list = sorted(episodes_list, key=lambda x: x['episodeNumber']) + + if args.episodeStart: + eps = get_episodes(args.episodeStart, len(episodes_list)) + episodes_list = [x for x in episodes_list if x['episodeNumber'] in eps] + + if 'video' in args.url_season: + episodes_list = [x for x in episodes_list if x['id'] in url_match.group(4)] + + for content_json in episodes_list: + start_process(content_json) + + if 'movies' in args.url_season: + while 1: + resp = requests.get(url=args.url_season + '/', headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + if resp.ok: + break + + html_data = resp + html_data = html_data.text.replace('\r\n', '').replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '') + html_data_list = re.split('()(?i)', html_data) + json_web = [] + for div in html_data_list: + if 'player.paramsVO.adCallParams' in div: + print() + rg = re.compile('(player.metaData = )(.*)(;player.tms_program_id)') + m = rg.search(div) + if m: + json_web = m.group(2) + json_web = json.loads(json_web) + + content_dict = {} + episodes_list = [] + year_regex = r'(\d{4})' + movieTitle = ReplaceDontLikeWord(json_web['seriesTitle']) + try: + r = re.search(year_regex, json_web['airdate']) + except KeyError: + r = re.search(year_regex, json_web['airdate_tv']) + seriesName = f'{movieTitle} ({r.group(0)})' + + content_dict = { + 'id':json_web['contentId'], + 'raw_url': str(args.url_season), + 'pid': json_web['pid'], + 'seriesName':seriesName, + 'folderName':None, + 'episodeNumber':1, + 'seasonNumber':1, + 'pmnpType': 'movie'} + episodes_list.append(content_dict) + + for content_json in episodes_list: + start_process(content_json) + + def get_license(id_json): + while 1: + resp = requests.get(url=id_json['raw_url'], headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + if resp.ok: + break + + html_data = resp + html_data = html_data.text.replace('\r\n', '').replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '') + html_data_list = re.split('()(?i)', html_data) + json_web = [] + for div in html_data_list: + if '(!window.CBS.Registry.drmPromise) {' in div: + rg = re.compile('(player.drm = )(.*)(;}player.enableCP)') + m = rg.search(div) + if m: + json_web = m.group(2) + json_web = json.loads(json_web) + + lic_url = json_web['widevine']['url'] + header_auth = json_web['widevine']['header']['Authorization'] + if not lic_url: + print('Too many requests...') + return lic_url, header_auth + + global folderdownloader + if args.output: + if not os.path.exists(args.output): + os.makedirs(args.output) + os.chdir(args.output) + if ":" in str(args.output): + folderdownloader = str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath + str(args.output).replace('/','\\').replace('.\\','\\') + else: + folderdownloader = dirPath.replace('/','\\').replace('.\\','\\') + + def get_manifest(id_json): + api_manifest = 'https://link.theplatform.com/s/dJ5BDC/{}?format=SMIL&manifest=m3u&Tracking=true&mbr=true'.format(id_json['pid']) + r = requests.get(url=api_manifest, headers=pmnp_headers, proxies=proxy_cfg.get_proxy('meta')) + xmls = xmltodict.parse(r.text) + smil = json.loads(json.dumps(xmls)) + videoSrc = [] + try: + for x in smil['smil']['body']['seq']['switch']: + videoSrc = x['video']['@src'] + except Exception: + videoSrc = smil['smil']['body']['seq']['switch']['video']['@src'] + lic_url, header_auth = get_license(id_json) + return {'mpd_url': videoSrc, 'license': lic_url, 'lic_header': header_auth} + + def start_process(content_info): + drm_info = get_manifest(content_info) + base_url, length, video_list, audio_list, pssh, xml = mpd_parsing(drm_info['mpd_url']) + video_bandwidth = dict(video_list[(-1)])['Bandwidth'] + video_height = str(dict(video_list[(-1)])['Height']) + video_width = str(dict(video_list[(-1)])['Width']) + video_codec = str(dict(video_list[(-1)])['Codec']) + video_format_id = str(dict(video_list[(-1)])['ID']) + video_track_id = str(dict(video_list[(-1)])['TID']) + if not args.onlykeys: + if not args.novideo: + print('\nVIDEO - Bitrate: ' + convert_size(int(video_bandwidth)) + ' - Profile: ' + video_codec.split('=')[0] + ' - Size: ' + get_size(length * float(video_bandwidth) * 0.125) + ' - Dimensions: ' + video_width + 'x' + video_height) + print() + + if not args.noaudio: + if audio_list != []: + for x in audio_list: + audio_bandwidth = x['Bandwidth'] + audio_representation_id = str(x['Codec']) + audio_lang = x['Language'] + print('AUDIO - Bitrate: ' + convert_size(int(audio_bandwidth)) + ' - Profile: ' + audio_representation_id.split('=')[0] + ' - Size: ' + get_size(length * float(audio_bandwidth) * 0.125) + ' - Language: ' + audio_lang) + print() + + print('Name: ' + content_info['seriesName']) + + if content_info['pmnpType'] == 'show': + CurrentName = content_info['seriesName'] + CurrentHeigh = str(video_height) + VideoOutputName = folderdownloader + '\\' + str(content_info['folderName']) + '\\' + str(CurrentName) + ' [' + str(CurrentHeigh) + 'p].mkv' + else: + CurrentName = content_info['seriesName'] + CurrentHeigh = str(video_height) + VideoOutputName = folderdownloader + '\\' + str(CurrentName) + '\\' + ' [' + str(CurrentHeigh) + 'p].mkv' + + if args.onlykeys: + keys_all = get_keys(drm_info, pssh) + with open(keys_file, 'a', encoding='utf8') as (file): + file.write(CurrentName + '\n') + print('\n' + CurrentName) + for key in keys_all: + with open(keys_file, 'a', encoding='utf8') as (file): + file.write(key + '\n') + print(key) + + else: + + if not args.novideo or (not args.noaudio): + print("\nGetting KEYS...") + + try: + keys_all = get_keys(drm_info, pssh) + except KeyError: + print('License request failed, using keys from txt') + keys_all = keys_file_txt + else: + with open(keys_file, "a", encoding="utf8") as file: + file.write(CurrentName + "\n") + for key in keys_all: + with open(keys_file, "a", encoding="utf8") as file: + file.write(key + "\n") + print("Done!") + + if not os.path.isfile(VideoOutputName): + + if not args.novideo: + inputVideo = CurrentName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo): + print('\n' + inputVideo + '\nFile has already been successfully downloaded previously.\n') + else: + wvdl_cfg = WvDownloaderConfig(xml, base_url, inputVideo, video_track_id, video_format_id, 'video') + wvdownloader = WvDownloader(wvdl_cfg) + wvdownloader.run() + + if not args.noaudio: + for x in audio_list: + langAbbrev = x['Language'] + format_id = x['ID'] + inputAudio = CurrentName + ' ' + '(' + langAbbrev + ').mp4' + inputAudio_demuxed = CurrentName + ' ' + '(' + langAbbrev + ')' + '.m4a' + if os.path.isfile(inputAudio) or os.path.isfile(inputAudio_demuxed): + print('\n' + inputAudio + '\nFile has already been successfully downloaded previously.\n') + else: + wvdl_cfg = WvDownloaderConfig(xml, base_url, inputAudio, x['TID'], x['ID'], 'audio') + wvdownloader = WvDownloader(wvdl_cfg) + wvdownloader.run() + + CorrectDecryptVideo = False + if not args.novideo: + inputVideo = CurrentName + ' [' + str(CurrentHeigh) + 'p].mp4' + if os.path.isfile(inputVideo): + CorrectDecryptVideo = DecryptVideo(inputVideo=inputVideo, keys_video=keys_all) + else: + CorrectDecryptVideo = True + + CorrectDecryptAudio = False + if not args.noaudio: + for x in audio_list: + langAbbrev = x['Language'] + inputAudio = CurrentName + ' ' + '(' + langAbbrev + ')' + '.mp4' + if os.path.isfile(inputAudio): + CorrectDecryptAudio = DecryptAudio(inputAudio=inputAudio, keys_audio=keys_all) + else: + CorrectDecryptAudio = True + + if not args.nomux: + if not args.novideo: + if not args.noaudio: + if CorrectDecryptVideo == True: + if CorrectDecryptAudio == True: + print('\nMuxing...') + + pmnpType = content_info['pmnpType'] + folderName = content_info['folderName'] + + if pmnpType=="show": + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=folderName, + CurrentHeigh=CurrentHeigh, + Type=pmnpType, + mkvmergeexe=mkvmergeexe) + + else: + MKV_Muxer=Muxer(CurrentName=CurrentName, + SeasonFolder=None, + CurrentHeigh=CurrentHeigh, + Type=pmnpType, + mkvmergeexe=mkvmergeexe) + + MKV_Muxer.mkvmerge_muxer(lang="English") + + if args.tag: + inputName = CurrentName + ' [' + CurrentHeigh + 'p].mkv' + release_group(base_filename=inputName, + default_filename=CurrentName, + folder_name=folderName, + type=pmnpType, + video_height=CurrentHeigh) + + if not args.keep: + for f in os.listdir(): + if re.fullmatch(re.escape(CurrentName) + r'.*\.(mp4|m4a|h264|h265|eac3|srt|txt|avs|lwi|mpd)', f): + os.remove(f) + print("Done!") + else: + print("\nFile '" + str(VideoOutputName) + "' already exists.") + + def release_group(base_filename, default_filename, folder_name, type, video_height): + if type=='show': + video_mkv = os.path.join(folder_name, base_filename) + else: + video_mkv = base_filename + + mediainfo = mediainfo_(video_mkv) + for v in mediainfo['media']['track']: # mediainfo do video + if v['@type'] == 'Video': + video_format = v['Format'] + + video_codec = '' + if video_format == "AVC": + video_codec = 'H.264' + elif video_format == "HEVC": + video_codec = 'H.265' + + for m in mediainfo['media']['track']: # mediainfo do audio + if m['@type'] == 'Audio': + codec_name = m['Format'] + channels_number = m['Channels'] + + audio_codec = '' + audio_channels = '' + if codec_name == "AAC": + audio_codec = 'AAC' + elif codec_name == "AC-3": + audio_codec = "DD" + elif codec_name == "E-AC-3": + audio_codec = "DDP" + elif codec_name == "E-AC-3 JOC": + audio_codec = "ATMOS" + + if channels_number == "2": + audio_channels = "2.0" + elif channels_number == "6": + audio_channels = "5.1" + + audio_ = audio_codec + audio_channels + + # renomear arquivo + default_filename = default_filename.replace('&', '.and.') + default_filename = re.sub(r'[]!"#$%\'()*+,:;<=>?@\\^_`{|}~[-]', '', default_filename) + default_filename = default_filename.replace(' ', '.') + default_filename = re.sub(r'\.{2,}', '.', default_filename) + default_filename = unidecode(default_filename) + + output_name = '{}.{}p.PMNP.WEB-DL.{}.{}-{}'.format(default_filename, video_height, audio_, video_codec, args.tag) + if type=='show': + outputName = os.path.join(folder_name, output_name + '.mkv') + else: + outputName = output_name + '.mkv' + + os.rename(video_mkv, outputName) + print("{} -> {}".format(base_filename, output_name)) + + from pywidevine.decrypt.wvdecryptcustom import WvDecrypt + from pywidevine.cdm import cdm, deviceconfig + + def do_decrypt(init_data_b64, cert_data_b64, device, licurl, licheader): + wvdecrypt = WvDecrypt(init_data_b64=init_data_b64, cert_data_b64=cert_data_b64, device=deviceconfig.device_android_generic) + chal = wvdecrypt.get_challenge() + headers = { + 'authorization': licheader + } + + try: + license_res = requests.Session().post(url=licurl, data=chal, headers=headers, proxies=proxy_cfg.get_proxy('meta')) + license_base64 = base64.b64encode(license_res.content) + except Exception: + print(license_res.text) + license_base64 = "Error" + return license_base64 + if license_base64 != 'Error': + wvdecrypt.update_license(license_base64) + wvdecrypt.start_process() + Correct, keyswvdecrypt = wvdecrypt.start_process() + return Correct, keyswvdecrypt + else: + keyswvdecrypt = [] + Correct = True + return Correct, keyswvdecrypt + + def get_keys(lic_info, pssh): + Correct = False + keys_new = [] + device = deviceconfig.device_android_generic + while Correct is False: + Correct, keys_new = do_decrypt(init_data_b64=bytes(pssh.encode()), cert_data_b64=None, device=device, licurl=lic_info['license'], licheader=lic_info['lic_header']) + return keys_new + + def DecryptAudio(inputAudio, keys_audio): + key_audio_id_original = getKeyId(inputAudio) + outputAudioTemp = inputAudio.replace('.mp4', '_dec.mp4') + if key_audio_id_original != 'nothing': + for key in keys_audio: + key_id = key[0:32] + if key_id == key_audio_id_original: + print('\nDecrypting audio...') + print('Using KEY: ' + key) + wvdecrypt_process = subprocess.Popen([mp4decryptexe, '--show-progress', '--key', key, inputAudio, outputAudioTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + time.sleep(0.05) + os.remove(inputAudio) + print('\nDemuxing audio...') + mediainfo = mediainfo_(outputAudioTemp) + for m in mediainfo['media']['track']: + if m['@type'] == 'Audio': + codec_name = m['Format'] + try: + codec_tag_string = m['Format_Commercial_IfAny'] + except Exception: + codec_tag_string = '' + ext = '' + if codec_name == "AAC": + ext = '.m4a' + elif codec_name == "E-AC-3": + ext = ".eac3" + elif codec_name == "AC-3": + ext = ".ac3" + outputAudio = outputAudioTemp.replace("_dec.mp4", ext) + print("{} -> {}".format(outputAudioTemp, outputAudio)) + ff = ffmpy.FFmpeg(executable=ffmpegpath, inputs={outputAudioTemp: None}, outputs={outputAudio: '-c copy'}, global_options="-y -hide_banner -loglevel warning") + ff.run() + time.sleep (50.0/1000.0) + os.remove(outputAudioTemp) + print("Done!") + return True + + elif key_audio_id_original == "nothing": + return True + + def DecryptVideo(inputVideo, keys_video): + key_video_id_original = getKeyId(inputVideo) + inputVideo = inputVideo + outputVideoTemp = inputVideo.replace('.mp4', '_dec.mp4') + outputVideo = inputVideo + if key_video_id_original != 'nothing': + for key in keys_video: + key_id = key[0:32] + if key_id == key_video_id_original: + print('\nDecrypting video...') + print('Using KEY: ' + key) + wvdecrypt_process = subprocess.Popen([mp4decryptexe, '--show-progress', '--key', key, inputVideo, outputVideoTemp]) + stdoutdata, stderrdata = wvdecrypt_process.communicate() + wvdecrypt_process.wait() + print('\nRemuxing video...') + ff = ffmpy.FFmpeg(executable=ffmpegpath, inputs={outputVideoTemp: None}, outputs={outputVideo: '-c copy'}, global_options='-y -hide_banner -loglevel warning') + ff.run() + time.sleep(0.05) + os.remove(outputVideoTemp) + print('Done!') + return True + + elif key_video_id_original == 'nothing': + return True + + def DemuxAudio(inputAudio): + if os.path.isfile(inputAudio): + print('\nDemuxing audio...') + mediainfo = mediainfo_(inputAudio) + for m in mediainfo['media']['track']: + if m['@type'] == 'Audio': + codec_name = m['Format'] + try: + codec_tag_string = m['Format_Commercial_IfAny'] + except Exception: + codec_tag_string = '' + + ext = '' + if codec_name == 'AAC': + ext = '.m4a' + else: + if codec_name == 'E-AC-3': + ext = '.eac3' + else: + if codec_name == 'AC-3': + ext = '.ac3' + outputAudio = inputAudio.replace('.mp4', ext) + print('{} -> {}'.format(inputAudio, outputAudio)) + ff = ffmpy.FFmpeg(executable=ffmpegpath, + inputs={inputAudio: None}, + outputs={outputAudio: '-c copy'}, + global_options='-y -hide_banner -loglevel warning') + ff.run() + time.sleep(0.05) + os.remove(inputAudio) + print('Done!') + + get_content_info() \ No newline at end of file diff --git a/pywidevine/__init__.py b/pywidevine/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pywidevine/cdm/__init__.py b/pywidevine/cdm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pywidevine/cdm/cdm.py b/pywidevine/cdm/cdm.py new file mode 100644 index 0000000..ac0e597 --- /dev/null +++ b/pywidevine/cdm/cdm.py @@ -0,0 +1,364 @@ +import base64 + +import os +import time +import binascii + +from google.protobuf.message import DecodeError +from google.protobuf import text_format + +from pywidevine.cdm.formats import wv_proto2_pb2 as wv_proto2 +from pywidevine.cdm.session import Session +from pywidevine.cdm.key import Key +from Cryptodome.Random import get_random_bytes +from Cryptodome.Random import random +from Cryptodome.Cipher import PKCS1_OAEP, AES +from Cryptodome.Hash import CMAC, SHA256, HMAC, SHA1 +from Cryptodome.PublicKey import RSA +from Cryptodome.Signature import pss +from Cryptodome.Util import Padding +import logging + +class Cdm: + def __init__(self): + self.logger = logging.getLogger(__name__) + self.sessions = {} + + def open_session(self, init_data_b64, device, raw_init_data = None, offline=False): + self.logger.debug("open_session(init_data_b64={}, device={}".format(init_data_b64, device)) + self.logger.info("opening new cdm session") + if device.session_id_type == 'android': + # format: 16 random hexdigits, 2 digit counter, 14 0s + rand_ascii = ''.join(random.choice('ABCDEF0123456789') for _ in range(16)) + counter = '01' # this resets regularly so its fine to use 01 + rest = '00000000000000' + session_id = rand_ascii + counter + rest + session_id = session_id.encode('ascii') + elif device.session_id_type == 'chrome': + rand_bytes = get_random_bytes(16) + session_id = rand_bytes + else: + # other formats NYI + self.logger.error("device type is unusable") + return 1 + if raw_init_data and isinstance(raw_init_data, (bytes, bytearray)): + # used for NF key exchange, where they don't provide a valid PSSH + init_data = raw_init_data + self.raw_pssh = True + else: + init_data = self._parse_init_data(init_data_b64) + self.raw_pssh = False + + if init_data: + new_session = Session(session_id, init_data, device, offline) + else: + self.logger.error("unable to parse init data") + return 1 + self.sessions[session_id] = new_session + self.logger.info("session opened and init data parsed successfully") + return session_id + + def _parse_init_data(self, init_data_b64): + parsed_init_data = wv_proto2.WidevineCencHeader() + try: + self.logger.debug("trying to parse init_data directly") + parsed_init_data.ParseFromString(base64.b64decode(init_data_b64)[32:]) + except DecodeError: + self.logger.debug("unable to parse as-is, trying with removed pssh box header") + try: + id_bytes = parsed_init_data.ParseFromString(base64.b64decode(init_data_b64)[32:]) + except DecodeError: + self.logger.error("unable to parse, unsupported init data format") + return None + self.logger.debug("init_data:") + for line in text_format.MessageToString(parsed_init_data).splitlines(): + self.logger.debug(line) + return parsed_init_data + + def close_session(self, session_id): + self.logger.debug("close_session(session_id={})".format(session_id)) + self.logger.info("closing cdm session") + if session_id in self.sessions: + self.sessions.pop(session_id) + self.logger.info("cdm session closed") + return 0 + else: + self.logger.info("session {} not found".format(session_id)) + return 1 + + def set_service_certificate(self, session_id, cert_b64): + self.logger.debug("set_service_certificate(session_id={}, cert={})".format(session_id, cert_b64)) + self.logger.info("setting service certificate") + + if session_id not in self.sessions: + self.logger.error("session id doesn't exist") + return 1 + + session = self.sessions[session_id] + + message = wv_proto2.SignedMessage() + + try: + message.ParseFromString(base64.b64decode(cert_b64)) + except DecodeError: + self.logger.error("failed to parse cert as SignedMessage") + + service_certificate = wv_proto2.SignedDeviceCertificate() + + + if message.Type: + self.logger.debug("service cert provided as signedmessage") + try: + service_certificate.ParseFromString(message.Msg) + + except DecodeError: + self.logger.error("failed to parse service certificate") + return 1 + else: + self.logger.debug("service cert provided as signeddevicecertificate") + try: + service_certificate.ParseFromString(base64.b64decode(cert_b64)) + except DecodeError: + self.logger.error("failed to parse service certificate") + return 1 + + self.logger.debug("service certificate:") + for line in text_format.MessageToString(service_certificate).splitlines(): + self.logger.debug(line) + + session.service_certificate = service_certificate + session.privacy_mode = True + + return 0 + + def get_license_request(self, session_id): + self.logger.debug("get_license_request(session_id={})".format(session_id)) + self.logger.info("getting license request") + + if session_id not in self.sessions: + self.logger.error("session ID does not exist") + return 1 + + session = self.sessions[session_id] + + # raw pssh will be treated as bytes and not parsed + if self.raw_pssh: + license_request = wv_proto2.SignedLicenseRequestRaw() + else: + license_request = wv_proto2.SignedLicenseRequest() + client_id = wv_proto2.ClientIdentification() + + if not os.path.exists(session.device_config.device_client_id_blob_filename): + self.logger.error("no client ID blob available for this device") + return 1 + + with open(session.device_config.device_client_id_blob_filename, "rb") as f: + try: + cid_bytes = client_id.ParseFromString(f.read()) + except DecodeError: + self.logger.error("client id failed to parse as protobuf") + return 1 + + self.logger.debug("building license request") + if not self.raw_pssh: + license_request.Type = wv_proto2.SignedLicenseRequest.MessageType.Value('LICENSE_REQUEST') + license_request.Msg.ContentId.CencId.Pssh.CopyFrom(session.init_data) + else: + license_request.Type = wv_proto2.SignedLicenseRequestRaw.MessageType.Value('LICENSE_REQUEST') + license_request.Msg.ContentId.CencId.Pssh = session.init_data # bytes + + if session.offline: + license_type = wv_proto2.LicenseType.Value('OFFLINE') + else: + license_type = wv_proto2.LicenseType.Value('DEFAULT') + license_request.Msg.ContentId.CencId.LicenseType = license_type + license_request.Msg.ContentId.CencId.RequestId = session_id + license_request.Msg.Type = wv_proto2.LicenseRequest.RequestType.Value('NEW') + license_request.Msg.RequestTime = int(time.time()) + license_request.Msg.ProtocolVersion = wv_proto2.ProtocolVersion.Value('CURRENT') + if session.device_config.send_key_control_nonce: + license_request.Msg.KeyControlNonce = random.randrange(1, 2**31) + + if session.privacy_mode: + if session.device_config.vmp: + self.logger.debug("vmp required, adding to client_id") + self.logger.debug("reading vmp hashes") + vmp_hashes = wv_proto2.FileHashes() + with open(session.device_config.device_vmp_blob_filename, "rb") as f: + try: + vmp_bytes = vmp_hashes.ParseFromString(f.read()) + except DecodeError: + self.logger.error("vmp hashes failed to parse as protobuf") + return 1 + client_id._FileHashes.CopyFrom(vmp_hashes) + self.logger.debug("privacy mode & service certificate loaded, encrypting client id") + self.logger.debug("unencrypted client id:") + for line in text_format.MessageToString(client_id).splitlines(): + self.logger.debug(line) + cid_aes_key = get_random_bytes(16) + cid_iv = get_random_bytes(16) + + cid_cipher = AES.new(cid_aes_key, AES.MODE_CBC, cid_iv) + + encrypted_client_id = cid_cipher.encrypt(Padding.pad(client_id.SerializeToString(), 16)) + + service_public_key = RSA.importKey(session.service_certificate._DeviceCertificate.PublicKey) + + service_cipher = PKCS1_OAEP.new(service_public_key) + + encrypted_cid_key = service_cipher.encrypt(cid_aes_key) + + encrypted_client_id_proto = wv_proto2.EncryptedClientIdentification() + + encrypted_client_id_proto.ServiceId = session.service_certificate._DeviceCertificate.ServiceId + encrypted_client_id_proto.ServiceCertificateSerialNumber = session.service_certificate._DeviceCertificate.SerialNumber + encrypted_client_id_proto.EncryptedClientId = encrypted_client_id + encrypted_client_id_proto.EncryptedClientIdIv = cid_iv + encrypted_client_id_proto.EncryptedPrivacyKey = encrypted_cid_key + + license_request.Msg.EncryptedClientId.CopyFrom(encrypted_client_id_proto) + else: + license_request.Msg.ClientId.CopyFrom(client_id) + + if session.device_config.private_key_available: + key = RSA.importKey(open(session.device_config.device_private_key_filename).read()) + session.device_key = key + else: + self.logger.error("need device private key, other methods unimplemented") + return 1 + + self.logger.debug("signing license request") + + hash = SHA1.new(license_request.Msg.SerializeToString()) + signature = pss.new(key).sign(hash) + + license_request.Signature = signature + + session.license_request = license_request + + self.logger.debug("license request:") + for line in text_format.MessageToString(session.license_request).splitlines(): + self.logger.debug(line) + self.logger.info("license request created") + self.logger.debug("license request b64: {}".format(base64.b64encode(license_request.SerializeToString()))) + return license_request.SerializeToString() + + def provide_license(self, session_id, license_b64): + self.logger.debug("provide_license(session_id={}, license_b64={})".format(session_id, license_b64)) + self.logger.info("decrypting provided license") + + if session_id not in self.sessions: + self.logger.error("session does not exist") + return 1 + + session = self.sessions[session_id] + + if not session.license_request: + self.logger.error("generate a license request first!") + return 1 + + license = wv_proto2.SignedLicense() + try: + license.ParseFromString(base64.b64decode(license_b64)) + except DecodeError: + self.logger.error("unable to parse license - check protobufs") + return 1 + + session.license = license + + self.logger.debug("license:") + for line in text_format.MessageToString(license).splitlines(): + self.logger.debug(line) + + self.logger.debug("deriving keys from session key") + + oaep_cipher = PKCS1_OAEP.new(session.device_key) + + session.session_key = oaep_cipher.decrypt(license.SessionKey) + + lic_req_msg = session.license_request.Msg.SerializeToString() + + enc_key_base = b"ENCRYPTION\000" + lic_req_msg + b"\0\0\0\x80" + auth_key_base = b"AUTHENTICATION\0" + lic_req_msg + b"\0\0\2\0" + + enc_key = b"\x01" + enc_key_base + auth_key_1 = b"\x01" + auth_key_base + auth_key_2 = b"\x02" + auth_key_base + auth_key_3 = b"\x03" + auth_key_base + auth_key_4 = b"\x04" + auth_key_base + + cmac_obj = CMAC.new(session.session_key, ciphermod=AES) + cmac_obj.update(enc_key) + + enc_cmac_key = cmac_obj.digest() + + cmac_obj = CMAC.new(session.session_key, ciphermod=AES) + cmac_obj.update(auth_key_1) + auth_cmac_key_1 = cmac_obj.digest() + + cmac_obj = CMAC.new(session.session_key, ciphermod=AES) + cmac_obj.update(auth_key_2) + auth_cmac_key_2 = cmac_obj.digest() + + cmac_obj = CMAC.new(session.session_key, ciphermod=AES) + cmac_obj.update(auth_key_3) + auth_cmac_key_3 = cmac_obj.digest() + + cmac_obj = CMAC.new(session.session_key, ciphermod=AES) + cmac_obj.update(auth_key_4) + auth_cmac_key_4 = cmac_obj.digest() + + auth_cmac_combined_1 = auth_cmac_key_1 + auth_cmac_key_2 + auth_cmac_combined_2 = auth_cmac_key_3 + auth_cmac_key_4 + + session.derived_keys['enc'] = enc_cmac_key + session.derived_keys['auth_1'] = auth_cmac_combined_1 + session.derived_keys['auth_2'] = auth_cmac_combined_2 + + self.logger.debug('verifying license signature') + + lic_hmac = HMAC.new(session.derived_keys['auth_1'], digestmod=SHA256) + lic_hmac.update(license.Msg.SerializeToString()) + + self.logger.debug("calculated sig: {} actual sig: {}".format(lic_hmac.hexdigest(), binascii.hexlify(license.Signature))) + + if lic_hmac.digest() != license.Signature: + self.logger.info("license signature doesn't match - writing bin so they can be debugged") + with open("original_lic.bin", "wb") as f: + f.write(base64.b64decode(license_b64)) + with open("parsed_lic.bin", "wb") as f: + f.write(license.SerializeToString()) + self.logger.info("continuing anyway") + + self.logger.debug("key count: {}".format(len(license.Msg.Key))) + for key in license.Msg.Key: + if key.Id: + key_id = key.Id + else: + key_id = wv_proto2.License.KeyContainer.KeyType.Name(key.Type).encode('utf-8') + encrypted_key = key.Key + iv = key.Iv + type = wv_proto2.License.KeyContainer.KeyType.Name(key.Type) + + cipher = AES.new(session.derived_keys['enc'], AES.MODE_CBC, iv=iv) + decrypted_key = cipher.decrypt(encrypted_key) + if type == "OPERATOR_SESSION": + permissions = [] + perms = key._OperatorSessionKeyPermissions + for (descriptor, value) in perms.ListFields(): + if value == 1: + permissions.append(descriptor.name) + print(permissions) + else: + permissions = [] + session.keys.append(Key(key_id, type, Padding.unpad(decrypted_key, 16), permissions)) + + self.logger.info("decrypted all keys") + return 0 + + def get_keys(self, session_id): + if session_id in self.sessions: + return self.sessions[session_id].keys + else: + self.logger.error("session not found") + return 1 diff --git a/pywidevine/cdm/deviceconfig.py b/pywidevine/cdm/deviceconfig.py new file mode 100644 index 0000000..981adae --- /dev/null +++ b/pywidevine/cdm/deviceconfig.py @@ -0,0 +1,53 @@ +import os + +device_android_generic = { + 'name': 'android_generic', + 'description': 'android generic l3', + 'security_level': 3, + 'session_id_type': 'android', + 'private_key_available': True, + 'vmp': False, + 'send_key_control_nonce': True +} + +devices_available = [device_android_generic] + +FILES_FOLDER = 'devices' + +class DeviceConfig: + def __init__(self, device): + self.device_name = device['name'] + self.description = device['description'] + self.security_level = device['security_level'] + self.session_id_type = device['session_id_type'] + self.private_key_available = device['private_key_available'] + self.vmp = device['vmp'] + self.send_key_control_nonce = device['send_key_control_nonce'] + + if 'keybox_filename' in device: + self.keybox_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], device['keybox_filename']) + else: + self.keybox_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], 'keybox') + + if 'device_cert_filename' in device: + self.device_cert_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], device['device_cert_filename']) + else: + self.device_cert_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], 'device_cert') + + if 'device_private_key_filename' in device: + self.device_private_key_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], device['device_private_key_filename']) + else: + self.device_private_key_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], 'device_private_key') + + if 'device_client_id_blob_filename' in device: + self.device_client_id_blob_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], device['device_client_id_blob_filename']) + else: + self.device_client_id_blob_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], 'device_client_id_blob') + + if 'device_vmp_blob_filename' in device: + self.device_vmp_blob_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], device['device_vmp_blob_filename']) + else: + self.device_vmp_blob_filename = os.path.join(os.path.dirname(__file__), FILES_FOLDER, device['name'], 'device_vmp_blob') + + def __repr__(self): + return "DeviceConfig(name={}, description={}, security_level={}, session_id_type={}, private_key_available={}, vmp={})".format(self.device_name, self.description, self.security_level, self.session_id_type, self.private_key_available, self.vmp) diff --git a/pywidevine/cdm/devices/android_generic/device_client_id_blob b/pywidevine/cdm/devices/android_generic/device_client_id_blob new file mode 100644 index 0000000000000000000000000000000000000000..cc32780826673a1deb75a8f4dbf90d2925a2163b GIT binary patch literal 1651 zcmZuvcT`h{8c#xv;WC6Yg%DRtSyo0;_BLz{BEtz{2=`u+2;qh-Oql{cKvEPC3L>S5 zR#Y@BF~|}XsBto^2#K7j$&wSMOW-|#v#)%l6r;lWP0H*FtQwWio`K7UJ%C@p8frUr{`RSq&=eLm9E_Bcts z+)__t(>pju8qhkTN7d-YooqsD17YB+)T&b+dD!mW%;tA*8=?|ct9pxAvXciG-~EEk zyqNHyLYVoy+l`96gc=4fmR#7JtW-35M7Y;{rd_mZ-9RZ>>g0zzD_^QiN=>=Cm+GT( z>)&?E=I26%Mw0uFC37a^<@B+k8rP}tG+R%M1{#I7m^ThUTb$1|Qef^xbJv)l~(xXc(>gKr3a6m<9-nzHvXOV>Zu1CDGr^m}yN36wz^2o@x`! z8GPNt9T{4b6mc5L&9^XI5Ox4dza2)@DeP*wZW~^?A8Jye>|X5=FN(DR{l}_STjt)w z1o$ae=a_7&+2XfyIV&e@*vsGUjiK!l%Ws{+jLs$`+-D%CB3pc{63bC!Os} zS{E%T8A_A-uF@R;-Hgl+Qq5$Ok=)ivfiTpYeG3B&cdhvlz{7->`YhIb~mW+RatLZVx{9 z{Gn8KKj_7BmeR|_tY%rgW3toA=g}I1%WNAtu)2w*HeIWZ@*FW8H?NVMznKEOj($;n z;<1HA;}udz-xL(hFxB#|s09v_C!_v=pm!e;aK=I_Zr&Rxbl-PiE}qmwji zu-|;^HIMTf-uunv6c-n7ZInc2<*ZpvSxub)758L`qxDIlW=i?U_n^I&@6@!s)VgS-8^c2(`fN1hB%6nKtlcUg|Gmy}DvwPjtG z`vnU{w0j-!^?p@>?$eNhx-^&3bIUxM%v6tdUa@umxt_(mgZkVpC^a|#SMvQBpL?X1 zZffPs(IxJ;3hCE0df%0Rmoi+RsOXgX1On6_it@&*QPjJqrxV(}jI+NQnp8xWJ$e?> zr#H!Sz*k4xhXuGEJvIr~{ z-!^qG8+%@M+& zP{fB<^ctTS5}*aaVh;EZrp1EeVLk_BeBw+1Z5|(iM4)iRKoCH&4A$S#3?3VahyPYZ z0Klg(h{1`ELGasGc$@zxwfV2%E{@hzYpPAqK5rX)I|n-_XGa&20Omt*w1{ORgatyY zSXd$;Spk~=tjB@yg`k0{4pJF(CReh=2h`Aj1KOi&=m~3PUi1CZpdI zlU16RX&&Q}TAW>yUl0@S>ZI%96CdL5?-LwTo|%$bmYJ6tpPgD+98*vUg`k0{4pJF(CReh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6w)*(xTqIJKxa zCaW|r(>%r{wK%&ZzaS>u)k)XICqBgA-zPXGFD)^*Dlev>vOF^-wJb9)H6}SFHzqB= lC^xaBI3_+mGcU6wK3=b&@)n0pZhlH>PO2Tqn$JMY000lYDyIMd literal 0 HcmV?d00001 diff --git a/pywidevine/cdm/formats/__pycache__/wv_proto2_pb2.cpython-37.pyc b/pywidevine/cdm/formats/__pycache__/wv_proto2_pb2.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c01ee97bc212108716d0f991732589ce0542f8d GIT binary patch literal 44607 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 SBRU+YV7&jo{uSIvj{hGI=wo~U literal 0 HcmV?d00001 diff --git a/pywidevine/cdm/formats/__pycache__/wv_proto2_pb2.cpython-38.pyc b/pywidevine/cdm/formats/__pycache__/wv_proto2_pb2.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84af63f93bba74b4b994ed6dde0f76014feb5761 GIT binary patch literal 48896 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 Zm(#-LO;F1H{xX$W5+IJBQtFiQ{{wW03$y?L literal 0 HcmV?d00001 diff --git a/pywidevine/cdm/formats/wv_proto2.proto b/pywidevine/cdm/formats/wv_proto2.proto new file mode 100644 index 0000000..04c9809 --- /dev/null +++ b/pywidevine/cdm/formats/wv_proto2.proto @@ -0,0 +1,466 @@ +syntax = "proto2"; + +// from x86 (partial), most of it from the ARM version: +message ClientIdentification { + enum TokenType { + KEYBOX = 0; + DEVICE_CERTIFICATE = 1; + REMOTE_ATTESTATION_CERTIFICATE = 2; + } + message NameValue { + required string Name = 1; + required string Value = 2; + } + message ClientCapabilities { + enum HdcpVersion { + HDCP_NONE = 0; + HDCP_V1 = 1; + HDCP_V2 = 2; + HDCP_V2_1 = 3; + HDCP_V2_2 = 4; + } + optional uint32 ClientToken = 1; + optional uint32 SessionToken = 2; + optional uint32 VideoResolutionConstraints = 3; + optional HdcpVersion MaxHdcpVersion = 4; + optional uint32 OemCryptoApiVersion = 5; + } + required TokenType Type = 1; + //optional bytes Token = 2; // by default the client treats this as blob, but it's usually a DeviceCertificate, so for usefulness sake, I'm replacing it with this one: + optional SignedDeviceCertificate Token = 2; // use this when parsing, "bytes" when building a client id blob + repeated NameValue ClientInfo = 3; + optional bytes ProviderClientToken = 4; + optional uint32 LicenseCounter = 5; + optional ClientCapabilities _ClientCapabilities = 6; // how should we deal with duped names? will have to look at proto docs later + optional FileHashes _FileHashes = 7; // vmp blob goes here +} + +message DeviceCertificate { + enum CertificateType { + ROOT = 0; + INTERMEDIATE = 1; + USER_DEVICE = 2; + SERVICE = 3; + } + required CertificateType Type = 1; // the compiled code reused this as ProvisionedDeviceInfo.WvSecurityLevel, however that is incorrect (compiler aliased it as they're both identical as a structure) + optional bytes SerialNumber = 2; + optional uint32 CreationTimeSeconds = 3; + optional bytes PublicKey = 4; + optional uint32 SystemId = 5; + optional uint32 TestDeviceDeprecated = 6; // is it bool or int? + optional bytes ServiceId = 7; // service URL for service certificates +} + +// missing some references, +message DeviceCertificateStatus { + enum CertificateStatus { + VALID = 0; + REVOKED = 1; + } + optional bytes SerialNumber = 1; + optional CertificateStatus Status = 2; + optional ProvisionedDeviceInfo DeviceInfo = 4; // where is 3? is it deprecated? +} + +message DeviceCertificateStatusList { + optional uint32 CreationTimeSeconds = 1; + repeated DeviceCertificateStatus CertificateStatus = 2; +} + +message EncryptedClientIdentification { + required string ServiceId = 1; + optional bytes ServiceCertificateSerialNumber = 2; + required bytes EncryptedClientId = 3; + required bytes EncryptedClientIdIv = 4; + required bytes EncryptedPrivacyKey = 5; +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +enum LicenseType { + ZERO = 0; + DEFAULT = 1; // 1 is STREAMING/temporary license; on recent versions may go up to 3 (latest x86); it might be persist/don't persist type, unconfirmed + OFFLINE = 2; +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +// this is just a guess because these globals got lost, but really, do we need more? +enum ProtocolVersion { + CURRENT = 21; // don't have symbols for this +} + + +message LicenseIdentification { + optional bytes RequestId = 1; + optional bytes SessionId = 2; + optional bytes PurchaseId = 3; + optional LicenseType Type = 4; + optional uint32 Version = 5; + optional bytes ProviderSessionToken = 6; +} + + +message License { + message Policy { + optional bool CanPlay = 1; // changed from uint32 to bool + optional bool CanPersist = 2; + optional bool CanRenew = 3; + optional uint32 RentalDurationSeconds = 4; + optional uint32 PlaybackDurationSeconds = 5; + optional uint32 LicenseDurationSeconds = 6; + optional uint32 RenewalRecoveryDurationSeconds = 7; + optional string RenewalServerUrl = 8; + optional uint32 RenewalDelaySeconds = 9; + optional uint32 RenewalRetryIntervalSeconds = 10; + optional bool RenewWithUsage = 11; // was uint32 + } + message KeyContainer { + enum KeyType { + SIGNING = 1; + CONTENT = 2; + KEY_CONTROL = 3; + OPERATOR_SESSION = 4; + } + enum SecurityLevel { + SW_SECURE_CRYPTO = 1; + SW_SECURE_DECODE = 2; + HW_SECURE_CRYPTO = 3; + HW_SECURE_DECODE = 4; + HW_SECURE_ALL = 5; + } + message OutputProtection { + enum CGMS { + COPY_FREE = 0; + COPY_ONCE = 2; + COPY_NEVER = 3; + CGMS_NONE = 0x2A; // PC default! + } + optional ClientIdentification.ClientCapabilities.HdcpVersion Hdcp = 1; // it's most likely a copy of Hdcp version available here, but compiler optimized it away + optional CGMS CgmsFlags = 2; + } + message KeyControl { + required bytes KeyControlBlock = 1; // what is this? + required bytes Iv = 2; + } + message OperatorSessionKeyPermissions { + optional uint32 AllowEncrypt = 1; + optional uint32 AllowDecrypt = 2; + optional uint32 AllowSign = 3; + optional uint32 AllowSignatureVerify = 4; + } + message VideoResolutionConstraint { + optional uint32 MinResolutionPixels = 1; + optional uint32 MaxResolutionPixels = 2; + optional OutputProtection RequiredProtection = 3; + } + optional bytes Id = 1; + optional bytes Iv = 2; + optional bytes Key = 3; + optional KeyType Type = 4; + optional SecurityLevel Level = 5; + optional OutputProtection RequiredProtection = 6; + optional OutputProtection RequestedProtection = 7; + optional KeyControl _KeyControl = 8; // duped names, etc + optional OperatorSessionKeyPermissions _OperatorSessionKeyPermissions = 9; // duped names, etc + repeated VideoResolutionConstraint VideoResolutionConstraints = 10; + } + optional LicenseIdentification Id = 1; + optional Policy _Policy = 2; // duped names, etc + repeated KeyContainer Key = 3; + optional uint32 LicenseStartTime = 4; + optional uint32 RemoteAttestationVerified = 5; // bool? + optional bytes ProviderClientToken = 6; + // there might be more, check with newer versions (I see field 7-8 in a lic) + // this appeared in latest x86: + optional uint32 ProtectionScheme = 7; // type unconfirmed fully, but it's likely as WidevineCencHeader describesit (fourcc) +} + +message LicenseError { + enum Error { + INVALID_DEVICE_CERTIFICATE = 1; + REVOKED_DEVICE_CERTIFICATE = 2; + SERVICE_UNAVAILABLE = 3; + } + //LicenseRequest.RequestType ErrorCode; // clang mismatch + optional Error ErrorCode = 1; +} + +message LicenseRequest { + message ContentIdentification { + message CENC { + //optional bytes Pssh = 1; // the client's definition is opaque, it doesn't care about the contents, but the PSSH has a clear definition that is understood and requested by the server, thus I'll replace it with: + optional WidevineCencHeader Pssh = 1; + optional LicenseType LicenseType = 2; // unfortunately the LicenseType symbols are not present, acceptable value seems to only be 1 (is this persist/don't persist? look into it!) + optional bytes RequestId = 3; + } + message WebM { + optional bytes Header = 1; // identical to CENC, aside from PSSH and the parent field number used + optional LicenseType LicenseType = 2; + optional bytes RequestId = 3; + } + message ExistingLicense { + optional LicenseIdentification LicenseId = 1; + optional uint32 SecondsSinceStarted = 2; + optional uint32 SecondsSinceLastPlayed = 3; + optional bytes SessionUsageTableEntry = 4; // interesting! try to figure out the connection between the usage table blob and KCB! + } + optional CENC CencId = 1; + optional WebM WebmId = 2; + optional ExistingLicense License = 3; + } + enum RequestType { + NEW = 1; + RENEWAL = 2; + RELEASE = 3; + } + optional ClientIdentification ClientId = 1; + optional ContentIdentification ContentId = 2; + optional RequestType Type = 3; + optional uint32 RequestTime = 4; + optional bytes KeyControlNonceDeprecated = 5; + optional ProtocolVersion ProtocolVersion = 6; // lacking symbols for this + optional uint32 KeyControlNonce = 7; + optional EncryptedClientIdentification EncryptedClientId = 8; +} + +// raw pssh hack +message LicenseRequestRaw { + message ContentIdentification { + message CENC { + optional bytes Pssh = 1; // the client's definition is opaque, it doesn't care about the contents, but the PSSH has a clear definition that is understood and requested by the server, thus I'll replace it with: + //optional WidevineCencHeader Pssh = 1; + optional LicenseType LicenseType = 2; // unfortunately the LicenseType symbols are not present, acceptable value seems to only be 1 (is this persist/don't persist? look into it!) + optional bytes RequestId = 3; + } + message WebM { + optional bytes Header = 1; // identical to CENC, aside from PSSH and the parent field number used + optional LicenseType LicenseType = 2; + optional bytes RequestId = 3; + } + message ExistingLicense { + optional LicenseIdentification LicenseId = 1; + optional uint32 SecondsSinceStarted = 2; + optional uint32 SecondsSinceLastPlayed = 3; + optional bytes SessionUsageTableEntry = 4; // interesting! try to figure out the connection between the usage table blob and KCB! + } + optional CENC CencId = 1; + optional WebM WebmId = 2; + optional ExistingLicense License = 3; + } + enum RequestType { + NEW = 1; + RENEWAL = 2; + RELEASE = 3; + } + optional ClientIdentification ClientId = 1; + optional ContentIdentification ContentId = 2; + optional RequestType Type = 3; + optional uint32 RequestTime = 4; + optional bytes KeyControlNonceDeprecated = 5; + optional ProtocolVersion ProtocolVersion = 6; // lacking symbols for this + optional uint32 KeyControlNonce = 7; + optional EncryptedClientIdentification EncryptedClientId = 8; +} + + +message ProvisionedDeviceInfo { + enum WvSecurityLevel { + LEVEL_UNSPECIFIED = 0; + LEVEL_1 = 1; + LEVEL_2 = 2; + LEVEL_3 = 3; + } + optional uint32 SystemId = 1; + optional string Soc = 2; + optional string Manufacturer = 3; + optional string Model = 4; + optional string DeviceType = 5; + optional uint32 ModelYear = 6; + optional WvSecurityLevel SecurityLevel = 7; + optional uint32 TestDevice = 8; // bool? +} + + +// todo: fill +message ProvisioningOptions { +} + +// todo: fill +message ProvisioningRequest { +} + +// todo: fill +message ProvisioningResponse { +} + +message RemoteAttestation { + optional EncryptedClientIdentification Certificate = 1; + optional string Salt = 2; + optional string Signature = 3; +} + +// todo: fill +message SessionInit { +} + +// todo: fill +message SessionState { +} + +// todo: fill +message SignedCertificateStatusList { +} + +message SignedDeviceCertificate { + + //optional bytes DeviceCertificate = 1; // again, they use a buffer where it's supposed to be a message, so we'll replace it with what it really is: + optional DeviceCertificate _DeviceCertificate = 1; // how should we deal with duped names? will have to look at proto docs later + optional bytes Signature = 2; + optional SignedDeviceCertificate Signer = 3; +} + + +// todo: fill +message SignedProvisioningMessage { +} + +// the root of all messages, from either server or client +message SignedMessage { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional bytes Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + + + +// This message is copied from google's docs, not reversed: +message WidevineCencHeader { + enum Algorithm { + UNENCRYPTED = 0; + AESCTR = 1; + }; + optional Algorithm algorithm = 1; + repeated bytes key_id = 2; + + // Content provider name. + optional string provider = 3; + + // A content identifier, specified by content provider. + optional bytes content_id = 4; + + // Track type. Acceptable values are SD, HD and AUDIO. Used to + // differentiate content keys used by an asset. + optional string track_type_deprecated = 5; + + // The name of a registered policy to be used for this asset. + optional string policy = 6; + + // Crypto period index, for media using key rotation. + optional uint32 crypto_period_index = 7; + + // Optional protected context for group content. The grouped_license is a + // serialized SignedMessage. + optional bytes grouped_license = 8; + + // Protection scheme identifying the encryption algorithm. + // Represented as one of the following 4CC values: + // 'cenc' (AESCTR), 'cbc1' (AESCBC), + // 'cens' (AESCTR subsample), 'cbcs' (AESCBC subsample). + optional uint32 protection_scheme = 9; + + // Optional. For media using key rotation, this represents the duration + // of each crypto period in seconds. + optional uint32 crypto_period_seconds = 10; +} + + +// remove these when using it outside of protoc: + +// from here on, it's just for testing, these messages don't exist in the binaries, I'm adding them to avoid detecting type programmatically +message SignedLicenseRequest { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional LicenseRequest Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + +// hack +message SignedLicenseRequestRaw { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional LicenseRequestRaw Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + + +message SignedLicense { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional License Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + +message SignedServiceCertificate { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional SignedDeviceCertificate Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + +//vmp support +message FileHashes { + message Signature { + optional string filename = 1; + optional bool test_signing = 2; //0 - release, 1 - testing + optional bytes SHA512Hash = 3; + optional bool main_exe = 4; //0 for dlls, 1 for exe, this is field 3 in file + optional bytes signature = 5; + } + optional bytes signer = 1; + repeated Signature signatures = 2; +} diff --git a/pywidevine/cdm/formats/wv_proto2_pb2.py b/pywidevine/cdm/formats/wv_proto2_pb2.py new file mode 100644 index 0000000..4c2a6d1 --- /dev/null +++ b/pywidevine/cdm/formats/wv_proto2_pb2.py @@ -0,0 +1,3324 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: pywidevine/cdm/formats/wv_proto2.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='pywidevine/cdm/formats/wv_proto2.proto', + package='', + syntax='proto2', + serialized_pb=_b('\n&pywidevine/cdm/formats/wv_proto2.proto\"\xe7\x05\n\x14\x43lientIdentification\x12-\n\x04Type\x18\x01 \x02(\x0e\x32\x1f.ClientIdentification.TokenType\x12\'\n\x05Token\x18\x02 \x01(\x0b\x32\x18.SignedDeviceCertificate\x12\x33\n\nClientInfo\x18\x03 \x03(\x0b\x32\x1f.ClientIdentification.NameValue\x12\x1b\n\x13ProviderClientToken\x18\x04 \x01(\x0c\x12\x16\n\x0eLicenseCounter\x18\x05 \x01(\r\x12\x45\n\x13_ClientCapabilities\x18\x06 \x01(\x0b\x32(.ClientIdentification.ClientCapabilities\x12 \n\x0b_FileHashes\x18\x07 \x01(\x0b\x32\x0b.FileHashes\x1a(\n\tNameValue\x12\x0c\n\x04Name\x18\x01 \x02(\t\x12\r\n\x05Value\x18\x02 \x02(\t\x1a\xa4\x02\n\x12\x43lientCapabilities\x12\x13\n\x0b\x43lientToken\x18\x01 \x01(\r\x12\x14\n\x0cSessionToken\x18\x02 \x01(\r\x12\"\n\x1aVideoResolutionConstraints\x18\x03 \x01(\r\x12L\n\x0eMaxHdcpVersion\x18\x04 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12\x1b\n\x13OemCryptoApiVersion\x18\x05 \x01(\r\"T\n\x0bHdcpVersion\x12\r\n\tHDCP_NONE\x10\x00\x12\x0b\n\x07HDCP_V1\x10\x01\x12\x0b\n\x07HDCP_V2\x10\x02\x12\r\n\tHDCP_V2_1\x10\x03\x12\r\n\tHDCP_V2_2\x10\x04\"S\n\tTokenType\x12\n\n\x06KEYBOX\x10\x00\x12\x16\n\x12\x44\x45VICE_CERTIFICATE\x10\x01\x12\"\n\x1eREMOTE_ATTESTATION_CERTIFICATE\x10\x02\"\x9b\x02\n\x11\x44\x65viceCertificate\x12\x30\n\x04Type\x18\x01 \x02(\x0e\x32\".DeviceCertificate.CertificateType\x12\x14\n\x0cSerialNumber\x18\x02 \x01(\x0c\x12\x1b\n\x13\x43reationTimeSeconds\x18\x03 \x01(\r\x12\x11\n\tPublicKey\x18\x04 \x01(\x0c\x12\x10\n\x08SystemId\x18\x05 \x01(\r\x12\x1c\n\x14TestDeviceDeprecated\x18\x06 \x01(\r\x12\x11\n\tServiceId\x18\x07 \x01(\x0c\"K\n\x0f\x43\x65rtificateType\x12\x08\n\x04ROOT\x10\x00\x12\x10\n\x0cINTERMEDIATE\x10\x01\x12\x0f\n\x0bUSER_DEVICE\x10\x02\x12\x0b\n\x07SERVICE\x10\x03\"\xc4\x01\n\x17\x44\x65viceCertificateStatus\x12\x14\n\x0cSerialNumber\x18\x01 \x01(\x0c\x12:\n\x06Status\x18\x02 \x01(\x0e\x32*.DeviceCertificateStatus.CertificateStatus\x12*\n\nDeviceInfo\x18\x04 \x01(\x0b\x32\x16.ProvisionedDeviceInfo\"+\n\x11\x43\x65rtificateStatus\x12\t\n\x05VALID\x10\x00\x12\x0b\n\x07REVOKED\x10\x01\"o\n\x1b\x44\x65viceCertificateStatusList\x12\x1b\n\x13\x43reationTimeSeconds\x18\x01 \x01(\r\x12\x33\n\x11\x43\x65rtificateStatus\x18\x02 \x03(\x0b\x32\x18.DeviceCertificateStatus\"\xaf\x01\n\x1d\x45ncryptedClientIdentification\x12\x11\n\tServiceId\x18\x01 \x02(\t\x12&\n\x1eServiceCertificateSerialNumber\x18\x02 \x01(\x0c\x12\x19\n\x11\x45ncryptedClientId\x18\x03 \x02(\x0c\x12\x1b\n\x13\x45ncryptedClientIdIv\x18\x04 \x02(\x0c\x12\x1b\n\x13\x45ncryptedPrivacyKey\x18\x05 \x02(\x0c\"\x9c\x01\n\x15LicenseIdentification\x12\x11\n\tRequestId\x18\x01 \x01(\x0c\x12\x11\n\tSessionId\x18\x02 \x01(\x0c\x12\x12\n\nPurchaseId\x18\x03 \x01(\x0c\x12\x1a\n\x04Type\x18\x04 \x01(\x0e\x32\x0c.LicenseType\x12\x0f\n\x07Version\x18\x05 \x01(\r\x12\x1c\n\x14ProviderSessionToken\x18\x06 \x01(\x0c\"\xa1\x0e\n\x07License\x12\"\n\x02Id\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12 \n\x07_Policy\x18\x02 \x01(\x0b\x32\x0f.License.Policy\x12\"\n\x03Key\x18\x03 \x03(\x0b\x32\x15.License.KeyContainer\x12\x18\n\x10LicenseStartTime\x18\x04 \x01(\r\x12!\n\x19RemoteAttestationVerified\x18\x05 \x01(\r\x12\x1b\n\x13ProviderClientToken\x18\x06 \x01(\x0c\x12\x18\n\x10ProtectionScheme\x18\x07 \x01(\r\x1a\xbb\x02\n\x06Policy\x12\x0f\n\x07\x43\x61nPlay\x18\x01 \x01(\x08\x12\x12\n\nCanPersist\x18\x02 \x01(\x08\x12\x10\n\x08\x43\x61nRenew\x18\x03 \x01(\x08\x12\x1d\n\x15RentalDurationSeconds\x18\x04 \x01(\r\x12\x1f\n\x17PlaybackDurationSeconds\x18\x05 \x01(\r\x12\x1e\n\x16LicenseDurationSeconds\x18\x06 \x01(\r\x12&\n\x1eRenewalRecoveryDurationSeconds\x18\x07 \x01(\r\x12\x18\n\x10RenewalServerUrl\x18\x08 \x01(\t\x12\x1b\n\x13RenewalDelaySeconds\x18\t \x01(\r\x12#\n\x1bRenewalRetryIntervalSeconds\x18\n \x01(\r\x12\x16\n\x0eRenewWithUsage\x18\x0b \x01(\x08\x1a\xf9\t\n\x0cKeyContainer\x12\n\n\x02Id\x18\x01 \x01(\x0c\x12\n\n\x02Iv\x18\x02 \x01(\x0c\x12\x0b\n\x03Key\x18\x03 \x01(\x0c\x12+\n\x04Type\x18\x04 \x01(\x0e\x32\x1d.License.KeyContainer.KeyType\x12\x32\n\x05Level\x18\x05 \x01(\x0e\x32#.License.KeyContainer.SecurityLevel\x12\x42\n\x12RequiredProtection\x18\x06 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x43\n\x13RequestedProtection\x18\x07 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x35\n\x0b_KeyControl\x18\x08 \x01(\x0b\x32 .License.KeyContainer.KeyControl\x12[\n\x1e_OperatorSessionKeyPermissions\x18\t \x01(\x0b\x32\x33.License.KeyContainer.OperatorSessionKeyPermissions\x12S\n\x1aVideoResolutionConstraints\x18\n \x03(\x0b\x32/.License.KeyContainer.VideoResolutionConstraint\x1a\xdb\x01\n\x10OutputProtection\x12\x42\n\x04Hdcp\x18\x01 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12>\n\tCgmsFlags\x18\x02 \x01(\x0e\x32+.License.KeyContainer.OutputProtection.CGMS\"C\n\x04\x43GMS\x12\r\n\tCOPY_FREE\x10\x00\x12\r\n\tCOPY_ONCE\x10\x02\x12\x0e\n\nCOPY_NEVER\x10\x03\x12\r\n\tCGMS_NONE\x10*\x1a\x31\n\nKeyControl\x12\x17\n\x0fKeyControlBlock\x18\x01 \x02(\x0c\x12\n\n\x02Iv\x18\x02 \x02(\x0c\x1a|\n\x1dOperatorSessionKeyPermissions\x12\x14\n\x0c\x41llowEncrypt\x18\x01 \x01(\r\x12\x14\n\x0c\x41llowDecrypt\x18\x02 \x01(\r\x12\x11\n\tAllowSign\x18\x03 \x01(\r\x12\x1c\n\x14\x41llowSignatureVerify\x18\x04 \x01(\r\x1a\x99\x01\n\x19VideoResolutionConstraint\x12\x1b\n\x13MinResolutionPixels\x18\x01 \x01(\r\x12\x1b\n\x13MaxResolutionPixels\x18\x02 \x01(\r\x12\x42\n\x12RequiredProtection\x18\x03 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\"J\n\x07KeyType\x12\x0b\n\x07SIGNING\x10\x01\x12\x0b\n\x07\x43ONTENT\x10\x02\x12\x0f\n\x0bKEY_CONTROL\x10\x03\x12\x14\n\x10OPERATOR_SESSION\x10\x04\"z\n\rSecurityLevel\x12\x14\n\x10SW_SECURE_CRYPTO\x10\x01\x12\x14\n\x10SW_SECURE_DECODE\x10\x02\x12\x14\n\x10HW_SECURE_CRYPTO\x10\x03\x12\x14\n\x10HW_SECURE_DECODE\x10\x04\x12\x11\n\rHW_SECURE_ALL\x10\x05\"\x98\x01\n\x0cLicenseError\x12&\n\tErrorCode\x18\x01 \x01(\x0e\x32\x13.LicenseError.Error\"`\n\x05\x45rror\x12\x1e\n\x1aINVALID_DEVICE_CERTIFICATE\x10\x01\x12\x1e\n\x1aREVOKED_DEVICE_CERTIFICATE\x10\x02\x12\x17\n\x13SERVICE_UNAVAILABLE\x10\x03\"\xac\x07\n\x0eLicenseRequest\x12\'\n\x08\x43lientId\x18\x01 \x01(\x0b\x32\x15.ClientIdentification\x12\x38\n\tContentId\x18\x02 \x01(\x0b\x32%.LicenseRequest.ContentIdentification\x12)\n\x04Type\x18\x03 \x01(\x0e\x32\x1b.LicenseRequest.RequestType\x12\x13\n\x0bRequestTime\x18\x04 \x01(\r\x12!\n\x19KeyControlNonceDeprecated\x18\x05 \x01(\x0c\x12)\n\x0fProtocolVersion\x18\x06 \x01(\x0e\x32\x10.ProtocolVersion\x12\x17\n\x0fKeyControlNonce\x18\x07 \x01(\r\x12\x39\n\x11\x45ncryptedClientId\x18\x08 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x1a\xa2\x04\n\x15\x43ontentIdentification\x12:\n\x06\x43\x65ncId\x18\x01 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.CENC\x12:\n\x06WebmId\x18\x02 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.WebM\x12\x46\n\x07License\x18\x03 \x01(\x0b\x32\x35.LicenseRequest.ContentIdentification.ExistingLicense\x1a_\n\x04\x43\x45NC\x12!\n\x04Pssh\x18\x01 \x01(\x0b\x32\x13.WidevineCencHeader\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1aL\n\x04WebM\x12\x0e\n\x06Header\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1a\x99\x01\n\x0f\x45xistingLicense\x12)\n\tLicenseId\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12\x1b\n\x13SecondsSinceStarted\x18\x02 \x01(\r\x12\x1e\n\x16SecondsSinceLastPlayed\x18\x03 \x01(\r\x12\x1e\n\x16SessionUsageTableEntry\x18\x04 \x01(\x0c\"0\n\x0bRequestType\x12\x07\n\x03NEW\x10\x01\x12\x0b\n\x07RENEWAL\x10\x02\x12\x0b\n\x07RELEASE\x10\x03\"\xa9\x07\n\x11LicenseRequestRaw\x12\'\n\x08\x43lientId\x18\x01 \x01(\x0b\x32\x15.ClientIdentification\x12;\n\tContentId\x18\x02 \x01(\x0b\x32(.LicenseRequestRaw.ContentIdentification\x12,\n\x04Type\x18\x03 \x01(\x0e\x32\x1e.LicenseRequestRaw.RequestType\x12\x13\n\x0bRequestTime\x18\x04 \x01(\r\x12!\n\x19KeyControlNonceDeprecated\x18\x05 \x01(\x0c\x12)\n\x0fProtocolVersion\x18\x06 \x01(\x0e\x32\x10.ProtocolVersion\x12\x17\n\x0fKeyControlNonce\x18\x07 \x01(\r\x12\x39\n\x11\x45ncryptedClientId\x18\x08 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x1a\x96\x04\n\x15\x43ontentIdentification\x12=\n\x06\x43\x65ncId\x18\x01 \x01(\x0b\x32-.LicenseRequestRaw.ContentIdentification.CENC\x12=\n\x06WebmId\x18\x02 \x01(\x0b\x32-.LicenseRequestRaw.ContentIdentification.WebM\x12I\n\x07License\x18\x03 \x01(\x0b\x32\x38.LicenseRequestRaw.ContentIdentification.ExistingLicense\x1aJ\n\x04\x43\x45NC\x12\x0c\n\x04Pssh\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1aL\n\x04WebM\x12\x0e\n\x06Header\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1a\x99\x01\n\x0f\x45xistingLicense\x12)\n\tLicenseId\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12\x1b\n\x13SecondsSinceStarted\x18\x02 \x01(\r\x12\x1e\n\x16SecondsSinceLastPlayed\x18\x03 \x01(\r\x12\x1e\n\x16SessionUsageTableEntry\x18\x04 \x01(\x0c\"0\n\x0bRequestType\x12\x07\n\x03NEW\x10\x01\x12\x0b\n\x07RENEWAL\x10\x02\x12\x0b\n\x07RELEASE\x10\x03\"\xa6\x02\n\x15ProvisionedDeviceInfo\x12\x10\n\x08SystemId\x18\x01 \x01(\r\x12\x0b\n\x03Soc\x18\x02 \x01(\t\x12\x14\n\x0cManufacturer\x18\x03 \x01(\t\x12\r\n\x05Model\x18\x04 \x01(\t\x12\x12\n\nDeviceType\x18\x05 \x01(\t\x12\x11\n\tModelYear\x18\x06 \x01(\r\x12=\n\rSecurityLevel\x18\x07 \x01(\x0e\x32&.ProvisionedDeviceInfo.WvSecurityLevel\x12\x12\n\nTestDevice\x18\x08 \x01(\r\"O\n\x0fWvSecurityLevel\x12\x15\n\x11LEVEL_UNSPECIFIED\x10\x00\x12\x0b\n\x07LEVEL_1\x10\x01\x12\x0b\n\x07LEVEL_2\x10\x02\x12\x0b\n\x07LEVEL_3\x10\x03\"\x15\n\x13ProvisioningOptions\"\x15\n\x13ProvisioningRequest\"\x16\n\x14ProvisioningResponse\"i\n\x11RemoteAttestation\x12\x33\n\x0b\x43\x65rtificate\x18\x01 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x12\x0c\n\x04Salt\x18\x02 \x01(\t\x12\x11\n\tSignature\x18\x03 \x01(\t\"\r\n\x0bSessionInit\"\x0e\n\x0cSessionState\"\x1d\n\x1bSignedCertificateStatusList\"\x86\x01\n\x17SignedDeviceCertificate\x12.\n\x12_DeviceCertificate\x18\x01 \x01(\x0b\x32\x12.DeviceCertificate\x12\x11\n\tSignature\x18\x02 \x01(\x0c\x12(\n\x06Signer\x18\x03 \x01(\x0b\x32\x18.SignedDeviceCertificate\"\x1b\n\x19SignedProvisioningMessage\"\x9b\x02\n\rSignedMessage\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedMessage.MessageType\x12\x0b\n\x03Msg\x18\x02 \x01(\x0c\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xc5\x02\n\x12WidevineCencHeader\x12\x30\n\talgorithm\x18\x01 \x01(\x0e\x32\x1d.WidevineCencHeader.Algorithm\x12\x0e\n\x06key_id\x18\x02 \x03(\x0c\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x12\n\ncontent_id\x18\x04 \x01(\x0c\x12\x1d\n\x15track_type_deprecated\x18\x05 \x01(\t\x12\x0e\n\x06policy\x18\x06 \x01(\t\x12\x1b\n\x13\x63rypto_period_index\x18\x07 \x01(\r\x12\x17\n\x0fgrouped_license\x18\x08 \x01(\x0c\x12\x19\n\x11protection_scheme\x18\t \x01(\r\x12\x1d\n\x15\x63rypto_period_seconds\x18\n \x01(\r\"(\n\tAlgorithm\x12\x0f\n\x0bUNENCRYPTED\x10\x00\x12\n\n\x06\x41\x45SCTR\x10\x01\"\xba\x02\n\x14SignedLicenseRequest\x12/\n\x04Type\x18\x01 \x01(\x0e\x32!.SignedLicenseRequest.MessageType\x12\x1c\n\x03Msg\x18\x02 \x01(\x0b\x32\x0f.LicenseRequest\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xc3\x02\n\x17SignedLicenseRequestRaw\x12\x32\n\x04Type\x18\x01 \x01(\x0e\x32$.SignedLicenseRequestRaw.MessageType\x12\x1f\n\x03Msg\x18\x02 \x01(\x0b\x32\x12.LicenseRequestRaw\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xa5\x02\n\rSignedLicense\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedLicense.MessageType\x12\x15\n\x03Msg\x18\x02 \x01(\x0b\x32\x08.License\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xcb\x02\n\x18SignedServiceCertificate\x12\x33\n\x04Type\x18\x01 \x01(\x0e\x32%.SignedServiceCertificate.MessageType\x12%\n\x03Msg\x18\x02 \x01(\x0b\x32\x18.SignedDeviceCertificate\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xb5\x01\n\nFileHashes\x12\x0e\n\x06signer\x18\x01 \x01(\x0c\x12)\n\nsignatures\x18\x02 \x03(\x0b\x32\x15.FileHashes.Signature\x1al\n\tSignature\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x14\n\x0ctest_signing\x18\x02 \x01(\x08\x12\x12\n\nSHA512Hash\x18\x03 \x01(\x0c\x12\x10\n\x08main_exe\x18\x04 \x01(\x08\x12\x11\n\tsignature\x18\x05 \x01(\x0c*1\n\x0bLicenseType\x12\x08\n\x04ZERO\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01\x12\x0b\n\x07OFFLINE\x10\x02*\x1e\n\x0fProtocolVersion\x12\x0b\n\x07\x43URRENT\x10\x15') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +_LICENSETYPE = _descriptor.EnumDescriptor( + name='LicenseType', + full_name='LicenseType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ZERO', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='DEFAULT', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='OFFLINE', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=8362, + serialized_end=8411, +) +_sym_db.RegisterEnumDescriptor(_LICENSETYPE) + +LicenseType = enum_type_wrapper.EnumTypeWrapper(_LICENSETYPE) +_PROTOCOLVERSION = _descriptor.EnumDescriptor( + name='ProtocolVersion', + full_name='ProtocolVersion', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='CURRENT', index=0, number=21, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=8413, + serialized_end=8443, +) +_sym_db.RegisterEnumDescriptor(_PROTOCOLVERSION) + +ProtocolVersion = enum_type_wrapper.EnumTypeWrapper(_PROTOCOLVERSION) +ZERO = 0 +DEFAULT = 1 +OFFLINE = 2 +CURRENT = 21 + + +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION = _descriptor.EnumDescriptor( + name='HdcpVersion', + full_name='ClientIdentification.ClientCapabilities.HdcpVersion', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='HDCP_NONE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V1', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2_1', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2_2', index=4, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=617, + serialized_end=701, +) +_sym_db.RegisterEnumDescriptor(_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION) + +_CLIENTIDENTIFICATION_TOKENTYPE = _descriptor.EnumDescriptor( + name='TokenType', + full_name='ClientIdentification.TokenType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='KEYBOX', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='DEVICE_CERTIFICATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REMOTE_ATTESTATION_CERTIFICATE', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=703, + serialized_end=786, +) +_sym_db.RegisterEnumDescriptor(_CLIENTIDENTIFICATION_TOKENTYPE) + +_DEVICECERTIFICATE_CERTIFICATETYPE = _descriptor.EnumDescriptor( + name='CertificateType', + full_name='DeviceCertificate.CertificateType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ROOT', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='INTERMEDIATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='USER_DEVICE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=997, + serialized_end=1072, +) +_sym_db.RegisterEnumDescriptor(_DEVICECERTIFICATE_CERTIFICATETYPE) + +_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS = _descriptor.EnumDescriptor( + name='CertificateStatus', + full_name='DeviceCertificateStatus.CertificateStatus', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='VALID', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REVOKED', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=1228, + serialized_end=1271, +) +_sym_db.RegisterEnumDescriptor(_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS) + +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS = _descriptor.EnumDescriptor( + name='CGMS', + full_name='License.KeyContainer.OutputProtection.CGMS', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='COPY_FREE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='COPY_ONCE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='COPY_NEVER', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CGMS_NONE', index=3, number=42, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2949, + serialized_end=3016, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS) + +_LICENSE_KEYCONTAINER_KEYTYPE = _descriptor.EnumDescriptor( + name='KeyType', + full_name='License.KeyContainer.KeyType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SIGNING', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CONTENT', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='KEY_CONTROL', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='OPERATOR_SESSION', index=3, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3351, + serialized_end=3425, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_KEYTYPE) + +_LICENSE_KEYCONTAINER_SECURITYLEVEL = _descriptor.EnumDescriptor( + name='SecurityLevel', + full_name='License.KeyContainer.SecurityLevel', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SW_SECURE_CRYPTO', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SW_SECURE_DECODE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_CRYPTO', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_DECODE', index=3, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_ALL', index=4, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3427, + serialized_end=3549, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_SECURITYLEVEL) + +_LICENSEERROR_ERROR = _descriptor.EnumDescriptor( + name='Error', + full_name='LicenseError.Error', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='INVALID_DEVICE_CERTIFICATE', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REVOKED_DEVICE_CERTIFICATE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_UNAVAILABLE', index=2, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3608, + serialized_end=3704, +) +_sym_db.RegisterEnumDescriptor(_LICENSEERROR_ERROR) + +_LICENSEREQUEST_REQUESTTYPE = _descriptor.EnumDescriptor( + name='RequestType', + full_name='LicenseRequest.RequestType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='NEW', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RENEWAL', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RELEASE', index=2, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=4599, + serialized_end=4647, +) +_sym_db.RegisterEnumDescriptor(_LICENSEREQUEST_REQUESTTYPE) + +_LICENSEREQUESTRAW_REQUESTTYPE = _descriptor.EnumDescriptor( + name='RequestType', + full_name='LicenseRequestRaw.RequestType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='NEW', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RENEWAL', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RELEASE', index=2, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=4599, + serialized_end=4647, +) +_sym_db.RegisterEnumDescriptor(_LICENSEREQUESTRAW_REQUESTTYPE) + +_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL = _descriptor.EnumDescriptor( + name='WvSecurityLevel', + full_name='ProvisionedDeviceInfo.WvSecurityLevel', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LEVEL_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_1', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_2', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_3', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=5805, + serialized_end=5884, +) +_sym_db.RegisterEnumDescriptor(_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL) + +_SIGNEDMESSAGE_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedMessage.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=3, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=4, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6450, + serialized_end=6575, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDMESSAGE_MESSAGETYPE) + +_WIDEVINECENCHEADER_ALGORITHM = _descriptor.EnumDescriptor( + name='Algorithm', + full_name='WidevineCencHeader.Algorithm', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='UNENCRYPTED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='AESCTR', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6863, + serialized_end=6903, +) +_sym_db.RegisterEnumDescriptor(_WIDEVINECENCHEADER_ALGORITHM) + +_SIGNEDLICENSEREQUEST_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedLicenseRequest.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=3, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=4, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6450, + serialized_end=6575, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUEST_MESSAGETYPE) + +_SIGNEDLICENSEREQUESTRAW_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedLicenseRequestRaw.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=3, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=4, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6450, + serialized_end=6575, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUESTRAW_MESSAGETYPE) + +_SIGNEDLICENSE_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedLicense.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=3, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=4, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6450, + serialized_end=6575, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSE_MESSAGETYPE) + +_SIGNEDSERVICECERTIFICATE_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedServiceCertificate.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=3, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=4, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6450, + serialized_end=6575, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDSERVICECERTIFICATE_MESSAGETYPE) + + +_CLIENTIDENTIFICATION_NAMEVALUE = _descriptor.Descriptor( + name='NameValue', + full_name='ClientIdentification.NameValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Name', full_name='ClientIdentification.NameValue.Name', index=0, + number=1, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Value', full_name='ClientIdentification.NameValue.Value', index=1, + number=2, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=366, + serialized_end=406, +) + +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES = _descriptor.Descriptor( + name='ClientCapabilities', + full_name='ClientIdentification.ClientCapabilities', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ClientToken', full_name='ClientIdentification.ClientCapabilities.ClientToken', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionToken', full_name='ClientIdentification.ClientCapabilities.SessionToken', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='VideoResolutionConstraints', full_name='ClientIdentification.ClientCapabilities.VideoResolutionConstraints', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='MaxHdcpVersion', full_name='ClientIdentification.ClientCapabilities.MaxHdcpVersion', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='OemCryptoApiVersion', full_name='ClientIdentification.ClientCapabilities.OemCryptoApiVersion', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=409, + serialized_end=701, +) + +_CLIENTIDENTIFICATION = _descriptor.Descriptor( + name='ClientIdentification', + full_name='ClientIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='ClientIdentification.Type', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Token', full_name='ClientIdentification.Token', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ClientInfo', full_name='ClientIdentification.ClientInfo', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderClientToken', full_name='ClientIdentification.ProviderClientToken', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseCounter', full_name='ClientIdentification.LicenseCounter', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_ClientCapabilities', full_name='ClientIdentification._ClientCapabilities', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_FileHashes', full_name='ClientIdentification._FileHashes', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_CLIENTIDENTIFICATION_NAMEVALUE, _CLIENTIDENTIFICATION_CLIENTCAPABILITIES, ], + enum_types=[ + _CLIENTIDENTIFICATION_TOKENTYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=43, + serialized_end=786, +) + + +_DEVICECERTIFICATE = _descriptor.Descriptor( + name='DeviceCertificate', + full_name='DeviceCertificate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='DeviceCertificate.Type', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SerialNumber', full_name='DeviceCertificate.SerialNumber', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CreationTimeSeconds', full_name='DeviceCertificate.CreationTimeSeconds', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PublicKey', full_name='DeviceCertificate.PublicKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SystemId', full_name='DeviceCertificate.SystemId', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='TestDeviceDeprecated', full_name='DeviceCertificate.TestDeviceDeprecated', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ServiceId', full_name='DeviceCertificate.ServiceId', index=6, + number=7, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _DEVICECERTIFICATE_CERTIFICATETYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=789, + serialized_end=1072, +) + + +_DEVICECERTIFICATESTATUS = _descriptor.Descriptor( + name='DeviceCertificateStatus', + full_name='DeviceCertificateStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='SerialNumber', full_name='DeviceCertificateStatus.SerialNumber', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Status', full_name='DeviceCertificateStatus.Status', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='DeviceInfo', full_name='DeviceCertificateStatus.DeviceInfo', index=2, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1075, + serialized_end=1271, +) + + +_DEVICECERTIFICATESTATUSLIST = _descriptor.Descriptor( + name='DeviceCertificateStatusList', + full_name='DeviceCertificateStatusList', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CreationTimeSeconds', full_name='DeviceCertificateStatusList.CreationTimeSeconds', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CertificateStatus', full_name='DeviceCertificateStatusList.CertificateStatus', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1273, + serialized_end=1384, +) + + +_ENCRYPTEDCLIENTIDENTIFICATION = _descriptor.Descriptor( + name='EncryptedClientIdentification', + full_name='EncryptedClientIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ServiceId', full_name='EncryptedClientIdentification.ServiceId', index=0, + number=1, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ServiceCertificateSerialNumber', full_name='EncryptedClientIdentification.ServiceCertificateSerialNumber', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientId', full_name='EncryptedClientIdentification.EncryptedClientId', index=2, + number=3, type=12, cpp_type=9, label=2, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientIdIv', full_name='EncryptedClientIdentification.EncryptedClientIdIv', index=3, + number=4, type=12, cpp_type=9, label=2, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedPrivacyKey', full_name='EncryptedClientIdentification.EncryptedPrivacyKey', index=4, + number=5, type=12, cpp_type=9, label=2, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1387, + serialized_end=1562, +) + + +_LICENSEIDENTIFICATION = _descriptor.Descriptor( + name='LicenseIdentification', + full_name='LicenseIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseIdentification.RequestId', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionId', full_name='LicenseIdentification.SessionId', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PurchaseId', full_name='LicenseIdentification.PurchaseId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='LicenseIdentification.Type', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Version', full_name='LicenseIdentification.Version', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderSessionToken', full_name='LicenseIdentification.ProviderSessionToken', index=5, + number=6, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1565, + serialized_end=1721, +) + + +_LICENSE_POLICY = _descriptor.Descriptor( + name='Policy', + full_name='License.Policy', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CanPlay', full_name='License.Policy.CanPlay', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CanPersist', full_name='License.Policy.CanPersist', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CanRenew', full_name='License.Policy.CanRenew', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RentalDurationSeconds', full_name='License.Policy.RentalDurationSeconds', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PlaybackDurationSeconds', full_name='License.Policy.PlaybackDurationSeconds', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseDurationSeconds', full_name='License.Policy.LicenseDurationSeconds', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalRecoveryDurationSeconds', full_name='License.Policy.RenewalRecoveryDurationSeconds', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalServerUrl', full_name='License.Policy.RenewalServerUrl', index=7, + number=8, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalDelaySeconds', full_name='License.Policy.RenewalDelaySeconds', index=8, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalRetryIntervalSeconds', full_name='License.Policy.RenewalRetryIntervalSeconds', index=9, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewWithUsage', full_name='License.Policy.RenewWithUsage', index=10, + number=11, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1958, + serialized_end=2273, +) + +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION = _descriptor.Descriptor( + name='OutputProtection', + full_name='License.KeyContainer.OutputProtection', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Hdcp', full_name='License.KeyContainer.OutputProtection.Hdcp', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CgmsFlags', full_name='License.KeyContainer.OutputProtection.CgmsFlags', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2797, + serialized_end=3016, +) + +_LICENSE_KEYCONTAINER_KEYCONTROL = _descriptor.Descriptor( + name='KeyControl', + full_name='License.KeyContainer.KeyControl', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='KeyControlBlock', full_name='License.KeyContainer.KeyControl.KeyControlBlock', index=0, + number=1, type=12, cpp_type=9, label=2, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Iv', full_name='License.KeyContainer.KeyControl.Iv', index=1, + number=2, type=12, cpp_type=9, label=2, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3018, + serialized_end=3067, +) + +_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS = _descriptor.Descriptor( + name='OperatorSessionKeyPermissions', + full_name='License.KeyContainer.OperatorSessionKeyPermissions', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='AllowEncrypt', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowEncrypt', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowDecrypt', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowDecrypt', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowSign', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowSign', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowSignatureVerify', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowSignatureVerify', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3069, + serialized_end=3193, +) + +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT = _descriptor.Descriptor( + name='VideoResolutionConstraint', + full_name='License.KeyContainer.VideoResolutionConstraint', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='MinResolutionPixels', full_name='License.KeyContainer.VideoResolutionConstraint.MinResolutionPixels', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='MaxResolutionPixels', full_name='License.KeyContainer.VideoResolutionConstraint.MaxResolutionPixels', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequiredProtection', full_name='License.KeyContainer.VideoResolutionConstraint.RequiredProtection', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3196, + serialized_end=3349, +) + +_LICENSE_KEYCONTAINER = _descriptor.Descriptor( + name='KeyContainer', + full_name='License.KeyContainer', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Id', full_name='License.KeyContainer.Id', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Iv', full_name='License.KeyContainer.Iv', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Key', full_name='License.KeyContainer.Key', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='License.KeyContainer.Type', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Level', full_name='License.KeyContainer.Level', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequiredProtection', full_name='License.KeyContainer.RequiredProtection', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestedProtection', full_name='License.KeyContainer.RequestedProtection', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_KeyControl', full_name='License.KeyContainer._KeyControl', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_OperatorSessionKeyPermissions', full_name='License.KeyContainer._OperatorSessionKeyPermissions', index=8, + number=9, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='VideoResolutionConstraints', full_name='License.KeyContainer.VideoResolutionConstraints', index=9, + number=10, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSE_KEYCONTAINER_OUTPUTPROTECTION, _LICENSE_KEYCONTAINER_KEYCONTROL, _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS, _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT, ], + enum_types=[ + _LICENSE_KEYCONTAINER_KEYTYPE, + _LICENSE_KEYCONTAINER_SECURITYLEVEL, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2276, + serialized_end=3549, +) + +_LICENSE = _descriptor.Descriptor( + name='License', + full_name='License', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Id', full_name='License.Id', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_Policy', full_name='License._Policy', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Key', full_name='License.Key', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseStartTime', full_name='License.LicenseStartTime', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestationVerified', full_name='License.RemoteAttestationVerified', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderClientToken', full_name='License.ProviderClientToken', index=5, + number=6, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProtectionScheme', full_name='License.ProtectionScheme', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSE_POLICY, _LICENSE_KEYCONTAINER, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1724, + serialized_end=3549, +) + + +_LICENSEERROR = _descriptor.Descriptor( + name='LicenseError', + full_name='LicenseError', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ErrorCode', full_name='LicenseError.ErrorCode', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _LICENSEERROR_ERROR, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3552, + serialized_end=3704, +) + + +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC = _descriptor.Descriptor( + name='CENC', + full_name='LicenseRequest.ContentIdentification.CENC', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Pssh', full_name='LicenseRequest.ContentIdentification.CENC.Pssh', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequest.ContentIdentification.CENC.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequest.ContentIdentification.CENC.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4268, + serialized_end=4363, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM = _descriptor.Descriptor( + name='WebM', + full_name='LicenseRequest.ContentIdentification.WebM', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Header', full_name='LicenseRequest.ContentIdentification.WebM.Header', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequest.ContentIdentification.WebM.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequest.ContentIdentification.WebM.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4365, + serialized_end=4441, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE = _descriptor.Descriptor( + name='ExistingLicense', + full_name='LicenseRequest.ContentIdentification.ExistingLicense', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='LicenseId', full_name='LicenseRequest.ContentIdentification.ExistingLicense.LicenseId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceStarted', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SecondsSinceStarted', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceLastPlayed', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SecondsSinceLastPlayed', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionUsageTableEntry', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SessionUsageTableEntry', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4444, + serialized_end=4597, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION = _descriptor.Descriptor( + name='ContentIdentification', + full_name='LicenseRequest.ContentIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CencId', full_name='LicenseRequest.ContentIdentification.CencId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='WebmId', full_name='LicenseRequest.ContentIdentification.WebmId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='License', full_name='LicenseRequest.ContentIdentification.License', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC, _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM, _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4051, + serialized_end=4597, +) + +_LICENSEREQUEST = _descriptor.Descriptor( + name='LicenseRequest', + full_name='LicenseRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ClientId', full_name='LicenseRequest.ClientId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ContentId', full_name='LicenseRequest.ContentId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='LicenseRequest.Type', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestTime', full_name='LicenseRequest.RequestTime', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonceDeprecated', full_name='LicenseRequest.KeyControlNonceDeprecated', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProtocolVersion', full_name='LicenseRequest.ProtocolVersion', index=5, + number=6, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=21, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonce', full_name='LicenseRequest.KeyControlNonce', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientId', full_name='LicenseRequest.EncryptedClientId', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUEST_CONTENTIDENTIFICATION, ], + enum_types=[ + _LICENSEREQUEST_REQUESTTYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3707, + serialized_end=4647, +) + + +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC = _descriptor.Descriptor( + name='CENC', + full_name='LicenseRequestRaw.ContentIdentification.CENC', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Pssh', full_name='LicenseRequestRaw.ContentIdentification.CENC.Pssh', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequestRaw.ContentIdentification.CENC.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequestRaw.ContentIdentification.CENC.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5229, + serialized_end=5303, +) + +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM = _descriptor.Descriptor( + name='WebM', + full_name='LicenseRequestRaw.ContentIdentification.WebM', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Header', full_name='LicenseRequestRaw.ContentIdentification.WebM.Header', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequestRaw.ContentIdentification.WebM.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequestRaw.ContentIdentification.WebM.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4365, + serialized_end=4441, +) + +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE = _descriptor.Descriptor( + name='ExistingLicense', + full_name='LicenseRequestRaw.ContentIdentification.ExistingLicense', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='LicenseId', full_name='LicenseRequestRaw.ContentIdentification.ExistingLicense.LicenseId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceStarted', full_name='LicenseRequestRaw.ContentIdentification.ExistingLicense.SecondsSinceStarted', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceLastPlayed', full_name='LicenseRequestRaw.ContentIdentification.ExistingLicense.SecondsSinceLastPlayed', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionUsageTableEntry', full_name='LicenseRequestRaw.ContentIdentification.ExistingLicense.SessionUsageTableEntry', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4444, + serialized_end=4597, +) + +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION = _descriptor.Descriptor( + name='ContentIdentification', + full_name='LicenseRequestRaw.ContentIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CencId', full_name='LicenseRequestRaw.ContentIdentification.CencId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='WebmId', full_name='LicenseRequestRaw.ContentIdentification.WebmId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='License', full_name='LicenseRequestRaw.ContentIdentification.License', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC, _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM, _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5003, + serialized_end=5537, +) + +_LICENSEREQUESTRAW = _descriptor.Descriptor( + name='LicenseRequestRaw', + full_name='LicenseRequestRaw', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ClientId', full_name='LicenseRequestRaw.ClientId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ContentId', full_name='LicenseRequestRaw.ContentId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='LicenseRequestRaw.Type', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestTime', full_name='LicenseRequestRaw.RequestTime', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonceDeprecated', full_name='LicenseRequestRaw.KeyControlNonceDeprecated', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProtocolVersion', full_name='LicenseRequestRaw.ProtocolVersion', index=5, + number=6, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=21, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonce', full_name='LicenseRequestRaw.KeyControlNonce', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientId', full_name='LicenseRequestRaw.EncryptedClientId', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUESTRAW_CONTENTIDENTIFICATION, ], + enum_types=[ + _LICENSEREQUESTRAW_REQUESTTYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4650, + serialized_end=5587, +) + + +_PROVISIONEDDEVICEINFO = _descriptor.Descriptor( + name='ProvisionedDeviceInfo', + full_name='ProvisionedDeviceInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='SystemId', full_name='ProvisionedDeviceInfo.SystemId', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Soc', full_name='ProvisionedDeviceInfo.Soc', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Manufacturer', full_name='ProvisionedDeviceInfo.Manufacturer', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Model', full_name='ProvisionedDeviceInfo.Model', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='DeviceType', full_name='ProvisionedDeviceInfo.DeviceType', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ModelYear', full_name='ProvisionedDeviceInfo.ModelYear', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecurityLevel', full_name='ProvisionedDeviceInfo.SecurityLevel', index=6, + number=7, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='TestDevice', full_name='ProvisionedDeviceInfo.TestDevice', index=7, + number=8, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5590, + serialized_end=5884, +) + + +_PROVISIONINGOPTIONS = _descriptor.Descriptor( + name='ProvisioningOptions', + full_name='ProvisioningOptions', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5886, + serialized_end=5907, +) + + +_PROVISIONINGREQUEST = _descriptor.Descriptor( + name='ProvisioningRequest', + full_name='ProvisioningRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5909, + serialized_end=5930, +) + + +_PROVISIONINGRESPONSE = _descriptor.Descriptor( + name='ProvisioningResponse', + full_name='ProvisioningResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5932, + serialized_end=5954, +) + + +_REMOTEATTESTATION = _descriptor.Descriptor( + name='RemoteAttestation', + full_name='RemoteAttestation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Certificate', full_name='RemoteAttestation.Certificate', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Salt', full_name='RemoteAttestation.Salt', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='RemoteAttestation.Signature', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5956, + serialized_end=6061, +) + + +_SESSIONINIT = _descriptor.Descriptor( + name='SessionInit', + full_name='SessionInit', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6063, + serialized_end=6076, +) + + +_SESSIONSTATE = _descriptor.Descriptor( + name='SessionState', + full_name='SessionState', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6078, + serialized_end=6092, +) + + +_SIGNEDCERTIFICATESTATUSLIST = _descriptor.Descriptor( + name='SignedCertificateStatusList', + full_name='SignedCertificateStatusList', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6094, + serialized_end=6123, +) + + +_SIGNEDDEVICECERTIFICATE = _descriptor.Descriptor( + name='SignedDeviceCertificate', + full_name='SignedDeviceCertificate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='_DeviceCertificate', full_name='SignedDeviceCertificate._DeviceCertificate', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedDeviceCertificate.Signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signer', full_name='SignedDeviceCertificate.Signer', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6126, + serialized_end=6260, +) + + +_SIGNEDPROVISIONINGMESSAGE = _descriptor.Descriptor( + name='SignedProvisioningMessage', + full_name='SignedProvisioningMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6262, + serialized_end=6289, +) + + +_SIGNEDMESSAGE = _descriptor.Descriptor( + name='SignedMessage', + full_name='SignedMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedMessage.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedMessage.Msg', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedMessage.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedMessage.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedMessage.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDMESSAGE_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6292, + serialized_end=6575, +) + + +_WIDEVINECENCHEADER = _descriptor.Descriptor( + name='WidevineCencHeader', + full_name='WidevineCencHeader', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='algorithm', full_name='WidevineCencHeader.algorithm', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='key_id', full_name='WidevineCencHeader.key_id', index=1, + number=2, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='provider', full_name='WidevineCencHeader.provider', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='content_id', full_name='WidevineCencHeader.content_id', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='track_type_deprecated', full_name='WidevineCencHeader.track_type_deprecated', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='policy', full_name='WidevineCencHeader.policy', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='crypto_period_index', full_name='WidevineCencHeader.crypto_period_index', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='grouped_license', full_name='WidevineCencHeader.grouped_license', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='protection_scheme', full_name='WidevineCencHeader.protection_scheme', index=8, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='crypto_period_seconds', full_name='WidevineCencHeader.crypto_period_seconds', index=9, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _WIDEVINECENCHEADER_ALGORITHM, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6578, + serialized_end=6903, +) + + +_SIGNEDLICENSEREQUEST = _descriptor.Descriptor( + name='SignedLicenseRequest', + full_name='SignedLicenseRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedLicenseRequest.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedLicenseRequest.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedLicenseRequest.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedLicenseRequest.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedLicenseRequest.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDLICENSEREQUEST_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6906, + serialized_end=7220, +) + + +_SIGNEDLICENSEREQUESTRAW = _descriptor.Descriptor( + name='SignedLicenseRequestRaw', + full_name='SignedLicenseRequestRaw', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedLicenseRequestRaw.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedLicenseRequestRaw.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedLicenseRequestRaw.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedLicenseRequestRaw.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedLicenseRequestRaw.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDLICENSEREQUESTRAW_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=7223, + serialized_end=7546, +) + + +_SIGNEDLICENSE = _descriptor.Descriptor( + name='SignedLicense', + full_name='SignedLicense', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedLicense.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedLicense.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedLicense.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedLicense.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedLicense.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDLICENSE_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=7549, + serialized_end=7842, +) + + +_SIGNEDSERVICECERTIFICATE = _descriptor.Descriptor( + name='SignedServiceCertificate', + full_name='SignedServiceCertificate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedServiceCertificate.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedServiceCertificate.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedServiceCertificate.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedServiceCertificate.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedServiceCertificate.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDSERVICECERTIFICATE_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=7845, + serialized_end=8176, +) + + +_FILEHASHES_SIGNATURE = _descriptor.Descriptor( + name='Signature', + full_name='FileHashes.Signature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='filename', full_name='FileHashes.Signature.filename', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='test_signing', full_name='FileHashes.Signature.test_signing', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SHA512Hash', full_name='FileHashes.Signature.SHA512Hash', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='main_exe', full_name='FileHashes.Signature.main_exe', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='signature', full_name='FileHashes.Signature.signature', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=8252, + serialized_end=8360, +) + +_FILEHASHES = _descriptor.Descriptor( + name='FileHashes', + full_name='FileHashes', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='signer', full_name='FileHashes.signer', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='signatures', full_name='FileHashes.signatures', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_FILEHASHES_SIGNATURE, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=8179, + serialized_end=8360, +) + +_CLIENTIDENTIFICATION_NAMEVALUE.containing_type = _CLIENTIDENTIFICATION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES.fields_by_name['MaxHdcpVersion'].enum_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES.containing_type = _CLIENTIDENTIFICATION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION.containing_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES +_CLIENTIDENTIFICATION.fields_by_name['Type'].enum_type = _CLIENTIDENTIFICATION_TOKENTYPE +_CLIENTIDENTIFICATION.fields_by_name['Token'].message_type = _SIGNEDDEVICECERTIFICATE +_CLIENTIDENTIFICATION.fields_by_name['ClientInfo'].message_type = _CLIENTIDENTIFICATION_NAMEVALUE +_CLIENTIDENTIFICATION.fields_by_name['_ClientCapabilities'].message_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES +_CLIENTIDENTIFICATION.fields_by_name['_FileHashes'].message_type = _FILEHASHES +_CLIENTIDENTIFICATION_TOKENTYPE.containing_type = _CLIENTIDENTIFICATION +_DEVICECERTIFICATE.fields_by_name['Type'].enum_type = _DEVICECERTIFICATE_CERTIFICATETYPE +_DEVICECERTIFICATE_CERTIFICATETYPE.containing_type = _DEVICECERTIFICATE +_DEVICECERTIFICATESTATUS.fields_by_name['Status'].enum_type = _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS +_DEVICECERTIFICATESTATUS.fields_by_name['DeviceInfo'].message_type = _PROVISIONEDDEVICEINFO +_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS.containing_type = _DEVICECERTIFICATESTATUS +_DEVICECERTIFICATESTATUSLIST.fields_by_name['CertificateStatus'].message_type = _DEVICECERTIFICATESTATUS +_LICENSEIDENTIFICATION.fields_by_name['Type'].enum_type = _LICENSETYPE +_LICENSE_POLICY.containing_type = _LICENSE +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.fields_by_name['Hdcp'].enum_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.fields_by_name['CgmsFlags'].enum_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS.containing_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER_KEYCONTROL.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT.fields_by_name['RequiredProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER.fields_by_name['Type'].enum_type = _LICENSE_KEYCONTAINER_KEYTYPE +_LICENSE_KEYCONTAINER.fields_by_name['Level'].enum_type = _LICENSE_KEYCONTAINER_SECURITYLEVEL +_LICENSE_KEYCONTAINER.fields_by_name['RequiredProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER.fields_by_name['RequestedProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER.fields_by_name['_KeyControl'].message_type = _LICENSE_KEYCONTAINER_KEYCONTROL +_LICENSE_KEYCONTAINER.fields_by_name['_OperatorSessionKeyPermissions'].message_type = _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS +_LICENSE_KEYCONTAINER.fields_by_name['VideoResolutionConstraints'].message_type = _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT +_LICENSE_KEYCONTAINER.containing_type = _LICENSE +_LICENSE_KEYCONTAINER_KEYTYPE.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_SECURITYLEVEL.containing_type = _LICENSE_KEYCONTAINER +_LICENSE.fields_by_name['Id'].message_type = _LICENSEIDENTIFICATION +_LICENSE.fields_by_name['_Policy'].message_type = _LICENSE_POLICY +_LICENSE.fields_by_name['Key'].message_type = _LICENSE_KEYCONTAINER +_LICENSEERROR.fields_by_name['ErrorCode'].enum_type = _LICENSEERROR_ERROR +_LICENSEERROR_ERROR.containing_type = _LICENSEERROR +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.fields_by_name['Pssh'].message_type = _WIDEVINECENCHEADER +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE.fields_by_name['LicenseId'].message_type = _LICENSEIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['CencId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['WebmId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['License'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE +_LICENSEREQUEST_CONTENTIDENTIFICATION.containing_type = _LICENSEREQUEST +_LICENSEREQUEST.fields_by_name['ClientId'].message_type = _CLIENTIDENTIFICATION +_LICENSEREQUEST.fields_by_name['ContentId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST.fields_by_name['Type'].enum_type = _LICENSEREQUEST_REQUESTTYPE +_LICENSEREQUEST.fields_by_name['ProtocolVersion'].enum_type = _PROTOCOLVERSION +_LICENSEREQUEST.fields_by_name['EncryptedClientId'].message_type = _ENCRYPTEDCLIENTIDENTIFICATION +_LICENSEREQUEST_REQUESTTYPE.containing_type = _LICENSEREQUEST +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC.containing_type = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM.containing_type = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE.fields_by_name['LicenseId'].message_type = _LICENSEIDENTIFICATION +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE.containing_type = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION.fields_by_name['CencId'].message_type = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION.fields_by_name['WebmId'].message_type = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION.fields_by_name['License'].message_type = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE +_LICENSEREQUESTRAW_CONTENTIDENTIFICATION.containing_type = _LICENSEREQUESTRAW +_LICENSEREQUESTRAW.fields_by_name['ClientId'].message_type = _CLIENTIDENTIFICATION +_LICENSEREQUESTRAW.fields_by_name['ContentId'].message_type = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION +_LICENSEREQUESTRAW.fields_by_name['Type'].enum_type = _LICENSEREQUESTRAW_REQUESTTYPE +_LICENSEREQUESTRAW.fields_by_name['ProtocolVersion'].enum_type = _PROTOCOLVERSION +_LICENSEREQUESTRAW.fields_by_name['EncryptedClientId'].message_type = _ENCRYPTEDCLIENTIDENTIFICATION +_LICENSEREQUESTRAW_REQUESTTYPE.containing_type = _LICENSEREQUESTRAW +_PROVISIONEDDEVICEINFO.fields_by_name['SecurityLevel'].enum_type = _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL +_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL.containing_type = _PROVISIONEDDEVICEINFO +_REMOTEATTESTATION.fields_by_name['Certificate'].message_type = _ENCRYPTEDCLIENTIDENTIFICATION +_SIGNEDDEVICECERTIFICATE.fields_by_name['_DeviceCertificate'].message_type = _DEVICECERTIFICATE +_SIGNEDDEVICECERTIFICATE.fields_by_name['Signer'].message_type = _SIGNEDDEVICECERTIFICATE +_SIGNEDMESSAGE.fields_by_name['Type'].enum_type = _SIGNEDMESSAGE_MESSAGETYPE +_SIGNEDMESSAGE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDMESSAGE_MESSAGETYPE.containing_type = _SIGNEDMESSAGE +_WIDEVINECENCHEADER.fields_by_name['algorithm'].enum_type = _WIDEVINECENCHEADER_ALGORITHM +_WIDEVINECENCHEADER_ALGORITHM.containing_type = _WIDEVINECENCHEADER +_SIGNEDLICENSEREQUEST.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUEST_MESSAGETYPE +_SIGNEDLICENSEREQUEST.fields_by_name['Msg'].message_type = _LICENSEREQUEST +_SIGNEDLICENSEREQUEST.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDLICENSEREQUEST_MESSAGETYPE.containing_type = _SIGNEDLICENSEREQUEST +_SIGNEDLICENSEREQUESTRAW.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUESTRAW_MESSAGETYPE +_SIGNEDLICENSEREQUESTRAW.fields_by_name['Msg'].message_type = _LICENSEREQUESTRAW +_SIGNEDLICENSEREQUESTRAW.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDLICENSEREQUESTRAW_MESSAGETYPE.containing_type = _SIGNEDLICENSEREQUESTRAW +_SIGNEDLICENSE.fields_by_name['Type'].enum_type = _SIGNEDLICENSE_MESSAGETYPE +_SIGNEDLICENSE.fields_by_name['Msg'].message_type = _LICENSE +_SIGNEDLICENSE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDLICENSE_MESSAGETYPE.containing_type = _SIGNEDLICENSE +_SIGNEDSERVICECERTIFICATE.fields_by_name['Type'].enum_type = _SIGNEDSERVICECERTIFICATE_MESSAGETYPE +_SIGNEDSERVICECERTIFICATE.fields_by_name['Msg'].message_type = _SIGNEDDEVICECERTIFICATE +_SIGNEDSERVICECERTIFICATE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDSERVICECERTIFICATE_MESSAGETYPE.containing_type = _SIGNEDSERVICECERTIFICATE +_FILEHASHES_SIGNATURE.containing_type = _FILEHASHES +_FILEHASHES.fields_by_name['signatures'].message_type = _FILEHASHES_SIGNATURE +DESCRIPTOR.message_types_by_name['ClientIdentification'] = _CLIENTIDENTIFICATION +DESCRIPTOR.message_types_by_name['DeviceCertificate'] = _DEVICECERTIFICATE +DESCRIPTOR.message_types_by_name['DeviceCertificateStatus'] = _DEVICECERTIFICATESTATUS +DESCRIPTOR.message_types_by_name['DeviceCertificateStatusList'] = _DEVICECERTIFICATESTATUSLIST +DESCRIPTOR.message_types_by_name['EncryptedClientIdentification'] = _ENCRYPTEDCLIENTIDENTIFICATION +DESCRIPTOR.message_types_by_name['LicenseIdentification'] = _LICENSEIDENTIFICATION +DESCRIPTOR.message_types_by_name['License'] = _LICENSE +DESCRIPTOR.message_types_by_name['LicenseError'] = _LICENSEERROR +DESCRIPTOR.message_types_by_name['LicenseRequest'] = _LICENSEREQUEST +DESCRIPTOR.message_types_by_name['LicenseRequestRaw'] = _LICENSEREQUESTRAW +DESCRIPTOR.message_types_by_name['ProvisionedDeviceInfo'] = _PROVISIONEDDEVICEINFO +DESCRIPTOR.message_types_by_name['ProvisioningOptions'] = _PROVISIONINGOPTIONS +DESCRIPTOR.message_types_by_name['ProvisioningRequest'] = _PROVISIONINGREQUEST +DESCRIPTOR.message_types_by_name['ProvisioningResponse'] = _PROVISIONINGRESPONSE +DESCRIPTOR.message_types_by_name['RemoteAttestation'] = _REMOTEATTESTATION +DESCRIPTOR.message_types_by_name['SessionInit'] = _SESSIONINIT +DESCRIPTOR.message_types_by_name['SessionState'] = _SESSIONSTATE +DESCRIPTOR.message_types_by_name['SignedCertificateStatusList'] = _SIGNEDCERTIFICATESTATUSLIST +DESCRIPTOR.message_types_by_name['SignedDeviceCertificate'] = _SIGNEDDEVICECERTIFICATE +DESCRIPTOR.message_types_by_name['SignedProvisioningMessage'] = _SIGNEDPROVISIONINGMESSAGE +DESCRIPTOR.message_types_by_name['SignedMessage'] = _SIGNEDMESSAGE +DESCRIPTOR.message_types_by_name['WidevineCencHeader'] = _WIDEVINECENCHEADER +DESCRIPTOR.message_types_by_name['SignedLicenseRequest'] = _SIGNEDLICENSEREQUEST +DESCRIPTOR.message_types_by_name['SignedLicenseRequestRaw'] = _SIGNEDLICENSEREQUESTRAW +DESCRIPTOR.message_types_by_name['SignedLicense'] = _SIGNEDLICENSE +DESCRIPTOR.message_types_by_name['SignedServiceCertificate'] = _SIGNEDSERVICECERTIFICATE +DESCRIPTOR.message_types_by_name['FileHashes'] = _FILEHASHES +DESCRIPTOR.enum_types_by_name['LicenseType'] = _LICENSETYPE +DESCRIPTOR.enum_types_by_name['ProtocolVersion'] = _PROTOCOLVERSION + +ClientIdentification = _reflection.GeneratedProtocolMessageType('ClientIdentification', (_message.Message,), dict( + + NameValue = _reflection.GeneratedProtocolMessageType('NameValue', (_message.Message,), dict( + DESCRIPTOR = _CLIENTIDENTIFICATION_NAMEVALUE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification.NameValue) + )) + , + + ClientCapabilities = _reflection.GeneratedProtocolMessageType('ClientCapabilities', (_message.Message,), dict( + DESCRIPTOR = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification.ClientCapabilities) + )) + , + DESCRIPTOR = _CLIENTIDENTIFICATION, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification) + )) +_sym_db.RegisterMessage(ClientIdentification) +_sym_db.RegisterMessage(ClientIdentification.NameValue) +_sym_db.RegisterMessage(ClientIdentification.ClientCapabilities) + +DeviceCertificate = _reflection.GeneratedProtocolMessageType('DeviceCertificate', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificate) + )) +_sym_db.RegisterMessage(DeviceCertificate) + +DeviceCertificateStatus = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatus', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATESTATUS, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificateStatus) + )) +_sym_db.RegisterMessage(DeviceCertificateStatus) + +DeviceCertificateStatusList = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatusList', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATESTATUSLIST, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificateStatusList) + )) +_sym_db.RegisterMessage(DeviceCertificateStatusList) + +EncryptedClientIdentification = _reflection.GeneratedProtocolMessageType('EncryptedClientIdentification', (_message.Message,), dict( + DESCRIPTOR = _ENCRYPTEDCLIENTIDENTIFICATION, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:EncryptedClientIdentification) + )) +_sym_db.RegisterMessage(EncryptedClientIdentification) + +LicenseIdentification = _reflection.GeneratedProtocolMessageType('LicenseIdentification', (_message.Message,), dict( + DESCRIPTOR = _LICENSEIDENTIFICATION, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseIdentification) + )) +_sym_db.RegisterMessage(LicenseIdentification) + +License = _reflection.GeneratedProtocolMessageType('License', (_message.Message,), dict( + + Policy = _reflection.GeneratedProtocolMessageType('Policy', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_POLICY, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:License.Policy) + )) + , + + KeyContainer = _reflection.GeneratedProtocolMessageType('KeyContainer', (_message.Message,), dict( + + OutputProtection = _reflection.GeneratedProtocolMessageType('OutputProtection', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.OutputProtection) + )) + , + + KeyControl = _reflection.GeneratedProtocolMessageType('KeyControl', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_KEYCONTROL, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.KeyControl) + )) + , + + OperatorSessionKeyPermissions = _reflection.GeneratedProtocolMessageType('OperatorSessionKeyPermissions', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.OperatorSessionKeyPermissions) + )) + , + + VideoResolutionConstraint = _reflection.GeneratedProtocolMessageType('VideoResolutionConstraint', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.VideoResolutionConstraint) + )) + , + DESCRIPTOR = _LICENSE_KEYCONTAINER, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer) + )) + , + DESCRIPTOR = _LICENSE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:License) + )) +_sym_db.RegisterMessage(License) +_sym_db.RegisterMessage(License.Policy) +_sym_db.RegisterMessage(License.KeyContainer) +_sym_db.RegisterMessage(License.KeyContainer.OutputProtection) +_sym_db.RegisterMessage(License.KeyContainer.KeyControl) +_sym_db.RegisterMessage(License.KeyContainer.OperatorSessionKeyPermissions) +_sym_db.RegisterMessage(License.KeyContainer.VideoResolutionConstraint) + +LicenseError = _reflection.GeneratedProtocolMessageType('LicenseError', (_message.Message,), dict( + DESCRIPTOR = _LICENSEERROR, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseError) + )) +_sym_db.RegisterMessage(LicenseError) + +LicenseRequest = _reflection.GeneratedProtocolMessageType('LicenseRequest', (_message.Message,), dict( + + ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (_message.Message,), dict( + + CENC = _reflection.GeneratedProtocolMessageType('CENC', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.CENC) + )) + , + + WebM = _reflection.GeneratedProtocolMessageType('WebM', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.WebM) + )) + , + + ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.ExistingLicense) + )) + , + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification) + )) + , + DESCRIPTOR = _LICENSEREQUEST, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest) + )) +_sym_db.RegisterMessage(LicenseRequest) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.CENC) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.WebM) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.ExistingLicense) + +LicenseRequestRaw = _reflection.GeneratedProtocolMessageType('LicenseRequestRaw', (_message.Message,), dict( + + ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (_message.Message,), dict( + + CENC = _reflection.GeneratedProtocolMessageType('CENC', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequestRaw.ContentIdentification.CENC) + )) + , + + WebM = _reflection.GeneratedProtocolMessageType('WebM', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequestRaw.ContentIdentification.WebM) + )) + , + + ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequestRaw.ContentIdentification.ExistingLicense) + )) + , + DESCRIPTOR = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequestRaw.ContentIdentification) + )) + , + DESCRIPTOR = _LICENSEREQUESTRAW, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequestRaw) + )) +_sym_db.RegisterMessage(LicenseRequestRaw) +_sym_db.RegisterMessage(LicenseRequestRaw.ContentIdentification) +_sym_db.RegisterMessage(LicenseRequestRaw.ContentIdentification.CENC) +_sym_db.RegisterMessage(LicenseRequestRaw.ContentIdentification.WebM) +_sym_db.RegisterMessage(LicenseRequestRaw.ContentIdentification.ExistingLicense) + +ProvisionedDeviceInfo = _reflection.GeneratedProtocolMessageType('ProvisionedDeviceInfo', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONEDDEVICEINFO, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:ProvisionedDeviceInfo) + )) +_sym_db.RegisterMessage(ProvisionedDeviceInfo) + +ProvisioningOptions = _reflection.GeneratedProtocolMessageType('ProvisioningOptions', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGOPTIONS, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningOptions) + )) +_sym_db.RegisterMessage(ProvisioningOptions) + +ProvisioningRequest = _reflection.GeneratedProtocolMessageType('ProvisioningRequest', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGREQUEST, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningRequest) + )) +_sym_db.RegisterMessage(ProvisioningRequest) + +ProvisioningResponse = _reflection.GeneratedProtocolMessageType('ProvisioningResponse', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGRESPONSE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningResponse) + )) +_sym_db.RegisterMessage(ProvisioningResponse) + +RemoteAttestation = _reflection.GeneratedProtocolMessageType('RemoteAttestation', (_message.Message,), dict( + DESCRIPTOR = _REMOTEATTESTATION, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:RemoteAttestation) + )) +_sym_db.RegisterMessage(RemoteAttestation) + +SessionInit = _reflection.GeneratedProtocolMessageType('SessionInit', (_message.Message,), dict( + DESCRIPTOR = _SESSIONINIT, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SessionInit) + )) +_sym_db.RegisterMessage(SessionInit) + +SessionState = _reflection.GeneratedProtocolMessageType('SessionState', (_message.Message,), dict( + DESCRIPTOR = _SESSIONSTATE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SessionState) + )) +_sym_db.RegisterMessage(SessionState) + +SignedCertificateStatusList = _reflection.GeneratedProtocolMessageType('SignedCertificateStatusList', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDCERTIFICATESTATUSLIST, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedCertificateStatusList) + )) +_sym_db.RegisterMessage(SignedCertificateStatusList) + +SignedDeviceCertificate = _reflection.GeneratedProtocolMessageType('SignedDeviceCertificate', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDDEVICECERTIFICATE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedDeviceCertificate) + )) +_sym_db.RegisterMessage(SignedDeviceCertificate) + +SignedProvisioningMessage = _reflection.GeneratedProtocolMessageType('SignedProvisioningMessage', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDPROVISIONINGMESSAGE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedProvisioningMessage) + )) +_sym_db.RegisterMessage(SignedProvisioningMessage) + +SignedMessage = _reflection.GeneratedProtocolMessageType('SignedMessage', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDMESSAGE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedMessage) + )) +_sym_db.RegisterMessage(SignedMessage) + +WidevineCencHeader = _reflection.GeneratedProtocolMessageType('WidevineCencHeader', (_message.Message,), dict( + DESCRIPTOR = _WIDEVINECENCHEADER, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:WidevineCencHeader) + )) +_sym_db.RegisterMessage(WidevineCencHeader) + +SignedLicenseRequest = _reflection.GeneratedProtocolMessageType('SignedLicenseRequest', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDLICENSEREQUEST, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedLicenseRequest) + )) +_sym_db.RegisterMessage(SignedLicenseRequest) + +SignedLicenseRequestRaw = _reflection.GeneratedProtocolMessageType('SignedLicenseRequestRaw', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDLICENSEREQUESTRAW, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedLicenseRequestRaw) + )) +_sym_db.RegisterMessage(SignedLicenseRequestRaw) + +SignedLicense = _reflection.GeneratedProtocolMessageType('SignedLicense', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDLICENSE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedLicense) + )) +_sym_db.RegisterMessage(SignedLicense) + +SignedServiceCertificate = _reflection.GeneratedProtocolMessageType('SignedServiceCertificate', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDSERVICECERTIFICATE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:SignedServiceCertificate) + )) +_sym_db.RegisterMessage(SignedServiceCertificate) + +FileHashes = _reflection.GeneratedProtocolMessageType('FileHashes', (_message.Message,), dict( + + Signature = _reflection.GeneratedProtocolMessageType('Signature', (_message.Message,), dict( + DESCRIPTOR = _FILEHASHES_SIGNATURE, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:FileHashes.Signature) + )) + , + DESCRIPTOR = _FILEHASHES, + __module__ = 'pywidevine.cdm.formats.wv_proto2_pb2' + # @@protoc_insertion_point(class_scope:FileHashes) + )) +_sym_db.RegisterMessage(FileHashes) +_sym_db.RegisterMessage(FileHashes.Signature) + + +# @@protoc_insertion_point(module_scope) diff --git a/pywidevine/cdm/formats/wv_proto3.proto b/pywidevine/cdm/formats/wv_proto3.proto new file mode 100644 index 0000000..7861b02 --- /dev/null +++ b/pywidevine/cdm/formats/wv_proto3.proto @@ -0,0 +1,389 @@ +// beware proto3 won't show missing fields it seems, need to change to "proto2" and add "optional" before every field, and remove all the dummy enum members I added: +syntax = "proto3"; + +// from x86 (partial), most of it from the ARM version: +message ClientIdentification { + enum TokenType { + KEYBOX = 0; + DEVICE_CERTIFICATE = 1; + REMOTE_ATTESTATION_CERTIFICATE = 2; + } + message NameValue { + string Name = 1; + string Value = 2; + } + message ClientCapabilities { + enum HdcpVersion { + HDCP_NONE = 0; + HDCP_V1 = 1; + HDCP_V2 = 2; + HDCP_V2_1 = 3; + HDCP_V2_2 = 4; + } + uint32 ClientToken = 1; + uint32 SessionToken = 2; + uint32 VideoResolutionConstraints = 3; + HdcpVersion MaxHdcpVersion = 4; + uint32 OemCryptoApiVersion = 5; + } + TokenType Type = 1; + //bytes Token = 2; // by default the client treats this as blob, but it's usually a DeviceCertificate, so for usefulness sake, I'm replacing it with this one: + SignedDeviceCertificate Token = 2; + repeated NameValue ClientInfo = 3; + bytes ProviderClientToken = 4; + uint32 LicenseCounter = 5; + ClientCapabilities _ClientCapabilities = 6; // how should we deal with duped names? will have to look at proto docs later +} + +message DeviceCertificate { + enum CertificateType { + ROOT = 0; + INTERMEDIATE = 1; + USER_DEVICE = 2; + SERVICE = 3; + } + //ProvisionedDeviceInfo.WvSecurityLevel Type = 1; // is this how one is supposed to call it? (it's an enum) there might be a bug here, with CertificateType getting confused with WvSecurityLevel, for now renaming it (verify against other binaries) + CertificateType Type = 1; + bytes SerialNumber = 2; + uint32 CreationTimeSeconds = 3; + bytes PublicKey = 4; + uint32 SystemId = 5; + uint32 TestDeviceDeprecated = 6; // is it bool or int? + bytes ServiceId = 7; // service URL for service certificates +} + +// missing some references, +message DeviceCertificateStatus { + enum CertificateStatus { + VALID = 0; + REVOKED = 1; + } + bytes SerialNumber = 1; + CertificateStatus Status = 2; + ProvisionedDeviceInfo DeviceInfo = 4; // where is 3? is it deprecated? +} + +message DeviceCertificateStatusList { + uint32 CreationTimeSeconds = 1; + repeated DeviceCertificateStatus CertificateStatus = 2; +} + +message EncryptedClientIdentification { + string ServiceId = 1; + bytes ServiceCertificateSerialNumber = 2; + bytes EncryptedClientId = 3; + bytes EncryptedClientIdIv = 4; + bytes EncryptedPrivacyKey = 5; +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +enum LicenseType { + ZERO = 0; + DEFAULT = 1; // do not know what this is either, but should be 1; on recent versions may go up to 3 (latest x86) +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +// this is just a guess because these globals got lost, but really, do we need more? +enum ProtocolVersion { + DUMMY = 0; + CURRENT = 21; // don't have symbols for this +} + + +message LicenseIdentification { + bytes RequestId = 1; + bytes SessionId = 2; + bytes PurchaseId = 3; + LicenseType Type = 4; + uint32 Version = 5; + bytes ProviderSessionToken = 6; +} + + +message License { + message Policy { + uint32 CanPlay = 1; + uint32 CanPersist = 2; + uint32 CanRenew = 3; + uint32 RentalDurationSeconds = 4; + uint32 PlaybackDurationSeconds = 5; + uint32 LicenseDurationSeconds = 6; + uint32 RenewalRecoveryDurationSeconds = 7; + string RenewalServerUrl = 8; + uint32 RenewalDelaySeconds = 9; + uint32 RenewalRetryIntervalSeconds = 10; + uint32 RenewWithUsage = 11; + uint32 UnknownPolicy12 = 12; + } + message KeyContainer { + enum KeyType { + _NOKEYTYPE = 0; // dummy, added to satisfy proto3, not present in original + SIGNING = 1; + CONTENT = 2; + KEY_CONTROL = 3; + OPERATOR_SESSION = 4; + } + enum SecurityLevel { + _NOSECLEVEL = 0; // dummy, added to satisfy proto3, not present in original + SW_SECURE_CRYPTO = 1; + SW_SECURE_DECODE = 2; + HW_SECURE_CRYPTO = 3; + HW_SECURE_DECODE = 4; + HW_SECURE_ALL = 5; + } + message OutputProtection { + enum CGMS { + COPY_FREE = 0; + COPY_ONCE = 2; + COPY_NEVER = 3; + CGMS_NONE = 0x2A; // PC default! + } + ClientIdentification.ClientCapabilities.HdcpVersion Hdcp = 1; // it's most likely a copy of Hdcp version available here, but compiler optimized it away + CGMS CgmsFlags = 2; + } + message KeyControl { + bytes KeyControlBlock = 1; // what is this? + bytes Iv = 2; + } + message OperatorSessionKeyPermissions { + uint32 AllowEncrypt = 1; + uint32 AllowDecrypt = 2; + uint32 AllowSign = 3; + uint32 AllowSignatureVerify = 4; + } + message VideoResolutionConstraint { + uint32 MinResolutionPixels = 1; + uint32 MaxResolutionPixels = 2; + OutputProtection RequiredProtection = 3; + } + bytes Id = 1; + bytes Iv = 2; + bytes Key = 3; + KeyType Type = 4; + SecurityLevel Level = 5; + OutputProtection RequiredProtection = 6; + OutputProtection RequestedProtection = 7; + KeyControl _KeyControl = 8; // duped names, etc + OperatorSessionKeyPermissions _OperatorSessionKeyPermissions = 9; // duped names, etc + repeated VideoResolutionConstraint VideoResolutionConstraints = 10; + } + LicenseIdentification Id = 1; + Policy _Policy = 2; // duped names, etc + repeated KeyContainer Key = 3; + uint32 LicenseStartTime = 4; + uint32 RemoteAttestationVerified = 5; // bool? + bytes ProviderClientToken = 6; + // there might be more, check with newer versions (I see field 7-8 in a lic) + // this appeared in latest x86: + uint32 ProtectionScheme = 7; // type unconfirmed fully, but it's likely as WidevineCencHeader describesit (fourcc) + bytes UnknownHdcpDataField = 8; +} + +message LicenseError { + enum Error { + DUMMY_NO_ERROR = 0; // dummy, added to satisfy proto3 + INVALID_DEVICE_CERTIFICATE = 1; + REVOKED_DEVICE_CERTIFICATE = 2; + SERVICE_UNAVAILABLE = 3; + } + //LicenseRequest.RequestType ErrorCode; // clang mismatch + Error ErrorCode = 1; +} + +message LicenseRequest { + message ContentIdentification { + message CENC { + // bytes Pssh = 1; // the client's definition is opaque, it doesn't care about the contents, but the PSSH has a clear definition that is understood and requested by the server, thus I'll replace it with: + WidevineCencHeader Pssh = 1; + LicenseType LicenseType = 2; // unfortunately the LicenseType symbols are not present, acceptable value seems to only be 1 + bytes RequestId = 3; + } + message WebM { + bytes Header = 1; // identical to CENC, aside from PSSH and the parent field number used + LicenseType LicenseType = 2; + bytes RequestId = 3; + } + message ExistingLicense { + LicenseIdentification LicenseId = 1; + uint32 SecondsSinceStarted = 2; + uint32 SecondsSinceLastPlayed = 3; + bytes SessionUsageTableEntry = 4; + } + CENC CencId = 1; + WebM WebmId = 2; + ExistingLicense License = 3; + } + enum RequestType { + DUMMY_REQ_TYPE = 0; // dummy, added to satisfy proto3 + NEW = 1; + RENEWAL = 2; + RELEASE = 3; + } + ClientIdentification ClientId = 1; + ContentIdentification ContentId = 2; + RequestType Type = 3; + uint32 RequestTime = 4; + bytes KeyControlNonceDeprecated = 5; + ProtocolVersion ProtocolVersion = 6; // lacking symbols for this + uint32 KeyControlNonce = 7; + EncryptedClientIdentification EncryptedClientId = 8; +} + +message ProvisionedDeviceInfo { + enum WvSecurityLevel { + LEVEL_UNSPECIFIED = 0; + LEVEL_1 = 1; + LEVEL_2 = 2; + LEVEL_3 = 3; + } + uint32 SystemId = 1; + string Soc = 2; + string Manufacturer = 3; + string Model = 4; + string DeviceType = 5; + uint32 ModelYear = 6; + WvSecurityLevel SecurityLevel = 7; + uint32 TestDevice = 8; // bool? +} + + +// todo: fill +message ProvisioningOptions { +} + +// todo: fill +message ProvisioningRequest { +} + +// todo: fill +message ProvisioningResponse { +} + +message RemoteAttestation { + EncryptedClientIdentification Certificate = 1; + string Salt = 2; + string Signature = 3; +} + +// todo: fill +message SessionInit { +} + +// todo: fill +message SessionState { +} + +// todo: fill +message SignedCertificateStatusList { +} + +message SignedDeviceCertificate { + + //bytes DeviceCertificate = 1; // again, they use a buffer where it's supposed to be a message, so we'll replace it with what it really is: + DeviceCertificate _DeviceCertificate = 1; // how should we deal with duped names? will have to look at proto docs later + bytes Signature = 2; + SignedDeviceCertificate Signer = 3; +} + + +// todo: fill +message SignedProvisioningMessage { +} + +// the root of all messages, from either server or client +message SignedMessage { + enum MessageType { + DUMMY_MSG_TYPE = 0; // dummy, added to satisfy proto3 + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + bytes Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + bytes SessionKey = 4; // often RSA wrapped for licenses + RemoteAttestation RemoteAttestation = 5; +} + + + +// This message is copied from google's docs, not reversed: +message WidevineCencHeader { + enum Algorithm { + UNENCRYPTED = 0; + AESCTR = 1; + }; + Algorithm algorithm = 1; + repeated bytes key_id = 2; + + // Content provider name. + string provider = 3; + + // A content identifier, specified by content provider. + bytes content_id = 4; + + // Track type. Acceptable values are SD, HD and AUDIO. Used to + // differentiate content keys used by an asset. + string track_type_deprecated = 5; + + // The name of a registered policy to be used for this asset. + string policy = 6; + + // Crypto period index, for media using key rotation. + uint32 crypto_period_index = 7; + + // Optional protected context for group content. The grouped_license is a + // serialized SignedMessage. + bytes grouped_license = 8; + + // Protection scheme identifying the encryption algorithm. + // Represented as one of the following 4CC values: + // 'cenc' (AESCTR), 'cbc1' (AESCBC), + // 'cens' (AESCTR subsample), 'cbcs' (AESCBC subsample). + uint32 protection_scheme = 9; + + // Optional. For media using key rotation, this represents the duration + // of each crypto period in seconds. + uint32 crypto_period_seconds = 10; +} + + + + +// from here on, it's just for testing, these messages don't exist in the binaries, I'm adding them to avoid detecting type programmatically +message SignedLicenseRequest { + enum MessageType { + DUMMY_MSG_TYPE = 0; // dummy, added to satisfy proto3 + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + LicenseRequest Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + bytes SessionKey = 4; // often RSA wrapped for licenses + RemoteAttestation RemoteAttestation = 5; +} + +message SignedLicense { + enum MessageType { + DUMMY_MSG_TYPE = 0; // dummy, added to satisfy proto3 + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + License Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + bytes SessionKey = 4; // often RSA wrapped for licenses + RemoteAttestation RemoteAttestation = 5; +} \ No newline at end of file diff --git a/pywidevine/cdm/formats/wv_proto3_pb2.py b/pywidevine/cdm/formats/wv_proto3_pb2.py new file mode 100644 index 0000000..11ae09f --- /dev/null +++ b/pywidevine/cdm/formats/wv_proto3_pb2.py @@ -0,0 +1,2686 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: wv_proto3.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='wv_proto3.proto', + package='', + syntax='proto3', + serialized_pb=_b('\n\x0fwv_proto3.proto\"\xc5\x05\n\x14\x43lientIdentification\x12-\n\x04Type\x18\x01 \x01(\x0e\x32\x1f.ClientIdentification.TokenType\x12\'\n\x05Token\x18\x02 \x01(\x0b\x32\x18.SignedDeviceCertificate\x12\x33\n\nClientInfo\x18\x03 \x03(\x0b\x32\x1f.ClientIdentification.NameValue\x12\x1b\n\x13ProviderClientToken\x18\x04 \x01(\x0c\x12\x16\n\x0eLicenseCounter\x18\x05 \x01(\r\x12\x45\n\x13_ClientCapabilities\x18\x06 \x01(\x0b\x32(.ClientIdentification.ClientCapabilities\x1a(\n\tNameValue\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\r\n\x05Value\x18\x02 \x01(\t\x1a\xa4\x02\n\x12\x43lientCapabilities\x12\x13\n\x0b\x43lientToken\x18\x01 \x01(\r\x12\x14\n\x0cSessionToken\x18\x02 \x01(\r\x12\"\n\x1aVideoResolutionConstraints\x18\x03 \x01(\r\x12L\n\x0eMaxHdcpVersion\x18\x04 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12\x1b\n\x13OemCryptoApiVersion\x18\x05 \x01(\r\"T\n\x0bHdcpVersion\x12\r\n\tHDCP_NONE\x10\x00\x12\x0b\n\x07HDCP_V1\x10\x01\x12\x0b\n\x07HDCP_V2\x10\x02\x12\r\n\tHDCP_V2_1\x10\x03\x12\r\n\tHDCP_V2_2\x10\x04\"S\n\tTokenType\x12\n\n\x06KEYBOX\x10\x00\x12\x16\n\x12\x44\x45VICE_CERTIFICATE\x10\x01\x12\"\n\x1eREMOTE_ATTESTATION_CERTIFICATE\x10\x02\"\x9b\x02\n\x11\x44\x65viceCertificate\x12\x30\n\x04Type\x18\x01 \x01(\x0e\x32\".DeviceCertificate.CertificateType\x12\x14\n\x0cSerialNumber\x18\x02 \x01(\x0c\x12\x1b\n\x13\x43reationTimeSeconds\x18\x03 \x01(\r\x12\x11\n\tPublicKey\x18\x04 \x01(\x0c\x12\x10\n\x08SystemId\x18\x05 \x01(\r\x12\x1c\n\x14TestDeviceDeprecated\x18\x06 \x01(\r\x12\x11\n\tServiceId\x18\x07 \x01(\x0c\"K\n\x0f\x43\x65rtificateType\x12\x08\n\x04ROOT\x10\x00\x12\x10\n\x0cINTERMEDIATE\x10\x01\x12\x0f\n\x0bUSER_DEVICE\x10\x02\x12\x0b\n\x07SERVICE\x10\x03\"\xc4\x01\n\x17\x44\x65viceCertificateStatus\x12\x14\n\x0cSerialNumber\x18\x01 \x01(\x0c\x12:\n\x06Status\x18\x02 \x01(\x0e\x32*.DeviceCertificateStatus.CertificateStatus\x12*\n\nDeviceInfo\x18\x04 \x01(\x0b\x32\x16.ProvisionedDeviceInfo\"+\n\x11\x43\x65rtificateStatus\x12\t\n\x05VALID\x10\x00\x12\x0b\n\x07REVOKED\x10\x01\"o\n\x1b\x44\x65viceCertificateStatusList\x12\x1b\n\x13\x43reationTimeSeconds\x18\x01 \x01(\r\x12\x33\n\x11\x43\x65rtificateStatus\x18\x02 \x03(\x0b\x32\x18.DeviceCertificateStatus\"\xaf\x01\n\x1d\x45ncryptedClientIdentification\x12\x11\n\tServiceId\x18\x01 \x01(\t\x12&\n\x1eServiceCertificateSerialNumber\x18\x02 \x01(\x0c\x12\x19\n\x11\x45ncryptedClientId\x18\x03 \x01(\x0c\x12\x1b\n\x13\x45ncryptedClientIdIv\x18\x04 \x01(\x0c\x12\x1b\n\x13\x45ncryptedPrivacyKey\x18\x05 \x01(\x0c\"\x9c\x01\n\x15LicenseIdentification\x12\x11\n\tRequestId\x18\x01 \x01(\x0c\x12\x11\n\tSessionId\x18\x02 \x01(\x0c\x12\x12\n\nPurchaseId\x18\x03 \x01(\x0c\x12\x1a\n\x04Type\x18\x04 \x01(\x0e\x32\x0c.LicenseType\x12\x0f\n\x07Version\x18\x05 \x01(\r\x12\x1c\n\x14ProviderSessionToken\x18\x06 \x01(\x0c\"\xfa\x0e\n\x07License\x12\"\n\x02Id\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12 \n\x07_Policy\x18\x02 \x01(\x0b\x32\x0f.License.Policy\x12\"\n\x03Key\x18\x03 \x03(\x0b\x32\x15.License.KeyContainer\x12\x18\n\x10LicenseStartTime\x18\x04 \x01(\r\x12!\n\x19RemoteAttestationVerified\x18\x05 \x01(\r\x12\x1b\n\x13ProviderClientToken\x18\x06 \x01(\x0c\x12\x18\n\x10ProtectionScheme\x18\x07 \x01(\r\x12\x1c\n\x14UnknownHdcpDataField\x18\x08 \x01(\x0c\x1a\xd4\x02\n\x06Policy\x12\x0f\n\x07\x43\x61nPlay\x18\x01 \x01(\r\x12\x12\n\nCanPersist\x18\x02 \x01(\r\x12\x10\n\x08\x43\x61nRenew\x18\x03 \x01(\r\x12\x1d\n\x15RentalDurationSeconds\x18\x04 \x01(\r\x12\x1f\n\x17PlaybackDurationSeconds\x18\x05 \x01(\r\x12\x1e\n\x16LicenseDurationSeconds\x18\x06 \x01(\r\x12&\n\x1eRenewalRecoveryDurationSeconds\x18\x07 \x01(\r\x12\x18\n\x10RenewalServerUrl\x18\x08 \x01(\t\x12\x1b\n\x13RenewalDelaySeconds\x18\t \x01(\r\x12#\n\x1bRenewalRetryIntervalSeconds\x18\n \x01(\r\x12\x16\n\x0eRenewWithUsage\x18\x0b \x01(\r\x12\x17\n\x0fUnknownPolicy12\x18\x0c \x01(\r\x1a\x9b\n\n\x0cKeyContainer\x12\n\n\x02Id\x18\x01 \x01(\x0c\x12\n\n\x02Iv\x18\x02 \x01(\x0c\x12\x0b\n\x03Key\x18\x03 \x01(\x0c\x12+\n\x04Type\x18\x04 \x01(\x0e\x32\x1d.License.KeyContainer.KeyType\x12\x32\n\x05Level\x18\x05 \x01(\x0e\x32#.License.KeyContainer.SecurityLevel\x12\x42\n\x12RequiredProtection\x18\x06 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x43\n\x13RequestedProtection\x18\x07 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x35\n\x0b_KeyControl\x18\x08 \x01(\x0b\x32 .License.KeyContainer.KeyControl\x12[\n\x1e_OperatorSessionKeyPermissions\x18\t \x01(\x0b\x32\x33.License.KeyContainer.OperatorSessionKeyPermissions\x12S\n\x1aVideoResolutionConstraints\x18\n \x03(\x0b\x32/.License.KeyContainer.VideoResolutionConstraint\x1a\xdb\x01\n\x10OutputProtection\x12\x42\n\x04Hdcp\x18\x01 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12>\n\tCgmsFlags\x18\x02 \x01(\x0e\x32+.License.KeyContainer.OutputProtection.CGMS\"C\n\x04\x43GMS\x12\r\n\tCOPY_FREE\x10\x00\x12\r\n\tCOPY_ONCE\x10\x02\x12\x0e\n\nCOPY_NEVER\x10\x03\x12\r\n\tCGMS_NONE\x10*\x1a\x31\n\nKeyControl\x12\x17\n\x0fKeyControlBlock\x18\x01 \x01(\x0c\x12\n\n\x02Iv\x18\x02 \x01(\x0c\x1a|\n\x1dOperatorSessionKeyPermissions\x12\x14\n\x0c\x41llowEncrypt\x18\x01 \x01(\r\x12\x14\n\x0c\x41llowDecrypt\x18\x02 \x01(\r\x12\x11\n\tAllowSign\x18\x03 \x01(\r\x12\x1c\n\x14\x41llowSignatureVerify\x18\x04 \x01(\r\x1a\x99\x01\n\x19VideoResolutionConstraint\x12\x1b\n\x13MinResolutionPixels\x18\x01 \x01(\r\x12\x1b\n\x13MaxResolutionPixels\x18\x02 \x01(\r\x12\x42\n\x12RequiredProtection\x18\x03 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\"Z\n\x07KeyType\x12\x0e\n\n_NOKEYTYPE\x10\x00\x12\x0b\n\x07SIGNING\x10\x01\x12\x0b\n\x07\x43ONTENT\x10\x02\x12\x0f\n\x0bKEY_CONTROL\x10\x03\x12\x14\n\x10OPERATOR_SESSION\x10\x04\"\x8b\x01\n\rSecurityLevel\x12\x0f\n\x0b_NOSECLEVEL\x10\x00\x12\x14\n\x10SW_SECURE_CRYPTO\x10\x01\x12\x14\n\x10SW_SECURE_DECODE\x10\x02\x12\x14\n\x10HW_SECURE_CRYPTO\x10\x03\x12\x14\n\x10HW_SECURE_DECODE\x10\x04\x12\x11\n\rHW_SECURE_ALL\x10\x05\"\xac\x01\n\x0cLicenseError\x12&\n\tErrorCode\x18\x01 \x01(\x0e\x32\x13.LicenseError.Error\"t\n\x05\x45rror\x12\x12\n\x0e\x44UMMY_NO_ERROR\x10\x00\x12\x1e\n\x1aINVALID_DEVICE_CERTIFICATE\x10\x01\x12\x1e\n\x1aREVOKED_DEVICE_CERTIFICATE\x10\x02\x12\x17\n\x13SERVICE_UNAVAILABLE\x10\x03\"\xc0\x07\n\x0eLicenseRequest\x12\'\n\x08\x43lientId\x18\x01 \x01(\x0b\x32\x15.ClientIdentification\x12\x38\n\tContentId\x18\x02 \x01(\x0b\x32%.LicenseRequest.ContentIdentification\x12)\n\x04Type\x18\x03 \x01(\x0e\x32\x1b.LicenseRequest.RequestType\x12\x13\n\x0bRequestTime\x18\x04 \x01(\r\x12!\n\x19KeyControlNonceDeprecated\x18\x05 \x01(\x0c\x12)\n\x0fProtocolVersion\x18\x06 \x01(\x0e\x32\x10.ProtocolVersion\x12\x17\n\x0fKeyControlNonce\x18\x07 \x01(\r\x12\x39\n\x11\x45ncryptedClientId\x18\x08 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x1a\xa2\x04\n\x15\x43ontentIdentification\x12:\n\x06\x43\x65ncId\x18\x01 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.CENC\x12:\n\x06WebmId\x18\x02 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.WebM\x12\x46\n\x07License\x18\x03 \x01(\x0b\x32\x35.LicenseRequest.ContentIdentification.ExistingLicense\x1a_\n\x04\x43\x45NC\x12!\n\x04Pssh\x18\x01 \x01(\x0b\x32\x13.WidevineCencHeader\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1aL\n\x04WebM\x12\x0e\n\x06Header\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1a\x99\x01\n\x0f\x45xistingLicense\x12)\n\tLicenseId\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12\x1b\n\x13SecondsSinceStarted\x18\x02 \x01(\r\x12\x1e\n\x16SecondsSinceLastPlayed\x18\x03 \x01(\r\x12\x1e\n\x16SessionUsageTableEntry\x18\x04 \x01(\x0c\"D\n\x0bRequestType\x12\x12\n\x0e\x44UMMY_REQ_TYPE\x10\x00\x12\x07\n\x03NEW\x10\x01\x12\x0b\n\x07RENEWAL\x10\x02\x12\x0b\n\x07RELEASE\x10\x03\"\xa6\x02\n\x15ProvisionedDeviceInfo\x12\x10\n\x08SystemId\x18\x01 \x01(\r\x12\x0b\n\x03Soc\x18\x02 \x01(\t\x12\x14\n\x0cManufacturer\x18\x03 \x01(\t\x12\r\n\x05Model\x18\x04 \x01(\t\x12\x12\n\nDeviceType\x18\x05 \x01(\t\x12\x11\n\tModelYear\x18\x06 \x01(\r\x12=\n\rSecurityLevel\x18\x07 \x01(\x0e\x32&.ProvisionedDeviceInfo.WvSecurityLevel\x12\x12\n\nTestDevice\x18\x08 \x01(\r\"O\n\x0fWvSecurityLevel\x12\x15\n\x11LEVEL_UNSPECIFIED\x10\x00\x12\x0b\n\x07LEVEL_1\x10\x01\x12\x0b\n\x07LEVEL_2\x10\x02\x12\x0b\n\x07LEVEL_3\x10\x03\"\x15\n\x13ProvisioningOptions\"\x15\n\x13ProvisioningRequest\"\x16\n\x14ProvisioningResponse\"i\n\x11RemoteAttestation\x12\x33\n\x0b\x43\x65rtificate\x18\x01 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x12\x0c\n\x04Salt\x18\x02 \x01(\t\x12\x11\n\tSignature\x18\x03 \x01(\t\"\r\n\x0bSessionInit\"\x0e\n\x0cSessionState\"\x1d\n\x1bSignedCertificateStatusList\"\x86\x01\n\x17SignedDeviceCertificate\x12.\n\x12_DeviceCertificate\x18\x01 \x01(\x0b\x32\x12.DeviceCertificate\x12\x11\n\tSignature\x18\x02 \x01(\x0c\x12(\n\x06Signer\x18\x03 \x01(\x0b\x32\x18.SignedDeviceCertificate\"\x1b\n\x19SignedProvisioningMessage\"\xb0\x02\n\rSignedMessage\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedMessage.MessageType\x12\x0b\n\x03Msg\x18\x02 \x01(\x0c\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"\x91\x01\n\x0bMessageType\x12\x12\n\x0e\x44UMMY_MSG_TYPE\x10\x00\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xc5\x02\n\x12WidevineCencHeader\x12\x30\n\talgorithm\x18\x01 \x01(\x0e\x32\x1d.WidevineCencHeader.Algorithm\x12\x0e\n\x06key_id\x18\x02 \x03(\x0c\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x12\n\ncontent_id\x18\x04 \x01(\x0c\x12\x1d\n\x15track_type_deprecated\x18\x05 \x01(\t\x12\x0e\n\x06policy\x18\x06 \x01(\t\x12\x1b\n\x13\x63rypto_period_index\x18\x07 \x01(\r\x12\x17\n\x0fgrouped_license\x18\x08 \x01(\x0c\x12\x19\n\x11protection_scheme\x18\t \x01(\r\x12\x1d\n\x15\x63rypto_period_seconds\x18\n \x01(\r\"(\n\tAlgorithm\x12\x0f\n\x0bUNENCRYPTED\x10\x00\x12\n\n\x06\x41\x45SCTR\x10\x01\"\xcf\x02\n\x14SignedLicenseRequest\x12/\n\x04Type\x18\x01 \x01(\x0e\x32!.SignedLicenseRequest.MessageType\x12\x1c\n\x03Msg\x18\x02 \x01(\x0b\x32\x0f.LicenseRequest\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"\x91\x01\n\x0bMessageType\x12\x12\n\x0e\x44UMMY_MSG_TYPE\x10\x00\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xba\x02\n\rSignedLicense\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedLicense.MessageType\x12\x15\n\x03Msg\x18\x02 \x01(\x0b\x32\x08.License\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"\x91\x01\n\x0bMessageType\x12\x12\n\x0e\x44UMMY_MSG_TYPE\x10\x00\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05*$\n\x0bLicenseType\x12\x08\n\x04ZERO\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01*)\n\x0fProtocolVersion\x12\t\n\x05\x44UMMY\x10\x00\x12\x0b\n\x07\x43URRENT\x10\x15\x62\x06proto3') +) + +_LICENSETYPE = _descriptor.EnumDescriptor( + name='LicenseType', + full_name='LicenseType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ZERO', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='DEFAULT', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6713, + serialized_end=6749, +) +_sym_db.RegisterEnumDescriptor(_LICENSETYPE) + +LicenseType = enum_type_wrapper.EnumTypeWrapper(_LICENSETYPE) +_PROTOCOLVERSION = _descriptor.EnumDescriptor( + name='ProtocolVersion', + full_name='ProtocolVersion', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CURRENT', index=1, number=21, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6751, + serialized_end=6792, +) +_sym_db.RegisterEnumDescriptor(_PROTOCOLVERSION) + +ProtocolVersion = enum_type_wrapper.EnumTypeWrapper(_PROTOCOLVERSION) +ZERO = 0 +DEFAULT = 1 +DUMMY = 0 +CURRENT = 21 + + +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION = _descriptor.EnumDescriptor( + name='HdcpVersion', + full_name='ClientIdentification.ClientCapabilities.HdcpVersion', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='HDCP_NONE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V1', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2_1', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2_2', index=4, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=560, + serialized_end=644, +) +_sym_db.RegisterEnumDescriptor(_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION) + +_CLIENTIDENTIFICATION_TOKENTYPE = _descriptor.EnumDescriptor( + name='TokenType', + full_name='ClientIdentification.TokenType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='KEYBOX', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='DEVICE_CERTIFICATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REMOTE_ATTESTATION_CERTIFICATE', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=646, + serialized_end=729, +) +_sym_db.RegisterEnumDescriptor(_CLIENTIDENTIFICATION_TOKENTYPE) + +_DEVICECERTIFICATE_CERTIFICATETYPE = _descriptor.EnumDescriptor( + name='CertificateType', + full_name='DeviceCertificate.CertificateType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ROOT', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='INTERMEDIATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='USER_DEVICE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=940, + serialized_end=1015, +) +_sym_db.RegisterEnumDescriptor(_DEVICECERTIFICATE_CERTIFICATETYPE) + +_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS = _descriptor.EnumDescriptor( + name='CertificateStatus', + full_name='DeviceCertificateStatus.CertificateStatus', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='VALID', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REVOKED', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=1171, + serialized_end=1214, +) +_sym_db.RegisterEnumDescriptor(_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS) + +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS = _descriptor.EnumDescriptor( + name='CGMS', + full_name='License.KeyContainer.OutputProtection.CGMS', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='COPY_FREE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='COPY_ONCE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='COPY_NEVER', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CGMS_NONE', index=3, number=42, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2947, + serialized_end=3014, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS) + +_LICENSE_KEYCONTAINER_KEYTYPE = _descriptor.EnumDescriptor( + name='KeyType', + full_name='License.KeyContainer.KeyType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='_NOKEYTYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SIGNING', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CONTENT', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='KEY_CONTROL', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='OPERATOR_SESSION', index=4, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3349, + serialized_end=3439, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_KEYTYPE) + +_LICENSE_KEYCONTAINER_SECURITYLEVEL = _descriptor.EnumDescriptor( + name='SecurityLevel', + full_name='License.KeyContainer.SecurityLevel', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='_NOSECLEVEL', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SW_SECURE_CRYPTO', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SW_SECURE_DECODE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_CRYPTO', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_DECODE', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_ALL', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3442, + serialized_end=3581, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_SECURITYLEVEL) + +_LICENSEERROR_ERROR = _descriptor.EnumDescriptor( + name='Error', + full_name='LicenseError.Error', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_NO_ERROR', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='INVALID_DEVICE_CERTIFICATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REVOKED_DEVICE_CERTIFICATE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_UNAVAILABLE', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3640, + serialized_end=3756, +) +_sym_db.RegisterEnumDescriptor(_LICENSEERROR_ERROR) + +_LICENSEREQUEST_REQUESTTYPE = _descriptor.EnumDescriptor( + name='RequestType', + full_name='LicenseRequest.RequestType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_REQ_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='NEW', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RENEWAL', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RELEASE', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=4651, + serialized_end=4719, +) +_sym_db.RegisterEnumDescriptor(_LICENSEREQUEST_REQUESTTYPE) + +_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL = _descriptor.EnumDescriptor( + name='WvSecurityLevel', + full_name='ProvisionedDeviceInfo.WvSecurityLevel', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LEVEL_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_1', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_2', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_3', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=4937, + serialized_end=5016, +) +_sym_db.RegisterEnumDescriptor(_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL) + +_SIGNEDMESSAGE_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedMessage.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_MSG_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=5583, + serialized_end=5728, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDMESSAGE_MESSAGETYPE) + +_WIDEVINECENCHEADER_ALGORITHM = _descriptor.EnumDescriptor( + name='Algorithm', + full_name='WidevineCencHeader.Algorithm', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='UNENCRYPTED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='AESCTR', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6016, + serialized_end=6056, +) +_sym_db.RegisterEnumDescriptor(_WIDEVINECENCHEADER_ALGORITHM) + +_SIGNEDLICENSEREQUEST_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedLicenseRequest.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_MSG_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=5583, + serialized_end=5728, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUEST_MESSAGETYPE) + +_SIGNEDLICENSE_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedLicense.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_MSG_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=5583, + serialized_end=5728, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSE_MESSAGETYPE) + + +_CLIENTIDENTIFICATION_NAMEVALUE = _descriptor.Descriptor( + name='NameValue', + full_name='ClientIdentification.NameValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Name', full_name='ClientIdentification.NameValue.Name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Value', full_name='ClientIdentification.NameValue.Value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=309, + serialized_end=349, +) + +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES = _descriptor.Descriptor( + name='ClientCapabilities', + full_name='ClientIdentification.ClientCapabilities', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ClientToken', full_name='ClientIdentification.ClientCapabilities.ClientToken', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionToken', full_name='ClientIdentification.ClientCapabilities.SessionToken', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='VideoResolutionConstraints', full_name='ClientIdentification.ClientCapabilities.VideoResolutionConstraints', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='MaxHdcpVersion', full_name='ClientIdentification.ClientCapabilities.MaxHdcpVersion', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='OemCryptoApiVersion', full_name='ClientIdentification.ClientCapabilities.OemCryptoApiVersion', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=352, + serialized_end=644, +) + +_CLIENTIDENTIFICATION = _descriptor.Descriptor( + name='ClientIdentification', + full_name='ClientIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='ClientIdentification.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Token', full_name='ClientIdentification.Token', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ClientInfo', full_name='ClientIdentification.ClientInfo', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderClientToken', full_name='ClientIdentification.ProviderClientToken', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseCounter', full_name='ClientIdentification.LicenseCounter', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_ClientCapabilities', full_name='ClientIdentification._ClientCapabilities', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_CLIENTIDENTIFICATION_NAMEVALUE, _CLIENTIDENTIFICATION_CLIENTCAPABILITIES, ], + enum_types=[ + _CLIENTIDENTIFICATION_TOKENTYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=20, + serialized_end=729, +) + + +_DEVICECERTIFICATE = _descriptor.Descriptor( + name='DeviceCertificate', + full_name='DeviceCertificate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='DeviceCertificate.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SerialNumber', full_name='DeviceCertificate.SerialNumber', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CreationTimeSeconds', full_name='DeviceCertificate.CreationTimeSeconds', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PublicKey', full_name='DeviceCertificate.PublicKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SystemId', full_name='DeviceCertificate.SystemId', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='TestDeviceDeprecated', full_name='DeviceCertificate.TestDeviceDeprecated', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ServiceId', full_name='DeviceCertificate.ServiceId', index=6, + number=7, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _DEVICECERTIFICATE_CERTIFICATETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=732, + serialized_end=1015, +) + + +_DEVICECERTIFICATESTATUS = _descriptor.Descriptor( + name='DeviceCertificateStatus', + full_name='DeviceCertificateStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='SerialNumber', full_name='DeviceCertificateStatus.SerialNumber', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Status', full_name='DeviceCertificateStatus.Status', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='DeviceInfo', full_name='DeviceCertificateStatus.DeviceInfo', index=2, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1018, + serialized_end=1214, +) + + +_DEVICECERTIFICATESTATUSLIST = _descriptor.Descriptor( + name='DeviceCertificateStatusList', + full_name='DeviceCertificateStatusList', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CreationTimeSeconds', full_name='DeviceCertificateStatusList.CreationTimeSeconds', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CertificateStatus', full_name='DeviceCertificateStatusList.CertificateStatus', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1216, + serialized_end=1327, +) + + +_ENCRYPTEDCLIENTIDENTIFICATION = _descriptor.Descriptor( + name='EncryptedClientIdentification', + full_name='EncryptedClientIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ServiceId', full_name='EncryptedClientIdentification.ServiceId', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ServiceCertificateSerialNumber', full_name='EncryptedClientIdentification.ServiceCertificateSerialNumber', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientId', full_name='EncryptedClientIdentification.EncryptedClientId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientIdIv', full_name='EncryptedClientIdentification.EncryptedClientIdIv', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedPrivacyKey', full_name='EncryptedClientIdentification.EncryptedPrivacyKey', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1330, + serialized_end=1505, +) + + +_LICENSEIDENTIFICATION = _descriptor.Descriptor( + name='LicenseIdentification', + full_name='LicenseIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseIdentification.RequestId', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionId', full_name='LicenseIdentification.SessionId', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PurchaseId', full_name='LicenseIdentification.PurchaseId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='LicenseIdentification.Type', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Version', full_name='LicenseIdentification.Version', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderSessionToken', full_name='LicenseIdentification.ProviderSessionToken', index=5, + number=6, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1508, + serialized_end=1664, +) + + +_LICENSE_POLICY = _descriptor.Descriptor( + name='Policy', + full_name='License.Policy', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CanPlay', full_name='License.Policy.CanPlay', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CanPersist', full_name='License.Policy.CanPersist', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CanRenew', full_name='License.Policy.CanRenew', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RentalDurationSeconds', full_name='License.Policy.RentalDurationSeconds', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PlaybackDurationSeconds', full_name='License.Policy.PlaybackDurationSeconds', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseDurationSeconds', full_name='License.Policy.LicenseDurationSeconds', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalRecoveryDurationSeconds', full_name='License.Policy.RenewalRecoveryDurationSeconds', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalServerUrl', full_name='License.Policy.RenewalServerUrl', index=7, + number=8, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalDelaySeconds', full_name='License.Policy.RenewalDelaySeconds', index=8, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalRetryIntervalSeconds', full_name='License.Policy.RenewalRetryIntervalSeconds', index=9, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewWithUsage', full_name='License.Policy.RenewWithUsage', index=10, + number=11, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='UnknownPolicy12', full_name='License.Policy.UnknownPolicy12', index=11, + number=12, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1931, + serialized_end=2271, +) + +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION = _descriptor.Descriptor( + name='OutputProtection', + full_name='License.KeyContainer.OutputProtection', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Hdcp', full_name='License.KeyContainer.OutputProtection.Hdcp', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CgmsFlags', full_name='License.KeyContainer.OutputProtection.CgmsFlags', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2795, + serialized_end=3014, +) + +_LICENSE_KEYCONTAINER_KEYCONTROL = _descriptor.Descriptor( + name='KeyControl', + full_name='License.KeyContainer.KeyControl', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='KeyControlBlock', full_name='License.KeyContainer.KeyControl.KeyControlBlock', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Iv', full_name='License.KeyContainer.KeyControl.Iv', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3016, + serialized_end=3065, +) + +_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS = _descriptor.Descriptor( + name='OperatorSessionKeyPermissions', + full_name='License.KeyContainer.OperatorSessionKeyPermissions', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='AllowEncrypt', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowEncrypt', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowDecrypt', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowDecrypt', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowSign', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowSign', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowSignatureVerify', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowSignatureVerify', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3067, + serialized_end=3191, +) + +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT = _descriptor.Descriptor( + name='VideoResolutionConstraint', + full_name='License.KeyContainer.VideoResolutionConstraint', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='MinResolutionPixels', full_name='License.KeyContainer.VideoResolutionConstraint.MinResolutionPixels', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='MaxResolutionPixels', full_name='License.KeyContainer.VideoResolutionConstraint.MaxResolutionPixels', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequiredProtection', full_name='License.KeyContainer.VideoResolutionConstraint.RequiredProtection', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3194, + serialized_end=3347, +) + +_LICENSE_KEYCONTAINER = _descriptor.Descriptor( + name='KeyContainer', + full_name='License.KeyContainer', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Id', full_name='License.KeyContainer.Id', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Iv', full_name='License.KeyContainer.Iv', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Key', full_name='License.KeyContainer.Key', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='License.KeyContainer.Type', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Level', full_name='License.KeyContainer.Level', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequiredProtection', full_name='License.KeyContainer.RequiredProtection', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestedProtection', full_name='License.KeyContainer.RequestedProtection', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_KeyControl', full_name='License.KeyContainer._KeyControl', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_OperatorSessionKeyPermissions', full_name='License.KeyContainer._OperatorSessionKeyPermissions', index=8, + number=9, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='VideoResolutionConstraints', full_name='License.KeyContainer.VideoResolutionConstraints', index=9, + number=10, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSE_KEYCONTAINER_OUTPUTPROTECTION, _LICENSE_KEYCONTAINER_KEYCONTROL, _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS, _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT, ], + enum_types=[ + _LICENSE_KEYCONTAINER_KEYTYPE, + _LICENSE_KEYCONTAINER_SECURITYLEVEL, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2274, + serialized_end=3581, +) + +_LICENSE = _descriptor.Descriptor( + name='License', + full_name='License', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Id', full_name='License.Id', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_Policy', full_name='License._Policy', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Key', full_name='License.Key', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseStartTime', full_name='License.LicenseStartTime', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestationVerified', full_name='License.RemoteAttestationVerified', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderClientToken', full_name='License.ProviderClientToken', index=5, + number=6, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProtectionScheme', full_name='License.ProtectionScheme', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='UnknownHdcpDataField', full_name='License.UnknownHdcpDataField', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSE_POLICY, _LICENSE_KEYCONTAINER, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1667, + serialized_end=3581, +) + + +_LICENSEERROR = _descriptor.Descriptor( + name='LicenseError', + full_name='LicenseError', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ErrorCode', full_name='LicenseError.ErrorCode', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _LICENSEERROR_ERROR, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3584, + serialized_end=3756, +) + + +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC = _descriptor.Descriptor( + name='CENC', + full_name='LicenseRequest.ContentIdentification.CENC', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Pssh', full_name='LicenseRequest.ContentIdentification.CENC.Pssh', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequest.ContentIdentification.CENC.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequest.ContentIdentification.CENC.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4320, + serialized_end=4415, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM = _descriptor.Descriptor( + name='WebM', + full_name='LicenseRequest.ContentIdentification.WebM', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Header', full_name='LicenseRequest.ContentIdentification.WebM.Header', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequest.ContentIdentification.WebM.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequest.ContentIdentification.WebM.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4417, + serialized_end=4493, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE = _descriptor.Descriptor( + name='ExistingLicense', + full_name='LicenseRequest.ContentIdentification.ExistingLicense', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='LicenseId', full_name='LicenseRequest.ContentIdentification.ExistingLicense.LicenseId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceStarted', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SecondsSinceStarted', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceLastPlayed', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SecondsSinceLastPlayed', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionUsageTableEntry', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SessionUsageTableEntry', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4496, + serialized_end=4649, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION = _descriptor.Descriptor( + name='ContentIdentification', + full_name='LicenseRequest.ContentIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CencId', full_name='LicenseRequest.ContentIdentification.CencId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='WebmId', full_name='LicenseRequest.ContentIdentification.WebmId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='License', full_name='LicenseRequest.ContentIdentification.License', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC, _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM, _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4103, + serialized_end=4649, +) + +_LICENSEREQUEST = _descriptor.Descriptor( + name='LicenseRequest', + full_name='LicenseRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ClientId', full_name='LicenseRequest.ClientId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ContentId', full_name='LicenseRequest.ContentId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='LicenseRequest.Type', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestTime', full_name='LicenseRequest.RequestTime', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonceDeprecated', full_name='LicenseRequest.KeyControlNonceDeprecated', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProtocolVersion', full_name='LicenseRequest.ProtocolVersion', index=5, + number=6, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonce', full_name='LicenseRequest.KeyControlNonce', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientId', full_name='LicenseRequest.EncryptedClientId', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUEST_CONTENTIDENTIFICATION, ], + enum_types=[ + _LICENSEREQUEST_REQUESTTYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3759, + serialized_end=4719, +) + + +_PROVISIONEDDEVICEINFO = _descriptor.Descriptor( + name='ProvisionedDeviceInfo', + full_name='ProvisionedDeviceInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='SystemId', full_name='ProvisionedDeviceInfo.SystemId', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Soc', full_name='ProvisionedDeviceInfo.Soc', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Manufacturer', full_name='ProvisionedDeviceInfo.Manufacturer', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Model', full_name='ProvisionedDeviceInfo.Model', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='DeviceType', full_name='ProvisionedDeviceInfo.DeviceType', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ModelYear', full_name='ProvisionedDeviceInfo.ModelYear', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecurityLevel', full_name='ProvisionedDeviceInfo.SecurityLevel', index=6, + number=7, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='TestDevice', full_name='ProvisionedDeviceInfo.TestDevice', index=7, + number=8, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4722, + serialized_end=5016, +) + + +_PROVISIONINGOPTIONS = _descriptor.Descriptor( + name='ProvisioningOptions', + full_name='ProvisioningOptions', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5018, + serialized_end=5039, +) + + +_PROVISIONINGREQUEST = _descriptor.Descriptor( + name='ProvisioningRequest', + full_name='ProvisioningRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5041, + serialized_end=5062, +) + + +_PROVISIONINGRESPONSE = _descriptor.Descriptor( + name='ProvisioningResponse', + full_name='ProvisioningResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5064, + serialized_end=5086, +) + + +_REMOTEATTESTATION = _descriptor.Descriptor( + name='RemoteAttestation', + full_name='RemoteAttestation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Certificate', full_name='RemoteAttestation.Certificate', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Salt', full_name='RemoteAttestation.Salt', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='RemoteAttestation.Signature', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5088, + serialized_end=5193, +) + + +_SESSIONINIT = _descriptor.Descriptor( + name='SessionInit', + full_name='SessionInit', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5195, + serialized_end=5208, +) + + +_SESSIONSTATE = _descriptor.Descriptor( + name='SessionState', + full_name='SessionState', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5210, + serialized_end=5224, +) + + +_SIGNEDCERTIFICATESTATUSLIST = _descriptor.Descriptor( + name='SignedCertificateStatusList', + full_name='SignedCertificateStatusList', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5226, + serialized_end=5255, +) + + +_SIGNEDDEVICECERTIFICATE = _descriptor.Descriptor( + name='SignedDeviceCertificate', + full_name='SignedDeviceCertificate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='_DeviceCertificate', full_name='SignedDeviceCertificate._DeviceCertificate', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedDeviceCertificate.Signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signer', full_name='SignedDeviceCertificate.Signer', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5258, + serialized_end=5392, +) + + +_SIGNEDPROVISIONINGMESSAGE = _descriptor.Descriptor( + name='SignedProvisioningMessage', + full_name='SignedProvisioningMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5394, + serialized_end=5421, +) + + +_SIGNEDMESSAGE = _descriptor.Descriptor( + name='SignedMessage', + full_name='SignedMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedMessage.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedMessage.Msg', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedMessage.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedMessage.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedMessage.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDMESSAGE_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5424, + serialized_end=5728, +) + + +_WIDEVINECENCHEADER = _descriptor.Descriptor( + name='WidevineCencHeader', + full_name='WidevineCencHeader', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='algorithm', full_name='WidevineCencHeader.algorithm', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='key_id', full_name='WidevineCencHeader.key_id', index=1, + number=2, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='provider', full_name='WidevineCencHeader.provider', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='content_id', full_name='WidevineCencHeader.content_id', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='track_type_deprecated', full_name='WidevineCencHeader.track_type_deprecated', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='policy', full_name='WidevineCencHeader.policy', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='crypto_period_index', full_name='WidevineCencHeader.crypto_period_index', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='grouped_license', full_name='WidevineCencHeader.grouped_license', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='protection_scheme', full_name='WidevineCencHeader.protection_scheme', index=8, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='crypto_period_seconds', full_name='WidevineCencHeader.crypto_period_seconds', index=9, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _WIDEVINECENCHEADER_ALGORITHM, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5731, + serialized_end=6056, +) + + +_SIGNEDLICENSEREQUEST = _descriptor.Descriptor( + name='SignedLicenseRequest', + full_name='SignedLicenseRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedLicenseRequest.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedLicenseRequest.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedLicenseRequest.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedLicenseRequest.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedLicenseRequest.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDLICENSEREQUEST_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6059, + serialized_end=6394, +) + + +_SIGNEDLICENSE = _descriptor.Descriptor( + name='SignedLicense', + full_name='SignedLicense', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedLicense.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedLicense.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedLicense.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedLicense.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedLicense.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDLICENSE_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6397, + serialized_end=6711, +) + +_CLIENTIDENTIFICATION_NAMEVALUE.containing_type = _CLIENTIDENTIFICATION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES.fields_by_name['MaxHdcpVersion'].enum_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES.containing_type = _CLIENTIDENTIFICATION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION.containing_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES +_CLIENTIDENTIFICATION.fields_by_name['Type'].enum_type = _CLIENTIDENTIFICATION_TOKENTYPE +_CLIENTIDENTIFICATION.fields_by_name['Token'].message_type = _SIGNEDDEVICECERTIFICATE +_CLIENTIDENTIFICATION.fields_by_name['ClientInfo'].message_type = _CLIENTIDENTIFICATION_NAMEVALUE +_CLIENTIDENTIFICATION.fields_by_name['_ClientCapabilities'].message_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES +_CLIENTIDENTIFICATION_TOKENTYPE.containing_type = _CLIENTIDENTIFICATION +_DEVICECERTIFICATE.fields_by_name['Type'].enum_type = _DEVICECERTIFICATE_CERTIFICATETYPE +_DEVICECERTIFICATE_CERTIFICATETYPE.containing_type = _DEVICECERTIFICATE +_DEVICECERTIFICATESTATUS.fields_by_name['Status'].enum_type = _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS +_DEVICECERTIFICATESTATUS.fields_by_name['DeviceInfo'].message_type = _PROVISIONEDDEVICEINFO +_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS.containing_type = _DEVICECERTIFICATESTATUS +_DEVICECERTIFICATESTATUSLIST.fields_by_name['CertificateStatus'].message_type = _DEVICECERTIFICATESTATUS +_LICENSEIDENTIFICATION.fields_by_name['Type'].enum_type = _LICENSETYPE +_LICENSE_POLICY.containing_type = _LICENSE +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.fields_by_name['Hdcp'].enum_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.fields_by_name['CgmsFlags'].enum_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS.containing_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER_KEYCONTROL.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT.fields_by_name['RequiredProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER.fields_by_name['Type'].enum_type = _LICENSE_KEYCONTAINER_KEYTYPE +_LICENSE_KEYCONTAINER.fields_by_name['Level'].enum_type = _LICENSE_KEYCONTAINER_SECURITYLEVEL +_LICENSE_KEYCONTAINER.fields_by_name['RequiredProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER.fields_by_name['RequestedProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER.fields_by_name['_KeyControl'].message_type = _LICENSE_KEYCONTAINER_KEYCONTROL +_LICENSE_KEYCONTAINER.fields_by_name['_OperatorSessionKeyPermissions'].message_type = _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS +_LICENSE_KEYCONTAINER.fields_by_name['VideoResolutionConstraints'].message_type = _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT +_LICENSE_KEYCONTAINER.containing_type = _LICENSE +_LICENSE_KEYCONTAINER_KEYTYPE.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_SECURITYLEVEL.containing_type = _LICENSE_KEYCONTAINER +_LICENSE.fields_by_name['Id'].message_type = _LICENSEIDENTIFICATION +_LICENSE.fields_by_name['_Policy'].message_type = _LICENSE_POLICY +_LICENSE.fields_by_name['Key'].message_type = _LICENSE_KEYCONTAINER +_LICENSEERROR.fields_by_name['ErrorCode'].enum_type = _LICENSEERROR_ERROR +_LICENSEERROR_ERROR.containing_type = _LICENSEERROR +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.fields_by_name['Pssh'].message_type = _WIDEVINECENCHEADER +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE.fields_by_name['LicenseId'].message_type = _LICENSEIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['CencId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['WebmId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['License'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE +_LICENSEREQUEST_CONTENTIDENTIFICATION.containing_type = _LICENSEREQUEST +_LICENSEREQUEST.fields_by_name['ClientId'].message_type = _CLIENTIDENTIFICATION +_LICENSEREQUEST.fields_by_name['ContentId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST.fields_by_name['Type'].enum_type = _LICENSEREQUEST_REQUESTTYPE +_LICENSEREQUEST.fields_by_name['ProtocolVersion'].enum_type = _PROTOCOLVERSION +_LICENSEREQUEST.fields_by_name['EncryptedClientId'].message_type = _ENCRYPTEDCLIENTIDENTIFICATION +_LICENSEREQUEST_REQUESTTYPE.containing_type = _LICENSEREQUEST +_PROVISIONEDDEVICEINFO.fields_by_name['SecurityLevel'].enum_type = _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL +_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL.containing_type = _PROVISIONEDDEVICEINFO +_REMOTEATTESTATION.fields_by_name['Certificate'].message_type = _ENCRYPTEDCLIENTIDENTIFICATION +_SIGNEDDEVICECERTIFICATE.fields_by_name['_DeviceCertificate'].message_type = _DEVICECERTIFICATE +_SIGNEDDEVICECERTIFICATE.fields_by_name['Signer'].message_type = _SIGNEDDEVICECERTIFICATE +_SIGNEDMESSAGE.fields_by_name['Type'].enum_type = _SIGNEDMESSAGE_MESSAGETYPE +_SIGNEDMESSAGE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDMESSAGE_MESSAGETYPE.containing_type = _SIGNEDMESSAGE +_WIDEVINECENCHEADER.fields_by_name['algorithm'].enum_type = _WIDEVINECENCHEADER_ALGORITHM +_WIDEVINECENCHEADER_ALGORITHM.containing_type = _WIDEVINECENCHEADER +_SIGNEDLICENSEREQUEST.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUEST_MESSAGETYPE +_SIGNEDLICENSEREQUEST.fields_by_name['Msg'].message_type = _LICENSEREQUEST +_SIGNEDLICENSEREQUEST.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDLICENSEREQUEST_MESSAGETYPE.containing_type = _SIGNEDLICENSEREQUEST +_SIGNEDLICENSE.fields_by_name['Type'].enum_type = _SIGNEDLICENSE_MESSAGETYPE +_SIGNEDLICENSE.fields_by_name['Msg'].message_type = _LICENSE +_SIGNEDLICENSE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDLICENSE_MESSAGETYPE.containing_type = _SIGNEDLICENSE +DESCRIPTOR.message_types_by_name['ClientIdentification'] = _CLIENTIDENTIFICATION +DESCRIPTOR.message_types_by_name['DeviceCertificate'] = _DEVICECERTIFICATE +DESCRIPTOR.message_types_by_name['DeviceCertificateStatus'] = _DEVICECERTIFICATESTATUS +DESCRIPTOR.message_types_by_name['DeviceCertificateStatusList'] = _DEVICECERTIFICATESTATUSLIST +DESCRIPTOR.message_types_by_name['EncryptedClientIdentification'] = _ENCRYPTEDCLIENTIDENTIFICATION +DESCRIPTOR.message_types_by_name['LicenseIdentification'] = _LICENSEIDENTIFICATION +DESCRIPTOR.message_types_by_name['License'] = _LICENSE +DESCRIPTOR.message_types_by_name['LicenseError'] = _LICENSEERROR +DESCRIPTOR.message_types_by_name['LicenseRequest'] = _LICENSEREQUEST +DESCRIPTOR.message_types_by_name['ProvisionedDeviceInfo'] = _PROVISIONEDDEVICEINFO +DESCRIPTOR.message_types_by_name['ProvisioningOptions'] = _PROVISIONINGOPTIONS +DESCRIPTOR.message_types_by_name['ProvisioningRequest'] = _PROVISIONINGREQUEST +DESCRIPTOR.message_types_by_name['ProvisioningResponse'] = _PROVISIONINGRESPONSE +DESCRIPTOR.message_types_by_name['RemoteAttestation'] = _REMOTEATTESTATION +DESCRIPTOR.message_types_by_name['SessionInit'] = _SESSIONINIT +DESCRIPTOR.message_types_by_name['SessionState'] = _SESSIONSTATE +DESCRIPTOR.message_types_by_name['SignedCertificateStatusList'] = _SIGNEDCERTIFICATESTATUSLIST +DESCRIPTOR.message_types_by_name['SignedDeviceCertificate'] = _SIGNEDDEVICECERTIFICATE +DESCRIPTOR.message_types_by_name['SignedProvisioningMessage'] = _SIGNEDPROVISIONINGMESSAGE +DESCRIPTOR.message_types_by_name['SignedMessage'] = _SIGNEDMESSAGE +DESCRIPTOR.message_types_by_name['WidevineCencHeader'] = _WIDEVINECENCHEADER +DESCRIPTOR.message_types_by_name['SignedLicenseRequest'] = _SIGNEDLICENSEREQUEST +DESCRIPTOR.message_types_by_name['SignedLicense'] = _SIGNEDLICENSE +DESCRIPTOR.enum_types_by_name['LicenseType'] = _LICENSETYPE +DESCRIPTOR.enum_types_by_name['ProtocolVersion'] = _PROTOCOLVERSION +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ClientIdentification = _reflection.GeneratedProtocolMessageType('ClientIdentification', (_message.Message,), dict( + + NameValue = _reflection.GeneratedProtocolMessageType('NameValue', (_message.Message,), dict( + DESCRIPTOR = _CLIENTIDENTIFICATION_NAMEVALUE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification.NameValue) + )) + , + + ClientCapabilities = _reflection.GeneratedProtocolMessageType('ClientCapabilities', (_message.Message,), dict( + DESCRIPTOR = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification.ClientCapabilities) + )) + , + DESCRIPTOR = _CLIENTIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification) + )) +_sym_db.RegisterMessage(ClientIdentification) +_sym_db.RegisterMessage(ClientIdentification.NameValue) +_sym_db.RegisterMessage(ClientIdentification.ClientCapabilities) + +DeviceCertificate = _reflection.GeneratedProtocolMessageType('DeviceCertificate', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificate) + )) +_sym_db.RegisterMessage(DeviceCertificate) + +DeviceCertificateStatus = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatus', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATESTATUS, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificateStatus) + )) +_sym_db.RegisterMessage(DeviceCertificateStatus) + +DeviceCertificateStatusList = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatusList', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATESTATUSLIST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificateStatusList) + )) +_sym_db.RegisterMessage(DeviceCertificateStatusList) + +EncryptedClientIdentification = _reflection.GeneratedProtocolMessageType('EncryptedClientIdentification', (_message.Message,), dict( + DESCRIPTOR = _ENCRYPTEDCLIENTIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:EncryptedClientIdentification) + )) +_sym_db.RegisterMessage(EncryptedClientIdentification) + +LicenseIdentification = _reflection.GeneratedProtocolMessageType('LicenseIdentification', (_message.Message,), dict( + DESCRIPTOR = _LICENSEIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseIdentification) + )) +_sym_db.RegisterMessage(LicenseIdentification) + +License = _reflection.GeneratedProtocolMessageType('License', (_message.Message,), dict( + + Policy = _reflection.GeneratedProtocolMessageType('Policy', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_POLICY, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.Policy) + )) + , + + KeyContainer = _reflection.GeneratedProtocolMessageType('KeyContainer', (_message.Message,), dict( + + OutputProtection = _reflection.GeneratedProtocolMessageType('OutputProtection', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.OutputProtection) + )) + , + + KeyControl = _reflection.GeneratedProtocolMessageType('KeyControl', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_KEYCONTROL, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.KeyControl) + )) + , + + OperatorSessionKeyPermissions = _reflection.GeneratedProtocolMessageType('OperatorSessionKeyPermissions', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.OperatorSessionKeyPermissions) + )) + , + + VideoResolutionConstraint = _reflection.GeneratedProtocolMessageType('VideoResolutionConstraint', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.VideoResolutionConstraint) + )) + , + DESCRIPTOR = _LICENSE_KEYCONTAINER, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer) + )) + , + DESCRIPTOR = _LICENSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License) + )) +_sym_db.RegisterMessage(License) +_sym_db.RegisterMessage(License.Policy) +_sym_db.RegisterMessage(License.KeyContainer) +_sym_db.RegisterMessage(License.KeyContainer.OutputProtection) +_sym_db.RegisterMessage(License.KeyContainer.KeyControl) +_sym_db.RegisterMessage(License.KeyContainer.OperatorSessionKeyPermissions) +_sym_db.RegisterMessage(License.KeyContainer.VideoResolutionConstraint) + +LicenseError = _reflection.GeneratedProtocolMessageType('LicenseError', (_message.Message,), dict( + DESCRIPTOR = _LICENSEERROR, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseError) + )) +_sym_db.RegisterMessage(LicenseError) + +LicenseRequest = _reflection.GeneratedProtocolMessageType('LicenseRequest', (_message.Message,), dict( + + ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (_message.Message,), dict( + + CENC = _reflection.GeneratedProtocolMessageType('CENC', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.CENC) + )) + , + + WebM = _reflection.GeneratedProtocolMessageType('WebM', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.WebM) + )) + , + + ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.ExistingLicense) + )) + , + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification) + )) + , + DESCRIPTOR = _LICENSEREQUEST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest) + )) +_sym_db.RegisterMessage(LicenseRequest) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.CENC) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.WebM) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.ExistingLicense) + +ProvisionedDeviceInfo = _reflection.GeneratedProtocolMessageType('ProvisionedDeviceInfo', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONEDDEVICEINFO, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisionedDeviceInfo) + )) +_sym_db.RegisterMessage(ProvisionedDeviceInfo) + +ProvisioningOptions = _reflection.GeneratedProtocolMessageType('ProvisioningOptions', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGOPTIONS, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningOptions) + )) +_sym_db.RegisterMessage(ProvisioningOptions) + +ProvisioningRequest = _reflection.GeneratedProtocolMessageType('ProvisioningRequest', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGREQUEST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningRequest) + )) +_sym_db.RegisterMessage(ProvisioningRequest) + +ProvisioningResponse = _reflection.GeneratedProtocolMessageType('ProvisioningResponse', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGRESPONSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningResponse) + )) +_sym_db.RegisterMessage(ProvisioningResponse) + +RemoteAttestation = _reflection.GeneratedProtocolMessageType('RemoteAttestation', (_message.Message,), dict( + DESCRIPTOR = _REMOTEATTESTATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:RemoteAttestation) + )) +_sym_db.RegisterMessage(RemoteAttestation) + +SessionInit = _reflection.GeneratedProtocolMessageType('SessionInit', (_message.Message,), dict( + DESCRIPTOR = _SESSIONINIT, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SessionInit) + )) +_sym_db.RegisterMessage(SessionInit) + +SessionState = _reflection.GeneratedProtocolMessageType('SessionState', (_message.Message,), dict( + DESCRIPTOR = _SESSIONSTATE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SessionState) + )) +_sym_db.RegisterMessage(SessionState) + +SignedCertificateStatusList = _reflection.GeneratedProtocolMessageType('SignedCertificateStatusList', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDCERTIFICATESTATUSLIST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedCertificateStatusList) + )) +_sym_db.RegisterMessage(SignedCertificateStatusList) + +SignedDeviceCertificate = _reflection.GeneratedProtocolMessageType('SignedDeviceCertificate', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDDEVICECERTIFICATE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedDeviceCertificate) + )) +_sym_db.RegisterMessage(SignedDeviceCertificate) + +SignedProvisioningMessage = _reflection.GeneratedProtocolMessageType('SignedProvisioningMessage', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDPROVISIONINGMESSAGE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedProvisioningMessage) + )) +_sym_db.RegisterMessage(SignedProvisioningMessage) + +SignedMessage = _reflection.GeneratedProtocolMessageType('SignedMessage', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDMESSAGE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedMessage) + )) +_sym_db.RegisterMessage(SignedMessage) + +WidevineCencHeader = _reflection.GeneratedProtocolMessageType('WidevineCencHeader', (_message.Message,), dict( + DESCRIPTOR = _WIDEVINECENCHEADER, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:WidevineCencHeader) + )) +_sym_db.RegisterMessage(WidevineCencHeader) + +SignedLicenseRequest = _reflection.GeneratedProtocolMessageType('SignedLicenseRequest', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDLICENSEREQUEST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedLicenseRequest) + )) +_sym_db.RegisterMessage(SignedLicenseRequest) + +SignedLicense = _reflection.GeneratedProtocolMessageType('SignedLicense', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDLICENSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedLicense) + )) +_sym_db.RegisterMessage(SignedLicense) + + +# @@protoc_insertion_point(module_scope) diff --git a/pywidevine/cdm/key.py b/pywidevine/cdm/key.py new file mode 100644 index 0000000..0f0b956 --- /dev/null +++ b/pywidevine/cdm/key.py @@ -0,0 +1,14 @@ +import binascii + +class Key: + def __init__(self, kid, type, key, permissions=[]): + self.kid = kid + self.type = type + self.key = key + self.permissions = permissions + + def __repr__(self): + if self.type == "OPERATOR_SESSION": + return "key(kid={}, type={}, key={}, permissions={})".format(self.kid, self.type, binascii.hexlify(self.key), self.permissions) + else: + return "key(kid={}, type={}, key={})".format(self.kid, self.type, binascii.hexlify(self.key)) diff --git a/pywidevine/cdm/session.py b/pywidevine/cdm/session.py new file mode 100644 index 0000000..0f7295c --- /dev/null +++ b/pywidevine/cdm/session.py @@ -0,0 +1,18 @@ +class Session: + def __init__(self, session_id, init_data, device_config, offline): + self.session_id = session_id + self.init_data = init_data + self.offline = offline + self.device_config = device_config + self.device_key = None + self.session_key = None + self.derived_keys = { + 'enc': None, + 'auth_1': None, + 'auth_2': None + } + self.license_request = None + self.license = None + self.service_certificate = None + self.privacy_mode = False + self.keys = [] diff --git a/pywidevine/cdm/vmp.py b/pywidevine/cdm/vmp.py new file mode 100644 index 0000000..42ab1bf --- /dev/null +++ b/pywidevine/cdm/vmp.py @@ -0,0 +1,102 @@ +try: + from google.protobuf.internal.decoder import _DecodeVarint as _di # this was tested to work with protobuf 3, but it's an internal API (any varint decoder might work) +except ImportError: + # this is generic and does not depend on pb internals, however it will decode "larger" possible numbers than pb decoder which has them fixed + def LEB128_decode(buffer, pos, limit = 64): + result = 0 + shift = 0 + while True: + b = buffer[pos] + pos += 1 + result |= ((b & 0x7F) << shift) + if not (b & 0x80): + return (result, pos) + shift += 7 + if shift > limit: + raise Exception("integer too large, shift: {}".format(shift)) + _di = LEB128_decode + + +class FromFileMixin: + @classmethod + def from_file(cls, filename): + """Load given a filename""" + with open(filename,"rb") as f: + return cls(f.read()) + +# the signatures use a format internally similar to +# protobuf's encoding, but without wire types +class VariableReader(FromFileMixin): + """Protobuf-like encoding reader""" + + def __init__(self, buf): + self.buf = buf + self.pos = 0 + self.size = len(buf) + + def read_int(self): + """Read a variable length integer""" + # _DecodeVarint will take care of out of range errors + (val, nextpos) = _di(self.buf, self.pos) + self.pos = nextpos + return val + + def read_bytes_raw(self, size): + """Read size bytes""" + b = self.buf[self.pos:self.pos+size] + self.pos += size + return b + + def read_bytes(self): + """Read a bytes object""" + size = self.read_int() + return self.read_bytes_raw(size) + + def is_end(self): + return (self.size == self.pos) + + +class TaggedReader(VariableReader): + """Tagged reader, needed for implementing a WideVine signature reader""" + + def read_tag(self): + """Read a tagged buffer""" + return (self.read_int(), self.read_bytes()) + + def read_all_tags(self, max_tag=3): + tags = {} + while (not self.is_end()): + (tag, bytes) = self.read_tag() + if (tag > max_tag): + raise IndexError("tag out of bound: got {}, max {}".format(tag, max_tag)) + + tags[tag] = bytes + return tags + +class WideVineSignatureReader(FromFileMixin): + """Parses a widevine .sig signature file.""" + + SIGNER_TAG = 1 + SIGNATURE_TAG = 2 + ISMAINEXE_TAG = 3 + + def __init__(self, buf): + reader = TaggedReader(buf) + self.version = reader.read_int() + if (self.version != 0): + raise Exception("Unsupported signature format version {}".format(self.version)) + self.tags = reader.read_all_tags() + + self.signer = self.tags[self.SIGNER_TAG] + self.signature = self.tags[self.SIGNATURE_TAG] + + extra = self.tags[self.ISMAINEXE_TAG] + if (len(extra) != 1 or (extra[0] > 1)): + raise Exception("Unexpected 'ismainexe' field value (not '\\x00' or '\\x01'), please check: {0}".format(extra)) + + self.mainexe = bool(extra[0]) + + @classmethod + def get_tags(cls, filename): + """Return a dictionary of each tag in the signature file""" + return cls.from_file(filename).tags diff --git a/pywidevine/clients/blim/__pycache__/client.cpython-37.pyc b/pywidevine/clients/blim/__pycache__/client.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa11f3dc9e33b5383d727bd1b84eaf495d98cfa8 GIT binary patch literal 1141 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 ML9nrx-dl|S3n&Rc!~g&Q literal 0 HcmV?d00001 diff --git a/pywidevine/clients/blim/__pycache__/downloader_pr.cpython-37.pyc b/pywidevine/clients/blim/__pycache__/downloader_pr.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11fdb0073ee90be457b9f0f81bc201e77e6b7f4e GIT binary patch literal 4684 zcmaJ_&2JmW72nzKB`H}}lsGm5H!+yDY!Ed_3m8ZZN3fL!DIDfQ4ivL8HY?6ZUTMjt zW`~wcEPIiQxJ6T-#}-9F9dqwr&~tCS&9OcC(o1hX_4j5;N^;y%n2(*EeKYgk@BQ8z z-C9_vS@?bQ;Xl9n#|6v!7d^~=E;?%{#bZ?5;w-Z|Rm(ceJlh@Hv`)t{t=sX?+L_-A zIsv1(P8RmUPH6gW7WHbK8v0(R{-MQv9z3>qAR5O`X93S4kMJBF+nq%`)p#9Gbz$vY z!22c6Hmp|TDRyGDTTBOqD2g=iqwA^z-b3qsHWWkg^i|C0(zMynMrRGBxPeMov~_Ho zar?1_Z9CjW>vE6#XgwbA5UtN6UPBx3I&Yv2`2v<-)QwN&dVbi?@`MZ7CCT)omdb6E z;$2iF+p|h5rk0^)Xl=AMS_iFz)iGRaB~o?Vz96{|6REw2Nj4M)OH~DSu=L76=3RIm z!7r|s?24E1rf8x946Fu#P(xXomRD?-tyJT9x57qmoP)=UMWd_^Zel;r7y_Y z=HLAQYZgR<1n|+-b36ae-~+ZT|(GU2ANYKuT%tVbkD0Hg=94mq7MqYu&nk zG8&34>g03*9ktD!CQ6hCxZdtBFUk(CzJlJke8_MK=s<+$z?B5=40&xE?K&*y+I-i zkQyHM^0Y50_O!yvHjP3_k@P?X+34lDdaz-vlJ<8$7CcRKy?XwLjAT#)?~4TJ#5j&5*iW5J zvoFoYW}77bkgucq8OqeDn%{M*=lpoC(^=RshWR%{%(y_YW9v7})S!3-5NppNS79*S z*KEh;Hg_I}%2gnLGTGQZS}AQfQe*6t&cr{ln02tW38RkPqiZF(*p;#OgiV4HVPXft z2kwLX0B++RbT-ME{iACN5=-}(8JAp!tND}Yi8ZO6z^0J*+f7T=X(!x2MvzjC63Gr_ z7CidK9!E!4$_VQ$BM60)g|bF4GT;3TE*VZ1X-~iMahe*P!{i6`wq~`tHY&SL5k?u0 zLDvp;{#+%jZKURdG`UFj>BY>wisxkPZpBzQAMeQ zG?x1*dLN+7Ak{nvDLL%F2t)=U6`44P+i%UcPXtd#*dT#KmnAsyGNnOw#YI!(X!fw$ z!h9b(ypbinZJylx9H0FM#Ts4ve_N?0T0(l%IW$^PsFjV#c?m^Ll94_8?lM1 z)f>5lW#sp$GTI~FH4ZJ?)H5bJtqf?01Svl>Ng@b243|SUTnb%DZ@MV+AHiV_#jyDQ z&eDl!b?r^&Q~KkA8#EC%d@eL3yB0H2 z5dF+0X=dcp2z%x_7MfAIAx0hVYiPFPLs^lesMd9ikSa)1pGrZ>P?iG!A0xIBgPPkF z^i4M{Nz&B&egxZxQ~q_rXIlK)t{%Y6>HBKwabW z3lai1W#bihk^q=CisNpUAZ3m#tr=aBCOJxBZr|`!_%1wj^zvC&J_Xqfe!J1;}9M@~z|#xX07}+#rjUWuoW?L5}xvCD*B8OiKNpVuUNT(m@MwLphnoL?!hDtZSiq%%9{}d@I z79qW953g{KqvOb1G~nmkd!nlh16Kg{t0bUu0Hcc2iuQ?^TSbJMgu`M572WReXEzX9 M5NzzFj~8qI1@o3arvLx| literal 0 HcmV?d00001 diff --git a/pywidevine/clients/blim/__pycache__/downloader_wv.cpython-37.pyc b/pywidevine/clients/blim/__pycache__/downloader_wv.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a994bea248e0e30ed52e28665b55e42e1496ed6 GIT binary patch literal 5625 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

hem-b+xcyt1epP zPbnjZFBg&3@mD7IUW?;@nMv*~Xn&NASNPXL7A8NS2B)*R6E#xpX>*`Dc?ggLT`&10 dBYD8IIS*VXyd|^9$W6FL1;gTY$KgSVWw@6yF!KN{-xDMltZLZgU4c<8+7k?!Ul6w!2h!_*T)h z+)cFPA6Vs-vu9*VQ*uHx!mS$Nc8#3U6Lw0bY_{Um$kfU#?xMHR7tlLBGIhs)$($zn z-Jhm~tiU~-Egmx29LJcIY6Ls`Q}3vpd3*sUihCr!Y?IVFEXlu8qJQ8sJKvC)JtP?g zXSqf|D>ZV=&Sq7!wg_6}OW!)vQs$o6S?QEg^5pk>Xz6 zW1XBc-8?Y?2%Pjc&?Q~BY{zUpiCdHmdxD!*v#dG}j;x|mg9 z&!VyCzp&@U9)bR)@qy9*Xu6y&8~tmC46^sfcVWS@vEbI!!!7mA%HV;-W1913HrDap zCl0UiOQ-Bz!hZx!E7=k>t!Pcp>61V1X}Z5hGM2enC0lxI!{?W`yE;Jhr+eLY(31B+ z;82Q3D08->$JU`M*EkMk2o?@D-`Q^2AOHH=y0SlBzq#%+%&y&B*Yx_$mUZLW`rnAp zl=Fv>rw7VC5Ml2il@=r$@}Jh`r|qv3A(QsqQ5@cAH$`%o4urCDeYLgI z-VgY%Zd~aHNh)M}cm!GEX&8%kHws0ZChh$w?6>o!a{EKq}13CVxBKrjgb3}a=$cBsGL3XqQ#9lgJO4@%GuPC&azj#Qoprv z=PxiwjYDfBrN>OJY3Cx(Xk5xiJvyb@u|C_D3*d(1N?{VlNgBjmp=|w7SfgV_AD;VA zx?okSdb1;6yV*~%k$514R%wZq=)`~fo4@7kYj@D@Gj~|SAR{LRg-#iIi?dTUv)bNP zOe7OWBv+yU!`P>)0E?oaD|{w3l*tR4oP}R*`tppYqutPng1F~{E73{`y+9`)yxr&@ zoSGDa5f6=zCr-o2u_d6G$VCw4Z9(!V=n1)m>BLLLIKBEbO(#~pepM0QHf-{eKA<_2 zcRP$k2Vv#Ast_gv9;8B5O?Y?sJOnH0APu5UBD#Z^C(8ScIQl}$fmCiV9EzAr{bc^C zvJmOApvAh8h+K_WJ0lq>HP(F48g* z+G92?VN|8e(5kgWUGwwk3iAq{{p$V_t+Ml7y;C(SC7f8J7n!U>_E`w(T+m^>iI)5u zWS&Nxp@bm_|BU`vCyz-eT@a@XfNqU8{>Qg6kG}MC@ zv0p-u0tbq+#w#dYZf2p-x~5coiBeHV>8kQYl&k_Yc;g2~!`*2SrA}*Df`;ego0#Pq zJ~A306S51CyKG8EE`J3DqLg`%pO?nJL;iCV2bx)#*CVDltZuh1?DPkN^k65IBIt*4 z@1Dj(VA~u9!|z|deA!ya_wU49j1m4C^ps! z3>kcy=fwX<1QW^MK++5Y$}= 0: + nend = result.find('$', nstart+1) + if nend >= 0: + var = result[nstart+1 : nend] + if 'Number%' in var: + value = var[6:] % (int(number)) + else: + value = number + result = result.replace('$'+var+'$', value) + if bandwidth is not None: result = result.replace('$Bandwidth$', bandwidth) + if time is not None: result = result.replace('$Time$', time) + result = result.replace('$$', '$').replace('../', '') + return result + + def generate_segments(self): + quality_level = self.get_quality_level() + return self.get_segments(quality_level) + + def get_segments(self, stream_index): + urls = [] + urls.append(self.init_url) + t = 0 + for seg in stream_index["c"]: + if '@t' in seg: + t = seg['@t'] + for i in range(int(seg.get('@r', 0)) + 1): + path = stream_index['@Url'].format(**{ + 'bitrate': self.bitrate, + 'start time': t}) + url = urllib.parse.urljoin(self.base_url, path) + urls.append(url) + t += int(seg['@d']) + return urls + + def get_quality_level(self): + X = [item for (i, item) in enumerate(self.ism['SmoothStreamingMedia']['StreamIndex']) if self.config.file_type in item.get('@Type')][0] + return X + + def run(self): + urls = self.generate_segments() + work_q = Queue() + result_q = Queue() + + print('\n' + self.output_file) + pool = [WorkerThread(work_q=work_q, result_q=result_q) for i in range(dlthreads)] + for thread in pool: + thread.start() + + work_count = 0 + for seg_url in urls: + work_q.put((work_count, seg_url)) + work_count += 1 + results = [] + + for _ in tqdm(range(work_count)): + results.append(result_q.get()) + outfile = open(self.output_file , 'wb+') + sortedr = sorted(results, key=lambda v: v[0]) + for r in sortedr: + outfile.write(r[1]) + outfile.close() + del results + print('Done!') + +class Downloader: + def __init__(self): + self.session = requests.Session() + + def DownloadSegment(self, url): + resp = self.session.get(url, stream=True) + resp.raw.decode_content = True + data = resp.raw.read() + return data + +class WorkerThread(threading.Thread): + def __init__(self, work_q, result_q): + super(WorkerThread, self).__init__() + self.work_q = work_q + self.result_q = result_q + self.stoprequest = threading.Event() + self.downloader = Downloader() + + def run(self): + while not self.stoprequest.isSet(): + try: + (seq, url) = self.work_q.get(True, 0.05) + self.result_q.put((seq, self.downloader.DownloadSegment(url))) + except: + continue + + def join(self, timeout=None): + self.stoprequest.set() + super(WorkerThread, self).join(timeout) diff --git a/pywidevine/clients/blim/downloader_wv.py b/pywidevine/clients/blim/downloader_wv.py new file mode 100644 index 0000000..0264fc9 --- /dev/null +++ b/pywidevine/clients/blim/downloader_wv.py @@ -0,0 +1,155 @@ +import threading, isodate +import requests +import math + +from requests.sessions import session +from tqdm import tqdm +from queue import Queue + +dlthreads = 24 + +class WvDownloader(object): + def __init__(self, config): + self.mpd = config.mpd + self.output_file = config.output_file + self.mimetype = config.file_type + self.formatId = config.format_id + self.config = config + + def process_url_templace(self, template, representation_id, bandwidth, time, number): + if representation_id is not None: result = template.replace('$RepresentationID$', representation_id) + if number is not None: + nstart = result.find('$Number') + if nstart >= 0: + nend = result.find('$', nstart+1) + if nend >= 0: + var = result[nstart+1 : nend] + if 'Number%' in var: + value = var[6:] % (int(number)) + else: + value = number + result = result.replace('$'+var+'$', value) + if bandwidth is not None: result = result.replace('$Bandwidth$', bandwidth) + if time is not None: result = result.replace('$Time$', time) + result = result.replace('$$', '$').replace('../', '') + return result + + def generate_segments(self): + segment_template = self.get_segment_template() + return self.get_segments(segment_template) + + def get_segments(self, segment_template): + urls = [] + urls.append(self.config.base_url + segment_template['@initialization'].replace('$RepresentationID$', self.config.format_id)) + print(urls) + try: + current_number = int(segment_template.get("@startNumber", 0)) + period_duration = self.get_duration() + segment_duration = int(segment_template["@duration"]) / int(segment_template["@timescale"]) + total_segments = math.ceil(period_duration / segment_duration) + for _ in range(current_number, current_number + total_segments): + urls.append(self.config.base_url + self.process_url_templace(segment_template['@media'], + representation_id=self.config.format_id, + bandwidth=None, time="0", number=str(current_number))) + current_number += 1 + except KeyError: + current_number = 0 + current_time = 0 + for seg in segment_template["SegmentTimeline"]["S"]: + if '@t' in seg: + current_time = seg['@t'] + for i in range(int(seg.get('@r', 0)) + 1): + urls.append(self.config.base_url + self.process_url_templace(segment_template['@media'], + representation_id=self.config.format_id, + bandwidth=None, time=str(current_time), number=str(current_number))) + current_number += 1 + current_time += seg['@d'] + return urls + + def get_duration(self): + media_duration = self.mpd["MPD"]["@mediaPresentationDuration"] + return isodate.parse_duration(media_duration).total_seconds() + + def get_segment_template(self): + tracks = self.mpd['MPD']['Period']['AdaptationSet'] + + segment_template = [] + if self.mimetype == "video/mp4": + for video_track in tracks: + if video_track["@mimeType"] == self.mimetype: + for v in video_track["Representation"]: + segment_template = v["SegmentTemplate"] + + if self.mimetype == "audio/mp4": + for audio_track in tracks: + if audio_track["@mimeType"] == self.mimetype: + try: + segment_template = audio_track["SegmentTemplate"] + except (KeyError, TypeError): + for a in self.list_representation(audio_track): + segment_template = a["SegmentTemplate"] + + return segment_template + + def list_representation(self, x): + if isinstance(x['Representation'], list): + X = x['Representation'] + else: + X = [x['Representation']] + return X + + def run(self): + urls = self.generate_segments() + work_q = Queue() + result_q = Queue() + + print('\n' + self.output_file) + pool = [WorkerThread(work_q=work_q, result_q=result_q) for i in range(dlthreads)] + for thread in pool: + thread.start() + + work_count = 0 + for seg_url in urls: + work_q.put((work_count, seg_url)) + work_count += 1 + results = [] + + for _ in tqdm(range(work_count)): + results.append(result_q.get()) + outfile = open(self.output_file , 'wb+') + sortedr = sorted(results, key=lambda v: v[0]) + for r in sortedr: + outfile.write(r[1]) + outfile.close() + del results + print('Done!') + +class Downloader: + def __init__(self): + self.session = requests.Session() + + def DownloadSegment(self, url): + resp = self.session.get(url, stream=True) + resp.raw.decode_content = True + data = resp.raw.read() + return data + +class WorkerThread(threading.Thread): + def __init__(self, work_q, result_q): + super(WorkerThread, self).__init__() + self.work_q = work_q + self.result_q = result_q + self.stoprequest = threading.Event() + self.downloader = Downloader() + + def run(self): + while not self.stoprequest.isSet(): + try: + (seq, url) = self.work_q.get(True, 0.05) + self.result_q.put((seq, self.downloader.DownloadSegment(url))) + except: + continue + + def join(self, timeout=None): + self.stoprequest.set() + super(WorkerThread, self).join(timeout) diff --git a/pywidevine/clients/blim/manifest_parse.py b/pywidevine/clients/blim/manifest_parse.py new file mode 100644 index 0000000..9e545dd --- /dev/null +++ b/pywidevine/clients/blim/manifest_parse.py @@ -0,0 +1,104 @@ +import isodate + +def get_mpd_list(mpd): + def get_height(width, height): + if width == '1920': + return '1080' + elif width in ('1280', '1248'): + return '720' + else: + return height + + length = isodate.parse_duration(mpd['MPD']['@mediaPresentationDuration']).total_seconds() + period = mpd['MPD']['Period'] + base_url = period['BaseURL'] + tracks = period['AdaptationSet'] + + video_list = [] + for video_tracks in tracks: + if video_tracks['@mimeType'] == 'video/mp4': + for x in video_tracks['Representation']: + try: + codecs = x['@codecs'] + except KeyError: + codecs = video_tracks['@codecs'] + + videoDict = { + 'Height':get_height(x['@width'], x['@height']), + 'Width':x['@width'], + 'Bandwidth':x['@bandwidth'], + 'ID':x['@id'], + 'Codec':codecs} + video_list.append(videoDict) + + def list_representation(x): + if isinstance(x['Representation'], list): + X = x['Representation'] + else: + X = [x['Representation']] + return X + + def replace_code_lang(x): + X = x.replace('es', 'es-la').replace('en', 'es-la') + return X + + audio_list = [] + for audio_tracks in tracks: + if audio_tracks['@mimeType'] == 'audio/mp4': + for x in list_representation(audio_tracks): + try: + codecs = x['@codecs'] + except KeyError: + codecs = audio_tracks['@codecs'] + audio_dict = { + 'Bandwidth':x['@bandwidth'], + 'ID':x['@id'], + 'Language':audio_tracks["@lang"], + 'Codec':codecs} + audio_list.append(audio_dict) + + subs_list = [] + for subs_tracks in tracks: + if subs_tracks['@mimeType'] == 'text/vtt': + for x in list_representation(subs_tracks): + subs_dict = { + 'ID':x['@id'], + 'Language':replace_code_lang(subs_tracks["@lang"]), + 'Codec':subs_tracks['@mimeType'], + 'File_URL':base_url + x['BaseURL'].replace('../', '')} + subs_list.append(subs_dict) + + return length, video_list, audio_list, subs_list + +def get_ism_list(ism): + length = float(ism['SmoothStreamingMedia']['@Duration'][:-7]) + tracks = ism['SmoothStreamingMedia']["StreamIndex"] + + video_list = [] + for video_tracks in tracks: + if video_tracks['@Type'] == 'video': + for x in video_tracks['QualityLevel']: + videoDict = { + 'Height':x['@MaxHeight'], + 'Width':x['@MaxWidth'], + 'ID':'0', + 'Bandwidth':x['@Bitrate'], + 'Codec':x["@FourCC"]} + video_list.append(videoDict) + + def replace_code_lang(x): + X = x.replace('255', 'es-la') + return X + + audio_list = [] + for audio_tracks in tracks: + if audio_tracks['@Type'] == 'audio': + for x in audio_tracks["QualityLevel"]: + audio_dict = { + 'Bandwidth':x['@Bitrate'], + 'ID':'0', + 'Language':replace_code_lang(x["@AudioTag"]), + 'Codec':x["@FourCC"]} + audio_list.append(audio_dict) + + return length, video_list, audio_list, [] diff --git a/pywidevine/clients/dictionary.py b/pywidevine/clients/dictionary.py new file mode 100644 index 0000000..b22e939 --- /dev/null +++ b/pywidevine/clients/dictionary.py @@ -0,0 +1,42 @@ +import re +from unidecode import unidecode + +def get_release_tag(default_filename, vcodec, video_height, acodec, channels, bitrate, module, tag, isDual): + video_codec = '' + + if 'avc' in vcodec: + video_codec = 'H.264' + if 'hvc' in vcodec: + video_codec = 'H.265' + elif 'dvh' in vcodec: + video_codec = 'HDR' + + if isDual==False: + audio_codec = '' + if 'mp4a' in acodec: + audio_codec = 'AAC' + if acodec == 'ac-3': + audio_codec = 'DD' + if acodec == 'ec-3': + audio_codec = 'DDP' + elif acodec == 'ec-3' and bitrate > 700000: + audio_codec = 'Atmos' + + audio_channels = '' + if channels == '2': + audio_channels = '2.0' + elif channels == '6': + audio_channels = '5.1' + audio_format = audio_codec + audio_channels + else: + audio_format = 'DUAL' + + + default_filename = default_filename.replace('&', '.and.') + default_filename = re.sub(r'[]!"#$%\'()*+,:;<=>?@\\^_`{|}~[-]', '', default_filename) + default_filename = default_filename.replace(' ', '.') + default_filename = re.sub(r'\.{2,}', '.', default_filename) + default_filename = unidecode(default_filename) + + output_name = '{}.{}p.{}.WEB-DL.{}.{}-{}'.format(default_filename, video_height, str(module), audio_format, video_codec, tag) + return output_name \ No newline at end of file diff --git a/pywidevine/clients/hbomax/__pycache__/authHelper.cpython-37.pyc b/pywidevine/clients/hbomax/__pycache__/authHelper.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e51aa92b77daaa4b4b09f0782dc2eca216e3494 GIT binary patch literal 1294 zcmZWn-EP}96ejg=*=`$PE!J)Wgx$0TI>nn^XKj~ZX_B@>Q+H_62GBGJipeIlWl1CH zB{Afy>@9{3_T}DXPr#d9?5eM@n~jv5dOs9+zH^R_cz8a2kD5&v$aS&xd-R(Dz#l5O zT)K3=lA9&cAb?;3f(l^(%UBDv67@hY(Fn{Et-vbL4s4_a4%UXXxr?0z4C8+ysbP>@F6~WM)>-@&W7LVd3T;YJ$Sx%*GtFZ7il;c!l5?Q=SBevxX?mv zrpg2*G>V;WYZ%oNvz5iHT zA?y{ybT2zT#^~!*xI7!-G~(wu7A6~H5*qPffEkO*H&ZS2-~J`nRNLH~Hg4myoY0t) zEWI7LtDw~sZhn4B5dMLrSlEMv;FL3ARX<8tRYDl!n506Zs#%^8E{q||Qeh@pjAZpu z%y6$OYDc{;!h;N9VJ%T-oVFUmn8?cuCyyCB%_tIPc}ZbLlL`nX8m#><{hw4GQ!eV|gg8Pm$G-x4OCI>=x7!awMIj4^lay?PJD81lmWPMC zk3QMiiw<7A*xL`&IPdf#j0lfZRk-3NTv8KO%!KiTpFG7$j;WuYDR1YxJrNg~7=f3oT<*4I{i2 z0sfKzzan56Qb(2P?3~dx<<$ohN~MGzlLQMRkNJskD2|hr_l?Tgh|n~aos?5%+*kX% tFQcs|yZwWbq4HMMwf{YUaK0F4Xp-PBp=`+Bm*$e_3KiWAXlTy0zX73jTI~P; literal 0 HcmV?d00001 diff --git a/pywidevine/clients/hbomax/__pycache__/authHelper.cpython-38.pyc b/pywidevine/clients/hbomax/__pycache__/authHelper.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..462521424f13ed83f080fab966eaf7cec02085c2 GIT binary patch literal 1135 zcmZ8fUuzRV5Z~GRlQg!qU@62urBA}4oW6)4r4-u-5e;Z5l@KV`>^8aNa(C=*OdBsx z?YrP7Nbt$8w68w(EBNHhC6d-XX69zto%zjg=6G$b#_;T3{5U;x8T(Dn?c<=ckD~Wb z2__(6&AEjpls<3r(mG97R0S8#H8efp3h$aVec_7=+KPZ97OdQ04%TRMGK+&X86h}8 z(E^nK!LQkb8&+VhD-iA#|9&`e3MRZhSNnxC1>w&CnBh~WfWnz^U>J303|P8_Q4eEq z!Z>@yKC#d2Cp%&%i~lc(9g$QTZNOUp4gp$0IYQAdQ5n{QDKFRz^m9X{0YPj`pn$0> zI2B(eEGVJVurM0)ZqPlZj!a5MDK-n?vLy3EbGToznCXKHCbP# zVGm!7xq7CEB1N19zVgvnS4-KqE?uy$7!GnbNU4={3POtgz0O1Udf@rTCL<2{@`ji}C0^E#XH7N5X` z7a*KE4aaSi$ZrU~U5(mpsr9@+oK|hgudOTyw*H(1>(2w$9Yk>&IMx|zWxbLb>zxjV zvG~6yFUdM_x`~xEtu}*gP}^wlG(u#Ol#S3`LmNgb4F$Ub+B1aB8{_-64_OEEb#~%3 z48vN$t(U7fHD%6#t4H`)JtjqawB%MjM7NHjiCrWXzcLm;BdDr1j9J&j1F48qyR#%A uTyPN1DOk8_3$K+EDJz$$Zj~&Hmou&I4l*%J>iq?GApW)h literal 0 HcmV?d00001 diff --git a/pywidevine/clients/hbomax/__pycache__/client.cpython-37.pyc b/pywidevine/clients/hbomax/__pycache__/client.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e191c2e87f8e70fad8b7ce108da108992468f97a GIT binary patch literal 3212 zcmcguOK;oC73PqXNWC9^-`=F`ZEhPik?f?&MPmd(97jQnBz9`MXh8Tvpfw|zGDR{o zBPUiVpg^)s+kIWY-nIXviwktmMK)a-=np8mY0nJB*tzYxBsjx4!7~KTLwMM4p}`79o?<6GvXLCCwkmtg)?}~Sy6iKx+24$?hQ|$`YaRz5kRJ)3c*u=T_$gbf$F1%OlIz~H6 zqjU}^l+6Z;^+DkJu939`;WJ<|C}WS0;L- zN9Y}zWVmvQxO#>r*(i&(C1qk@{ZxxGXDBjo=Drds1NbsBU^cs?VB>=}F?l932ibQB zn}-@5a3eBL%`*k(mXvo0DLjYsqEDog94>$(O1O+GCwd=E^0Ox}n9|ha(CnPtw*xrreDW%w+4&wNB-#Bh3Y~)$ z|9bdjb?kX5tUID`tcQc?pyc0pzC<-K}%S9u|_&;oO?tZN~ralNnCP9 z{2-w2*x_#A(=6=P(5L~O{8SoCb7CkCJuN^pzB;1*Dxg~he;hg8<0d1VyMCXo4go(N z&tJ?3J=Y_td@+@SpXu?c=P(|6&M~a0q%(qfR)?ga$Eu6zl2G}n8Cy;mdTv)DT|V-0 z3ox{f?zMU&&$}TxuGSyB;Y|yZp676K)7q!wYfl|a1AqDMO6$%_Yo>)-9N4hdckyA;yIU_Cu`w0Jxsea6r5VQ5OL2)3@E|*w=8zd@MNWl$TuJ&S@gYCJ0iOh(!M> zzlp#s^c-+Ews>H9F5^~66aUAF7sqp{o6`vyuvp&@@Ud;CLMqOUotq9f@c6DDeA>$D z1>m8ZR+kd+uod{?v657^93OPkW6S9~P=>xf;5=lj%gZ9jB36*iqVOzFcitf$>GDR7 zUJ=;;-@Y^;s00oHy(+Ao6>;jMah?JMg30%(;{#0`hs4fL#U04ZF9l@l!rj3>WTkKM z17bn)I39#R(2W`w*VfnDJ3F1-t!M4cxYB<0a$|dKcVla_v%B%49iunn%!v1zzkuRx zrfGC8YApz|F61H*jyU6u8Crrao)PC+oY~9NRZMDqH}HFIKhE|7I&?U#!uPZ$n!0Fa zL?gJ1&O#H{hJ-tUt2$}2#_F%uV$CCdtaBHNzaE6}UVi#w?Uh8|d9v}m9cSK9mjf5# z(J*9jrt1ZaG!|oH2do6M>~eyI_&9`r5nxb2#leb%BAIhUl0Or=04VITq^6Xj5AB>Z zO~8`$W1DhJNodRbNO`<7V0JxGlmsZ*!LG?LekLkk5&^^8rAuSj5|%!_bj`X0tFHZl+g*DV=r(pkZ1_`g_A1o%Z0Hqo&3IcY9i~8pg;!c@*eEXL^g}!r-KFb zfzXC_8#8fs-(lpNJ9GskR8+}W4OmjPt&2L_n%3D1W|F7Jn2O_U!dP)OIaY}oM!;I3 z!w;w`wl#L(&q9>VZ^Wp)zP0siqrKC4vi1CNdz;=C>TiffxK`r3WS96SpfdF4{b7Jd Y9(f>mmx)t*9m;u8#1JB8YWY|H0jUw0CIA2c literal 0 HcmV?d00001 diff --git a/pywidevine/clients/hbomax/__pycache__/client.cpython-38.pyc b/pywidevine/clients/hbomax/__pycache__/client.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65e4c6f0fec30066b8fc45a67016ad04c15ed9b7 GIT binary patch literal 2272 zcmcIm&2!sC6qjWABZ=L_X-a7LsOSg8ZDh;wN1PNo(56E>rD>;0r;H|pXQj7}Rm+mP zTBnI7y-==PxDsaCBYzJ!UE#tBW*825n1Q#l6GG_~dGvPQTfNWyy z_Jb)&`cW_^9|f6@@eP-dfCREDnWIrQ<%CyE1r$hqC7CHuA&sL7@}^YE{EQmXhArsH zCxy%ne8W5vE^+yV@=|&(G~|s^Do%x*#p+<-fSDGw{=LLh{4ycKYd6-mABL2L+m8pH zv$DNT!yfm8?XKl-2m4PQpu3Jow{6#<9uI}MPxi)aIoOX2JJh3$aM~8O(;^I!p(L{m zQahOo9v>k%gKrY+uQ=h-bLpAF<;M!hm@(!I>VX1j$T%`&4>OR137CW_$U^~6!8FW3 z5oX~u%)yz%0=)5c>RAfr4^l5uFQs0Vb-6m4!<%O@e_7&bIQv}wQXWg^&q~kKv9|?y z>p(h?;q5~e-hp@F+<`hTfp(yLE5Un$ewTvtZ~-pDrLk`j$@_`#4-Sio?=<>OkA44y zzLWV0-;0UwM0%if6x@%}Mx=E)55l!d#rFG@mr3B1v8H9@D%|f;FN`iWS`Euswp%(_ zw5r!@%N^aST9#g|+MVW#(XpsyL<<)4pN3T1#U1k7flKx+V)xn|MyWYF+O4+DDB!L+ z#0|~U0om^(bD#M_h28Lhnp2jGN`1n5l$SE*#8?lJQW#G|ibi;x4sAc6@#GF89&hvg z0G$YA*mRRJw7)UvTa=kIBdzshWu0&mX(R|-$0pqIy~?f!NwT}E<<7u$uRIQYFDmXt zPOzi_?YM}dCCy?{ntJ*mjOIkCuu`=~x!P=$m+Lqf(UsRpD*@S|l>zhCu$XItS?gkb z<23CDeBV@UpM}w+&HOObLxvT@Ix6>+qMy>>vt@Tt!rYQ469 zu!;iI8g=O|q7m9?)E^+^`@}r%85$cC3|`l{%@G93QQVxY@k}}6;Pf#*`T7LS2ep!SV;Lt1K!bF zQR;H#a#S2Q9fpd>zc{U;^J54$j5796dG$32EEQw5>xVp^w0+N`wm1ah0vYfwA}dPH zglKxS!2zQ#8F+R#%73n3ujyL?D7S$XvC2^%)j5`47Y7d$*DEUsa!QbCL1qNO+g4)Y z4rH@}oEBsbNu0jPn9oX?^8h=xN&n)ES8968CQ^%Trs#&3t!8d>O<*VZ_>K{j%>=Jq|rJ05U6Mq$w jgp*PvODAGZ{uLyF=RU-S9=PAPb0? literal 0 HcmV?d00001 diff --git a/pywidevine/clients/hbomax/__pycache__/client_.cpython-37.pyc b/pywidevine/clients/hbomax/__pycache__/client_.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a0dae522737df83efeb6487e81b527ea328145c3 GIT binary patch literal 1625 zcmZvc&u`l{6vs(Qwq)5(^Q&z<1Ve%L;zL~w?b=}|h9K>B7>aa2RtyjfxQt0VvMo^~ z>7>c*Q+FD$|DYJ`_)cu+Wi&-?;L5J4v-E*kNQfD6KNhD^0_$}raYN+`YMf^xjL6x z4brJe`k%F#3#UfvjHl9tIXC89Y0<|;@Ie_s8u9`@a|Xte1znOkvCMi4Z%N)$LHEd< z&ZuBxUylUT$4rl`KdQ`#@LB|{U)V~Ei0ZH2oLM$wqbiIH#vb$xW^55Ii3nRT8zr_T zYUo$3QH#K_>qnZx>dC{owaF-WB`d?>GQ zv}^EwAL_kAsCML<{YfG-+v}@rkPO|%P}(xqOR|A-UXoeo+XR#e42(-u=KNe4>*~gG zJ2fy+NLR@p;``RtfMj%oZ~Y@*Yz4kEI$$MZ#CKUclw3=F@29zI@~J&lI=SQ)#4iyC z(B~%ZLU>(+R*mVb>u4I-siB+T+zw*JiEgrOOw=&R*5s=LrBiMTMf4UrK( z(I8=c8w>!h6%!)g;?BikQP(mr(3WNox|TGqS4YiPG@^pX-kQdz5b5JJ#phpn_W&AJ zc}It24%xF{Gf)kw2=)OOVYYyR-chj`$Z3{{vgnl>Yz}26HMg>t^NWe%!c}>m%S^OA zOsA|&oM09F?-{mG!85pdYCZfuY{{S=c&U84OEqq?eaBT#xRFnvXuNPP)bhuvG}bt# zjJtn*dpoP!+gbgrAORtxGUynrBCcA7Tc;+5dbM(qE5?)Y}tly(H2NiqAuH;SO;yZBvOh<+3}RBP#|YW!2$th07@dt zev&^TRZ*&TANLpXDR|9Oeqo=|4G=oKc5OD5kcFO^Mo&*q-&h$KND1&O{bNr{jtIg( zaS{F!FnI-!{Y4Z6Dp1i7NHB^-^w$!RV3dqVD@vjwzKa-rtr&^5;w0Wmkc5wm8p&3Q zq+0!?AJ%;|_C+9RmOc^40F9GDT_8g=L6bB^`%fcmh^Ai(bbt=hq278J)+1z?j*=02 zg^sadHbSq`YxFw3aT+J1bR7OS=`A`zZ__)vNbjD;$Q3q7Wi~+X(fjlPeF&H_7GrVx z=tMjb$yJtMSLx#uiCpt%PhfVPPLdlmL&oV-a+5wIx9Aj^@E?WTrde`_rG8AXYpkE< z#)YQzlZdmI0*kU6!0|4O<1orF-h}ZUjJIIC590)k4`93v<3kwl!1#zx(>&;hX5I*NkuH4^=n{K+5+Tp1SP?SM|An?GXGE{>XkV}IXChvl>fF>? z%u8^l8Ewtk_o5#y-ONZ{99K4LdvRtS>fAExxI6qsV6qC2od)0tj`*YWlW>Bkh-Kg# zu^sM3I~|>ReFzIb3%nmFeelbx*U$IXij`t{b!UCMy1cXZc4bRe&TYNRXIPMoqiz$V!rS~KAtaRvkTeTd3kcneuk zXsxW)*0XSdY~5<*w2rf%bF2eq+U}E(99}Tz8^my32d?k#{uUwSt(*Z`Fm09#b@#^u z)&(W~&^EL#*p_x51JwrWzGK|hE%S#Nuu?3L#EbV%@=`r6>d~Pm8QQssy&HY^F83~p zc!?~$#n$&p{ww)Csbjl+%v5$O?q4rids8<%$1mh%lX6R^@mkTviwy{qMNxnU<>Y=&FAy*-ac@wwmb=evr*mJ z&Oq!2C@AJ&BVQ!RL*!pyowb+dVfFf_B-(VEOnb!^5Jn1PFp9V_6X zN)T_#Vc;X~NPrDOOu;@(VjGlhmW$7bi1Sz0eB1xBZp+H51Q%q%TUFU>6E zYxA?zy;-~0YS9Z4ESBg7m$62)FOks&6m&|PI38fqUS8;TUBdH2S5UgUlemH%UD^7GLA^n7+c|GU%B z-HV9|75hT2?`zy<&JP`@p)9%&&XW@O^K^D`?$!%g=pg@SVgr&9{q+TJ@f~Ft z9R>4X=vp6OlZ_V;BuSLSG(6!yA@aw7ucOo858I7CczowUw?gOn1gt=aaG#i_ga&9n&m#ok6{20Mh(KvhWTRtGXwOEV#D zW5)9m$SvsLLT;HTzYfyyYY3hom;{iC1PZtdbCL`=tDqN&%SiGFNhA`fH<}ztzE;!~ zR1|hE7s9FmbhiHi;Oi1O0bdwk6zGT}6k-`hh-WZE%uBs3E&q9kH6fRt z@rb}Sd{&W17Jvf+gBhi9;d3|#{iN|J};rFet4)}N>!mIb_}MfURqWE($S3I4M+3v z9D;B74WGgncxn_tLQKSbOlFEFVGSQAUE9NK1IlY-isN3)-tRcN!7--2xMgSY;yt7`csIRv+*NQvd;Of@a#`&6zl(q|N#nqh;+f~)4{Xm9G#kKY2_44bj z5HpBGyQS@LJyhCwS1RtjDTauF*RM<4#W!b5IC6PrHC&EWc2}zF)y<*`jKgER)cMI? z^6W@2-aE@ngok*sfV&q9*m?t(_;JjUehT%o1jqP=B2oLu>P}#>Z&;2fm)C^B4Nm8B$7QAVG@)rJ&(*IJ=zvX6Bo{TdB+|czyiu z|9;acE6V@qVR|j#;Gg&penkNasE%T!chyjn=Zuko3}k;$j4aQ7uNXPV8F|P<0g6z9 zIhcnFX9c4GWvIXcEJ78QU>PpLC7%0Hf!9d>l!e#fGF*X`vx-sV1-QDRq!O;d8#sD% zMS-{AZCeEm*DCQmyu)+wE?kEj@E&UBU=`j+59Z+})bM@*K7bGLUIukvsonZN`mS^> zlG7`TgM0W7aKnmJr22E_Kg#!Ht#)hKI2%Y2=fcp2I8So@7e(aJG7-NW-rMOt3AhM) zUxco`+1us8vGn}j;r+Y%?nConZ|~uLug_p@Qy;NFa?$h0Pi^2Qw#$2#V{=yqy`#Q2 zVy8XJa|6jxQTNC3;*h&sFv(3aws?*_%%D(IQA8PuM_yz*4r_GkP3`8P?Sl6-(7Fd& zt66V;q@iMC{UhykW4)%`@qLFM^8N!`HacsY^|cM{=7Y};9zDFJIrcHvKIPW2SJUnt z32($3+pT)DzP`TMu5WH?`)t63J((5hM^gI1PNOkI$DXpW?l8$lb>`c3+(X^+MhzCq zqlWa3xf?|9PtEZKmoG8K9ZN(Y`uUFx`Kd2>5a^Q$jemv0efCL;3@U-&h7|Z!Uw9B& zGF75ekJ#xd`lp{@jBL-neX_l3d7&%CI5i0anli8*uFJ7c>kL@v$ko6ex*T-dy)8w^ zqbGmlA&61K!8o}AZ%hOH$uS>e7;pOy8w<{0yoy#2`1tFIFYV|?XRFh1wyiB4`n;vD zueAqyzt!*St(G;|*lZ5^yx)v&Fl*3kvCcs6Z1A?e&f44hHbeV1&f3~!8yih%*9vhV z#XT-gV8Q}Qaf^!+*W$S}=SG>aTdw@Y#?zFo-*7yh9H=N0=jV zo{xMvHgc9Hf@t0n9>zSdCI9=feQS-fz13W+Z?w*5`){fqUH^=MKs?&pXw|H@J5Ahv zQsLUo-TV6w4)(sR#l?v#o(o+B2P+$DmAJqxi~BNKOz%2(F;8uG_*~&IcNpT%;MoXP-xy>$A@ZIP)RKP{*aPl**@ie@&NyS=@%`(y5LB z>uJ!ZH4rVO+DZAiY{a9>=Tu%WwG|hLYp(VMk_*>PkhwgQg4}1;u{jW&8_Sc7vIGZo z08=Rt#H7YWpN&VT`BHc^PuxS-jSGDTXO5US=CW2uRyQh>6>!&r%Qzocp3md?p+GJ) zsVI%*)YbhYQ@i1)&xKJN|8b+!tgj^jUEen5?sRt_?|r^|@by8h5G|hrg5Y+hC?>ndxG)(a8Aa99GC*F! zlFSzEph89}*w?cpf67V~axcyTXLHX~ zIuCrOKzT($S;4-(aF%YJ%cv6Q@?5OdOMrfK!pi_=)9!Z)daO`iq9Q%^v&_0n2J z+M-j0#vOiwWen`V9{Nlmgvt3#yp1n~MuPS&u9CP$;$0H7o5W*5 zYrWKi(m#-WLWh4$B^J=;xi+c)CDOW&X5_mG@8LLtjf0up- D*w=mp literal 0 HcmV?d00001 diff --git a/pywidevine/clients/hbomax/client.py b/pywidevine/clients/hbomax/client.py new file mode 100644 index 0000000..100d8e7 --- /dev/null +++ b/pywidevine/clients/hbomax/client.py @@ -0,0 +1,106 @@ +import base64, time, requests, os, json +import pywidevine.clients.hbomax.config as hmaxcfg +from os.path import join + +SESSION = requests.Session() +HMAXTOKEN_FILE = join(hmaxcfg.COOKIES_FOLDER, 'hmax_login_data.json') + + +login_config = { + 'username': 'rivas909@me.com', + 'password': 'NoCambieselPass.12345' +} + +def login(SESSION, login_endpoint, content_url, save_login=True): + def get_free_token(token_url): + token_data = hmaxcfg.get_token_info() + free_token = requests.post(url=token_url, headers=token_data['headers'], json=token_data['data']) + if int(free_token.status_code) != 200: + print(free_token.json()['message']) + exit(1) + return free_token.json()['access_token'] + free_access_tk = get_free_token(login_endpoint) + auth_data = hmaxcfg.get_auth_token_info(login_config) + headers = auth_data['headers'] + headers['authorization'] = "Bearer {}".format(free_access_tk) + auth_rep = SESSION.post(url=login_endpoint, headers=headers, json=auth_data['data']) + if int(auth_rep.status_code) != 200: + print(auth_rep.json()['message']) + exit(1) + + access_token_js = auth_rep.json() + + login_grant_access = [ + { + "id": "urn:hbo:privacy-settings:mined", + "id": "urn:hbo:profiles:mined", + "id": "urn:hbo:query:lastplayed", + "id": "urn:hbo:user:me"} + ] + user_grant_access = { + "accept": "application/vnd.hbo.v9.full+json", + "accept-encoding": "gzip, deflate, br", + "accept-language": hmaxcfg.metadata_language, + "user-agent": hmaxcfg.UA, + "x-hbo-client-version": "Hadron/50.40.0.111 desktop (DESKTOP)", + "x-hbo-device-name": "desktop", + "x-hbo-device-os-version": "undefined", + "Authorization": f"Bearer {access_token_js['refresh_token']}" + } + user_grant_req = SESSION.post(content_url, json=login_grant_access, headers=user_grant_access) + + if int(user_grant_req.status_code) != 207: + print("failed to list profiles") + + user_grant_js = user_grant_req.json() + user_grant_id = "" + + for profile in user_grant_js: + if profile['id'] == "urn:hbo:profiles:mine": + if len(profile['body']['profiles']) > 0: + user_grant_id = profile['body']['profiles'][0]['profileId'] + else: + print("no profiles found, create one on hbomax and try again") + exit(1) + + profile_headers = { + "accept": "application/vnd.hbo.v9.full+json", + "accept-encoding": "gzip, deflate, br", + "accept-language": hmaxcfg.metadata_language, + "user-agent": hmaxcfg.UA, + "x-hbo-client-version": "Hadron/50.40.0.111 desktop (DESKTOP)", + "x-hbo-device-name": "desktop", + "x-hbo-device-os-version": "undefined", + "referer": "https://play.hbomax.com/profileSelect", + "Authorization": f"Bearer {free_access_tk}" #~ free token + } + + user_profile = { + "grant_type": "user_refresh_profile", + "profile_id": user_grant_id, + "refresh_token": f"{access_token_js['refresh_token']}", + } + + user_profile_req = SESSION.post(login_endpoint, json=user_profile, headers=profile_headers) + + if int(user_profile_req.status_code) != 200: + error_msg = "failed to obatin the final token" + print(error_msg) + + user_profile_js = user_profile_req.json() + + refresh_token = user_profile_js['refresh_token'] + + login_data = {'ACCESS_TOKEN': refresh_token, 'EXPIRATION_TIME': int(time.time())} + if save_login: + with open(HMAXTOKEN_FILE, 'w', encoding='utf-8') as f: + f.write(json.dumps(login_data, indent=4)) + f.close() + return auth_rep.json()['access_token'] + + +def get_video_payload(urn): + headers = hmaxcfg.generate_payload() + payload = [] + payload.append({"id":urn, "headers": headers['headers']}) + return payload diff --git a/pywidevine/clients/hbomax/config.py b/pywidevine/clients/hbomax/config.py new file mode 100644 index 0000000..befd2c0 --- /dev/null +++ b/pywidevine/clients/hbomax/config.py @@ -0,0 +1,125 @@ +import uuid, sys +import configparser + +from shutil import which +from os.path import dirname, realpath, join +from os import pathsep, environ + +def generate_device(): + return str(uuid.uuid4()) +_uuid = generate_device() #traceid + +user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36' +config = {} + +config['la'] = { + 'tokens': 'https://gateway-latam.api.hbo.com/auth/tokens', + 'content': 'https://comet-latam.api.hbo.com/content', + 'license_wv': 'https://comet-latam.api.hbo.com/drm/license/widevine?keygen=playready&drmKeyVersion=2' +} + +config['us'] = { + 'tokens': 'https://gateway.api.hbo.com/auth/tokens', + 'content': 'https://comet.api.hbo.com/content', + 'license_wv': 'https://comet.api.hbo.com/drm/license/widevine?keygen=playready&drmKeyVersion=2' +} + +metadata_language = 'en-US' + +UA = 'Mozilla/5.0 (Linux; Android 7.1.1; SHIELD Android TV Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/84.0.4147.135 Safari/537.36' + +login_headers = { + "accept": "application/vnd.hbo.v9.full+json", + "accept-encoding": "gzip, deflate, br", + "accept-language": metadata_language, + "user-agent": UA, + "x-hbo-client-version": "Hadron/50.40.0.111 desktop (DESKTOP)", + "x-hbo-device-name": "desktop", + "x-hbo-device-os-version": "undefined", +} + +login_json = { + "client_id": '24fa5e36-3dc4-4ed0-b3f1-29909271b63d', + "client_secret": '24fa5e36-3dc4-4ed0-b3f1-29909271b63d', + "scope":"browse video_playback_free", + "grant_type":"client_credentials", + "deviceSerialNumber": 'b394a2da-b3a7-429d-8f70-5c4eae50a678', + "clientDeviceData":{ + "paymentProviderCode":"apple" + } +} + +payload = { + 'x-hbo-device-model':user_agent, + 'x-hbo-video-features':'server-stitched-playlist,mlp', + 'x-hbo-session-id':_uuid, + 'x-hbo-video-player-version':'QUANTUM_BROWSER/50.30.0.249', + 'x-hbo-device-code-override':'ANDROIDTV', + 'x-hbo-video-mlp':True, +} + +SCRIPT_PATH = dirname(realpath('hbomax')) + +BINARIES_FOLDER = join(SCRIPT_PATH, 'binaries') +COOKIES_FOLDER = join(SCRIPT_PATH, 'cookies') + +MP4DECRYPT_BINARY = 'mp4decrypt' +MEDIAINFO_BINARY = 'mediainfo' +MP4DUMP_BINARY = 'mp4dump' +MKVMERGE_BINARY = 'mkvmerge' +FFMPEG_BINARY = 'ffmpeg' +FFMPEG_BINARY = 'ffmpeg' +ARIA2C_BINARY = 'aria2c' +SUBTITLE_EDIT_BINARY = 'subtitleedit' + +# Add binaries folder to PATH as the first item +environ['PATH'] = pathsep.join([BINARIES_FOLDER, environ['PATH']]) + +MP4DECRYPT = which(MP4DECRYPT_BINARY) +MEDIAINFO = which(MEDIAINFO_BINARY) +MP4DUMP = which(MP4DUMP_BINARY) +MKVMERGE = which(MKVMERGE_BINARY) +FFMPEG = which(FFMPEG_BINARY) +ARIA2C = which(ARIA2C_BINARY) +SUBTITLE_EDIT = which(SUBTITLE_EDIT_BINARY) + +def get_token_info(): + return {'headers': login_headers, 'data': login_json} + +def get_user_headers(): + headers = { + 'origin': 'https://play.hbomax.com', + 'referer': 'https://play.hbomax.com/', + 'x-b3-traceid': f'{_uuid}-{_uuid}', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36', + 'accept': 'application/vnd.hbo.v9.full+json', + 'content-type': 'application/json; charset=utf-8', + 'x-hbo-client-version': 'Hadron/50.50.0.85 desktop (DESKTOP)', + 'x-hbo-device-name': 'desktop', + 'x-hbo-device-os-version': 'undefined'} + return {'headers': headers} + +def get_auth_token_info(cfg): + data = { + "grant_type": "user_name_password", + "scope": "browse video_playback device elevated_account_management", + "username": cfg['username'], + "password": cfg['password'], + } + return {'headers': login_headers, 'data': data, 'device_id': _uuid} + +def generate_payload(): + return {"headers": payload} + +class HMAXRegion(object): + def configHBOMaxLatam(): + tokens = config['la']['tokens'] + content = config['la']['content'] + license_wv = config['la']['license_wv'] + return tokens, content, license_wv + + def configHBOMaxUS(): + tokens = config['us']['tokens'] + content = config['us']['content'] + license_wv = config['us']['license_wv'] + return tokens, content, license_wv diff --git a/pywidevine/clients/paramountplus/__pycache__/config.cpython-37.pyc b/pywidevine/clients/paramountplus/__pycache__/config.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08e16c99aedd549f67a57a79f6188168566ec2eb GIT binary patch literal 1090 zcmZWo&u`N(6t?qwZPV^IOk5DR9@t?_LP8VT)^=rrj;b3VtV$t`-7Q<31Si=T>WS{J z-~>k`{vuyFapKO2=dOiK*z)(i_iVqse71L8w}hZAfBN~kg^!Tc!o^Al;DCShFHq^-P+rP5~cc_@-t zx~VUGo)mGOMny)PK^XfYWEm;(bd$0`T&B6Sm0j?ZIQ;CKGjYtMH5~Gk9TN*y`x}8Y zx;sbD0#(YaX<%%_$d&;ZBA6ngQB1WfM0Bb{>4scOall9s91JDdM ztJC#7S@Jxd&>~WH#q-`5esnz}R#fS#<{O}nK~wQsacK+1=W-hTJUQwL9KyZZ+_z5UjqxA*czv(+ODo$h9{ z)#$y26_dHQq^d%%I^CIH>pXwmY4zHzS-{=f>vUV~zb+))*=S5%S^Aez+S63hndOky z^=4vS?~+zBIAuXT`NJD3Ohi#qNN4L>yr&qv>^?vRFXMTwqLnlQPrJUVIe6N&KdWC9 AXaE2J literal 0 HcmV?d00001 diff --git a/pywidevine/clients/paramountplus/__pycache__/downloader.cpython-37.pyc b/pywidevine/clients/paramountplus/__pycache__/downloader.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f0a1b9ca3ff463c0fa50c4d9fb5ced562bfd207 GIT binary patch literal 4510 zcmZ`+TW=f372eq!mlQ=^EX$UY8jhi~W?L%G%}!Ixa8jWcCl#F7fL+!Gv*L`Tm6p5I z?9i4M%a=Mqiy}tQ=fD8L))NlN)H+9dyE?6(F5)`)do*9qwXuxyOBs z9>Rp+?O27?p^;%^1@+JrGT3_4(awG^)>G*~^#`i68O1{T-89*ZwwktfGZAk} z4^sYN$qI%SpRIj-e0}kRmp)M?rhNO zh4OJLN^lAf!+7;FaZl{qk|G<#YIPgOkROkOq;?dQJSnKX(IBo5SJ!diZ9}Hs}+lfB3^wI$|QGN z`|n;spP7CKz1@oLG@16y`gvvLou97s`X6Zf(FUk)FXckpawGR^Ymod_b4J&)!A4)E zU6Ezlk%L56`k~s6qYdre!bDFg(d&0M(->}`J-HR9c$4-;qWx@ppdz5VoAw{m#?y@* zZKs)bNrLvpew3+9`?9B`0Pdye!O+_4OIWoTNJ6BZE>8$ZHO^6`z5}a>_SE=I+E-b- zo}~lX6~==y_^8NKlo%6f*L>)g491Phj$o`ClOyXW8FqK4K+ArP&a!Rx>feWVH0)W{ zU^TR5R>xRl`5VXl<+#MI@hb=<(d5d;YyN`?FmLTvyFI3pl}Qg@fWmz8d|k*4UN97am+Eo!%G@s+4Ooozx<`> z1NewL#_+#eTh1%X>x15gkdi^+7i{@Cjd`UczWtnRlTR&w8YUc(OKmUb{_>ruCzf-2 zc{z7hR^HJTVq`^%ejIiM9c99`L-3d?;Smt}Vz`f<1JjY!I}z8_jfr6GDu~s7Vs=AN zBmZpsNv1-n+HN99?!yoWhBFVuNti5*J)kp?ai?6eE8fQLvt@J$n^qmrsG-e{+oJ8V zg_4eU3oL)@7)V|xuS>?EA0-e6%|K-ylfoKV2i6d&V}t~9Kxq%j!`2I1LUl5+)q~B) z+kz$PN2poTE)6w%lI^65b6X-25|*3@%&ubPj1o7ch5Y=n{lCI|m;otI)zQr6|BcC( zHM9%hr9ckYu?xo8k~MO;ZJvQ7;F%(_Gj#U<3I#n<5b?hlxj*P-M$_=Vt2Xjdv$n6^nt%Q2+-{=V*g-uuf4DTd` z6xpI~rDWyJDI}jh!X!5dUI!atCJ0{gC*aW4%~bY6MJQgt6p?Lwet>a|1dm7?CR;)_ ziP^z{%lFJIQ?gkxCoVrEf(waRyU`s;PT=**{TMPP${EGZma0IhS~)vZ$X?ft;}H|SN?s$^(2bSQY+ti`C-$rx z<%T9|e*ymS_K}(FS2EIZ?!z!cCqfyCMpKvn+1iBNQ6&e;`U||3J2)YD9`}}vm%(>@ z_#rcVl?mSnK7GK*3&-!v^9t5qSqPVcGGK1OF(15n-yY&{u@Du9NQO(+t}Wfd{+qq$ zQiRK$8xe<1XpcHD`5FFzd|6cvJ&qUcqAR-i`q4UK{xI7um1th8O2lI z%0K)epdNteg>|xrxx=8KDBAiX#jRPgMorxudAg#|+gyeQBuK4!*39 zsi^pYM{n1a->Qb18O;8(W%1! z9@W{iayNM9SP2y56FyZqnAM*--@APJnP>J(91X+4o;hR6!hyxCy}uv5r@#)U3(A0~ z`k(>hGl#d5*>%lo`P{LxcSY^1+@(TYQh+h}MzavnU2T4Zx;+p{H|4k}5Y4y8lm)`z|=XYuv{T1F0r!o+UauBpQtrbk6?*V!WS)I8cn^oyv}^Vwsr zk6X-ovrhM4x=3_7y4LC7<}<*}qND4b&fXx5%Qv!$Ma-^Eel6`riBVG8F#cqG#BA%x zR$uOyVh;tdjOsY#PA@nY%m;2T6IAf`B)xA|bs)vw0GF0b&VeBRNFCj=&CzHldz=~b eYae$g(N*TN*R7|6Yo#XFDKr_korNLJ+W!Y0-)H6k literal 0 HcmV?d00001 diff --git a/pywidevine/clients/paramountplus/config.py b/pywidevine/clients/paramountplus/config.py new file mode 100644 index 0000000..e840559 --- /dev/null +++ b/pywidevine/clients/paramountplus/config.py @@ -0,0 +1,30 @@ +from shutil import which +from os.path import dirname, realpath, join +from os import pathsep, environ + +SCRIPT_PATH = dirname(realpath('paramountplus')) + +BINARIES_FOLDER = join(SCRIPT_PATH, 'binaries') + +MP4DECRYPT_BINARY = 'mp4decrypt' +MP4DUMP_BINARY = 'mp4dump' +MKVMERGE_BINARY = 'mkvmerge' +FFMPEG_BINARY = 'ffmpeg' +ARIA2C_BINARY = 'aria2c' + +# Add binaries folder to PATH as the first item +environ['PATH'] = pathsep.join([BINARIES_FOLDER, environ['PATH']]) + +MP4DECRYPT = which(MP4DECRYPT_BINARY) +MP4DUMP = which(MP4DUMP_BINARY) +MKVMERGE = which(MKVMERGE_BINARY) +FFMPEG = which(FFMPEG_BINARY) +ARIA2C = which(ARIA2C_BINARY) + +class WvDownloaderConfig(object): + def __init__(self, xml, base_url, output_file, track_id, format_id): + self.xml = xml + self.base_url = base_url + self.output_file = output_file + self.track_id = track_id + self.format_id = format_id diff --git a/pywidevine/clients/paramountplus/config_orignal.py b/pywidevine/clients/paramountplus/config_orignal.py new file mode 100644 index 0000000..ad6bfdc --- /dev/null +++ b/pywidevine/clients/paramountplus/config_orignal.py @@ -0,0 +1,9 @@ + +class WvDownloaderConfig(object): + def __init__(self, xml, base_url, output_file, track_id, format_id, file_type): + self.xml = xml + self.base_url = base_url + self.output_file = output_file + self.track_id = track_id + self.format_id = format_id + self.file_type = file_type \ No newline at end of file diff --git a/pywidevine/clients/paramountplus/downloader.py b/pywidevine/clients/paramountplus/downloader.py new file mode 100644 index 0000000..396c1f9 --- /dev/null +++ b/pywidevine/clients/paramountplus/downloader.py @@ -0,0 +1,116 @@ +import requests, pathlib +import math, subprocess +import os, sys, shutil + +class WvDownloader(object): + def __init__(self, config): + self.xml = config.xml + self.output_file = config.output_file + self.config = config + + def download_track(self, aria2c_infile, file_name): + aria2c_opts = [ + 'aria2c', + '--enable-color=false', + '--allow-overwrite=true', + '--summary-interval=0', + '--download-result=hide', + '--async-dns=false', + '--check-certificate=false', + '--auto-file-renaming=false', + '--file-allocation=none', + '--console-log-level=warn', + '-x16', '-s16', '-j16', + '-i', aria2c_infile] + subprocess.run(aria2c_opts, check=True) + + source_files = pathlib.Path(temp_folder).rglob(r'./*.mp4') + with open(file_name, mode='wb') as (destination): + for file in source_files: + with open(file, mode='rb') as (source): + shutil.copyfileobj(source, destination) + if os.path.exists(temp_folder): + shutil.rmtree(temp_folder) + os.remove(aria2c_infile) + print('\nDone!') + + def process_url_templace(self, template, representation_id, bandwidth, time, number): + if representation_id is not None: result = template.replace('$RepresentationID$', representation_id) + if number is not None: + nstart = result.find('$Number') + if nstart >= 0: + nend = result.find('$', nstart+1) + if nend >= 0: + var = result[nstart+1 : nend] + if 'Number%' in var: + value = var[6:] % (int(number)) + else: + value = number + result = result.replace('$'+var+'$', value) + if bandwidth is not None: result = result.replace('$Bandwidth$', bandwidth) + if time is not None: result = result.replace('$Time$', time) + result = result.replace('$$', '$').replace('../', '') + return result + + def generate_segments(self): + segment_template = self.get_segment_template() + return self.get_segments(segment_template) + + def get_segments(self, segment_template): + urls = [] + urls.append(self.config.base_url + segment_template['@initialization'].replace('$RepresentationID$', self.config.format_id)) + current_number = 1 + for seg in self.force_segmentimeline(segment_template): + if '@t' in seg: + current_time = seg['@t'] + for i in range(int(seg.get('@r', 0)) + 1): + urls.append(self.config.base_url + self.process_url_templace(segment_template['@media'], + representation_id=self.config.format_id, + bandwidth=None, time=str(current_time), number=str(current_number))) + current_number += 1 + current_time += seg['@d'] + return urls + + def force_segmentimeline(self, segment_timeline): + if isinstance(segment_timeline['SegmentTimeline']['S'], list): + x16 = segment_timeline['SegmentTimeline']['S'] + else: + x16 = [segment_timeline['SegmentTimeline']['S']] + return x16 + + def force_instance(self, x): + if isinstance(x['Representation'], list): + X = x['Representation'] + else: + X = [x['Representation']] + return X + + def get_segment_template(self): + x = [item for (i, item) in enumerate(self.xml['MPD']['Period']['AdaptationSet']) if self.config.track_id == item["@id"]][0] + segment_level = [item['SegmentTemplate'] for (i, item) in enumerate(self.force_instance(x)) if self.config.format_id == item["@id"]][0] + return segment_level + + def run(self): + urls = self.generate_segments() + + print('\n' + self.output_file) + global temp_folder + aria2c_infile = 'aria2c_infile.txt' + if os.path.isfile(aria2c_infile): + os.remove(aria2c_infile) + temp_folder = self.output_file.replace('.mp4', '') + if os.path.exists(temp_folder): + shutil.rmtree(temp_folder) + if not os.path.exists(temp_folder): + os.makedirs(temp_folder) + + if len(urls) > 1: + num_segments = int(math.log10(len(urls))) + 1 + with open(aria2c_infile, 'a', encoding='utf8') as (file): + for (i, url) in enumerate(urls): + file.write(f'{url}\n') + file.write(f'\tout={temp_folder}.{i:0{num_segments}d}.mp4\n') + file.write(f'\tdir={temp_folder}\n') + file.flush() + self.download_track(aria2c_infile, self.output_file) + print('Done!') diff --git a/pywidevine/clients/paramountplus/downloader_oringal.py b/pywidevine/clients/paramountplus/downloader_oringal.py new file mode 100644 index 0000000..906f1ce --- /dev/null +++ b/pywidevine/clients/paramountplus/downloader_oringal.py @@ -0,0 +1,110 @@ +import requests, pathlib +import math, subprocess +import os, sys, shutil + +class WvDownloader(object): + def __init__(self, config): + self.xml = config.xml + self.output_file = config.output_file + self.config = config + + def download_track(self, aria2c_infile, file_name): + aria2c_opts = [ + 'aria2c', + '--allow-overwrite=true', + '--download-result=hide', + '--console-log-level=warn', + '-x16', '-s16', '-j16', + '-i', aria2c_infile] + subprocess.run(aria2c_opts, check=True) + + source_files = pathlib.Path(temp_folder).rglob(r'./*.mp4') + with open(file_name, mode='wb') as (destination): + for file in source_files: + with open(file, mode='rb') as (source): + shutil.copyfileobj(source, destination) + if os.path.exists(temp_folder): + shutil.rmtree(temp_folder) + os.remove(aria2c_infile) + print('\nDone!') + + def process_url_templace(self, template, representation_id, bandwidth, time, number): + if representation_id is not None: result = template.replace('$RepresentationID$', representation_id) + if number is not None: + nstart = result.find('$Number') + if nstart >= 0: + nend = result.find('$', nstart+1) + if nend >= 0: + var = result[nstart+1 : nend] + if 'Number%' in var: + value = var[6:] % (int(number)) + else: + value = number + result = result.replace('$'+var+'$', value) + if bandwidth is not None: result = result.replace('$Bandwidth$', bandwidth) + if time is not None: result = result.replace('$Time$', time) + result = result.replace('$$', '$').replace('../', '') + return result + + def generate_segments(self): + segment_template = self.get_segment_template() + return self.get_segments(segment_template) + + def get_segments(self, segment_template): + urls = [] + urls.append(self.config.base_url + segment_template['@initialization'].replace('$RepresentationID$', self.config.format_id)) + current_number = 1 + for seg in self.force_segmentimeline(segment_template): + if '@t' in seg: + current_time = seg['@t'] + for i in range(int(seg.get('@r', 0)) + 1): + urls.append(self.config.base_url + self.process_url_templace(segment_template['@media'], + representation_id=self.config.format_id, + bandwidth=None, time=str(current_time), number=str(current_number))) + current_number += 1 + current_time += seg['@d'] + return urls + + def force_segmentimeline(self, segment_timeline): + if isinstance(segment_timeline['SegmentTimeline']['S'], list): + x16 = segment_timeline['SegmentTimeline']['S'] + else: + x16 = [segment_timeline['SegmentTimeline']['S']] + return x16 + + def force_instance(self, x): + if isinstance(x['Representation'], list): + X = x['Representation'] + else: + X = [x['Representation']] + return X + + def get_segment_template(self): + x = [item for (i, item) in enumerate(self.xml['MPD']['Period']['AdaptationSet']) if self.config.track_id in item["@id"]][0] + segment_level = [item['SegmentTemplate'] for (i, item) in enumerate(self.force_instance(x)) if self.config.format_id in item["@id"]][0] + return segment_level + + def run(self): + urls = self.generate_segments() + + print('\n' + self.output_file) + global temp_folder + aria2c_infile = 'aria2c_infile.txt' + if os.path.isfile(aria2c_infile): + os.remove(aria2c_infile) + temp_folder = self.output_file.replace('.mp4', '') + if os.path.exists(temp_folder): + shutil.rmtree(temp_folder) + if not os.path.exists(temp_folder): + os.makedirs(temp_folder) + + if len(urls) > 1: + num_segments = int(math.log10(len(urls))) + 1 + with open(aria2c_infile, 'a', encoding='utf8') as (file): + for (i, url) in enumerate(urls): + file.write(f'{url}\n') + file.write(f'\tout={temp_folder}.{i:0{num_segments}d}.mp4\n') + file.write(f'\tdir={temp_folder}\n') + file.flush() + self.download_track(aria2c_infile, self.output_file) + print('Done!') diff --git a/pywidevine/clients/paramountplus/paramountplus.rar b/pywidevine/clients/paramountplus/paramountplus.rar new file mode 100644 index 0000000000000000000000000000000000000000..16d4c3eea7844683e5493cf5158c12c4e62b0cfb GIT binary patch literal 5420 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 Lt|k%+GT{FKZZ}XK literal 0 HcmV?d00001 diff --git a/pywidevine/clients/proxy_config.py b/pywidevine/clients/proxy_config.py new file mode 100644 index 0000000..73f003d --- /dev/null +++ b/pywidevine/clients/proxy_config.py @@ -0,0 +1,15 @@ + +config = { + 'proxies': { + 'none': None + }, +} + +class ProxyConfig(object): + def __init__(self, proxies): + self.config = config + self.config['proxies'] = proxies + + def get_proxy(self, proxy): + return self.config['proxies'].get(proxy) + diff --git a/pywidevine/decrypt/wvdecrypt.py b/pywidevine/decrypt/wvdecrypt.py new file mode 100644 index 0000000..effe6e8 --- /dev/null +++ b/pywidevine/decrypt/wvdecrypt.py @@ -0,0 +1,55 @@ +import logging, subprocess, re, base64 +from pywidevine.cdm import cdm, deviceconfig + +class WvDecrypt(object): + WV_SYSTEM_ID = [ + 237, 239, 139, 169, 121, 214, 74, 206, 163, 200, 39, 220, 213, 29, 33, 237] + + def __init__(self, init_data_b64, cert_data_b64, device): + self.init_data_b64 = init_data_b64 + self.cert_data_b64 = cert_data_b64 + self.device = device + self.cdm = cdm.Cdm() + + def check_pssh(pssh_b64): + pssh = base64.b64decode(pssh_b64) + if not pssh[12:28] == bytes(self.WV_SYSTEM_ID): + new_pssh = bytearray([0, 0, 0]) + new_pssh.append(32 + len(pssh)) + new_pssh[4:] = bytearray(b'pssh') + new_pssh[8:] = [0, 0, 0, 0] + new_pssh[13:] = self.WV_SYSTEM_ID + new_pssh[29:] = [0, 0, 0, 0] + new_pssh[31] = len(pssh) + new_pssh[32:] = pssh + return base64.b64encode(new_pssh) + else: + return pssh_b64 + + self.session = self.cdm.open_session(check_pssh(self.init_data_b64), deviceconfig.DeviceConfig(self.device)) + if self.cert_data_b64: + self.cdm.set_service_certificate(self.session, self.cert_data_b64) + + def log_message(self, msg): + return '{}'.format(msg) + + def start_process(self): + keyswvdecrypt = [] + try: + for key in self.cdm.get_keys(self.session): + if key.type == 'CONTENT': + keyswvdecrypt.append(self.log_message('{}:{}'.format(key.kid.hex(), key.key.hex()))) + + except Exception: + return ( + False, keyswvdecrypt) + else: + return ( + True, keyswvdecrypt) + + def get_challenge(self): + return self.cdm.get_license_request(self.session) + + def update_license(self, license_b64): + self.cdm.provide_license(self.session, license_b64) + return True \ No newline at end of file diff --git a/pywidevine/decrypt/wvdecryptcustom.py b/pywidevine/decrypt/wvdecryptcustom.py new file mode 100644 index 0000000..9c19f0f --- /dev/null +++ b/pywidevine/decrypt/wvdecryptcustom.py @@ -0,0 +1,59 @@ +# uncompyle6 version 3.7.3 +# Python bytecode 3.6 (3379) +# Decompiled from: Python 3.7.8 (tags/v3.7.8:4b47a5b6ba, Jun 28 2020, 08:53:46) [MSC v.1916 64 bit (AMD64)] +# Embedded file name: pywidevine\decrypt\wvdecryptcustom.py +import logging, subprocess, re, base64 +from pywidevine.cdm import cdm, deviceconfig + +class WvDecrypt(object): + WV_SYSTEM_ID = [ + 237, 239, 139, 169, 121, 214, 74, 206, 163, 200, 39, 220, 213, 29, 33, 237] + + def __init__(self, init_data_b64, cert_data_b64, device): + self.init_data_b64 = init_data_b64 + self.cert_data_b64 = cert_data_b64 + self.device = device + self.cdm = cdm.Cdm() + + def check_pssh(pssh_b64): + pssh = base64.b64decode(pssh_b64) + if not pssh[12:28] == bytes(self.WV_SYSTEM_ID): + new_pssh = bytearray([0, 0, 0]) + new_pssh.append(32 + len(pssh)) + new_pssh[4:] = bytearray(b'pssh') + new_pssh[8:] = [0, 0, 0, 0] + new_pssh[13:] = self.WV_SYSTEM_ID + new_pssh[29:] = [0, 0, 0, 0] + new_pssh[31] = len(pssh) + new_pssh[32:] = pssh + return base64.b64encode(new_pssh) + else: + return pssh_b64 + + self.session = self.cdm.open_session(check_pssh(self.init_data_b64), deviceconfig.DeviceConfig(self.device)) + if self.cert_data_b64: + self.cdm.set_service_certificate(self.session, self.cert_data_b64) + + def log_message(self, msg): + return '{}'.format(msg) + + def start_process(self): + keyswvdecrypt = [] + try: + for key in self.cdm.get_keys(self.session): + if key.type == 'CONTENT': + keyswvdecrypt.append(self.log_message('{}:{}'.format(key.kid.hex(), key.key.hex()))) + + except Exception: + return ( + False, keyswvdecrypt) + else: + return ( + True, keyswvdecrypt) + + def get_challenge(self): + return self.cdm.get_license_request(self.session) + + def update_license(self, license_b64): + self.cdm.provide_license(self.session, license_b64) + return True \ No newline at end of file diff --git a/pywidevine/downloader/__init__.py b/pywidevine/downloader/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pywidevine/downloader/tracks.py b/pywidevine/downloader/tracks.py new file mode 100644 index 0000000..f39657a --- /dev/null +++ b/pywidevine/downloader/tracks.py @@ -0,0 +1,72 @@ +import pywidevine.downloader.wvdownloaderconfig as wvdl_cfg + +class VideoTrack(object): + def __init__(self, encrypted, size, id, url, codec, bitrate, width, height): + self.encrypted = encrypted + self.size = size + self.id = id + self.url = url + self.codec = codec + self.bitrate = bitrate + self.width = width + self.height = height + + def get_type(self): + return "video" + + def __repr__(self): + return "(encrypted={}, size={}, id={}, url={}, codec={}, bitrate={}, width={}, height={})"\ + .format(self.encrypted, self.size, self.id, self.url, self.codec, self.bitrate, self.width, self.height) + + def get_filename(self, filename, decrypted=False, fixed=False): + if not self.encrypted or decrypted: + fn = wvdl_cfg.DECRYPTED_FILENAME + else: + fn = wvdl_cfg.ENCRYPTED_FILENAME + if fixed: + fn = fn + '_fixed.mkv' + return fn.format(filename=filename, track_type="video", track_no=self.id) + + + +class AudioTrack(object): + def __init__(self, encrypted, size, id, url, codec, bitrate, language): + self.encrypted = encrypted + self.size = size + self.id = id + self.url = url + self.codec = codec + self.bitrate = bitrate + self.language = language + + def get_type(self): + return "audio" + + def __repr__(self): + return "(encrypted={}, size={}, id={}, url={}, codec={}, bitrate={})"\ + .format(self.encrypted, self.size, self.id, self.url, self.codec, self.bitrate) + + def get_filename(self, filename, decrypted=False, fixed=False): + if not self.encrypted or decrypted: + fn = wvdl_cfg.DECRYPTED_FILENAME + else: + fn = wvdl_cfg.ENCRYPTED_FILENAME + if fixed: + fn = fn + '_fixed.mka' + return fn.format(filename=filename, track_type="audio", track_no=self.id) + + +class SubtitleTrack(object): + def __init__(self, id, name, language_code, default, url, type): + self.id = id + self.name = name + self.language_code = language_code + self.url = url + self.type = type + self.default = default + + def __repr__(self): + return "(id={}, name={}, language_code={}, url={}, type={})".format(self.id, self.name, self.language_code, self.url, self.type) + + def get_filename(self, filename, subtitle_format): + return wvdl_cfg.SUBTITLES_FILENAME.format(filename=filename, language_code=self.language_code, id=self.id, subtitle_type=subtitle_format) diff --git a/pywidevine/downloader/wvdownloader.py b/pywidevine/downloader/wvdownloader.py new file mode 100644 index 0000000..1deffc8 --- /dev/null +++ b/pywidevine/downloader/wvdownloader.py @@ -0,0 +1,199 @@ + +import threading +import os +import requests +import math +import shutil +import pathlib, sys, subprocess + +from requests.sessions import session +from tqdm import tqdm +from queue import Queue + +dlthreads = 24 + +class WvDownloader(object): + def __init__(self, config): + self.xml = config.xml + self.output_file = config.output_file + self.tqdm_mode = config.tqdm_mode + self.cookies = config.cookies + self.config = config + + def download_track(self, aria_input, file_name): + aria_command = ['aria2c', '-i', aria_input, + '--enable-color=false', + '--allow-overwrite=true', + '--summary-interval=0', + '--download-result=hide', + '--async-dns=false', + '--check-certificate=false', + '--auto-file-renaming=false', + '--file-allocation=none', + '--console-log-level=warn', + '-x16', '-j16', '-s16'] + if sys.version_info >= (3, 5): + aria_out = subprocess.run(aria_command) + aria_out.check_returncode() + + source_files = pathlib.Path(temp_folder).rglob(r'./*.mp4') + with open(file_name, mode='wb') as (destination): + for file in source_files: + with open(file, mode='rb') as (source): + shutil.copyfileobj(source, destination) + if os.path.exists(temp_folder): + shutil.rmtree(temp_folder) + os.remove(aria_input) + print('\nDone!') + + def process_url_templace(self, template, representation_id, bandwidth, time, number): + if representation_id is not None: result = template.replace('$RepresentationID$', representation_id) + if number is not None: + nstart = result.find('$Number') + if nstart >= 0: + nend = result.find('$', nstart+1) + if nend >= 0: + var = result[nstart+1 : nend] + if 'Number%' in var: + value = var[6:] % (int(number)) + else: + value = number + result = result.replace('$'+var+'$', value) + if bandwidth is not None: result = result.replace('$Bandwidth$', bandwidth) + if time is not None: result = result.replace('$Time$', time) + result = result.replace('$$', '$').replace('../', '') + return result + + def generate_segments(self): + segs = self.get_representation_number() + return self.get_segments(segs) + + def get_segments(self, segment_level): + media = segment_level['@media'] + current_number = 1 + current_time = 0 + for seg in self.force_segment_level(segment_level): + if '@t' in seg: + current_time = seg['@t'] + for _ in range(int(seg.get('@r', 0)) + 1): + url = self.process_url_templace(media, representation_id=self.config.format_id, bandwidth=self.config.bandwidth, time=str(current_time), number=str(current_number)) + current_number += 1 + current_time += int(seg['@d']) + yield url + + def force_segment_level(self, segment_level): + if isinstance(segment_level['SegmentTimeline']['S'], list): + segment_level = segment_level['SegmentTimeline']['S'] + else: + segment_level = [segment_level['SegmentTimeline']['S']] + return segment_level + + def get_representation_number(self): + x = [] + for [idx, item] in enumerate(self.xml['MPD']['Period']['AdaptationSet']): + try: + if self.config.file_type in item.get('@mimeType'): + x = idx + except TypeError: + if self.config.file_type in item.get('@contentType'): + x = idx + + y = [] + if 'video' in self.config.file_type: + for [number, rep] in enumerate(self.xml['MPD']['Period']['AdaptationSet'][x]['Representation']): + if self.config.format_id == rep.get('@id'): + y = number + + mpd = self.xml['MPD']['Period'] + try: + segment_level = mpd['AdaptationSet'][x]['SegmentTemplate'] + except TypeError: + segment_level = mpd['AdaptationSet'][x]['SegmentTemplate'] + + return segment_level + + def run(self): + segment_list = self.generate_segments() + urls = [] + for seg_url in segment_list: + url = self.config.base_url + '/' + seg_url + urls.append(url) + + print('\n' + self.output_file) + # download por aria2c + if not self.tqdm_mode: + global temp_folder + aria2c_infile = 'aria2c_infile.txt' + if os.path.isfile(aria2c_infile): + os.remove(aria2c_infile) + temp_folder = self.output_file.replace('.mp4', '') + if os.path.exists(temp_folder): + shutil.rmtree(temp_folder) + if not os.path.exists(temp_folder): + os.makedirs(temp_folder) + + if len(urls) > 1: + num_segments = int(math.log10(len(urls))) + 1 + with open(aria2c_infile, 'a', encoding='utf8') as (file): + for (i, url) in enumerate(urls): + file.write(f'{url}\n') + file.write(f'\tout={temp_folder}.{i:0{num_segments}d}.mp4\n') + file.write(f'\tdir={temp_folder}\n') + file.flush() + self.download_track(aria2c_infile, self.output_file) + else: + # download por thread + work_q = Queue() + result_q = Queue() + + pool = [WorkerThread(work_q=work_q, result_q=result_q, cookies=self.cookies) for i in range(dlthreads)] + for thread in pool: + thread.start() + + work_count = 0 + for seg_url in urls: + url = seg_url + work_q.put((work_count, url, self.cookies)) + work_count += 1 + results = [] + + for _ in tqdm(range(work_count)): + results.append(result_q.get()) + outfile = open(self.output_file , 'wb+') + sortedr = sorted(results, key=lambda v: v[0]) + for r in sortedr: + outfile.write(r[1]) + outfile.close() + del results + print('Done!') + +class Downloader: + def __init__(self): + self.session = requests.Session() + + def DownloadSegment(self, url, cookies): + resp = self.session.get(url, cookies=cookies, stream=True) + resp.raw.decode_content = True + data = resp.raw.read() + return data + +class WorkerThread(threading.Thread): + def __init__(self, work_q, result_q, cookies): + super(WorkerThread, self).__init__() + self.work_q = work_q + self.result_q = result_q + self.cookies = cookies + self.stoprequest = threading.Event() + self.downloader = Downloader() + + def run(self): + while not self.stoprequest.isSet(): + try: + (seq, url, cookies) = self.work_q.get(True, 0.05) + self.result_q.put((seq, self.downloader.DownloadSegment(url, cookies))) + except: + continue + + def join(self, timeout=None): + self.stoprequest.set() + super(WorkerThread, self).join(timeout) diff --git a/pywidevine/downloader/wvdownloaderconfig.py b/pywidevine/downloader/wvdownloaderconfig.py new file mode 100644 index 0000000..6e7a481 --- /dev/null +++ b/pywidevine/downloader/wvdownloaderconfig.py @@ -0,0 +1,14 @@ +import re +import os +import platform + +class WvDownloaderConfig(object): + def __init__(self, xml, base_url, output_file, format_id, bandwidth, cookies, file_type, tqdm_mode): + self.xml = xml + self.output_file = output_file + self.base_url = base_url + self.format_id = format_id + self.bandwidth = bandwidth + self.cookies = cookies + self.file_type = file_type + self.tqdm_mode = tqdm_mode diff --git a/pywidevine/muxer/muxer.py b/pywidevine/muxer/muxer.py new file mode 100644 index 0000000..fe2aa74 --- /dev/null +++ b/pywidevine/muxer/muxer.py @@ -0,0 +1,271 @@ +# -*- coding: utf-8 -*- +import os +import subprocess + +class Muxer(object): + def __init__(self, CurrentName, SeasonFolder, CurrentHeigh, Type, mkvmergeexe): + self.CurrentName = CurrentName + self.SeasonFolder = SeasonFolder + self.CurrentHeigh = CurrentHeigh + self.Type = Type + self.mkvmergeexe = mkvmergeexe + + def mkvmerge_muxer(self, lang): + VideoInputNoExist = False + if os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].h264'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].h264' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].mkv' + + if os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p].h264'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p].h264' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].mp4'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].mp4' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].h265'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].h265' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HEVC].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].mp4'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].mp4' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].vp9'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].vp9' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [VP9].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].mp4'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].mp4' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].h265'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].h265' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [HDR].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].mp4'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].mp4' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].h264'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].h264' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [AVC HIGH].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].mp4'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].mp4' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p] [CBR].mkv' + + elif os.path.isfile(self.CurrentName + ' [' + self.CurrentHeigh + 'p].mp4'): + VideoInputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p].mp4' + if self.Type == "show": + VideoOutputName = os.path.join(self.SeasonFolder, self.CurrentName + ' [' + self.CurrentHeigh + 'p].mkv') + else: + VideoOutputName = self.CurrentName + ' [' + self.CurrentHeigh + 'p].mkv' + else: + VideoInputNoExist = True + + if VideoInputNoExist == False: + AudioExtensionsList=[ + ".ac3", + ".mka", + ".eac3", + ".m4a", + ".dts", + ".mp3", + ".aac" + ] + + SubsExtensionsList= [ + ".srt", + ".ass", + ] + + if lang == "English": + language_tag = "English" + + if language_tag == "English": + subs_forced = 'Forced' + subs_sdh = 'SDH' + #["en", "en", "eng", "English", "yes", "yes"] + #[audio_language, subs_language, language_id, language_name, audio_default, subs_default] + LanguageList = [ + ["es-la", "es-la", "spa", "Spanish", "yes", "no"], + ["en", "en", "eng", "English", "no", "no"], + ["pt-br", "pt-br", "por", "Brazilian Portuguese", "no", "no"], + ["es", "es", "spa", "Castilian", "no", "no"], + ["cat", "cat", "cat", "Catalan", "no", "no"], + ["eu", "eu", "baq", "Basque", "no", "no"], + ["fr", "fr", "fre", "French", "no", "no"], + ["fr-bg", "fr-bg", "fre", "French (Belgium)", "no", "no"], + ["fr-lu", "fr-lu", "fre", "French (Luxembourg)", "no", "no"], + ["fr-ca", "fr-ca", "fre", "French (Canada)", "no", "no"], + ["de", "de", "ger", "German", "no", "no"], + ["it", "it", "ita", "Italian", "no", "no"], + ["pl", "pl", "pol", "Polish", "no", "no"], + ["tr", "tr", "tur", "Turkish", "no", "no"], + ["hy", "hy", "arm", "Armenian", "no", "no"], + ["sv", "sv", "swe", "Swedish", "no", "no"], + ["da", "da", "dan", "Danish", "no", "no"], + ["fi", "fi", "fin", "Finnish", "no", "no"], + ["nl", "nl", "dut", "Dutch", "no", "no"], + ["nl-be", "nl-be", "dut", "Flemish", "no", "no"], + ["no", "no", "nor", "Norwegian", "no", "no"], + ["lv", "lv", "lav", "Latvian", "no", "no"], + ["is", "is", "ice", "Icelandic", "no", "no"], + ["ru", "ru", "rus", "Russian", "no", "no"], + ["uk", "uk", "ukr", "Ukrainian", "no", "no"], + ["hu", "hu", "hun", "Hungarian", "no", "no"], + ["bg", "bg", "bul", "Bulgarian", "no", "no"], + ["hr", "hr", "hrv", "Croatian", "no", "no"], + ["lt", "lt", "lit", "Lithuanian", "no", "no"], + ["et", "et", "est", "Estonian", "no", "no"], + ["el", "el", "gre", "Greek", "no", "no"], + ["he", "he", "heb", "Hebrew", "no", "no"], + ["ar", "ar", "ara", "Arabic", "no", "no"], + ["fa", "fa", "per", "Persian", "no", "no"], + ["ro", "ro", "rum", "Romanian", "no", "no"], + ["sr", "sr", "srp", "Serbian", "no", "no"], + ["cs", "cs", "cze", "Czech", "no", "no"], + ["sk", "sk", "slo", "Slovak", "no", "no"], + ["sl", "sl", "slv", "Slovenian", "no", "no"], + ["sq", "sq", "alb", "Albanian", "no", "no"], + ["bs", "bs", "bos", "Bosnian", "no", "no"], + ["mk", "mk", "mac", "Macedonian", "no", "no"], + ["hi", "hi", "hin", "Hindi", "no", "no"], + ["bn", "bn", "ben", "Bengali", "no", "no"], + ["ur", "ur", "urd", "Urdu", "no", "no"], + ["pa", "pa", "pan", "Punjabi", "no", "no"], + ["ta", "ta", "tam", "Tamil", "no", "no"], + ["te", "te", "tel", "Telugu", "no", "no"], + ["mr", "mr", "mar", "Marathi", "no", "no"], + ["kn", "kn", "kan", "Kannada (India)", "no", "no"], + ["gu", "gu", "guj", "Gujarati", "no", "no"], + ["ml", "ml", "mal", "Malayalam", "no", "no"], + ["si", "si", "sin", "Sinhala", "no", "no"], + ["as", "as", "asm", "Assamese", "no", "no"], + ["mni", "mni", "mni", "Manipuri", "no", "no"], + ["tl", "tl", "tgl", "Tagalog", "no", "no"], + ["id", "id", "ind", "Indonesian", "no", "no"], + ["ms", "ms", "may", "Malay", "no", "no"], + ["fil", "fil", "fil", "Filipino", "no", "no"], + ["vi", "vi", "vie", "Vietnamese", "no", "no"], + ["th", "th", "tha", "Thai", "no", "no"], + ["km", "km", "khm", "Khmer", "no", "no"], + ["ko", "ko", "kor", "Korean", "no", "no"], + ["zh", "zh", "chi", "Mandarin", "no", "no"], + ["yue", "yue", "chi", "Cantonese", "no", "no"], + ["zh-hans", "zh-hans", "chi", "Chinese (Simplified)", "no", "no"], + ["zh-hant", "zh-hant", "chi", "Chinese (Traditional)", "no", "no"], + ["zh-hk", "zh-hk", "chi", "Chinese (Simplified)", "no", "no"], + ["zh-tw", "zh-tw", "chi", "Chinese (Traditional)", "no", "no"], + ["zh-sg", "zh-sg", "chi", "Chinese (Singapore)", "no", "no"], + ["ja", "ja", "jpn", "Japanese", "no", "no"], + ["tlh", "tlh", "tlh", "Klingon", "no", "no"], + ["zxx", "zxx", "zxx", "No Dialogue", "no", "no"] + ] + + ALLAUDIOS = [] + default_active_audio = False + for audio_language, subs_language, language_id, language_name, audio_default, subs_default in LanguageList: + for AudioExtension in AudioExtensionsList: + if os.path.isfile(self.CurrentName + ' (' + audio_language + ')' + AudioExtension): + if default_active_audio == True: audio_default = "no" + ALLAUDIOS = ALLAUDIOS + ['--language', '0:' + language_id, '--track-name', '0:' + language_name, '--default-track', '0:' + audio_default, '(', self.CurrentName + ' (' + audio_language + ')' + AudioExtension, ')'] + if audio_default == "yes": default_active_audio = True + + for audio_language, subs_language, language_id, language_name, audio_default, subs_default in LanguageList: + for AudioExtension in AudioExtensionsList: + if os.path.isfile(self.CurrentName + ' (' + audio_language + '-ad)' + AudioExtension): + if default_active_audio == True: audio_default = "no" + ALLAUDIOS = ALLAUDIOS + ['--language', '0:' + language_id, '--track-name', '0:' + language_name + ' (Audio Description)', '--default-track', '0:no', '(', self.CurrentName + ' (' + audio_language + '-ad)' + AudioExtension, ')'] + if audio_default == "yes": default_active_audio = True + + OnlyOneLanguage = False + if len(ALLAUDIOS) == 9: + OnlyOneLanguage = True + + elif len(ALLAUDIOS) == 18: + if ALLAUDIOS[1] == ALLAUDIOS[10]: + if '-ad' in ALLAUDIOS[7] or '-ad' in ALLAUDIOS[16]: + OnlyOneLanguage = True + else: + OnlyOneLanguage = False + + + ALLSUBS = [] + default_active_subs = False + for audio_language, subs_language, language_id, language_name, audio_default, subs_default in LanguageList: + for SubsExtension in SubsExtensionsList: + if os.path.isfile(self.CurrentName + ' (' + subs_language + '-forced)' + SubsExtension): + if subs_default == "yes": default_active_subs = True + ALLSUBS = ALLSUBS + ['--language', '0:' + language_id, '--track-name', '0:' + subs_forced, '--forced-track', '0:yes', '--default-track', '0:' + subs_default, '--compression', '0:none', '(', self.CurrentName + ' (' + subs_language + '-forced)' + SubsExtension, ')'] + + if OnlyOneLanguage == True: + if default_active_subs == True: subs_default = "no" + if os.path.isfile(self.CurrentName + ' (' + subs_language + ')' + SubsExtension): + ALLSUBS = ALLSUBS + ['--language', '0:' + language_id, '--forced-track', '0:no', '--default-track', '0:' + subs_default, '--compression', '0:none', '(', self.CurrentName + ' (' + subs_language + ')' + SubsExtension, ')'] + + else: + if os.path.isfile(self.CurrentName + ' (' + subs_language + ')' + SubsExtension): + ALLSUBS = ALLSUBS + ['--language', '0:' + language_id, '--forced-track', '0:no', '--default-track', '0:no', '--compression', '0:none', '(', self.CurrentName + ' (' + subs_language + ')' + SubsExtension, ')'] + + if os.path.isfile(self.CurrentName + ' (' + subs_language + '-sdh)' + SubsExtension): + ALLSUBS = ALLSUBS + ['--language', '0:' + language_id, '--track-name', '0:' + subs_sdh, '--forced-track', '0:no', '--default-track', '0:no', '--compression', '0:none', '(', self.CurrentName + ' (' + subs_language + '-sdh)' + SubsExtension, ')'] + + #(Chapters) + if os.path.isfile(self.CurrentName+' Chapters.txt'): + CHAPTERS=['--chapter-charset', 'UTF-8', '--chapters', self.CurrentName + ' Chapters.txt'] + else: + CHAPTERS=[] + + + mkvmerge_command_video = [self.mkvmergeexe, + '-q', + '--output', + VideoOutputName, + '--language', + '0:und', + '--default-track', + '0:yes', + '(', + VideoInputName, + ')'] + + + + mkvmerge_command = mkvmerge_command_video + ALLAUDIOS + ALLSUBS + CHAPTERS + mkvmerge_process = subprocess.run(mkvmerge_command) diff --git a/requeriments.txt b/requeriments.txt new file mode 100644 index 0000000..971086f --- /dev/null +++ b/requeriments.txt @@ -0,0 +1,28 @@ +astroid>=1.5.3 +beautifulsoup4>=4.4.1 +certifi>=2017.4.17 +chardet>=3.0.3 +colorama>=0.3.9 +cssutils>=1.0.2 +dnspython>=1.15.0 +future>=0.16.0 +idna>=2.5 +isort>=4.2.14 +lazy-object-proxy>=1.3.1 +lxml>=4.2.4 +mccabe>=0.6.1 +pathvalidate>=0.22.0 +protobuf>=3.0.0b2 +pycountry>=18.5.26 +pycryptodomex>=3.4.6 +pymsl>=1.2 +pylint>=1.7.1 +pysubs2>=0.2.1 +requests>=2.17.3 +six>=1.10.0 +tqdm>=4.14.0 +unidecode>=1.0.23 +urllib3>=1.21.1 +win10toast>=0.9; sys_platform == 'win32' +wrapt>=1.10.10 +xmltodict>=0.11.0