diff --git a/README.md b/README.md index 0f92d20..2f0954d 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,44 @@ For more options, use the `--help` flag. --- +# Decrypting Subtitles + +If you want to decrypt the downloaded subtitles, you need to pass the `--decrypt-subtitle` or `-ds` flag along with a decryption key and initialization vector. Check [#14](https://github.com/debakarr/kisskh-dl/issues/14). + +Here is an example of how to pass these parameters from the command line: + +```bash +kisskh download "" --decrypt-subtitle --key "your_key_here" --initialization-vector "your_iv_here" +``` + +You can also set these parameters as environment variables. If you set the `KISSKH_KEY` and `KISSKH_INITIALIZATION_VECTOR` environment variables, they will be used by default. + +Here is an example of how to set these environment variables: + +- On Linux/Mac: + +```bash +export KISSKH_KEY="your_key_here" +export KISSKH_INITIALIZATION_VECTOR="your_iv_here" +``` + +- On Windows: + +```cmd +set KISSKH_KEY="your_key_here" +set KISSKH_INITIALIZATION_VECTOR="your_iv_here" +``` + +After setting these environment variables, you can use the `--decrypt-subtitle` flag without passing the key and initialization vector explicitly: + +```bash +kisskh download "Drama Name" --decrypt-subtitle +``` + +Please make sure to replace `"your_key_here"` and `"your_iv_here"` with your actual decryption key and initialization vector. + +--- + # 🐞 DEBUG To enable debugging, use the `-vv` flag while running `kisskh dl`. diff --git a/poetry.lock b/poetry.lock index b750aba..3e5ec37 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "anyio" version = "3.6.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "dev" optional = false python-versions = ">=3.6.2" files = [ @@ -25,7 +24,6 @@ trio = ["trio (>=0.16,<0.22)"] name = "argcomplete" version = "2.0.0" description = "Bash tab completion for argparse" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -40,7 +38,6 @@ test = ["coverage", "flake8", "pexpect", "wheel"] name = "attrs" version = "22.2.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -59,7 +56,6 @@ tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy name = "bandit" version = "1.7.4" description = "Security oriented static analyser for python code." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -82,7 +78,6 @@ yaml = ["PyYAML"] name = "black" version = "23.1.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -132,7 +127,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "brotli" version = "1.0.9" description = "Python bindings for the Brotli compression library" -category = "main" optional = false python-versions = "*" files = [ @@ -224,7 +218,6 @@ files = [ name = "brotlicffi" version = "1.0.9.2" description = "Python CFFI bindings to the Brotli library" -category = "main" optional = false python-versions = "*" files = [ @@ -267,7 +260,6 @@ cffi = ">=1.0.0" name = "certifi" version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -279,7 +271,6 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = "*" files = [ @@ -356,7 +347,6 @@ pycparser = "*" name = "chardet" version = "5.1.0" description = "Universal encoding detector for Python 3" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -368,7 +358,6 @@ files = [ name = "charset-normalizer" version = "3.0.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = "*" files = [ @@ -466,7 +455,6 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -481,7 +469,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -493,7 +480,6 @@ files = [ name = "coverage" version = "7.2.1" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -560,7 +546,6 @@ toml = ["tomli"] name = "datamodel-code-generator" version = "0.17.1" description = "Datamodel Code Generator" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -598,7 +583,6 @@ http = ["httpx"] name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -610,7 +594,6 @@ files = [ name = "dnspython" version = "2.3.0" description = "DNS toolkit" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -631,7 +614,6 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] name = "email-validator" version = "1.3.1" description = "A robust email address syntax and deliverability validation library." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -647,7 +629,6 @@ idna = ">=2.0.0" name = "exceptiongroup" version = "1.1.0" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -662,7 +643,6 @@ test = ["pytest (>=6)"] name = "flake8" version = "6.0.0" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = ">=3.8.1" files = [ @@ -679,7 +659,6 @@ pyflakes = ">=3.0.0,<3.1.0" name = "flake8-bandit" version = "4.1.1" description = "Automated security testing with bandit and flake8." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -695,7 +674,6 @@ flake8 = ">=5.0.0" name = "flake8-black" version = "0.3.6" description = "flake8 plugin to call black as a code style validator" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -715,7 +693,6 @@ develop = ["build", "twine"] name = "flake8-bugbear" version = "23.2.13" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -734,7 +711,6 @@ dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", name = "flake8-comprehensions" version = "3.10.1" description = "A flake8 plugin to help you write better list/set/dict comprehensions." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -749,7 +725,6 @@ flake8 = ">=3.0,<3.2.0 || >3.2.0" name = "flake8-isort" version = "6.0.0" description = "flake8 plugin that integrates isort ." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -768,7 +743,6 @@ test = ["pytest"] name = "genson" version = "1.2.2" description = "GenSON is a powerful, user-friendly JSON Schema generator." -category = "dev" optional = false python-versions = "*" files = [ @@ -779,7 +753,6 @@ files = [ name = "gitdb" version = "4.0.10" description = "Git Object Database" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -794,7 +767,6 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.31" description = "GitPython is a Python library used to interact with Git repositories" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -809,7 +781,6 @@ gitdb = ">=4.0.1,<5" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -821,7 +792,6 @@ files = [ name = "httpcore" version = "0.16.3" description = "A minimal low-level HTTP client." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -833,17 +803,16 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = ">=1.0.0,<2.0.0" +sniffio = "==1.*" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "httpx" version = "0.23.3" description = "The next generation HTTP client." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -859,15 +828,14 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -879,7 +847,6 @@ files = [ name = "importlib-resources" version = "5.12.0" description = "Read resources from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -898,7 +865,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "inflect" version = "5.6.2" description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles; convert numbers to words" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -914,7 +880,6 @@ testing = ["pygments", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdo name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -926,7 +891,6 @@ files = [ name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -944,7 +908,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -962,7 +925,6 @@ i18n = ["Babel (>=2.7)"] name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -984,7 +946,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "jsonschema-spec" version = "0.1.3" description = "JSONSchema Spec with object-oriented paths" -category = "dev" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ @@ -1002,7 +963,6 @@ typing-extensions = ">=4.3.0,<5.0.0" name = "lazy-object-proxy" version = "1.9.0" description = "A fast and thorough lazy object proxy." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1048,7 +1008,6 @@ files = [ name = "markupsafe" version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1108,7 +1067,6 @@ files = [ name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1120,7 +1078,6 @@ files = [ name = "mutagen" version = "1.46.0" description = "read and write audio tags for many formats" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1132,7 +1089,6 @@ files = [ name = "mypy" version = "1.0.1" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1179,7 +1135,6 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1191,7 +1146,6 @@ files = [ name = "openapi-schema-validator" version = "0.3.4" description = "OpenAPI schema validation for Python" -category = "dev" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ @@ -1212,7 +1166,6 @@ strict-rfc3339 = ["strict-rfc3339"] name = "openapi-spec-validator" version = "0.5.1" description = "OpenAPI 2.0 (aka Swagger) and OpenAPI 3 spec validator" -category = "dev" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ @@ -1235,7 +1188,6 @@ requests = ["requests"] name = "packaging" version = "23.0" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1247,7 +1199,6 @@ files = [ name = "pathable" version = "0.4.3" description = "Object-oriented paths" -category = "dev" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ @@ -1259,7 +1210,6 @@ files = [ name = "pathspec" version = "0.11.0" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1271,7 +1221,6 @@ files = [ name = "pbr" version = "5.11.1" description = "Python Build Reasonableness" -category = "dev" optional = false python-versions = ">=2.6" files = [ @@ -1283,7 +1232,6 @@ files = [ name = "pep8-naming" version = "0.13.3" description = "Check PEP-8 naming conventions, plugin for flake8" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1298,7 +1246,6 @@ flake8 = ">=5.0.0" name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1310,7 +1257,6 @@ files = [ name = "platformdirs" version = "3.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1326,7 +1272,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytes name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1342,7 +1287,6 @@ testing = ["pytest", "pytest-benchmark"] name = "prance" version = "0.22.2.22.0" description = "Resolving Swagger/OpenAPI 2.0 and 3.0.0 Parser" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1369,7 +1313,6 @@ ssv = ["swagger-spec-validator (>=2.4,<3.0)"] name = "pycodestyle" version = "2.10.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1381,7 +1324,6 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1389,11 +1331,51 @@ files = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] +[[package]] +name = "pycryptodome" +version = "3.19.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"}, + {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"}, +] + [[package]] name = "pycryptodomex" version = "3.17" description = "Cryptographic library for Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1436,7 +1418,6 @@ files = [ name = "pydantic" version = "1.10.5" description = "Data validation and settings management using python type hints" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1490,7 +1471,6 @@ email = ["email-validator (>=1.0.3)"] name = "pyflakes" version = "3.0.1" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1502,7 +1482,6 @@ files = [ name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1539,7 +1518,6 @@ files = [ name = "pysnooper" version = "1.1.1" description = "A poor man's debugger for Python." -category = "dev" optional = false python-versions = "*" files = [ @@ -1550,11 +1528,23 @@ files = [ [package.extras] tests = ["pytest"] +[[package]] +name = "pysrt" +version = "1.1.2" +description = "SubRip (.srt) subtitle parser and writer" +optional = false +python-versions = "*" +files = [ + {file = "pysrt-1.1.2.tar.gz", hash = "sha256:b4f844ba33e4e7743e9db746492f3a193dc0bc112b153914698e7c1cdeb9b0b9"}, +] + +[package.dependencies] +chardet = "*" + [[package]] name = "pytest" version = "7.2.1" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1578,7 +1568,6 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. name = "pytest-cov" version = "4.0.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1593,11 +1582,24 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +[[package]] +name = "python-dotenv" +version = "1.0.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1647,7 +1649,6 @@ files = [ name = "requests" version = "2.28.2" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=3.7, <4" files = [ @@ -1669,7 +1670,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "rfc3986" version = "1.5.0" description = "Validating URI References per RFC 3986" -category = "dev" optional = false python-versions = "*" files = [ @@ -1687,7 +1687,6 @@ idna2008 = ["idna"] name = "ruamel-yaml" version = "0.17.21" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" -category = "dev" optional = false python-versions = ">=3" files = [ @@ -1706,7 +1705,6 @@ jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] name = "ruamel-yaml-clib" version = "0.2.7" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1717,8 +1715,11 @@ files = [ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"}, {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"}, - {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"}, @@ -1750,7 +1751,6 @@ files = [ name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1762,7 +1762,6 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1774,7 +1773,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1786,7 +1784,6 @@ files = [ name = "stevedore" version = "5.0.0" description = "Manage dynamic plugins for Python applications" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1801,7 +1798,6 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1813,7 +1809,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1825,7 +1820,6 @@ files = [ name = "typed-ast" version = "1.5.4" description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1859,7 +1853,6 @@ files = [ name = "types-requests" version = "2.28.11.15" description = "Typing stubs for requests" -category = "dev" optional = false python-versions = "*" files = [ @@ -1874,7 +1867,6 @@ types-urllib3 = "<1.27" name = "types-urllib3" version = "1.26.25.8" description = "Typing stubs for urllib3" -category = "dev" optional = false python-versions = "*" files = [ @@ -1886,7 +1878,6 @@ files = [ name = "typing-extensions" version = "4.5.0" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1898,7 +1889,6 @@ files = [ name = "urllib3" version = "1.26.14" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -1915,7 +1905,6 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "validators" version = "0.20.0" description = "Python Data Validation for Humans™." -category = "main" optional = false python-versions = ">=3.4" files = [ @@ -1932,7 +1921,6 @@ test = ["flake8 (>=2.4.0)", "isort (>=4.2.2)", "pytest (>=2.2.3)"] name = "websockets" version = "10.4" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2011,7 +1999,6 @@ files = [ name = "yt-dlp" version = "2023.2.17" description = "A youtube-dl fork with additional features and patches" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2031,7 +2018,6 @@ websockets = "*" name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2046,4 +2032,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "155d9bac7ecf2c869ef3de7db08ec7943c9a135ffcd6544277251bf8e1d06070" +content-hash = "b9f8aab3649a37605dfc5aabe798a6afd671ba6fdc4c5e837655d5bd21f1726d" diff --git a/pyproject.toml b/pyproject.toml index 397d5cd..f575e30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,9 @@ requests = "^2.28.2" pydantic = "^1.10.5" validators = "^0.20.0" yt-dlp = "^2023.2.17" +pycryptodome = "^3.19.0" +pysrt = "^1.1.2" +python-dotenv = "^1.0.0" [tool.poetry.dev-dependencies] datamodel-code-generator = { extras = ["http"], version = "^0.17.1" } diff --git a/src/kisskh_downloader/cli.py b/src/kisskh_downloader/cli.py index bf5730a..333677d 100644 --- a/src/kisskh_downloader/cli.py +++ b/src/kisskh_downloader/cli.py @@ -1,4 +1,5 @@ import logging +import os import re import sys from pathlib import Path @@ -7,11 +8,15 @@ import click import validators +from dotenv import load_dotenv from kisskh_downloader.downloader import Downloader from kisskh_downloader.enums.quality import Quality +from kisskh_downloader.helper.decrypt_subtitle import SubtitleDecrypter from kisskh_downloader.kisskh_api import KissKHApi +load_dotenv() + @click.group() @click.option("-v", "--verbose", count=True, help="Increase log level verbosity") @@ -47,6 +52,24 @@ def kisskh(verbose): default=Path.home() / "Downloads", help="Output directory where downloaded files will be store.", ) +@click.option( + "--decrypt-subtitle", + "-ds", + is_flag=True, + help="Decrypt the downloaded subtitle", +) +@click.option( + "--key", + "-k", + default=os.getenv("KISSKH_KEY"), + help="Decryption key", +) +@click.option( + "--initialization-vector", + "-iv", + default=os.getenv("KISSKH_INITIALIZATION_VECTOR"), + help="Initialization vector for decryption", +) def dl( drama_url_or_name: str, first: int, @@ -54,8 +77,20 @@ def dl( quality: str, sub_langs: List[str], output_dir: Union[Path, str], + decrypt_subtitle: bool, + key: str, + initialization_vector: str, ) -> None: logger = logging.getLogger(__name__) + + if decrypt_subtitle and not (key and initialization_vector): + raise click.UsageError( + "--key and --initialization-vector must be provided when --decrypt-subtitle is set. " + "Either pass them or set them via KISSKH_KEY and KISSKH_INITIALIZATION_VECTOR environment variable." + ) + + decrypter = SubtitleDecrypter(key=key, initialization_vector=initialization_vector) if decrypt_subtitle else None + kisskh_api = KissKHApi() downloader = Downloader(referer="https://kisskh.co") episode_ids: Dict[int, int] = {} @@ -94,7 +129,7 @@ def dl( filepath = f"{output_dir}/{drama_name}/{drama_name}_E{episode_number:02d}" logger.debug(f"Using video url: {video_stream_url}") downloader.download_video_from_stream_url(video_stream_url, filepath, quality) - downloader.download_subtitles(subtitles, filepath) + downloader.download_subtitles(subtitles, filepath, decrypter) if __name__ == "__main__": diff --git a/src/kisskh_downloader/downloader.py b/src/kisskh_downloader/downloader.py index e55dc73..3e0c0ff 100644 --- a/src/kisskh_downloader/downloader.py +++ b/src/kisskh_downloader/downloader.py @@ -1,12 +1,13 @@ import logging import os from pathlib import Path -from typing import List +from typing import List, Optional from urllib.parse import urlparse import requests import yt_dlp +from kisskh_downloader.helper.decrypt_subtitle import SubtitleDecrypter from kisskh_downloader.models.sub import SubItem logger = logging.getLogger(__name__) @@ -35,7 +36,9 @@ def download_video_from_stream_url(self, video_stream_url: str, filepath: str, q with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.download(video_stream_url) - def download_subtitles(self, subtitles: List[SubItem], filepath: str) -> None: + def download_subtitles( + self, subtitles: List[SubItem], filepath: str, decrypter: Optional[SubtitleDecrypter] = None + ) -> None: """Download subtitles :param subtitles: list of all subtitles @@ -45,4 +48,8 @@ def download_subtitles(self, subtitles: List[SubItem], filepath: str) -> None: logger.info(f"Downloading {subtitle.label} sub...") extension = os.path.splitext(urlparse(subtitle.src).path)[-1] response = requests.get(subtitle.src) - Path(f"{filepath}.{subtitle.land}{extension}").write_bytes(response.content) + output_path = Path(f"{filepath}.{subtitle.land}{extension}") + output_path.write_bytes(response.content) + if decrypter is not None: + decrypted_subtitle = decrypter.decrypt_subtitles(output_path) + decrypted_subtitle.save(output_path)