diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index a5da654..9559a9b 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -38,7 +38,7 @@ body:
id: version
attributes:
label: 哔哩哔哩漫画下载器版本号
- placeholder: v1.1.1
+ placeholder: v1.3.0
validations:
required: true
- type: dropdown
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index ba1c6b8..91abb11 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,4 +8,4 @@ updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
- interval: "daily"
+ interval: "weekly"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8bf2f36
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,134 @@
+.vscode/
+Report.*
+
+~$rEPORT.DOCX
+
+codiga.yml
+哔哩哔哩漫画下载器.exe
+
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+# *.spec
+myPyinstaller.json
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+Pipfile.lock
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
diff --git a/Pipfile b/Pipfile
index 52dfab6..32bc085 100644
--- a/Pipfile
+++ b/Pipfile
@@ -4,15 +4,17 @@ verify_ssl = true
name = "pypi"
[packages]
-piexif = ">=1.1.3"
-py7zr = ">=0.20.4"
-pypdf2 = ">=3.0.1"
-pyside6 = ">=6.4.2"
-requests = ">=2.28.1"
-retrying = ">=1.3.4"
-pillow = ">=9.4.0"
-pypinyin = ">=0.48.0"
-qt-material = ">=2.14"
+piexif = "*"
+py7zr = "*"
+pypdf2 = "*"
+pyside6 = "*"
+requests = "*"
+retrying = "*"
+pillow = "*"
+pypinyin = "*"
+qt-material = "*"
+beautifulsoup4 = "*"
+qrcode = "*"
[dev-packages]
rich = "*"
diff --git a/Pipfile.lock b/Pipfile.lock
deleted file mode 100644
index 71c032c..0000000
--- a/Pipfile.lock
+++ /dev/null
@@ -1,1137 +0,0 @@
-{
- "_meta": {
- "hash": {
- "sha256": "10565c5875da770b09489e4a67116bdfaabc7dd212980f57bd74ee7f87317b98"
- },
- "pipfile-spec": 6,
- "requires": {
- "python_version": "3.11"
- },
- "sources": [
- {
- "name": "pypi",
- "url": "https://pypi.org/simple",
- "verify_ssl": true
- }
- ]
- },
- "default": {
- "brotli": {
- "hashes": [
- "sha256:02177603aaca36e1fd21b091cb742bb3b305a569e2402f1ca38af471777fb019",
- "sha256:11d3283d89af7033236fa4e73ec2cbe743d4f6a81d41bd234f24bf63dde979df",
- "sha256:12effe280b8ebfd389022aa65114e30407540ccb89b177d3fbc9a4f177c4bd5d",
- "sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8",
- "sha256:16d528a45c2e1909c2798f27f7bf0a3feec1dc9e50948e738b961618e38b6a7b",
- "sha256:19598ecddd8a212aedb1ffa15763dd52a388518c4550e615aed88dc3753c0f0c",
- "sha256:1c48472a6ba3b113452355b9af0a60da5c2ae60477f8feda8346f8fd48e3e87c",
- "sha256:268fe94547ba25b58ebc724680609c8ee3e5a843202e9a381f6f9c5e8bdb5c70",
- "sha256:269a5743a393c65db46a7bb982644c67ecba4b8d91b392403ad8a861ba6f495f",
- "sha256:26d168aac4aaec9a4394221240e8a5436b5634adc3cd1cdf637f6645cecbf181",
- "sha256:29d1d350178e5225397e28ea1b7aca3648fcbab546d20e7475805437bfb0a130",
- "sha256:2aad0e0baa04517741c9bb5b07586c642302e5fb3e75319cb62087bd0995ab19",
- "sha256:3148362937217b7072cf80a2dcc007f09bb5ecb96dae4617316638194113d5be",
- "sha256:330e3f10cd01da535c70d09c4283ba2df5fb78e915bea0a28becad6e2ac010be",
- "sha256:336b40348269f9b91268378de5ff44dc6fbaa2268194f85177b53463d313842a",
- "sha256:3496fc835370da351d37cada4cf744039616a6db7d13c430035e901443a34daa",
- "sha256:35a3edbe18e876e596553c4007a087f8bcfd538f19bc116917b3c7522fca0429",
- "sha256:3b78a24b5fd13c03ee2b7b86290ed20efdc95da75a3557cc06811764d5ad1126",
- "sha256:3b8b09a16a1950b9ef495a0f8b9d0a87599a9d1f179e2d4ac014b2ec831f87e7",
- "sha256:3c1306004d49b84bd0c4f90457c6f57ad109f5cc6067a9664e12b7b79a9948ad",
- "sha256:3ffaadcaeafe9d30a7e4e1e97ad727e4f5610b9fa2f7551998471e3736738679",
- "sha256:40d15c79f42e0a2c72892bf407979febd9cf91f36f495ffb333d1d04cebb34e4",
- "sha256:44bb8ff420c1d19d91d79d8c3574b8954288bdff0273bf788954064d260d7ab0",
- "sha256:4688c1e42968ba52e57d8670ad2306fe92e0169c6f3af0089be75bbac0c64a3b",
- "sha256:495ba7e49c2db22b046a53b469bbecea802efce200dffb69b93dd47397edc9b6",
- "sha256:4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438",
- "sha256:503fa6af7da9f4b5780bb7e4cbe0c639b010f12be85d02c99452825dd0feef3f",
- "sha256:56d027eace784738457437df7331965473f2c0da2c70e1a1f6fdbae5402e0389",
- "sha256:5913a1177fc36e30fcf6dc868ce23b0453952c78c04c266d3149b3d39e1410d6",
- "sha256:5b6ef7d9f9c38292df3690fe3e302b5b530999fa90014853dcd0d6902fb59f26",
- "sha256:5bf37a08493232fbb0f8229f1824b366c2fc1d02d64e7e918af40acd15f3e337",
- "sha256:5cb1e18167792d7d21e21365d7650b72d5081ed476123ff7b8cac7f45189c0c7",
- "sha256:61a7ee1f13ab913897dac7da44a73c6d44d48a4adff42a5701e3239791c96e14",
- "sha256:622a231b08899c864eb87e85f81c75e7b9ce05b001e59bbfbf43d4a71f5f32b2",
- "sha256:68715970f16b6e92c574c30747c95cf8cf62804569647386ff032195dc89a430",
- "sha256:6b2ae9f5f67f89aade1fab0f7fd8f2832501311c363a21579d02defa844d9296",
- "sha256:6c772d6c0a79ac0f414a9f8947cc407e119b8598de7621f39cacadae3cf57d12",
- "sha256:6d847b14f7ea89f6ad3c9e3901d1bc4835f6b390a9c71df999b0162d9bb1e20f",
- "sha256:73fd30d4ce0ea48010564ccee1a26bfe39323fde05cb34b5863455629db61dc7",
- "sha256:76ffebb907bec09ff511bb3acc077695e2c32bc2142819491579a695f77ffd4d",
- "sha256:7bbff90b63328013e1e8cb50650ae0b9bac54ffb4be6104378490193cd60f85a",
- "sha256:7cb81373984cc0e4682f31bc3d6be9026006d96eecd07ea49aafb06897746452",
- "sha256:7ee83d3e3a024a9618e5be64648d6d11c37047ac48adff25f12fa4226cf23d1c",
- "sha256:854c33dad5ba0fbd6ab69185fec8dab89e13cda6b7d191ba111987df74f38761",
- "sha256:85f7912459c67eaab2fb854ed2bc1cc25772b300545fe7ed2dc03954da638649",
- "sha256:87fdccbb6bb589095f413b1e05734ba492c962b4a45a13ff3408fa44ffe6479b",
- "sha256:88c63a1b55f352b02c6ffd24b15ead9fc0e8bf781dbe070213039324922a2eea",
- "sha256:8a674ac10e0a87b683f4fa2b6fa41090edfd686a6524bd8dedbd6138b309175c",
- "sha256:8ed6a5b3d23ecc00ea02e1ed8e0ff9a08f4fc87a1f58a2530e71c0f48adf882f",
- "sha256:93130612b837103e15ac3f9cbacb4613f9e348b58b3aad53721d92e57f96d46a",
- "sha256:9744a863b489c79a73aba014df554b0e7a0fc44ef3f8a0ef2a52919c7d155031",
- "sha256:9749a124280a0ada4187a6cfd1ffd35c350fb3af79c706589d98e088c5044267",
- "sha256:97f715cf371b16ac88b8c19da00029804e20e25f30d80203417255d239f228b5",
- "sha256:9bf919756d25e4114ace16a8ce91eb340eb57a08e2c6950c3cebcbe3dff2a5e7",
- "sha256:9d12cf2851759b8de8ca5fde36a59c08210a97ffca0eb94c532ce7b17c6a3d1d",
- "sha256:9ed4c92a0665002ff8ea852353aeb60d9141eb04109e88928026d3c8a9e5433c",
- "sha256:a72661af47119a80d82fa583b554095308d6a4c356b2a554fdc2799bc19f2a43",
- "sha256:afde17ae04d90fbe53afb628f7f2d4ca022797aa093e809de5c3cf276f61bbfa",
- "sha256:b1375b5d17d6145c798661b67e4ae9d5496920d9265e2f00f1c2c0b5ae91fbde",
- "sha256:b336c5e9cf03c7be40c47b5fd694c43c9f1358a80ba384a21969e0b4e66a9b17",
- "sha256:b3523f51818e8f16599613edddb1ff924eeb4b53ab7e7197f85cbc321cdca32f",
- "sha256:b43775532a5904bc938f9c15b77c613cb6ad6fb30990f3b0afaea82797a402d8",
- "sha256:b663f1e02de5d0573610756398e44c130add0eb9a3fc912a09665332942a2efb",
- "sha256:b83bb06a0192cccf1eb8d0a28672a1b79c74c3a8a5f2619625aeb6f28b3a82bb",
- "sha256:ba72d37e2a924717990f4d7482e8ac88e2ef43fb95491eb6e0d124d77d2a150d",
- "sha256:c2415d9d082152460f2bd4e382a1e85aed233abc92db5a3880da2257dc7daf7b",
- "sha256:c83aa123d56f2e060644427a882a36b3c12db93727ad7a7b9efd7d7f3e9cc2c4",
- "sha256:c8e521a0ce7cf690ca84b8cc2272ddaf9d8a50294fd086da67e517439614c755",
- "sha256:cab1b5964b39607a66adbba01f1c12df2e55ac36c81ec6ed44f2fca44178bf1a",
- "sha256:cb02ed34557afde2d2da68194d12f5719ee96cfb2eacc886352cb73e3808fc5d",
- "sha256:cc0283a406774f465fb45ec7efb66857c09ffefbe49ec20b7882eff6d3c86d3a",
- "sha256:cfc391f4429ee0a9370aa93d812a52e1fee0f37a81861f4fdd1f4fb28e8547c3",
- "sha256:db844eb158a87ccab83e868a762ea8024ae27337fc7ddcbfcddd157f841fdfe7",
- "sha256:defed7ea5f218a9f2336301e6fd379f55c655bea65ba2476346340a0ce6f74a1",
- "sha256:e16eb9541f3dd1a3e92b89005e37b1257b157b7256df0e36bd7b33b50be73bcb",
- "sha256:e1abbeef02962596548382e393f56e4c94acd286bd0c5afba756cffc33670e8a",
- "sha256:e23281b9a08ec338469268f98f194658abfb13658ee98e2b7f85ee9dd06caa91",
- "sha256:e2d9e1cbc1b25e22000328702b014227737756f4b5bf5c485ac1d8091ada078b",
- "sha256:e48f4234f2469ed012a98f4b7874e7f7e173c167bed4934912a29e03167cf6b1",
- "sha256:e4c4e92c14a57c9bd4cb4be678c25369bf7a092d55fd0866f759e425b9660806",
- "sha256:ec1947eabbaf8e0531e8e899fc1d9876c179fc518989461f5d24e2223395a9e3",
- "sha256:f909bbbc433048b499cb9db9e713b5d8d949e8c109a2a548502fb9aa8630f0b1"
- ],
- "markers": "platform_python_implementation == 'CPython'",
- "version": "==1.0.9"
- },
- "certifi": {
- "hashes": [
- "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
- "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2023.7.22"
- },
- "charset-normalizer": {
- "hashes": [
- "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96",
- "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c",
- "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710",
- "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706",
- "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020",
- "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252",
- "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad",
- "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329",
- "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a",
- "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f",
- "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6",
- "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4",
- "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a",
- "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46",
- "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2",
- "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23",
- "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace",
- "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd",
- "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982",
- "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10",
- "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2",
- "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea",
- "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09",
- "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5",
- "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149",
- "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489",
- "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9",
- "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80",
- "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592",
- "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3",
- "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6",
- "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed",
- "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c",
- "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200",
- "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a",
- "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e",
- "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d",
- "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6",
- "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623",
- "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669",
- "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3",
- "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa",
- "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9",
- "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2",
- "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f",
- "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1",
- "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4",
- "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a",
- "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8",
- "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3",
- "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029",
- "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f",
- "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959",
- "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22",
- "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7",
- "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952",
- "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346",
- "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e",
- "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d",
- "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299",
- "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd",
- "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a",
- "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3",
- "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037",
- "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94",
- "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c",
- "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858",
- "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a",
- "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449",
- "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c",
- "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918",
- "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1",
- "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c",
- "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac",
- "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.2.0"
- },
- "idna": {
- "hashes": [
- "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
- "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==3.4"
- },
- "inflate64": {
- "hashes": [
- "sha256:08c3b03514d4b849901762a32a45eeba7fd5d784fec698eca6975f41cca33672",
- "sha256:094ef56a87c7b7398d93af7bfe7f24f830f24b6e55b77426f6516cef43e05460",
- "sha256:09dd0f8d6dee0da467c264dbd9bca8b33f9c915860fc3385f2a633640a65bd10",
- "sha256:0b0c8aa2fcdb1052d3bc6c5b5b1191b9c708d30e47af98ba0a8117ae1f6c9efc",
- "sha256:130dfdca4bd38e588ea4f878bf62635e36f83ddf7f2842d1055d1c16a11890cf",
- "sha256:1749da3a02b53035cde1cf95f885e78e0c2c49b201e97d368b3ba97e0f3d42c3",
- "sha256:17aaac096f40bd80dd72481831607a0846271d401ba3cd863386b8c244c7ebc1",
- "sha256:1d861fed6b2098d1862b64db9df650b9bd41fc41caa9fcaeee399079342aa4a8",
- "sha256:26e8319fd032c520203e2c001f1693c1c03774d85915900427e884011718f41d",
- "sha256:29946840e6970d68e7739207ca21140c59ffebe7e02d28c7e86348166ce32418",
- "sha256:35e24ffd8d6225fbfe26c524b45ace1bb8956811bd79e9f3d523a721d51b0d4e",
- "sha256:3a17e1dd1a5a872edfc02bc4a048868ada4865a3f4ee3ad5d224b192f2e53df7",
- "sha256:3bacbe9d4b7c185011b59268223a010ed777a28ed8cf40efc74fab1b7262e904",
- "sha256:3c270d373ca3717dbeb9b171eea53cbf2c9d7471b9b5de1e57f165e60cf58037",
- "sha256:3c913b679f023f5907a54bfa9a6e438407ed4e40eee23ed19b4118128bdd091c",
- "sha256:3cf41f82dd4e90e8684c7be4583d7232bd800a561f3ed0241c84e39148861887",
- "sha256:41504988023042452d2d84e4110c9ef4ff8ebd33cb90ba83e44b92c9a6753c43",
- "sha256:42a6ef375b3e7059bd52993a0938f2bf97725cb5dc380f0c4dbaa9fc3780e025",
- "sha256:473e0081c268ffa4b18683586b55170eb96d8b4fc684dd3ed9599c17c512d2e4",
- "sha256:48fd2527a462374dc19be06301d6aa30a03190532f2f8bddfbc39b7158561750",
- "sha256:4d807cfa9ddad940401ef04502eb367a77f569850f59c2e71670347d558a3830",
- "sha256:4e7b0a598adaa11366ffbbb7b3d3110db29edd4b732d9336570891363b22b002",
- "sha256:525bc309d8533ef9917e006284996ee7a9a71ac6dd19fb57c0f741ad0c805d4f",
- "sha256:553cd992f02af574d2116c74ca48d7cf10894c6b9ba8159f488f3bfac3c201ae",
- "sha256:5c5b2eb7e89d550d287774dea7d429ee24ce44ca34499a6cef113a14f108e700",
- "sha256:5efd55c21b794601fd44b99b8e2f17498744f573116ce27a745bc5e08f0457e1",
- "sha256:6059eaba5044739ad6424588e845bd856f89a1a18f1addc31b97c49f02f68728",
- "sha256:664929528047b6b472852a4c0d12b4b9cf6e663059ba64ebd10f08aa56365755",
- "sha256:67e37d96ea2ee8257b12cde83a09e4f0276950268a7a2f777aee7de60db5ec72",
- "sha256:67efdfd21d7b99f30a43560b22264c1e580ff08ae9831e78c99445575962dbc7",
- "sha256:6ff89f94823b2466bae45759fc324bd25bd20c490607a7d8407237cf64ccafa9",
- "sha256:74ceb9d172ce06572632bc8070d54b963455421e216013575383f991e722bb7d",
- "sha256:7b7966193f1bf23e050af72b4c4720dffa5f33471de7afea37ba0d0f0195adef",
- "sha256:7ba954600441eafe8f6f54eadffeac4d1ab2416d5d1a6b0ab403e50284ba457b",
- "sha256:7c142fbbbfbe0877fe821ff8bc4cc10f96d344b7400721579b3d17deeae28f59",
- "sha256:7f8346e644de449a4a90dcb22971dea456398b6cc788102013675b11256ae47e",
- "sha256:80a125dd5cb7b7985c05a78b0bfd7751249d0d84fc330901dbd9faa693e1f53f",
- "sha256:82393e46b8ba2f8613d030f38c7c492b0896ff8803f7ff870677f25d3e5e7113",
- "sha256:84287d1d09fd879353d3ccadd43f3d8adea75e830476ddfd46d8849d36d25afe",
- "sha256:853f3442eceda8035072686533694ab833c4293d10c9d0685147200f0e964356",
- "sha256:906a4b57df32f903e847766ca685e44ed3e7ee3a960fa94264d5e68b836d446d",
- "sha256:90f95b92d0f672d11151cb964964d1723e2e3ce3a19d32d24aece1acdec1e287",
- "sha256:91233b5300bbb7562804c3d07617e9ce2983e8434218991db98ef175491e417f",
- "sha256:9297115bf144c585e9d6a746e851c64c81d8f1ce8b62da4885babe66c36f7d29",
- "sha256:9f6737a575c6e7e818963d95a998be4c91484374961734cee97265f3c4c3b979",
- "sha256:a075b174bace5174828906c7c87019a2af3cc5707025f01ee0395fb4b88fd98e",
- "sha256:a1b481343f12641b1ae7a19135a70c44ecf020dccb670e02522c2b02db920851",
- "sha256:a2f4aaa02f9a5ada944960428b6528a0a9d773925efc73485882f34bf42654be",
- "sha256:a6bec3d2f30f6f2656e1c5a4147181e401c8d7026cd598d86ad5647c616fc618",
- "sha256:aa7476129e7f81e67a9253470c3085a9fd75ec77e6fae3de61f7795138ce725e",
- "sha256:ab8f9e14ba6495f440101751ba8aa371e4a52941b5e343c6f3e8c61021e2df5e",
- "sha256:ac60868745f7bfbcd615329fbdc35997fa36043ce358a1c64d229ef448ebecf0",
- "sha256:ad4cae5097bdff7e0bb1ab676d86ad08716597baa3b616e5b710a724f5d5cbc4",
- "sha256:ad84ac611eae17a961124c5fbe754b6982291a3945ab2b9c334a08e2e56f9ccc",
- "sha256:b52dd8fefd2ba179e5dfa18d6eca7e2fc822584616271c039d5ef1f9ca90c71c",
- "sha256:b7aa123c740f2f9798f72873e50d7c6d43664d12cad7a1405296079987bdb04a",
- "sha256:c1faf43890dbfff31195f5d59e37e49824f5ff4be77d67f7144a6b953bbde51c",
- "sha256:c28cb635ccb9aae399fbc8e82c85b89ea0a7bb2219e7d582bbc007a29fb6e149",
- "sha256:c71821f93c931ae379cf9c9bbdd7099738fa00802ccf2a5271e2b68bc67a6ab8",
- "sha256:ced0af509a31dcba0cd98ecdd06cb7c9ce66ebde78e0d99ba3515d4e991e34d0",
- "sha256:d4e2a337c6c03b0e96ccd79940cbb04fe2063974d56fff6d78f8d57839546c57",
- "sha256:d71af8b23ac23bc9e9f776451c125be6320ad4589a7d5bcb5ab5e1fc61b4e58f",
- "sha256:d881b605b7448be451f02c59128dc5fac262dbd0dcff4638e702dc8c7bbb8ef0",
- "sha256:e1987bbc482aa3e2e7fb72c70b22483cfaed3dbebc5ba6f9ac6f75240794709b",
- "sha256:e32a78c81afba5699569c3493066ecb38fb45ccdf4c35b3c2232c9c2585b5257",
- "sha256:f2a4dac4ebc4ad58a4ac911e39cf97cd74906c0c82c16333887aa9f287e98d5b",
- "sha256:f39b57974db0e85897fff40518da420f4c4012b73515ca6f415a472228fea288",
- "sha256:fd04764d0bb830414788cae897d082bf6ad92324e571a5511bd7e1de4a0cdc67",
- "sha256:fde3f85864c84badb26f42d95639360e627fd09c529a76c46a06dbd7a5735c51"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==0.3.1"
- },
- "jinja2": {
- "hashes": [
- "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
- "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.1.2"
- },
- "markupsafe": {
- "hashes": [
- "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e",
- "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e",
- "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431",
- "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686",
- "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559",
- "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc",
- "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c",
- "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0",
- "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4",
- "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9",
- "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575",
- "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba",
- "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d",
- "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3",
- "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00",
- "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155",
- "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac",
- "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52",
- "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f",
- "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8",
- "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b",
- "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24",
- "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea",
- "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198",
- "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0",
- "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee",
- "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be",
- "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2",
- "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707",
- "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6",
- "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58",
- "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779",
- "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636",
- "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c",
- "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad",
- "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee",
- "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc",
- "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2",
- "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48",
- "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7",
- "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e",
- "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b",
- "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa",
- "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5",
- "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e",
- "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb",
- "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9",
- "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57",
- "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc",
- "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==2.1.3"
- },
- "multivolumefile": {
- "hashes": [
- "sha256:237f4353b60af1703087cf7725755a1f6fcaeeea48421e1896940cd1c920d678",
- "sha256:a0648d0aafbc96e59198d5c17e9acad7eb531abea51035d08ce8060dcad709d6"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.2.3"
- },
- "piexif": {
- "hashes": [
- "sha256:3bc435d171720150b81b15d27e05e54b8abbde7b4242cddd81ef160d283108b6",
- "sha256:83cb35c606bf3a1ea1a8f0a25cb42cf17e24353fd82e87ae3884e74a302a5f1b"
- ],
- "index": "pypi",
- "version": "==1.1.3"
- },
- "pillow": {
- "hashes": [
- "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5",
- "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530",
- "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d",
- "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca",
- "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891",
- "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992",
- "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7",
- "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3",
- "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba",
- "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3",
- "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3",
- "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f",
- "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538",
- "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3",
- "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d",
- "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c",
- "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017",
- "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3",
- "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223",
- "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e",
- "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3",
- "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6",
- "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640",
- "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334",
- "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1",
- "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba",
- "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa",
- "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0",
- "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396",
- "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d",
- "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485",
- "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf",
- "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43",
- "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37",
- "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2",
- "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd",
- "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86",
- "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967",
- "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629",
- "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568",
- "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed",
- "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f",
- "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551",
- "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3",
- "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614",
- "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff",
- "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d",
- "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883",
- "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684",
- "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0",
- "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de",
- "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b",
- "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3",
- "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199",
- "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51",
- "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"
- ],
- "index": "pypi",
- "version": "==10.0.0"
- },
- "psutil": {
- "hashes": [
- "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d",
- "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217",
- "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4",
- "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c",
- "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f",
- "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da",
- "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4",
- "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42",
- "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5",
- "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4",
- "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9",
- "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f",
- "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30",
- "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"
- ],
- "markers": "sys_platform != 'cygwin'",
- "version": "==5.9.5"
- },
- "py7zr": {
- "hashes": [
- "sha256:c7cfb7183fb8f48038f1036a116ca89dc8bd57979d05b75567f00e88a5afe698",
- "sha256:d036dee11fce69ad8d4fa86025ccfc4a3511ec27ee1c6b5bd8d6759313dbd077"
- ],
- "index": "pypi",
- "version": "==0.20.6"
- },
- "pybcj": {
- "hashes": [
- "sha256:023082fd677f67ebd36fe96322a4a45ac33a2b340d49010d88e1867c76744c50",
- "sha256:05fad9a905772774aacc96cb174571ac1f5afa80b9f54c6ec414d369865d305c",
- "sha256:09872b32edad4e3653d5b357b244d267ca58fe52d4e1dd3cdff816d3bb9d9f7c",
- "sha256:0eaa90639992b6096afb1485380fae7f084483db6b92867847a3bfdf22cc4efc",
- "sha256:10182725b0e6aa944d13a10a4a9cb5208bafe0016b4326253340948153de4bc0",
- "sha256:10961ea10ae930b9348132707b9dd3cf3e71a41ef1df7656fbc4f14a71f10747",
- "sha256:15edd1786617127ecfda4274bbb04f09ae299c474ada86e369bcf050d5cb88dd",
- "sha256:1a5365edcaa82dc47e7757ba2efb48f96b9b352e3811a2aaa90084802479ddbe",
- "sha256:1c0e1657c233f9f4070ab578951e03d569f1b645042ce661341091f50e41b541",
- "sha256:1e6434a46f852cd3e6929633b43537887bd381bc614dbf5c4a128fdde4966b3a",
- "sha256:20fc0d8f67e2d9747e0c31082d5f64b112258ae602a85aa5c7e6bf5a7cad287b",
- "sha256:21098001200273c3c9fd90e7bf909fb905a8e1c102c80b604cb7c6a3103ef7e0",
- "sha256:225a0addf4b3d580bf4eae583b5168dac0125a703c53ded8b3f120882e1e0312",
- "sha256:262f53e27bca6096e3424c63e5e59948b10985eee4b03a5d70c3f3f6161a79e7",
- "sha256:2d6b34ec233fcf5a83ccfbf422fef22256947eaa7077aaa012e5961d15aa302c",
- "sha256:2e1859d36c073231737956fbeb5bbcfa8dba880e1b66bfbd001466718d6d89dc",
- "sha256:358dba3dc39a07cded6897b9f99bb5b951a0ad95d567eda535b44861caa02f5b",
- "sha256:3847387b43af47d9677952b8a22d9c2d8a544c2175b6d5304c200669c05d39e1",
- "sha256:393d95f83e47976d137bcec7b66986f51282dcb2091933f88983dd7eb89e59c4",
- "sha256:39dd836134e261ec769cd5aa9ae7a3a330a7dac81efb66eb5504643abd8235df",
- "sha256:421ed75e54ebecd79c80178c1df5bdbe1e0e3e10e7efef5f011b5f0be6a9a12f",
- "sha256:421f211fb15aeb836b4ba61174cb409fc82222ab3b2486deb4953ae863e6507b",
- "sha256:43e8bc75773ca06ee7a64602b799613171e4edf4d9d8fd38fa5c49f1cdbb4407",
- "sha256:46b82fe50eb8171ee2205e935f3fd5900e31beb5e54e10c88f23a5420902467d",
- "sha256:4bc8720f3a224c27bd413a930b9bec5f225fda050641258967b1ebb252a053fb",
- "sha256:4d10dd75fad48555e9530c5565c7ccf13754adad2fe331feefb263055cdca7b3",
- "sha256:534b8b253dbdb746c06bab28383db31d7e2b42aa9b33ed4e7836319622dcd75b",
- "sha256:570a3cf4e016dcb0fc561991833e5170a2a0bc6ee88fe5667591f356bd7b7895",
- "sha256:5de90f8b6c7fc1d28dbe74c29b1d5053a7a8703cbc2c6f4f112907ffd7529f8e",
- "sha256:603daa737579cf69efb368fab716cdce18d0b2615af77bb623f5f42aa546b3d8",
- "sha256:6485c6b091504c0e6431a9495309271626eaa9ecb23276903486824f94f4c551",
- "sha256:6ca6ddae1302477879099d4c4efc65790f4610d71ceff7fbe8f8b60f6ac6dcff",
- "sha256:6df9eccc99a0d7bc091b58cff2f507b89f076d657253975fa2ca9eb42dbb4733",
- "sha256:6f589af70286ec6565e3415145a03abc3c14a23ed7ed198ac741de81af332f26",
- "sha256:731800acfc6112132aa2b7d08f9d6fe49a0c0071b30985809d084e238af98dac",
- "sha256:74d34340323996b70dbd73e9530cca71c05ff7c97e30fe4d32aeea2f877836ca",
- "sha256:7801ee9a9fcd47b92d4d90ff9a28cfdc23195cad72bd8032938ab3c794942b43",
- "sha256:795dff9229dc024e54bd0f618f5a3adb269ee0cccd7ac9a0bef29df388beed23",
- "sha256:7b3773a77ae3b18778c9bf22c7ba6478a0e5416f84b7d2ac6d764001f6d0d985",
- "sha256:872697d8bff2572e4225ed8cbce17be338faac28ec1ab3c00419aaef2f56dd3c",
- "sha256:8b682ed08caabfb7c042d4be083e28ddc692afb1deff5567111f8855071b75c3",
- "sha256:8e846a8272bf02202794fe22beaf389ed27c2d8ebf59aafb43af4935feac0389",
- "sha256:8efed581f2ee74f1e0ec04a10e97881b93abc258d13b15ef966aee71732ac152",
- "sha256:970dc23ca1c64611d35a3abe76a059cf551da53d62faefd84c5bf3e0af1602d1",
- "sha256:9b56eeff51efa556ecc186260ac486a4ddd79ad37bc88d669e96c45190f3c0da",
- "sha256:9fc313b1a5547c5416982853f2de1454980704f3ab3dbcad18dacdc565a2eafc",
- "sha256:a74e70bf3fd50a413fdce4264e037b8e8f34cb8d9207ac364167b6eb076c14ec",
- "sha256:a77796b4c5370cedd4fad2264b6d7a78cb40229c7fa3cbcab24df3adea768962",
- "sha256:a81f14f213a75597f9be44feb97740a51adda558465fb159114472dc2ab39ef8",
- "sha256:acfc4a02ddf22f6df7184441b39f38c31e95aa8af41de4d2f825821ab1fb85c6",
- "sha256:b3861996b06b8238f799b4f1bd9542d1a8ae8e4765adbdde25ed011c3bda11df",
- "sha256:b901f12380e988da07f21bb6b75da7f91fd9feffb43fcf70fad698e40a2ef3a7",
- "sha256:b99f4291e59dcbe548be5a1e8c6a1a19a860184526c2d14fc374ec687b98ad7d",
- "sha256:bb378b0f133e19d437eca4327bac7c3f38e30950c5c604092c72b18cba839bc2",
- "sha256:bbb49772fc3896850a704215160df8316db89e5e8876b2d8af6c6c15b4e0f6ea",
- "sha256:bc1684b9f7ec92d2ae94a137ec311bd2227f684429521061af7ceed4952c7f72",
- "sha256:bdabbe7fd66886943393ecf98318d7801dd40183af80314acd4464bccdd44d53",
- "sha256:bf87f2a7f827656bc6e1d9888d47931aa0ae35cdc4ff33b1cec70d8d462590b3",
- "sha256:c1e02170f8d358a8ddc716606760c73d55eea6bdb0cca2d97b86447e9524708b",
- "sha256:c72ff262613c9a6f20e80bcf1e8bbc000b78b95a7fa301164ab3e3bd23bd936c",
- "sha256:c854a206d8c3a5a959b803405760f3627bb4878450e2f36b5d35af09c89152fc",
- "sha256:d5b327df02761c42399c878cd6c37f885bf0639befbd4d1ab763cd44ba1e0552",
- "sha256:d5c4ca6faff0af4b5f3e7d88d13ec76f8cac36c9bcc814b8c84d9f3f951b2cf9",
- "sha256:d61f287f820787d3acf60d113c5ce6e506870d9d3103bc37a74373e72ce9d7a6",
- "sha256:dc23f2ac2c1ded250f1aa66fbd1a3d823f76de549978b61eed4fb34affc11338",
- "sha256:dc79ed4773cd35328377a8fedbbdcafb3a9d242ee63b96863c0692c81faefab8",
- "sha256:df75707f466ab6fa086f164bff2df75fd16543c8d43ca43a268f938c1144e792",
- "sha256:e6a74cb618da93ac1322d6a548a4508e76eb4c388ed1c80560bc25d8764cf272",
- "sha256:e89a814f1727be7d543ac6910f0d94131f43a337e811ab684606d42dbc22b701",
- "sha256:efe75e3b8768c4f9d454d3c1b2b2a67e757f2b00d638146d3a4cddb38460fc3a",
- "sha256:f2f950ca403ffaa808a017e40e3371115bcb0b4b1061772b03e7d842555132ac",
- "sha256:f4428b6808d781f4b605a27f53fc10a3ca343d1cd901c691b9ba2e4ed85a5fc7",
- "sha256:f46ba61c942ee64198444c9562c5cf089eaf97f17b413e15fa1c0614df304734",
- "sha256:f472da992a6ba58381c0314b994c01d20e522ff8836417ef1c0975bdae142406",
- "sha256:f58e489e43c9a1688c7d5ceb7455b44952d87f183b7b9c915b301478a2b3bfbe",
- "sha256:f8576a1dcf445ef064bf8c3b2cdc1d6353e41cb4b366329946883e285dcbcec0",
- "sha256:fa787b414c4dc6b6cd75338fac18a7dbb53a09443dd863020a2d2bda76940ca6",
- "sha256:fda423836d7d69cba6a6f99e7a34c2e5fe3621e5e945cd25ea9ba60a96223254"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.0.1"
- },
- "pycryptodomex": {
- "hashes": [
- "sha256:160a39a708c36fa0b168ab79386dede588e62aec06eb505add870739329aecc6",
- "sha256:192306cf881fe3467dda0e174a4f47bb3a8bb24b90c9cdfbdc248eec5fc0578c",
- "sha256:1949e09ea49b09c36d11a951b16ff2a05a0ffe969dda1846e4686ee342fe8646",
- "sha256:215be2980a6b70704c10796dd7003eb4390e7be138ac6fb8344bf47e71a8d470",
- "sha256:27072a494ce621cc7a9096bbf60ed66826bb94db24b49b7359509e7951033e74",
- "sha256:2dc4eab20f4f04a2d00220fdc9258717b82d31913552e766d5f00282c031b70a",
- "sha256:302a8f37c224e7b5d72017d462a2be058e28f7be627bdd854066e16722d0fc0c",
- "sha256:3d9314ac785a5b75d5aaf924c5f21d6ca7e8df442e5cf4f0fefad4f6e284d422",
- "sha256:3e3ecb5fe979e7c1bb0027e518340acf7ee60415d79295e5251d13c68dde576e",
- "sha256:4d9379c684efea80fdab02a3eb0169372bca7db13f9332cb67483b8dc8b67c37",
- "sha256:50308fcdbf8345e5ec224a5502b4215178bdb5e95456ead8ab1a69ffd94779cb",
- "sha256:5594a125dae30d60e94f37797fc67ce3c744522de7992c7c360d02fdb34918f8",
- "sha256:58fc0aceb9c961b9897facec9da24c6a94c5db04597ec832060f53d4d6a07196",
- "sha256:6421d23d6a648e83ba2670a352bcd978542dad86829209f59d17a3f087f4afef",
- "sha256:6875eb8666f68ddbd39097867325bd22771f595b4e2b0149739b5623c8bf899b",
- "sha256:6ed3606832987018615f68e8ed716a7065c09a0fe94afd7c9ca1b6777f0ac6eb",
- "sha256:71687eed47df7e965f6e0bf3cadef98f368d5221f0fb89d2132effe1a3e6a194",
- "sha256:73d64b32d84cf48d9ec62106aa277dbe99ab5fbfd38c5100bc7bddd3beb569f7",
- "sha256:75672205148bdea34669173366df005dbd52be05115e919551ee97171083423d",
- "sha256:76f0a46bee539dae4b3dfe37216f678769349576b0080fdbe431d19a02da42ff",
- "sha256:8ff129a5a0eb5ff16e45ca4fa70a6051da7f3de303c33b259063c19be0c43d35",
- "sha256:ac614363a86cc53d8ba44b6c469831d1555947e69ab3276ae8d6edc219f570f7",
- "sha256:ba95abd563b0d1b88401658665a260852a8e6c647026ee6a0a65589287681df8",
- "sha256:bbdcce0a226d9205560a5936b05208c709b01d493ed8307792075dedfaaffa5f",
- "sha256:bec6c80994d4e7a38312072f89458903b65ec99bed2d65aa4de96d997a53ea7a",
- "sha256:c2953afebf282a444c51bf4effe751706b4d0d63d7ca2cc51db21f902aa5b84e",
- "sha256:d35a8ffdc8b05e4b353ba281217c8437f02c57d7233363824e9d794cf753c419",
- "sha256:d56c9ec41258fd3734db9f5e4d2faeabe48644ba9ca23b18e1839b3bdf093222",
- "sha256:d84e105787f5e5d36ec6a581ff37a1048d12e638688074b2a00bcf402f9aa1c2",
- "sha256:e00a4bacb83a2627e8210cb353a2e31f04befc1155db2976e5e239dd66482278",
- "sha256:f237278836dda412a325e9340ba2e6a84cb0f56b9244781e5b61f10b3905de88",
- "sha256:f9ab5ef0718f6a8716695dea16d83b671b22c45e9c0c78fd807c32c0192e54b5"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==3.18.0"
- },
- "pypdf2": {
- "hashes": [
- "sha256:a74408f69ba6271f71b9352ef4ed03dc53a31aa404d29b5d31f53bfecfee1440",
- "sha256:d16e4205cfee272fbdc0568b68d82be796540b1537508cef59388f839c191928"
- ],
- "index": "pypi",
- "version": "==3.0.1"
- },
- "pypinyin": {
- "hashes": [
- "sha256:3791f5b647e446866e6b5d3a63942ecbaeb29b49fed268a9d9a4982241c35fe0",
- "sha256:a5d61a79c5f48f6b4a422f010c20d48fcd53c705784df4aa80e329493219a4be"
- ],
- "index": "pypi",
- "version": "==0.49.0"
- },
- "pyppmd": {
- "hashes": [
- "sha256:024f714ebb8ddf59dae164adc3c220c24555d470f4adb5bd022abc50298cfff3",
- "sha256:05950d8a39fd9bf6c64572d69a6dd0a1af3fadf8d4a2a0bb62f5b04c0a618300",
- "sha256:075c9bd297e3b0a87dd7aeabca7fee668218acbe69ecc1c6511064558de8840f",
- "sha256:07e067e114f05918c8a4ab1fa6a070e2c7a9e497aa73fbf6d87a90e7a6e62a57",
- "sha256:09668aa43e4f02b8725e6233dfc66e532c72f0e69fa1b34dd814a9f7200e0496",
- "sha256:0e9c001719527dbafdd7fd8709b98bd63c173451c2eddbaa77abf62486a13da0",
- "sha256:10c8a41093952cde52b6d89488dc601ee7b10f6c95c430488f68987393777b46",
- "sha256:12a783a0e3c76484a1bc93783867a36ab9a60de5b5298d57c9fe7348e848346e",
- "sha256:12be01e919a34c6944568592b35451acf7c98ed18e005bb4b1c046ed520aff7f",
- "sha256:1658714d012a5f9a8a3e67f3a9ede3519a2558064ccbd3163c39aca0cfd2412b",
- "sha256:18d7cf4d0a9ced96ff1fa44de9ee3d65f5b06278c8f9a61c3edeb660f12f146b",
- "sha256:18f863d58c4451e00765137be731c2b2150aff829468f59de4169e052429e1fd",
- "sha256:1c0fd06aaf782e65b7b5bbc47f8a9dbe050c1ba18474ccbe0a2b37f57a8d8c72",
- "sha256:1ec00b07c6b68feb402d6596f3575a7892ad69e4f455deee7b5301df703e60dd",
- "sha256:2858471a291b51fab49242d78bd67c2b7719368618a02e4aa995de8c855da73c",
- "sha256:2c31e5b331923f3b3b2cfbc66a60ecfd73db1a19a646bd1faf25bfde709a80d0",
- "sha256:31a09fd1b10518342ff442b57dd8c890b9bfea6bbdbb785c729f0d139092e42e",
- "sha256:385a0b1341ebdfd7cb101c43eea130546830073c01bdb5036bca45c033ee633e",
- "sha256:3bc75ed4e969b09fd1a766dd79cb3d5efe56edc11c86ac0b357b5648c7181ce2",
- "sha256:3ea6a0d26db17027805a804d013cf761d732df5bce9d6b314cd1c727fe347277",
- "sha256:3ecb83e0cc92960f959111518ea208b51a58e8cc303ff959e9cd2cc56dd36a63",
- "sha256:47ea218f7dfa94d15286c25d60db3091db1082ba958fa0a32ccaaaeaca7fc712",
- "sha256:5331a7780d3444d7029e15e68385c94d6a26f688c1e87a5a9ee2e836ea6e4559",
- "sha256:556b6a3af3fca2b41ca25f51c481e5df8df4da842fc5a567da7bb099cfa52423",
- "sha256:5805c73590fb8f0ceb3e6cb115774b66a6f4700ae84b31d962ad69667e05dfbd",
- "sha256:5847c47127ff9ea323f5910c62b9f136c3fab181a5144bfe72be13f051047357",
- "sha256:5d90d87377d83d909eafbf23301057fe16e6662c98ffea738159a234d9000a68",
- "sha256:6059ea0c9acc3b52b2961412ac75d1da72656f8b69bb8fc3d92eec6776176011",
- "sha256:61acfeee5ed59796037499119edd3159bf6b8c5fcaef17e295a2ca4103112d60",
- "sha256:6279f1c4b6aefacb95df49db2f2e232530592d1849c37b73478a4f26eb405d12",
- "sha256:62f970173baf80aad9472c7c6edca4a021ae7965174b1c5d6f400c9571e92efc",
- "sha256:63ddd5a81d6aaed9373cd9fc4de9529f10fa052aaf064ab283dc6218418cc5b5",
- "sha256:68184b7246ea73a92a764e16cc18b74ccf3c8d6bfc438bbace57aeb1914118a7",
- "sha256:6a0c524be57698fe61fff893d485a9af21e6bc0aa2d385b71a63ff951921d4b6",
- "sha256:6e2f5ff5071e4e43c92065f383753d4ad59778816485a01ee7b29e2a1ff48140",
- "sha256:6f8a3b9192714b3e4773fc49c100ca13defa2502cb38e56205eb5a131ccf555d",
- "sha256:703c4fbc9b5e1454f403fb1d6b4a6c4c729f72eef14690146deecd2166429d6d",
- "sha256:706d33cec3601d894f8a4a158bc652b7a3f01cd9e92c2da5d8711efeb9755835",
- "sha256:71f994f281439705cb04c497adc2863551fa5813606af6fb26c673a44a36c4e3",
- "sha256:74bd56b165283bb5586ff9ac7a896b217b3c94effe144b768279807840142bb4",
- "sha256:7ae419f71afa88784d53dd2449882af982bbd0328fa22a7e6a339221f3143918",
- "sha256:7e8d3c309061ae7fb40e4a26d30f8982b367abc562b9b8621cb79932cb3b94d9",
- "sha256:7f1e7a1747518b5822eb755f3715d88bd1459e24de828aed86b7c1aa35e3ed76",
- "sha256:8049c19af4b78b400b2347bff4514763257b55516c359144e9d8091991ed12e8",
- "sha256:8680008b1b1e9e77f3337a1a53c1b32541cac9f93f79ae12d34de050585999ac",
- "sha256:8a90b98f9d501eaedaca4d0e82f9e771bd2d780d71effcdeacc9fc6180a00e07",
- "sha256:8aafe6fc436a782e6d424a0ac00de08a1559b6d6ddd08031adbe791ff4e54c90",
- "sha256:93d0d6ed97046ce25d64427ec493e06c23f32838972258bf11d603c9c998d6b3",
- "sha256:a5fbec6f39a307818593508d8623d9328baf494137d191fc98e11f47e058ceee",
- "sha256:a63adeeb9dc4afd6d377ac1c9801f9539f9a81430e9c96d332023bf2ad6c04a1",
- "sha256:a7240c00083527cf0b1bbdc92f6967e522efb9ad6968c953be174c390b091b3e",
- "sha256:a7f83970a057157c88d4a53a40431d07d8d3f38029ad2eae621422f955bd243b",
- "sha256:aadc63d0ac83f8c5744eb34ea47a70ff7bfab519b293482d7ccb09946c374dc7",
- "sha256:ab4e29f774e064af09baf8478acd967684524e566b78fcc4f6f669757f0a2ab5",
- "sha256:ac19ec1b6e3a0aadc1537466f537017189373593e23fe254df050fdd01f4a722",
- "sha256:ac1aeba466617cf975cd6719070ca9721bcd83a1a84bd8cf74c3a2808724481e",
- "sha256:aee9c52a6f232f3f7c683b87213aa3a9eacd281ab31187e784290ba1c05024fe",
- "sha256:b0a87399ade5820f787758449976e758604c7739eb5f79ed9e594b5fa3a6a1bc",
- "sha256:b6b6c01e46fcf785ad6c272be400ebcbcb434a1d91150614e10de8cc569b8bff",
- "sha256:b8eee08c615ae9edd7bf1f214a377cac3d27417f22112685e581d4bab43029b0",
- "sha256:bae08176e0d3ed0a5cbd838ff1ac557dfa088a652af633ab1905ab35bb9d7bc4",
- "sha256:c60031de93834e5cd262db4b27272101d04a9a18c4cc49f81d483221211a97c8",
- "sha256:ca6a926d229a6dbf2ccdb0d4e692d81ff927459b59a1cec14ef522522df6d757",
- "sha256:ca8a842b4ff671642b63ed4edd4e1ff7dc0ba0a7af4135758233f056ab992fca",
- "sha256:ccdfc8b2a1d73b2186850b9a5bd96106d5fd4419a620d344b0ab8bf630680cf8",
- "sha256:cd227b8c292ac43d3297a91055fab51c27894dba39d04ccc774a72d9e6f85752",
- "sha256:cecf0859b461bcf04439f32bcfb6e081016fa6204c92b5950d19d248fd1aad6b",
- "sha256:cfb716a4a07ccbef84ed9fc31d012cef3b38404a6510e24d307cf64025999b21",
- "sha256:d2c3c16f644afb1b3caa4f6c717682030f7c3f54a12af8b1416b21877f0b5226",
- "sha256:d5c6c40f15b9fdea10bf966e5b07ee0a0ebcb8cf188ed9a466029c894816b303",
- "sha256:e17b08a5c283faf48b4ee888f8fa53f919cd8afd0930eae4d59f719f6be519fb",
- "sha256:ea4b1a326afe2055304740a03a233f7389f615179b9f6377264b306f619bfb11",
- "sha256:f488164e8876d213b0627a7a6cb798081eaf84fd9ec6dde5a1668296b15e1a6c",
- "sha256:f751882dd529328ca43af8018f79cdd02ed707fcda30a2fa9acb1ee5c48261a6",
- "sha256:f79ebcd7312b541d3520e1a0d4c362731e24403e2f9f6761679b2ad819d5c706",
- "sha256:f7a1b08612627d5280ef2dad1fadb0b1a10c70df0c484f9091eff5fab5e4c84e",
- "sha256:f8dbe3076fe20c4d65cb1d1b51eeb17a1c177402b83100017a55daad888e198e",
- "sha256:f9a3782f5accab4186d68c86defc61fcc7d0146e9cdc5b54e18656852c71db16"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.0.0"
- },
- "pyside6": {
- "hashes": [
- "sha256:0356dc73c138c25b980d716e425801a61d4aa1d9f7811cf8a825499edfd4d1ae",
- "sha256:ad82cb12f805c5bec7693d6f1c0d6e4ae4b9462eb368a81bc0d3091de8fae76e",
- "sha256:b509e4d3ffde4a594d70000f881452643c9aaed800bad2959882075c01f72428",
- "sha256:ca259b4377eb74e4c9cb74a2afb18c37658f0c83dc18229d1f325974739f6df2",
- "sha256:e6d879ca0f8827a7866856fbedd08857e4bd8f9a858dc998dea10d1913e97938",
- "sha256:f0944cb0da34dc3b0bb62c7a20b6618667760eccdaa4262a90ba7f64b19fb783"
- ],
- "index": "pypi",
- "version": "==6.5.2"
- },
- "pyside6-addons": {
- "hashes": [
- "sha256:15bf592e54b3409853c3db23bdb20fb14725b84d50feee862e8b2a3a8a3a0627",
- "sha256:26b55a658fed94a0b3c09927b408663860aca530bf6e83040dcb8fdcc221877d",
- "sha256:793a53b7db32f7780fa9571a14f0bce3700604247127cdb2125b380c577a92eb",
- "sha256:a31cb7eca2e8cd80332e131124ed9ad197610a2a80eac4f2bd58e9124e38060a",
- "sha256:bea98d823179b814109dcf3ac6c8a0eddf886570aa9ef8ef09b6bae37bc227ca",
- "sha256:c77e06fd511cc8b9292c01724504d6806c33c1f5904bc59f5a8c560a74c15438"
- ],
- "markers": "python_version < '3.12' and python_version >= '3.7'",
- "version": "==6.5.2"
- },
- "pyside6-essentials": {
- "hashes": [
- "sha256:149f1db77d82f35c6a88a403f5297645ebe737df28e163ac4dc402dfa0b961ee",
- "sha256:1620e82b38714a1570b142c01694d0415a25526517b24620ff9b00c9f76cfca9",
- "sha256:4be6ed964cb863823f2788717b9a6ba8f1d94eb3fa2bf1584f4621ab5e021e27",
- "sha256:6b21cf78b33554f793d409d79b828d9578d34200c86f813ef1b8dac756589b71",
- "sha256:c9606de7afaee57f2c0861cc4b973bd630556dd38ec0d1542560cba81c27ab81",
- "sha256:e67b10f96f0ac5ed24d7e3c4985d37c70550a9dee6f38b127faf5e5341151665"
- ],
- "markers": "python_version < '3.12' and python_version >= '3.7'",
- "version": "==6.5.2"
- },
- "pyzstd": {
- "hashes": [
- "sha256:00c188704141c709da96cc4a79f058d51f5318e839d6f904c7cc9badcf78e98e",
- "sha256:013321ddaff083b24e43a8b06303446771978343b488ed73adf56c70a46e2783",
- "sha256:0a4334e972109bdd17fb40dbdd9fcca6137648cab416fca505a2dcd186f50533",
- "sha256:12668ceb8329aaa908b4d907d3a77bb748ff28b309c3b105c995a8715d535d2b",
- "sha256:14121a4d95070f54bdc9a80dab1dd8fd9093907a1e687926447ca69b5b40a4d5",
- "sha256:1b9cda5314982d64c856f9298be0d9bf69fbff0ca514d1651037616354b473ff",
- "sha256:1cbf212253abd65e6451acdfb608adafe98ad8f05462fb9a054ddab816545caa",
- "sha256:1dbe76b6d8fe75f6dbec24793fc07b1d1ae9464de9941138d5b9668f7670e6b0",
- "sha256:209a92fbe892bd69cde58ffcb4861468e2c3c2d0626763e16e122bb55cb1fb1a",
- "sha256:20f2dd56d46441cd9277077060c34c0b9ce3469412665ea5ccd506dd2708d994",
- "sha256:23695dabdfd5081beab25754dc0105b42fbd2085a7c293901bcb45045969c5ec",
- "sha256:250dad90140a6faea4cef555f339b6ceaad5cf03ed1127b8d06de214ff0db2e7",
- "sha256:289e25871fe232d2482c0985a75a1faa7c92e10a6c3e3914d165f62d005d0aa6",
- "sha256:2919afd114fd12309ed2f831ef6e95730ebf13c2a92d258ad055769d00ef4d7a",
- "sha256:29e452caaf0de9cc17319225921d8c28cdc7a879948e990ff1e7735e7f976517",
- "sha256:305c232462dbe80d0ee5ec91b1b0ec9153ec6ba6393d5348741af5d30b07ef52",
- "sha256:31f60f01884350aec24e7a68f3ad089151b7a636490203c41a1a7c8e0cddd9b8",
- "sha256:3351ad2feb51dcbb936defd47cab00d6f114214f224636503ed08298f30164c9",
- "sha256:346f835e368e1051f8ea187ad9b49759cf6249c9ebf2f2a3861e435a568104b8",
- "sha256:370b34a7c2f9c53cee494028daa5a7264690e1756a89c3855fd0be5ad298ec30",
- "sha256:3a26df749589d898cd3253d2139eb85b867ddffc49286059c8bdb3cb9ce9b545",
- "sha256:3bc0e7e2cccf78e562ab416daf68448b6552a5b6450a1ff3e15cabfc19254883",
- "sha256:3f0fe2ef7ebc6e9b347585e414c4fefd32270ba8bdf9eb82496f3030cbdca465",
- "sha256:3f72f310b10b730cddfb654006ae497e7706c81e6a7642d3da7fd2439df7d88d",
- "sha256:40bdb468281a5cd525e2e990b97344f0974e0589bd1b395501c25471fcd7edda",
- "sha256:4358dd80b315c82d760b44c6df7857c9c898d04e7b0c14abb0eb3692354e9379",
- "sha256:441078bfd3b508597415338af667c3575980364f1286eedde58291558b9c2832",
- "sha256:47c2a4c319300c381f194274203f47b12c433e1fd86b90ecdc7fb258c630f93b",
- "sha256:49c57ae18f138a4b66480b2364fe6a0f2345ada919e93fc729c95c6b17ec73a4",
- "sha256:4a0dcb32ac4d1d67a77ae6a2d60ea0921af7e682b3427202d8acb8e86642391c",
- "sha256:4ed01beb31d5177456ec2c4b66591a0df83dbc72df29f05f40502bfefe47bbe4",
- "sha256:50ccbaafee80b4f1c5c55bbe07f80871b9b8fe3499bf7357dde2c23fb1c2ac0e",
- "sha256:51607d7d44f94a364ef0e3ccf9a92390def0faf6e7572eef082f15c657b5d03a",
- "sha256:5345c7a697327e2fa7c37534bb2968ea84595d8ec7fc8c4a60216ec1be6e65bd",
- "sha256:542808d88464d538f5d2c6b48b545a7fe15f0d20c7fa703b469d039a08c9fa10",
- "sha256:5819d502dacd54114c30bc24efcb76e723b93f8f528be70851056a396a792c46",
- "sha256:5aed5fc86d0bfc5f16e871cbb35ec93df61476d7fde4c1c6081015a075ecfbc1",
- "sha256:5d9ec8634ab0cbfbcff535ac07555ebdae0282ad66762f0471fad11c16181e33",
- "sha256:5fb00c706d0b59c53124f982bd84b7d46866a8ea2a7670aaaa1ab4dbe6001b50",
- "sha256:5fd7cf79949174d1018b896638f88aea1ff2a969f87a6199ea23b25b506e26c5",
- "sha256:606b2452d78f0f731566d392f8d83cd012c2ffadb2cb2e2903fdd360c1faac8a",
- "sha256:6128cb653d011f3781554b70ce1f1f388cd516820fbaf8fd03ee245ecaa48349",
- "sha256:639935b5b3d9ed3911493504581254b76cb578279302f7f340924ac5bfca4090",
- "sha256:64564f4c175c5bb8e744de5816d69ee0b940e472160a5e665f30adc412b694f3",
- "sha256:69f12ce4866a3725138e97f22f2c4cb21d3ae18cd422906cd57ed12a9ffd86c5",
- "sha256:6a60ee6836599363a24367cf780ad45446b07eba49ec72d19bad761d5414aca7",
- "sha256:6b9af8d62c087354abd071e01d9445ea51b31779c8a4a0d5c14ee12caee3d18f",
- "sha256:6c456882baab2a48a5bfabe458a557af25d0768ff29acbe200461e84c0f697d5",
- "sha256:6f281cc2f096530c339f122e0d9866545f5592dd9bffe0fade565c2771130a45",
- "sha256:73877eebbdcb8259cf0099665f8c8274d4273b361371405a611fb6bd9f4d64f6",
- "sha256:74455bd918e7bc9883e3178a1a8fe796308670f0ee4488c80a0d9514e13807a1",
- "sha256:7452ae7e6d80e697d78d3f56d1b4d2a350286eea229afb35f55ab88b934b6acd",
- "sha256:77294f0f797c97a46ffb3daff1fe097c9d5aa9f96867333978e6791286963e50",
- "sha256:7ac886e04f253960ae82e38ded8352085c61d78de99412d178a94ecf475b5e5f",
- "sha256:7c420878726d677da7484f6021dbe7e1f9345a791b155de632c6ce36678fb621",
- "sha256:836f1d85a4b5d3689d455aeb1dc6c42acb96aaf8e5282825c00ccf2545ad5630",
- "sha256:84aa6eecba967bdac167451501dcaceec548d8b8c4ca7fa41ceda4dbfc279297",
- "sha256:866ba6ce85f337fa1677516217b6f10fc25e19acb6e17a501d5822e66396bdd5",
- "sha256:86e0e65e205793b337d62d9764700dfd02b5f83b01e26ad345736e7ac0554ebd",
- "sha256:87a1a4ca93da414f3b6da8131e61aca6d48a4e837fb0b1cbde05ae9d13332317",
- "sha256:8d3a1b6fa71a0ae7abc320d9db91b5a96a71eef1dbee0d62a6232b71c97af962",
- "sha256:8f9eb97fb6fd4551ff9d5012b4fcee9abeea9c8af6b9e3ebc3c76cc2bd0a43a7",
- "sha256:91453ce9476363d777b2ea2e9c6dccecd2073cf35697e048de2e8d47e1f36c7c",
- "sha256:9596aeb8c71192f4fba1ca25cec420da195219398d2df811d5082559efd9561f",
- "sha256:960ab83a977a44284c4ffab2820ccd6c9b332571a3d622fefa4b29b0a5de72b0",
- "sha256:97e05f66c5847e6889594508298d78ddb84a0115e9234d598415dc5a06d3a4a7",
- "sha256:9ac634753f6d26cba503cea7bb5b350aec7c5366f44fa68c79e9c90be9fd0ebc",
- "sha256:9e1097d8b57f64878a3f176f4cd6b9a1bbe9fb2d236f1a85a4357722626d8f25",
- "sha256:a1b81cc86b69ff530d45e735ed479e14704999f534ad28a39f04be4a8fe2b91f",
- "sha256:a4f786f1b1ab39a0908db04ebe5b2c7cbc6f1ce07a27d3a12eb980bffd7fea7d",
- "sha256:a594795ef89bd83297c860ff585f2d25580ce9805eb9cc44c831d311e7f1951a",
- "sha256:a708b9e6ff1826504940beb6b5c2c9dfd4e3b55c16ab88a4572f5b9dbb64cc56",
- "sha256:a90b901ccfd24b028faea19c927ff03f3cfefe82ba0b931fbb8da4ef0664911b",
- "sha256:ae3d0575721a372c20130681bfaf873225fd9e1c290b7d56b7e0c14f413318f6",
- "sha256:afef9eb882cf3b395eef9c85b737a4acd09528975e6a5d9faedf28874ca65f52",
- "sha256:aff1b469187f6c789cdf17cd95c9b24e87396dc86953b1cf38b9a05cea873c80",
- "sha256:b2ae8993f3863632d31ca8921c8a5dc9ecc5551c7b88895cefb5a26d17643391",
- "sha256:b2dd39e12f7467a7422ce50711524759d4d22016714cbae6a7096b954bc2fa32",
- "sha256:b4de7741d542a477387299bf9450e8be3e768c352d6b3438254eb02af1e59462",
- "sha256:b5b517fbbc5d223fc36041673e7c2a0d3a82be6a5464a5f0599069330b76f97d",
- "sha256:bdc09de97b1b3f6c3d87fec04d6fe29dd4fefe6b354ad2d822fc369b8aa0942b",
- "sha256:c249741b10eb714578d765487b767e0e7fcc2ac84a299209a6073566e730dbea",
- "sha256:c2b093a74b10232c70b5d29814fcee6544bb6f30e2d922d26db9ab4b4cd00c04",
- "sha256:c31f6dd5bd60688d51487a3f5e2ae29ed1948926e44d7a2316b193b083f80d5d",
- "sha256:c41e5457f4de5d38a270bc44619873589bbe6fe251225deec583ed20199df0f3",
- "sha256:c46e77c2ad614a0399503dc675d72436cbf6332a20d49a0e5bad03058d6cbfad",
- "sha256:c9589cb79d4e401630481755c92b072aa7ba5505ec81dec865ef43932ec037e4",
- "sha256:ca19213785f864781848e0216cba07e97f563f60a50bbc7885b54461d8c64873",
- "sha256:cbfdde6c5768ffa5d2f14127bbc1d7c3c2d03c0ceaeb0736946197e06275ccc7",
- "sha256:cd6a8d43a0c294918e3afb7e4b1d8c04d2e4c3ea9ddf05475fdaf366c7e5b3a6",
- "sha256:cffaab46f9e04856dc3daa6097bfb3d3bea0b1771237e869c57b13f3dcc2c238",
- "sha256:d0929302d187bfeca335b7f710f774f1b2ea3f610b2a80e8a1ac2da216cd9766",
- "sha256:d44a7d4586f02b630658298c089ff755e74d0677b93c71e09d33dd35bdd4987a",
- "sha256:d7ddbf234c9adc72189bb552d830e9a0c2c4401b5baf7b003eacd5c552ddcc00",
- "sha256:dca286c6c1ca5febf13f5f2ae7e8aa7536e49bd07f4232796651a43ff741ceca",
- "sha256:dcb2172ca8b62f82af9d1f8db80c21c64c5ba3991935caefde88bb378f0afb51",
- "sha256:e4e00c1600022b47ef0e9e1f893cb0c2322209ec6c1581a3e3f63ed78330ddf0",
- "sha256:e789e19095b818f7126180b4387c0f01700c3ad2378a4e7649b2ddf4bf47ffbc",
- "sha256:e79babb67b415aa54abb213897ceaa011515a5f3e146a2a97f4e6486b9743af4",
- "sha256:e8f75e839ee253af60b03d9957182fdd069dfaebb62b4e999bd74016f4e120bb",
- "sha256:e9934277abdddf9c733267e4dcc4886de8a3302d28f390237d447e215e8ce47d",
- "sha256:ef3399e0544b46d31c2a8ff14ae1fb3c3571ae1153bbbc5ddf0d242c67bde624",
- "sha256:f169e166774587227255f6ffe71f5b3303ea73cde0e2c6d52e53b9e12c03d787",
- "sha256:f1d8b58f00137ccbe8b828a5ede92be3f0115cef75e6bed88d4d0bd1e7a0b1fc",
- "sha256:f2839c13e486e4a23b19b1d2dc4624565cec6c228bbf803c066be1106515966b",
- "sha256:f66790e4b2dcfcabc0aa54dd89317ea5671cabf06aa93cbef7cbdd4d2fdb7ee3",
- "sha256:f6d8a881b50bb2015e9bdba5edb0331e85d41ff44ab33cde551047480b98d748",
- "sha256:f7cfc683d320402d61205a196ace77f15dcfd16b5771f8b9ffaf406868c98e78",
- "sha256:f9c5fc29a5b9d61a8f0a3494172107e0e6cf23d0cb800d6285c6722ba7fc3535",
- "sha256:fc92a718bccb8ce5c9eb63fca743c38f3fa4c4e47f58f0c4ada51b2474668184"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==0.15.9"
- },
- "qt-material": {
- "hashes": [
- "sha256:b5dbb5ade97217cf7ae336bb7c047c90beb39dc7f2048a498c916ad5f2f7ae23",
- "sha256:ceddd9b3aca167e5d620644ce350c3df4c0220c5df457ab6059f634d7ac747e3"
- ],
- "index": "pypi",
- "version": "==2.14"
- },
- "requests": {
- "hashes": [
- "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
- "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
- ],
- "index": "pypi",
- "version": "==2.31.0"
- },
- "retrying": {
- "hashes": [
- "sha256:345da8c5765bd982b1d1915deb9102fd3d1f7ad16bd84a9700b85f64d24e8f3e",
- "sha256:8cc4d43cb8e1125e0ff3344e9de678fefd85db3b750b81b2240dc0183af37b35"
- ],
- "index": "pypi",
- "version": "==1.3.4"
- },
- "shiboken6": {
- "hashes": [
- "sha256:3fbc35ff3c19e7d39433671bfc1be3d7fa9d071bfdd0ffe1c2a4d27acd6cf6a5",
- "sha256:4e073b40734a7f9cc6ac289c735362967bb45c34f591f7c0fab7cef1d62e6a66",
- "sha256:558bdb3b0ccc8aac5f9029eabfd6ad8d41f93a87cd7f54395e07732fce39280d",
- "sha256:ba7af130d34ea03e329baebd80982d2635aee7e58dbb07a07085509a501ed03f",
- "sha256:cc89759aabafce49b629b189ed7c81986fedaac695714a4eed1aaeb16783c6a9",
- "sha256:e60d8dd3292e3f87662b9e37ae5c558c519f8250da627c473b68bd8d24ed3243"
- ],
- "markers": "python_version < '3.12' and python_version >= '3.7'",
- "version": "==6.5.2"
- },
- "six": {
- "hashes": [
- "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
- "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.16.0"
- },
- "texttable": {
- "hashes": [
- "sha256:290348fb67f7746931bcdfd55ac7584ecd4e5b0846ab164333f0794b121760f2",
- "sha256:b7b68139aa8a6339d2c320ca8b1dc42d13a7831a346b446cb9eb385f0c76310c"
- ],
- "version": "==1.6.7"
- },
- "urllib3": {
- "hashes": [
- "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11",
- "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==2.0.4"
- }
- },
- "develop": {
- "altgraph": {
- "hashes": [
- "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd",
- "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe"
- ],
- "version": "==0.17.3"
- },
- "astroid": {
- "hashes": [
- "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c",
- "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"
- ],
- "markers": "python_full_version >= '3.7.2'",
- "version": "==2.15.6"
- },
- "dill": {
- "hashes": [
- "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e",
- "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"
- ],
- "markers": "python_version >= '3.11'",
- "version": "==0.3.7"
- },
- "isort": {
- "hashes": [
- "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504",
- "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"
- ],
- "markers": "python_full_version >= '3.8.0'",
- "version": "==5.12.0"
- },
- "lazy-object-proxy": {
- "hashes": [
- "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382",
- "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82",
- "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9",
- "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494",
- "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46",
- "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30",
- "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63",
- "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4",
- "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae",
- "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be",
- "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701",
- "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd",
- "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006",
- "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a",
- "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586",
- "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8",
- "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821",
- "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07",
- "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b",
- "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171",
- "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b",
- "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2",
- "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7",
- "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4",
- "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8",
- "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e",
- "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f",
- "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda",
- "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4",
- "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e",
- "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671",
- "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11",
- "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455",
- "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734",
- "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb",
- "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==1.9.0"
- },
- "markdown-it-py": {
- "hashes": [
- "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1",
- "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"
- ],
- "markers": "python_full_version >= '3.8.0'",
- "version": "==3.0.0"
- },
- "mccabe": {
- "hashes": [
- "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
- "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.7.0"
- },
- "mdurl": {
- "hashes": [
- "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
- "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==0.1.2"
- },
- "platformdirs": {
- "hashes": [
- "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d",
- "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==3.10.0"
- },
- "pygments": {
- "hashes": [
- "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692",
- "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==2.16.1"
- },
- "pyinstaller": {
- "hashes": [
- "sha256:0df43697c4914285ecd333be968d2cd042ab9b2670124879ee87931d2344eaf5",
- "sha256:1fde4381155f21d6354dc450dcaa338cd8a40aaacf6bd22b987b0f3e1f96f3ee",
- "sha256:24009eba63cfdbcde6d2634e9c87f545eb67249ddf3b514e0cd3b2cdaa595828",
- "sha256:28d9742c37e9fb518444b12f8c8ab3cb4ba212d752693c34475c08009aa21ccf",
- "sha256:2d03419904d1c25c8968b0ad21da0e0f33d8d65716e29481b5bd83f7f342b0c5",
- "sha256:3a331951f9744bc2379ea5d65d36f3c828eaefe2785f15039592cdc08560b262",
- "sha256:5e446df41255e815017d96318e39f65a3eb807e74a796c7e7ff7f13b6366a2e9",
- "sha256:78975043edeb628e23a73fb3ef0a273cda50e765f1716f75212ea3e91b09dede",
- "sha256:7fdd319828de679f9c5e381eff998ee9b4164bf4457e7fca56946701cf002c3f",
- "sha256:9fc27c5a853b14a90d39c252707673c7a0efec921cd817169aff3af0fca8c127",
- "sha256:cd7d5c06f2847195a23d72ede17c60857d6f495d6f0727dc6c9bc1235f2eb79c",
- "sha256:e5fb17de6c325d3b2b4ceaeb55130ad7100a79096490e4c5b890224406fa42f4"
- ],
- "index": "pypi",
- "version": "==5.13.0"
- },
- "pyinstaller-hooks-contrib": {
- "hashes": [
- "sha256:596a72009d8692b043e0acbf5e1b476d93149900142ba01845dded91a0770cb5",
- "sha256:aa6d7d038814df6aa7bec7bdbebc7cb4c693d3398df858f6062957f0797d397b"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==2023.6"
- },
- "pylint": {
- "hashes": [
- "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413",
- "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"
- ],
- "index": "pypi",
- "version": "==2.17.5"
- },
- "rich": {
- "hashes": [
- "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808",
- "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39"
- ],
- "index": "pypi",
- "version": "==13.5.2"
- },
- "setuptools": {
- "hashes": [
- "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f",
- "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==68.0.0"
- },
- "tomlkit": {
- "hashes": [
- "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86",
- "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==0.12.1"
- },
- "wrapt": {
- "hashes": [
- "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0",
- "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420",
- "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a",
- "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c",
- "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079",
- "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923",
- "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f",
- "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1",
- "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8",
- "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86",
- "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0",
- "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364",
- "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e",
- "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c",
- "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e",
- "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c",
- "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727",
- "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff",
- "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e",
- "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29",
- "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7",
- "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72",
- "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475",
- "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a",
- "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317",
- "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2",
- "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd",
- "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640",
- "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98",
- "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248",
- "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e",
- "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d",
- "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec",
- "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1",
- "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e",
- "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9",
- "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92",
- "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb",
- "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094",
- "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46",
- "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29",
- "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd",
- "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705",
- "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8",
- "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975",
- "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb",
- "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e",
- "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b",
- "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418",
- "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019",
- "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1",
- "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba",
- "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6",
- "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2",
- "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3",
- "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7",
- "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752",
- "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416",
- "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f",
- "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1",
- "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc",
- "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145",
- "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee",
- "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a",
- "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7",
- "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b",
- "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653",
- "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0",
- "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90",
- "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29",
- "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6",
- "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034",
- "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09",
- "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559",
- "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"
- ],
- "markers": "python_version >= '3.11'",
- "version": "==1.15.0"
- }
- }
-}
diff --git a/README.md b/README.md
index a4f5819..e5ad06b 100644
--- a/README.md
+++ b/README.md
@@ -16,19 +16,15 @@
**由于作者某天实在是受不了B漫网页版的观看体验 ~~(时而混入漫画中的广告,无法便捷快速的放大图片,进度栏作死一样的反复横跳挡视线等等...)~~,再加上作者的仓鼠属性 😛**
**因此 将将将~ 🎉 一个好用的哔哩哔哩漫画下载器就此诞生!**
-
-
![](https://user-images.githubusercontent.com/72005386/222969436-a31d4d16-2d24-40ba-bb0b-06c883ba7406.png)
-
![](https://user-images.githubusercontent.com/72005386/222970947-25bad523-5fac-4a95-972e-2186b774f535.jpg)
-
## :sparkles: 主要功能 / 特性
+- **~~(白嫖)~~ 黑科技下载未解锁章节!**
- **已打包成单个可执行文件,双击即用!**
- **易操作的图形界面!~~(不用再费劲的部署环境跑命令行)~~**
- **无需漫画ID,可直接关键词搜索漫画!并附带搜索词高亮!**
-- **丰富的漫画详情信息,并提供元数据下载!**
- **可配置的多线程下载,速度拉满!**
- **实现了应对网络波动等情况的异常重试,以及应用了指数级退让来避免在短时间大量重试被拉黑名单**
-- **本地漫画管理功能,一键检查更新!**
+- **丰富的漫画详情信息,本地漫画管理功能,一键检查更新!**
- **通过正则匹配过滤重复的章节名称内容,以及过滤非法字符!**
- **提供多种可选的保存格式:**
- PDF
@@ -41,23 +37,48 @@
- **一键清空用户数据,妈妈再也不用担心我删不干净软件了!~~(bushi)~~**
- **多种主题选择**
+## 📸 相关截图
+**使用哔站解析**
+
+
![](https://github.com/Zeal-L/BiliBili-Manga-Downloader/assets/72005386/39f4e66f-50f1-410b-8761-971eeb9cf30e)
+
+
+**使用BiliPlus解析**
+
+
![](https://github.com/Zeal-L/BiliBili-Manga-Downloader/assets/72005386/4686f08b-2e88-4070-8d90-661c0a4392b6)
+
+
+**下载进度界面**
+
+
![](https://github.com/Zeal-L/BiliBili-Manga-Downloader/assets/72005386/9c99e3c8-4283-4b0d-a5cd-23dab08b78b6)
+
+
## 📝 使用指南
-- **本软件的正式版只能下载免费章节和用户已解锁的章节**
- - 不过呢有需要的可以尝试预发布版本 (~~黑科技~~实验性功能) 详情请见 [v1.2.0-alpha](https://github.com/BiliBili-Manga-Downloader-Dev-Team/BiliBili-Manga-Downloader/releases/tag/v1.2.0-alpha)
+- **本软件有两种下载解析方法:**
+ - **B站解析**
+ - 只能下载免费章节和用户已解锁的章节
+ - **首先获得你的Cookie**
+ - 方法一 - B漫手机客户端扫码登入
+ - 方法二 - 手动获取Cookie:
+ 1. 以谷歌浏览器为例,打开B漫首页并且登入
+ 2. 点击 `F12` 打开开发者工具
+ 3. 点击 `应用` 标签
+ 4. 在边栏中找到 `Cookie` ,点击 `https://manga.bilibili.com`
+ 5. 在右侧的详情中找到 `SESSDATA`,复制 `值` 粘贴到程序设置选项中的 `我的Cookie` ,回车确认
+ 6. 如果提示 `Cookie有效!` 那么就成功了!
+ 7. 否则请再次确认上述步骤,检查是否正确复制内容不含空格,还有疑问的话欢迎联系作者或提 `Issues`
+ - **BiliPlus解析**
+ - 利用 [biliplus](https://www.biliplus.com/) 提供的 [ComicWebReader](https://www.biliplus.com/manga/) 在线漫画平台的api来尝试获取未解锁的漫画章节
+ - 该网站现有 4w+ 已关联 `Bilibili` 帐号的访客,也就是说很有概率你想看的漫画已经有人购买了,所以你可以白嫖
+ - **特别提示: 毕竟是要提供 Cookie 给第三方网站托管,因此可能会有潜在的安全风险。敏感人群请不要使用自己主账号的 Cookie**
+ - `BiliPlus` 的 `Cookie` 获取方法跟上述一致,在 [ComicWebReader](https://www.biliplus.com/manga/) 登入后在开发者工具中找到 `access_key` 粘贴到程序设置选项中的 `BiliPlus Cookie` 即可
+
- **兼容性:目前只在64位的Winodw 10上测试通过,不过其他>=windows 10的版本应该都能运行,发现问题的欢迎提Issues**
-- **首先获得你的Cookie**
- 1. 以谷歌浏览器为例,打开B漫首页并且登入
- 2. 点击顶部地址栏左侧的🔒图标
- 3. 点击Cookie选项
- 4. 在弹出的界面中依次展开"bilibili.com" -> "Cookie"
- 5. 找到"SESSDATA"值,复制"内容"粘贴到程序设置选项中的"我的Cookie",回车确认
- 6. 如果提示"Cookie有效!"那么就成功了!
- 7. 否则请再次确认上述步骤,检查是否正确复制内容不含空格,还有疑问的话欢迎联系作者或提Issues
- **搜索 / 选择章节 / 下载 的功能介绍我想已经不言而喻了,这就是图形化界面的好处!**
- **值得注意的是:本软件不支持断点续传和下载任务缓存的功能 ~~(毕竟一章漫画太小了,好像也没什么必要,断了不如重下)~~,所以请确保不要在下载中途关闭!**
- 如果程序意外中断,可以选择把下了一半的文件都删掉(一般在目标漫画文件夹的根目录下),重新下载
- **程序缓存和日志历史文件存在 `C:\Users\AppData\Roaming\BiliBili-Manga-Downloader\` 目录下,可以通过"清空用户数据"功能一键删除**
-- **如果想用"本地库存"功能,需要注意的是:下载好的漫画的文件夹名以及章节名都不能更改,否则将会无法正确读取漫画数据**
+- **如果想用"本地库存"功能,需要注意的是:下载好的漫画章节名以及保存的 `元数据.json` 都不能更改,否则将会无法正确读取漫画数据**
- **🔥 下面我要隆重的推荐一款搭配本软件使用的漫画浏览器 ~~(可以说就是为了这点儿醋 我才包的这顿饺子)~~**
-
- **NeeView** 是一款 Windows 下开源的图片浏览器,其特色是可以像翻书一样同时浏览两张照片,还支持压缩包看图、鼠标手势、触摸操作、多线程和超前查看、支持 PDF / 视频。 原生支持中文
@@ -73,11 +94,11 @@
## 💡 TODO List ~~(在可见的未来...)~~
- **PS: 也欢迎小伙伴们多多的在Issues里提意见,不管是Bug还是操作逻辑,界面优化等等作者统统笑纳~**
- 🟦 缓存更多资源,减少网络请求
- - 🟦 添加二维码扫码登入功能
- 🟦 添加一个启动程序加载进度条
- 🟦 添加我的追漫界面,以及追漫功能
- 🟦 对于有特典的漫画,提供特典下载界面
- **已解决**
+ - ✅ ~~添加二维码扫码登入功能~~
- ✅ ~~添加不同的界面主题~~
- ✅ ~~添加检测cookie无效或者过期功能,并且弹窗~~
- ✅ ~~鼠标移动到漫画封面改变鼠标图标,提示用户可以点击跳转~~
@@ -103,9 +124,8 @@
2. 这一步可能会花费一定时间,中途需要手动确认安全漏洞检查
2. 打包好的程序会被移动到项目的根目录 "哔哩哔哩漫画下载器.exe"
- **彻底清除项目 ~~(删库跑路)~~**
- 1. 执行 `pipenv uninstall --all`
- 2. 执行 `pipenv --rm `
- 3. 执行 `cd .. && rm -rf BiliBili-Manga-Downloader/`
+ 1. 执行 `pipenv --rm `
+ 2. 执行 `cd .. && rm -rf BiliBili-Manga-Downloader/`
## 🔨 PR 格式
- 遵循项目已有代码的 python doc 格式
@@ -118,10 +138,21 @@
## ⚰️ 更新记录
-![Alt](https://repobeats.axiom.co/api/embed/da4fa229ddede4560beefbe2dee47490257186e5.svg "Repobeats analytics image")
-### v1.2.0-alpha - *2022-07-4*
-- 非生产准备就绪的实验性版本
-- 新增功能: 利用 [biliplus](https://www.biliplus.com/) 提供的 [ComicWebReader](https://www.biliplus.com/manga/) 在线漫画平台的api来尝试获取未解锁的漫画章节
+![Alt](https://repobeats.axiom.co/api/embed/cc62fded834eb06fc9b30cf7ffd54eeb53d700fc.svg "Repobeats analytics image")
+
+### v1.3.0 - *2022-08-11*
+- 新增功能:
+ - 二维码登入
+ - 利用 [biliplus](https://www.biliplus.com/) 提供的 [ComicWebReader](https://www.biliplus.com/manga/) 在线漫画平台的api来尝试获取未解锁的漫画章节
+- 优化配置: 移除保存文件夹名里的漫画ID信息;元数据现在默认保存,并且以此来初始化我的库存
+ - 老用户需要重新下载一章漫画,然后把以前下载好的移动到新文件夹中
+- 修复bug:
+ - 修复个别`png`保存为`jpg`的情况
+ - 修复`BiliPlus Cookie`检测可能出现的隐藏`bug` ([#61][i61])
+ - 修复`BiliPlus`可以看未解锁的漫画章节,软件无法下载 ([#52][i52])
+
+[i52]: https://github.com/Zeal-L/BiliBili-Manga-Downloader/issues/52
+[i61]: https://github.com/Zeal-L/BiliBili-Manga-Downloader/issues/61
### v1.2.0 - *2022-06-20*
- 新增功能: 现在可以一键保存漫画的元数据了,包括漫画封面,漫画信息, 等等 (json格式) ([#39][i39])
@@ -129,6 +160,7 @@
[i39]: https://github.com/Zeal-L/BiliBili-Manga-Downloader/issues/39
+
### v1.1.0 - *2022-05-19*
- 新增功能: 添加了多种主题选择
- 新增功能: 一键检查软件更新
diff --git a/setup.sh b/setup.sh
index 0ec5c3e..f9e54bd 100644
--- a/setup.sh
+++ b/setup.sh
@@ -12,10 +12,12 @@ echo -e "\033[34m\n 重新编译UI文件 ... \n\033[0m"
pipenv run pyside6-rcc src/ui/PySide_src/resource.qrc -o src/ui/PySide_src/resource_rc.py
pipenv run pyside6-uic src/ui/PySide_src/mainWindow.ui -o src/ui/PySide_src/mainWindow_ui.py
pipenv run pyside6-uic src/ui/PySide_src/myAbout.ui -o src/ui/PySide_src/myAbout_ui.py
+pipenv run pyside6-uic src/ui/PySide_src/qrCode.ui -o src/ui/PySide_src/qrCode_ui.py
echo -e "\033[34m\n 修复UI文件中的导入问题 ... \n\033[0m"
sed -i 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/mainWindow_ui.py
sed -i 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/myAbout_ui.py
+sed -i 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/qrCode_ui.py
echo -e "\033[34m\n 显示项目目录 ... \n\033[0m"
pipenv run pipenv --where
diff --git a/src/BiliPlus.py b/src/BiliPlus.py
new file mode 100644
index 0000000..b715ddf
--- /dev/null
+++ b/src/BiliPlus.py
@@ -0,0 +1,223 @@
+from __future__ import annotations
+
+import typing
+
+import requests
+from retrying import retry
+from bs4 import BeautifulSoup
+
+from src.Comic import Comic
+from src.Episode import Episode
+from src.utils import logger, MAX_RETRY_SMALL, RETRY_WAIT_EX, TIMEOUT_SMALL
+
+if typing.TYPE_CHECKING:
+ from ui.MainGUI import MainGUI
+
+
+class BiliPlusComic(Comic):
+ """BiliPlus 单本漫画 综合信息类"""
+
+ def __init__(self, comic_id: int, mainGUI: MainGUI) -> None:
+ super().__init__(comic_id, mainGUI)
+ self.access_key = mainGUI.getConfig("biliplus_cookie")
+ self.headers = {
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
+ "cookie": f"manga_pic_format=jpg-full;login=2;access_key={self.access_key}",
+ }
+
+ ############################################################
+ def getEpisodesInfo(self) -> list[Episode]:
+ """获取章节信息,但是得到的解锁章节和资源是BiliPlus的数据
+
+ Returns:
+ list: 章节信息列表
+ """
+ if self.episodes:
+ return self.episodes
+ if not self.data:
+ return []
+
+ # ?###########################################################
+ # ? 解析章节
+ ep_list = self.data["ep_list"]
+ for episode in reversed(ep_list):
+ epi = BiliPlusEpisode(
+ episode,
+ self.sessdata,
+ self.headers,
+ self.comic_id,
+ self.data,
+ self.mainGUI,
+ )
+ self.episodes.append(epi)
+ if epi.isDownloaded():
+ self.num_downloaded += 1
+
+ self.retrieveAvailableEpisode(self.episodes, self.comic_id, self.mainGUI)
+
+ return self.episodes
+
+ ############################################################
+ def retrieveAvailableEpisode(
+ self, episodes: list[BiliPlusEpisode], comic_id: str, mainGUI: MainGUI
+ ):
+ """从BiliPlus重新获取解锁状态"""
+ biliplus_detail_url = (
+ f"https://www.biliplus.com/manga/?act=detail_preview&mangaid={comic_id}"
+ )
+ biliplus_html = ""
+
+ @retry(
+ stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
+ )
+ def _(url: str = biliplus_detail_url) -> dict:
+ try:
+ res = requests.post(
+ url,
+ headers=self.headers,
+ timeout=TIMEOUT_SMALL,
+ )
+ except requests.RequestException as e:
+ logger.warning(f"漫画id:{self.comic_id} 在BiliPlus获取漫画信息失败! 重试中...\n{e}")
+ raise e
+ if "未登录" in res.text:
+ mainGUI.message_box.emit("请先在设置界面填写正确的BiliPlus Cookie!")
+ return
+ if res.status_code != 200:
+ logger.warning(
+ f"漫画id:{self.comic_id} 在BiliPlus爬取漫画信息失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
+ )
+ raise requests.HTTPError()
+ return res.text
+
+ try:
+ biliplus_html = _()
+ except requests.RequestException as e:
+ logger.error(f"漫画id:{self.comic_id} 在BiliPlus重复获取漫画信息多次后失败!\n{e}")
+ logger.exception(e)
+
+ # ?###########################################################
+ # ? 解析BiliPlus解锁章节信息
+ try:
+ document = BeautifulSoup(biliplus_html, "html.parser")
+ ep_items = document.find_all("div", {"class": "episode-item"})
+ ep_available = []
+ for ep in ep_items:
+ if ep.img["src"] != "about:blank":
+ ep_available.append(ep.a["href"].split("epid=")[1])
+ total_ep_element = document.select_one("center p")
+ if total_ep_element:
+ total_ep = total_ep_element.contents[0].split("/")[1]
+ total_pages = int(int(total_ep) / 200) + 1
+ for pages in range(2, total_pages + 1):
+ mainGUI.resolve_status.emit(f"正在解析漫画章节({pages}/{total_pages})...")
+ page_html = _(f"{biliplus_detail_url}&page={pages}")
+ document = BeautifulSoup(page_html, "html.parser")
+ ep_items = document.find_all("div", {"class": "episode-item"})
+ for ep in ep_items:
+ if ep.img["src"] != "about:blank":
+ ep_available.append(ep.a["href"].split("epid=")[1])
+ for ep in episodes:
+ if str(ep.id) in ep_available:
+ ep.available = True
+ except Exception as e:
+ logger.error(f"漫画id:{self.comic_id} 在处理BiliPlus解锁章节数据时失败!\n{e}")
+ logger.exception(e)
+ mainGUI.message_box.emit(
+ f"漫画id:{self.comic_id} 在处理BiliPlus解锁章节数据时失败!\n\n更多详细信息请查看日志文件, 或联系开发者!"
+ )
+
+
+############################################################
+class BiliPlusEpisode(Episode):
+ """BiliPlus漫画章节类,用于管理漫画章节的详细信息"""
+
+ def __init__(
+ self,
+ episode: dict,
+ sessData: str,
+ headers: str,
+ comic_id: str,
+ comic_info: dict,
+ mainGUI: MainGUI,
+ ) -> None:
+ super().__init__(episode, sessData, comic_id, comic_info, mainGUI)
+ self.headers = headers
+ self.comic_id = comic_id
+
+ ############################################################
+ def init_imgsList(self, mainGUI: MainGUI) -> bool:
+ """重写用于初始化从BiliPlus获取的章节内所有图片的列表(自带token)
+
+ Returns
+ bool: 是否初始化成功
+ """
+ # ?###########################################################
+ # ? 获取图片列表
+ biliplus_img_url = f"https://www.biliplus.com/manga/?act=read&mangaid={self.comic_id}&epid={self.id}"
+ biliplus_html = ""
+
+ @retry(
+ stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
+ )
+ def _() -> list[dict]:
+ try:
+ res = requests.post(
+ biliplus_img_url,
+ headers=self.headers,
+ timeout=TIMEOUT_SMALL,
+ )
+ except requests.RequestException as e:
+ logger.warning(
+ f"《{self.comic_name}》章节:{self.title},从BiliPlus获取图片列表失败! 重试中...\n{e}"
+ )
+ raise e
+ if res.status_code != 200:
+ logger.warning(
+ f"《{self.comic_name}》章节:{self.title} 从BiliPlus获取图片列表失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
+ )
+ raise requests.HTTPError()
+ return res.text
+
+ try:
+ biliplus_html = _()
+ except requests.RequestException as e:
+ logger.error(
+ f"《{self.comic_name}》章节:{self.title} 从BiliPlus重复获取图片列表多次后失败!,跳过!\n{e}"
+ )
+ logger.exception(e)
+ mainGUI.message_box.emit(
+ f"《{self.comic_name}》章节:{self.title} 从BiliPlus重复获取图片列表多次后失败!\n已暂时跳过此章节!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件, 或联系开发者!"
+ )
+ return False
+
+ # ?###########################################################
+ # ? 解析BiliPlus解锁章节图片地址
+ try:
+ biliplus_imgs_token = []
+ document = BeautifulSoup(biliplus_html, "html.parser")
+ images = document.find_all("img", {"class": "comic-single"})
+ for img in images:
+ img_url = img["_src"]
+ url, token = img_url.split("?token=")
+ biliplus_imgs_token.append({"url": url, "token": token})
+ self.imgs_token = biliplus_imgs_token
+ if not biliplus_imgs_token:
+ logger.error(
+ f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus地址时因Cookie有误导致失败!"
+ )
+ mainGUI.message_box.emit(
+ f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus解锁章节图片地址时因Cookie有误导致失败!"
+ )
+ return False
+ except Exception as e:
+ logger.error(
+ f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus解锁章节图片地址时失败!\n{e}"
+ )
+ logger.exception(e)
+ mainGUI.message_box.emit(
+ f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus解锁章节图片地址时失败!\n\n更多详细信息请查看日志文件, 或联系开发者!"
+ )
+ return False
+
+ return True
diff --git a/src/BiliQrCode.py b/src/BiliQrCode.py
new file mode 100644
index 0000000..0d789d1
--- /dev/null
+++ b/src/BiliQrCode.py
@@ -0,0 +1,134 @@
+from __future__ import annotations
+import io
+import time
+
+import typing
+
+import requests
+import qrcode
+from retrying import retry
+from PySide6.QtCore import SignalInstance
+from PySide6.QtWidgets import QMessageBox
+
+from src.utils import logger, MAX_RETRY_SMALL, RETRY_WAIT_EX, TIMEOUT_SMALL
+
+if typing.TYPE_CHECKING:
+ from ui.MainGUI import MainGUI
+
+
+class QrCode:
+ def __init__(self, mainGUI: MainGUI) -> None:
+ self.mainGUI = mainGUI
+ self.generate_url = (
+ "https://passport.bilibili.com/x/passport-login/web/qrcode/generate"
+ )
+ self.poll_url = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll"
+ self.code_url = None
+ self.qrcode_key = None
+ self.close_flag = False
+
+ def generate(self) -> str | None:
+ """生成登入二维码
+
+ Returns:
+ str: 二维码内容, 二维码图片
+
+ """
+
+ @retry(
+ stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
+ )
+ def _() -> dict:
+ try:
+ res = requests.get(self.generate_url, timeout=TIMEOUT_SMALL)
+ except requests.RequestException as e:
+ logger.warning(f"获取登入二维码失败! 重试中...\n {e}")
+ raise e
+ if res.status_code != 200:
+ logger.warning(
+ f"获取登入二维码失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
+ )
+ raise requests.HTTPError()
+ return res.json()["data"]
+
+ try:
+ data = _()
+ self.code_url = data["url"]
+ self.qrcode_key = data["qrcode_key"]
+ except requests.RequestException as e:
+ logger.error(f"重复获取登入二维码多次后失败! {e}")
+ logger.exception(e)
+ QMessageBox.warning(
+ self.mainGUI, "警告", "重复获取登入二维码多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件"
+ )
+ return None
+
+ img = qrcode.make(self.code_url)
+
+ image_bytes = io.BytesIO()
+ img.save(image_bytes, format="PNG")
+ image_bytes = image_bytes.getvalue()
+
+ return image_bytes
+
+ def confirm(self) -> dict | None:
+ """确认登入
+
+ Returns:
+ str: SESSDATA cookie
+ """
+
+ @retry(
+ stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
+ )
+ def _() -> dict:
+ try:
+ res = requests.get(
+ self.poll_url,
+ params={
+ "qrcode_key": self.qrcode_key,
+ },
+ timeout=TIMEOUT_SMALL,
+ )
+ except requests.RequestException as e:
+ logger.warning(f"确认二维码登入失败! 重试中...\n {e}")
+ raise e
+ if res.status_code != 200:
+ logger.warning(
+ f"确认二维码登入失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
+ )
+ raise requests.HTTPError()
+ return res.json()["data"]
+
+ try:
+ data = _()
+ except requests.RequestException as e:
+ logger.error(f"重复确认登入多次后失败! {e}")
+ logger.exception(e)
+ QMessageBox.warning(
+ self.mainGUI, "警告", "重复确认登入多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件"
+ )
+ return None
+
+ return data
+
+ def get_cookie(self, qr_res: SignalInstance) -> None:
+ """获取cookie
+
+ Args:
+ qr_res (SignalInstance): 信号槽,用于传递二维码扫描结果
+
+ """
+
+ while not self.close_flag:
+ data = self.confirm()
+
+ # 扫码登录成功或者二维码过期或者请求失败
+ if data["code"] in [0, 86038] or data is None:
+ qr_res.emit(data)
+ break
+
+ qr_res.emit(data)
+
+ # 每隔1秒确认一次
+ time.sleep(1)
diff --git a/src/Comic.py b/src/Comic.py
index 0abcb28..0b6c275 100644
--- a/src/Comic.py
+++ b/src/Comic.py
@@ -3,11 +3,17 @@
import typing
import requests
-from retrying import retry
+from retrying import RetryError, retry
import re
from src.Episode import Episode
-from src.utils import logger, MAX_RETRY_SMALL, RETRY_WAIT_EX, TIMEOUT_SMALL
+from src.utils import (
+ logger,
+ MAX_RETRY_SMALL,
+ RETRY_WAIT_EX,
+ TIMEOUT_SMALL,
+ isCheckSumValid,
+)
if typing.TYPE_CHECKING:
from ui.MainGUI import MainGUI
@@ -82,10 +88,51 @@ def _() -> dict:
self.data["styles"] = ",".join(self.data["styles"])
self.data[
"save_path"
- ] = f"{self.save_path}/《{self.data['title']}》 作者:{self.data['author_name']} ID-{self.comic_id}"
+ ] = f"{self.save_path}/《{self.data['title']}》 作者:{self.data['author_name']}"
return self.data
+ ############################################################
+ def getComicCover(self, data: dict) -> int:
+ """获取漫画封面图片
+
+ Returns:
+ QPixmap: 漫画封面图片
+ """
+
+ @retry(
+ stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
+ )
+ def _() -> bytes:
+ try:
+ res = requests.get(data["vertical_cover"], timeout=TIMEOUT_SMALL)
+ except requests.RequestException() as e:
+ logger.warning(f"获取封面图片失败! 重试中...\n{e}")
+ raise e
+ if res.status_code != 200:
+ logger.warning(
+ f"获取封面图片失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
+ )
+ raise requests.HTTPError()
+ isValid, md5 = isCheckSumValid(res.headers["Etag"], res.content)
+ if not isValid:
+ logger.warning(
+ f"图片内容 Checksum 不正确! 重试中...\n\t{res.headers['Etag']} ≠ {md5}"
+ )
+ raise requests.HTTPError()
+ return res.content
+
+ logger.info(f"获取《{data['title']}》的封面图片中...")
+ try:
+ img = _()
+ return img
+ except RetryError as e:
+ logger.error(f"获取封面图片多次后失败,跳过!\n{e}")
+ self.mainGUI.message_box.emit(
+ f"获取封面图片多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件, 或联系开发者!"
+ )
+ return open(":/imgs/fail_img.jpg")
+
############################################################
def getEpisodesInfo(self) -> list[Episode]:
"""获取章节信息
diff --git a/src/Episode.py b/src/Episode.py
index 4fe1fb7..55fce47 100644
--- a/src/Episode.py
+++ b/src/Episode.py
@@ -1,12 +1,12 @@
from __future__ import annotations
-import hashlib
import json
import os
import re
import shutil
import typing
+
import piexif
import requests
from PIL import Image
@@ -25,6 +25,7 @@
__copyright__,
__version__,
logger,
+ isCheckSumValid,
)
if typing.TYPE_CHECKING:
@@ -301,6 +302,7 @@ def _():
append_images=temp_imgs[1:],
quality=95,
)
+
# 在pdf文件属性中记录章节标题作者和软件版本以及版权信息
with open(self.epi_path_pdf, "rb") as f:
pdf = PdfReader(f)
@@ -342,24 +344,30 @@ def saveToFolder(self, mainGUI: MainGUI, imgs_path: list[str]) -> None:
def _():
try:
for index, path in enumerate(imgs_path, start=1):
- # 在图片文件属性中记录章节标题作者和软件版本以及版权信息
- info = {}
- info[
- piexif.ImageIFD.ImageDescription
- ] = f"《{self.comic_name}》 - {self.title}".encode("utf-8")
- info[piexif.ImageIFD.Artist] = self.author.encode("utf-8")
- info[
- piexif.ImageIFD.Software
- ] = f"{__app_name__} {__version__}".encode("utf-8")
- info[piexif.ImageIFD.Copyright] = __copyright__.encode("utf-8")
- exif_bytes = piexif.dump({"0th": info})
+
+ def jpg_exif():
+ # 在jpg文件属性中记录章节标题作者和软件版本以及版权信息
+ exif_data = {
+ "0th": {
+ piexif.ImageIFD.ImageDescription: f"《{self.comic_name}》 - {self.title}".encode(
+ "utf-8"
+ ),
+ piexif.ImageIFD.Artist: self.author.encode("utf-8"),
+ piexif.ImageIFD.Software: f"{__app_name__} {__version__}".encode(
+ "utf-8"
+ ),
+ piexif.ImageIFD.Copyright: __copyright__,
+ }
+ }
+ exif_bytes = piexif.dump(exif_data)
+ piexif.insert(exif_bytes, path)
+
+ img_format = path.split(".")[-1]
# 将 exif 数据插入到图像文件中, 如果插入失败则跳过
try:
- piexif.insert(
- exif_bytes,
- path,
- )
+ if img_format == "jpg":
+ jpg_exif()
except piexif.InvalidImageDataError as e:
logger.warning(f"Failed to insert exif data for {path}: {e}")
logger.exception(e)
@@ -368,7 +376,7 @@ def _():
shutil.copy2(
path,
os.path.join(
- self.epi_path_folder, f"{str(index).zfill(3)}.jpg"
+ self.epi_path_folder, f"{str(index).zfill(3)}.{img_format}"
),
)
@@ -458,9 +466,10 @@ def _() -> bytes:
f"《{self.comic_name}》章节:{self.title} - {index} - {img_url} 获取图片 header 失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
)
raise requests.HTTPError()
- if res.headers["Etag"] != hashlib.md5(res.content).hexdigest():
+ isValid, md5 = isCheckSumValid(res.headers["Etag"], res.content)
+ if not isValid:
logger.warning(
- f"《{self.comic_name}》章节:{self.title} - {index} - {img_url} - 下载内容Checksum不正确! 重试中...\n\t{res.headers['Etag']} ≠ {hashlib.md5(res.content).hexdigest()}"
+ f"《{self.comic_name}》章节:{self.title} - {index} - {img_url} - 下载内容Checksum不正确! 重试中...\n\t{res.headers['Etag']} ≠ {md5}"
)
raise requests.HTTPError()
return res.content
@@ -479,7 +488,8 @@ def _() -> bytes:
# ?###########################################################
# ? 保存图片
- path_to_save = os.path.join(self.save_path, f"{self.ord}_{index}.jpg")
+ img_format = img_url.split(".")[-1].split("?")[0].lower()
+ path_to_save = os.path.join(self.save_path, f"{self.ord}_{index}.{img_format}")
@retry(stop_max_attempt_number=5)
def _() -> None:
diff --git a/src/ui/DownloadUI.py b/src/ui/DownloadUI.py
index 0a2740b..23092b8 100644
--- a/src/ui/DownloadUI.py
+++ b/src/ui/DownloadUI.py
@@ -1,5 +1,6 @@
from __future__ import annotations
+import json
import os
from concurrent.futures import ThreadPoolExecutor
from typing import TYPE_CHECKING
@@ -110,31 +111,27 @@ def addFinished(self, mainGUI: MainGUI, label_title: QWidget, path: str) -> None
"""
# ?###########################################################
# ? 添加到已完成列表
- h_layout_donwlowd_list = QHBoxLayout()
- h_layout_donwlowd_list.addWidget(label_title)
- h_layout_donwlowd_list.addStretch(1)
+ h_layout_download_list = QHBoxLayout()
+ h_layout_download_list.addWidget(label_title)
+ h_layout_download_list.addStretch(1)
# ?###########################################################
# ? 超链接打开保存路径
label_file_path = QLabel("打开文件夹")
label_file_path.linkActivated.connect(lambda: openFolderAndSelectItems(path))
- h_layout_donwlowd_list.addWidget(label_file_path)
+ h_layout_download_list.addWidget(label_file_path)
widget = QWidget()
- widget.setLayout(h_layout_donwlowd_list)
+ widget.setLayout(h_layout_download_list)
mainGUI.verticalLayout_finished.addWidget(widget)
############################################################
def addTask(self, mainGUI: MainGUI, epi: Episode) -> None:
- """添加下载任务
+ """添加漫画下载任务
Args:
epi (Episode): 漫画章节类实例
"""
- # ?###########################################################
- # ? 初始化储存文件夹
- if not os.path.exists(epi.save_path):
- os.makedirs(epi.save_path)
# ?###########################################################
# ? 创建任务
@@ -149,8 +146,8 @@ def addTask(self, mainGUI: MainGUI, epi: Episode) -> None:
# ?###########################################################
# ? 添加任务组件到正在下载列表
- h_layout_donwlowd_list = QHBoxLayout()
- h_layout_donwlowd_list.addWidget(
+ h_layout_download_list = QHBoxLayout()
+ h_layout_download_list.addWidget(
QLabel(
f"{epi.comic_name} > {epi.title}"
)
@@ -159,11 +156,11 @@ def addTask(self, mainGUI: MainGUI, epi: Episode) -> None:
bar.setTextVisible(True)
self.all_tasks[task_id]["bar"] = bar
- h_layout_donwlowd_list.addWidget(bar)
- h_layout_donwlowd_list.setStretch(0, 1)
- h_layout_donwlowd_list.setStretch(1, 1)
+ h_layout_download_list.addWidget(bar)
+ h_layout_download_list.setStretch(0, 1)
+ h_layout_download_list.setStretch(1, 1)
widget = QWidget()
widget.setObjectName(task_id)
- widget.setLayout(h_layout_donwlowd_list)
+ widget.setLayout(h_layout_download_list)
mainGUI.verticalLayout_processing.addWidget(widget)
self.id_count += 1
diff --git a/src/ui/MainGUI.py b/src/ui/MainGUI.py
index 95cda35..f6b79d7 100644
--- a/src/ui/MainGUI.py
+++ b/src/ui/MainGUI.py
@@ -20,8 +20,9 @@ class MainGUI(QMainWindow, Ui_MainWindow, QtStyleTools):
# ? 主要是为了 Episode 类里面的提示框准备的,
# ? 因为 Episode 类是在另一个线程里面运行的,而只有主线程才能修改 GUI
message_box = Signal(str)
- # ? 用于多线程更新我的库存
- my_library_add_widget = Signal(dict)
+
+ # ? 用于多线程报告程序详情
+ resolve_status = Signal(str)
def __init__(self, app):
super().__init__()
@@ -30,6 +31,9 @@ def __init__(self, app):
self.setWindowTitle(f"哔哩哔哩漫画下载器 v{__version__}")
self.setFont(QFont("Microsoft YaHei", 10))
self.message_box.connect(lambda msg: QMessageBox.warning(None, "警告", msg))
+ self.resolve_status.connect(
+ lambda status: self.label_resolve_status.setText(status)
+ )
logger.info("\n\n\t\t\t------------------- 程序启动,初始化主窗口 -------------------\n")
diff --git a/src/ui/MangaUI.py b/src/ui/MangaUI.py
index 81cde91..e105c20 100644
--- a/src/ui/MangaUI.py
+++ b/src/ui/MangaUI.py
@@ -4,13 +4,11 @@
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
from functools import partial
-from hashlib import md5
-from re import search, sub
+from re import sub
from typing import TYPE_CHECKING
-import requests
from pypinyin import lazy_pinyin
-from PySide6.QtCore import QEvent, QPoint, QSize, Qt, QUrl
+from PySide6.QtCore import QObject, QEvent, QPoint, QSize, Qt, QUrl, Signal
from PySide6.QtGui import QColor, QDesktopServices, QImage, QPixmap
from PySide6.QtWidgets import (
QHBoxLayout,
@@ -20,25 +18,43 @@
QMessageBox,
QWidget,
)
-from retrying import RetryError, retry
from src.Comic import Comic
+from src.BiliPlus import BiliPlusComic
from src.searchComic import SearchComic
-from src.utils import MAX_RETRY_SMALL, RETRY_WAIT_EX, TIMEOUT_SMALL, logger
+from src.utils import logger
if TYPE_CHECKING:
from src.ui.MainGUI import MainGUI
-class MangaUI:
+class MangaUI(QObject):
+ """漫画UI类,用于搜索、下载、管理漫画"""
+
+ # ?###########################################################
+ # ? 用于多线程更新我的库存
+ my_library_add_widget = Signal(dict)
+
+ # ? 用于多线程更新漫画详情
+ my_comic_detail_widget = Signal(dict)
+
+ # ? 用于多线程更新封面图
+ my_cover_update_widget = Signal(dict)
+
+ # ? 用于多线程刷新漫画章节列表
+ my_comic_list_widget = Signal(dict)
+
def __init__(self, mainGUI: MainGUI):
+ super().__init__()
self.search_info = None
self.num_selected = 0
self.epi_list = None
+ self.present_comic_id = 0
self.init_mangaSearch(mainGUI)
self.init_mangaDetails(mainGUI)
self.init_myLibrary(mainGUI)
self.init_episodesDetails(mainGUI)
+ self.executor = ThreadPoolExecutor()
############################################################
@@ -87,21 +103,45 @@ def _() -> None:
############################################################
def init_mangaDetails(self, mainGUI: MainGUI) -> None:
- """绑定双击显示漫画详情事件
+ """绑定漫画详情点击事件
Args:
mainGUI (MainGUI): 主窗口类实例
"""
+ # ?###########################################################
+ # ? 双击获取选中漫画详情绑定
def _(item: QListWidgetItem) -> None:
index = mainGUI.listWidget_manga_search.indexFromItem(item).row()
- comic = Comic(self.search_info[index]["id"], mainGUI)
- self.updateComicInfo(mainGUI, comic)
+ self.present_comic_id = self.search_info[index]["id"]
+ self.resolveEnable(mainGUI, "resolving")
+ comic = Comic(self.present_comic_id, mainGUI)
+ self.updateComicInfoEvent(mainGUI, comic, "bilibili")
mainGUI.listWidget_manga_search.itemDoubleClicked.connect(_)
+
+ # ?###########################################################
+ # ? 单击修改当前选择id绑定
+ def _(item: QListWidgetItem) -> None:
+ index = mainGUI.listWidget_manga_search.indexFromItem(item).row()
+ self.present_comic_id = self.search_info[index]["id"]
+
+ mainGUI.listWidget_manga_search.itemClicked.connect(_)
# 鼠标移动到图片上的时候更改鼠标样式, 提示用户可以用鼠标点击
mainGUI.label_manga_image.setCursor(Qt.PointingHandCursor)
+ # ?###########################################################
+ # ? 漫画封面图更新触发函数绑定
+ self.my_cover_update_widget.connect(self.updateComicCover)
+
+ # ?###########################################################
+ # ? 漫画解析触发函数绑定
+ self.my_comic_detail_widget.connect(self.updateComicInfo)
+
+ # ?###########################################################
+ # ? 漫画章节列表更新触发函数绑定
+ self.my_comic_list_widget.connect(self.updateComicList)
+
############################################################
def init_myLibrary(self, mainGUI: MainGUI) -> None:
"""绑定更新我的库存事件
@@ -111,7 +151,7 @@ def init_myLibrary(self, mainGUI: MainGUI) -> None:
"""
# 布局对齐
mainGUI.v_Layout_myLibrary.setAlignment(Qt.AlignTop)
- mainGUI.my_library_add_widget.connect(self.updateMyLibrarySingleAdd)
+ self.my_library_add_widget.connect(self.updateMyLibrarySingleAdd)
if mainGUI.getConfig("cookie"):
self.updateMyLibrary(mainGUI)
@@ -151,11 +191,15 @@ def updateMyLibrary(self, mainGUI: MainGUI) -> bool:
if os.path.exists(path):
for item in os.listdir(path):
- if search(r"ID-\d+", item):
- my_library[int(search(r"ID-(\d+)", item)[1])] = {
- "comic_name": search(r"(《.*》)", item)[1],
- "comic_path": os.path.join(path, item),
- }
+ if os.path.exists(os.path.join(path, item, "元数据.json")):
+ with open(
+ os.path.join(path, item, "元数据.json"), "r", encoding="utf-8"
+ ) as f:
+ data = json.load(f)
+ my_library[data["id"]] = {
+ "comic_name": data["title"],
+ "comic_path": os.path.join(path, item),
+ }
else:
mainGUI.lineEdit_save_path.setText(os.getcwd())
mainGUI.updateConfig("save_path", os.getcwd())
@@ -213,7 +257,7 @@ def updateMyLibrarySingle(
"comic_path": comic_path,
}
- mainGUI.my_library_add_widget.emit(info)
+ self.my_library_add_widget.emit(info)
return None
############################################################
@@ -245,7 +289,8 @@ def updateMyLibrarySingleAdd(self, info: dict) -> None:
# ?###########################################################
# ? 绑定列表内漫画被点击事件:当前点击变色,剩余恢复
- def _(_event: QEvent, widget: QWidget) -> None:
+ def _(_event: QEvent, widget: QWidget, comic: Comic) -> None:
+ self.present_comic_id = comic.comic_id
for i in range(mainGUI.v_Layout_myLibrary.count()):
temp = mainGUI.v_Layout_myLibrary.itemAt(i).widget()
temp.setStyleSheet("font-size: 10pt;")
@@ -253,8 +298,10 @@ def _(_event: QEvent, widget: QWidget) -> None:
"background-color:rgb(200, 200, 255); font-size: 10pt;"
)
- widget.mousePressEvent = partial(_, widget=widget)
- widget.mouseDoubleClickEvent = partial(self.updateComicInfo, mainGUI, comic)
+ widget.mousePressEvent = partial(_, widget=widget, comic=comic)
+ widget.mouseDoubleClickEvent = partial(
+ self.updateComicInfoEvent, mainGUI, comic, "bilibili"
+ )
widget.setLayout(h_layout_my_library)
# ?###########################################################
@@ -280,28 +327,74 @@ def myMenu_openFolder(widget: QWidget, comic_path: str, pos: QPoint) -> None:
.findChild(QLabel)
.text()
)
- left_titile: str = left[left.find(">") + 1 : left.rfind("<")]
+ left_title: str = left[left.find(">") + 1 : left.rfind("<")]
if i == mainGUI.v_Layout_myLibrary.count() - 1:
mainGUI.v_Layout_myLibrary.addWidget(widget)
break
- if lazy_pinyin(data["title"]) <= lazy_pinyin(left_titile):
+ if lazy_pinyin(data["title"]) <= lazy_pinyin(left_title):
mainGUI.v_Layout_myLibrary.insertWidget(i, widget)
break
############################################################
+ # 以下三个函数是为了获取漫画信息详情
+ ############################################################
- def updateComicInfo(
- self, mainGUI: MainGUI, comic: Comic, _event: QEvent = None
+ ############################################################
+ def updateComicInfoEvent(
+ self, mainGUI: MainGUI, comic: Comic, resolve_type: str, _event: QEvent = None
) -> None:
"""更新漫画信息详情界面
Args:
comic (Comic): 漫画类实例
mainGUI (MainGUI): 主窗口类实例
+ resolve_type (str): 更新的解析类型
"""
- # ?###########################################################
- # ? 更新漫画信息
+
+ # 用多线程更新漫画信息,避免卡顿
+ self.executor.submit(
+ self.getComicInfo,
+ mainGUI,
+ comic,
+ resolve_type,
+ )
+
+ ############################################################
+ def getComicInfo(self, mainGUI: MainGUI, comic: Comic, resolve_type: str) -> None:
+ """更新封面的执行函数
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ comic (Comic): 获取的漫画实例
+ resolve_type (str): 更新的解析类型
+
+ """
+ mainGUI.resolve_status.emit("正在解析漫画详情...")
data = comic.getComicInfo()
+ mainGUI.resolve_status.emit("解析漫画详情完毕")
+ self.my_comic_detail_widget.emit(
+ {
+ "mainGUI": mainGUI,
+ "comic": comic,
+ "data": data,
+ "resolve_type": resolve_type,
+ }
+ )
+
+ ############################################################
+ def updateComicInfo(self, info: dict) -> None:
+ """更新漫画信息详情回调函数
+
+ Args:
+ info (dict): 执行更新漫画信息详情后返回的数据
+ """
+
+ mainGUI: MainGUI = info["mainGUI"]
+ comic: Comic = info["comic"]
+ data: dict = info["data"]
+ resolve_type: str = info["resolve_type"]
+
+ self.present_comic_id = comic.comic_id
# ? 获取漫画信息失败直接跳过
if not data:
mainGUI.message_box.emit(
@@ -324,41 +417,12 @@ def updateComicInfo(
f"概要:{data['evaluate'] or '无'}"
)
- self.init_save_mata(mainGUI, data)
+ # ?###########################################################
+ # ? 用多线程获取封面,避免卡顿
+ self.executor.submit(self.getComicCover, mainGUI, comic, data)
# ?###########################################################
- # ? 加载图片,以及绑定双击和悬停事件
- @retry(
- stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
- )
- def _() -> bytes:
- try:
- res = requests.get(data["vertical_cover"], timeout=TIMEOUT_SMALL)
- except requests.RequestException() as e:
- logger.warning(f"获取封面图片失败! 重试中...\n{e}")
- raise e
- if res.status_code != 200:
- logger.warning(
- f"获取封面图片失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
- )
- raise requests.HTTPError()
- if res.headers["Etag"] != md5(res.content).hexdigest():
- logger.warning(
- f"图片内容 Checksum 不正确! 重试中...\n\t{res.headers['Etag']} ≠ {md5(res.content).hexdigest()}"
- )
- raise requests.HTTPError()
- return res.content
-
- logger.info(f"获取《{data['title']}》的封面图片中...")
- try:
- img = _()
- label_img = QPixmap.fromImage(QImage.fromData(img))
- except RetryError as e:
- logger.error(f"获取封面图片多次后失败,跳过!\n{e}")
- label_img = QPixmap(":/imgs/fail_img.jpg")
- QMessageBox.warning(
- mainGUI, "警告", "获取封面图片多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件, 或联系开发者!"
- )
+ # ? 封面的绑定双击和悬停事件
mainGUI.label_manga_image.mouseDoubleClickEvent = (
lambda _event: QDesktopServices.openUrl(
@@ -370,7 +434,45 @@ def _() -> bytes:
)
# ?###########################################################
- # ? 重写图片大小改变事件,使图片不会变形
+ # ? 用多线程更新漫画章节详情界面显示,避免卡顿
+ self.executor.submit(self.getComicList, mainGUI, comic, resolve_type)
+
+ ############################################################
+ # 以下两个函数是为了获取漫画封面
+ ############################################################
+
+ ############################################################
+ def getComicCover(self, mainGUI: MainGUI, comic: Comic, data: dict) -> None:
+ """更新封面的执行函数
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ comic (Comic): 获取的漫画实例
+ data (dict): 漫画实例的数据
+
+ """
+ img_byte = comic.getComicCover(data)
+ self.my_cover_update_widget.emit(
+ {
+ "mainGUI": mainGUI,
+ "img_byte": img_byte,
+ }
+ )
+
+ ############################################################
+ def updateComicCover(self, info: dict) -> None:
+ """更新封面的回调函数
+
+ Args:
+ info (dict): 执行更新封面后返回的数据
+
+ """
+ mainGUI: MainGUI = info["mainGUI"]
+ img_byte: bytes = info["img_byte"]
+
+ # 重写图片大小改变事件,使图片不会变形
+ label_img = QPixmap.fromImage(QImage.fromData(img_byte))
+
def _(event: QEvent = None) -> None:
new_size = event.size() if event else mainGUI.label_manga_image.size()
if new_size.width() < 200:
@@ -384,13 +486,50 @@ def _(event: QEvent = None) -> None:
mainGUI.label_manga_image.resizeEvent = _
_()
- # ?###########################################################
- # ? 更新漫画章节详情
- mainGUI.listWidget_chp_detail.clear()
+ ############################################################
+ # 以下两个函数是为了刷新漫画详情界面
+ ############################################################
+
+ ############################################################
+ def getComicList(self, mainGUI: MainGUI, comic: Comic, resolve_type: str) -> None:
+ """更新详情界面的执行函数
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ comic (Comic): 获取的漫画实例
+
+ """
+ mainGUI.resolve_status.emit("正在解析漫画章节...")
self.num_selected = 0
num_unlocked = 0
if comic:
self.epi_list = comic.getEpisodesInfo()
+ mainGUI.resolve_status.emit("解析漫画章节完毕")
+ self.my_comic_list_widget.emit(
+ {
+ "mainGUI": mainGUI,
+ "comic": comic,
+ "resolve_type": resolve_type,
+ "num_unlocked": num_unlocked,
+ }
+ )
+
+ ############################################################
+ def updateComicList(self, info: dict) -> None:
+ """更新漫画详情界面的回调函数
+
+ Args:
+ info (dict): 执行更新封面后返回的数据
+
+ """
+ mainGUI: MainGUI = info["mainGUI"]
+ comic: Comic = info["comic"]
+ resolve_type: str = info["resolve_type"]
+ num_unlocked: int = info["num_unlocked"]
+
+ # ?###########################################################
+ # ? 更新漫画章节详情
+ mainGUI.listWidget_chp_detail.clear()
for epi in self.epi_list:
temp = QListWidgetItem(epi.title)
temp.setCheckState(Qt.Unchecked)
@@ -415,51 +554,10 @@ def _(event: QEvent = None) -> None:
f"已下载:{comic.getNumDownloaded()}"
)
mainGUI.label_chp_detail_num_selected.setText(f"已选中:{self.num_selected}")
+ self.resolveEnable(mainGUI, resolve_type)
+ mainGUI.resolve_status.emit("")
############################################################
-
- def init_save_mata(self, mainGUI: MainGUI, data: dict) -> None:
- """保存元数据
-
- Args:
- mainGUI (MainGUI): 主窗口类实例
- data (dict): 漫画元数据
-
- """
-
- def _(data: dict) -> None:
- mata = {}
-
- # 过滤信息
- mata['id'] = data['id']
- mata['title'] = data['title']
- mata['horizontal_cover'] = data['horizontal_cover']
- mata['square_cover'] = data['square_cover']
- mata['vertical_cover'] = data['vertical_cover']
- mata['author_name'] = data['author_name']
- mata['styles'] = data['styles']
- mata['evaluate'] = data['evaluate']
- mata['renewal_time'] = data['renewal_time']
- mata['hall_icon_text'] = data['hall_icon_text']
- mata['tags'] = data['tags']
-
- # ? 如果文件夹不存在,创建文件夹
- if not os.path.exists(data['save_path']):
- os.makedirs(data['save_path'])
-
- with open(os.path.join(data['save_path'], "元数据.json"), "w", encoding='utf-8') as f:
- json.dump(mata, f, indent=4, ensure_ascii=False)
-
- # ? 弹出提示框
- QMessageBox.information(mainGUI, "提示", "保存成功!")
- mainGUI.pushButton_save_mata.setEnabled(False)
- mainGUI.pushButton_save_mata.clicked.disconnect()
-
- mainGUI.pushButton_save_mata.setEnabled(True)
- mainGUI.pushButton_save_mata.clicked.connect(partial(_, data))
-
- ############################################################
-
def init_episodesDetails(self, mainGUI: MainGUI) -> None:
"""绑定章节界面的多选以及右键菜单事件
@@ -560,18 +658,33 @@ def _() -> None:
# ?###########################################################
# ? 更新章节详情界面
- num_num_downloaded = (
+ num_downloaded = (
int(mainGUI.label_chp_detail_num_downloaded.text().split(":")[1])
+ self.num_selected
)
self.num_selected = 0
- mainGUI.label_chp_detail_num_downloaded.setText(f"已下载:{num_num_downloaded}")
+ mainGUI.label_chp_detail_num_downloaded.setText(f"已下载:{num_downloaded}")
mainGUI.label_chp_detail_num_selected.setText(f"已选中:{self.num_selected}")
+ # ?###########################################################
+ # ? 初始化储存文件夹
+ save_path = self.epi_list[0].save_path
+ if not os.path.exists(save_path):
+ os.makedirs(save_path)
+
+ # ?###########################################################
+ # ? 保存元数据
+ if not os.path.exists(os.path.join(save_path, "元数据.json")):
+ comic = Comic(self.present_comic_id, mainGUI)
+ self.save_meta(comic.getComicInfo())
+
+ # ?###########################################################
+ # ? 开始下载选中章节
mainGUI.listWidget_chp_detail.itemChanged.disconnect()
for i in range(mainGUI.listWidget_chp_detail.count()):
item = mainGUI.listWidget_chp_detail.item(i)
if item.flags() != Qt.NoItemFlags and item.checkState() == Qt.Checked:
+ comic = Comic(self.present_comic_id, mainGUI)
mainGUI.downloadUI.addTask(mainGUI, self.epi_list[i])
item.setFlags(Qt.NoItemFlags)
item.setBackground(QColor(0, 255, 0, 50))
@@ -583,7 +696,7 @@ def _() -> None:
temp = mainGUI.v_Layout_myLibrary.itemAt(i).widget().layout()
if self.epi_list[0].comic_name in temp.itemAt(0).widget().text():
temp.itemAt(2).widget().setText(
- f"{num_num_downloaded}/{len(self.epi_list)}"
+ f"{num_downloaded}/{len(self.epi_list)}"
)
break
@@ -593,3 +706,88 @@ def _() -> None:
mainGUI.tabWidget_download_list.setCurrentIndex(0)
mainGUI.pushButton_chp_detail_download_selected.clicked.connect(_)
+ mainGUI.pushButton_biliplus_detail_download_selected.clicked.connect(_)
+
+ # ?###########################################################
+ # ? 绑定B站解析按钮事件
+ def _() -> None:
+ if self.present_comic_id == 0:
+ QMessageBox.critical(mainGUI, "警告", "请先在搜索或库存列表选择一个漫画!")
+ return
+ if not mainGUI.getConfig("cookie"):
+ QMessageBox.critical(mainGUI, "警告", "请先在设置界面填写自己的Cookie!")
+ return
+ self.resolveEnable(mainGUI, "resolving")
+ comic = Comic(self.present_comic_id, mainGUI)
+ self.updateComicInfoEvent(mainGUI, comic, "bilibili")
+
+ mainGUI.pushButton_resolve_detail.clicked.connect(_)
+
+ # ?###########################################################
+ # ? 绑定BiliPlus解析按钮事件
+ def _() -> None:
+ if self.present_comic_id == 0:
+ QMessageBox.critical(mainGUI, "警告", "请先在搜索或库存列表选择一个漫画!")
+ return
+ if not mainGUI.getConfig("biliplus_cookie"):
+ QMessageBox.critical(mainGUI, "警告", "请先在设置界面填写自己的BiliPlus Cookie!")
+ return
+ self.resolveEnable(mainGUI, "resolving")
+ comic = BiliPlusComic(self.present_comic_id, mainGUI)
+ self.updateComicInfoEvent(mainGUI, comic, "biliplus")
+
+ mainGUI.pushButton_biliplus_resolve_detail.clicked.connect(_)
+
+ ###########################################################
+ def resolveEnable(self, mainGUI: MainGUI, resolve_type: str) -> None:
+ """根据解析状态对按钮进行允许和禁用状态的改变
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ resolve_type (str): 解析状态
+ """
+ if resolve_type == "resolving":
+ mainGUI.pushButton_resolve_detail.setEnabled(False)
+ mainGUI.pushButton_biliplus_resolve_detail.setEnabled(False)
+ mainGUI.pushButton_chp_detail_download_selected.setEnabled(False)
+ mainGUI.pushButton_biliplus_detail_download_selected.setEnabled(False)
+ else:
+ mainGUI.pushButton_resolve_detail.setEnabled(True)
+ mainGUI.pushButton_biliplus_resolve_detail.setEnabled(True)
+
+ if resolve_type == "bilibili":
+ mainGUI.pushButton_chp_detail_download_selected.setEnabled(True)
+ mainGUI.pushButton_biliplus_detail_download_selected.setEnabled(False)
+ elif resolve_type == "biliplus":
+ mainGUI.pushButton_chp_detail_download_selected.setEnabled(False)
+ mainGUI.pushButton_biliplus_detail_download_selected.setEnabled(True)
+
+ ############################################################
+
+ def save_meta(self, data: dict) -> None:
+ """保存元数据
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ data (dict): 漫画元数据
+
+ """
+
+ meta = {
+ "id": data["id"],
+ "title": data["title"],
+ "horizontal_cover": data["horizontal_cover"],
+ "square_cover": data["square_cover"],
+ "vertical_cover": data["vertical_cover"],
+ "author_name": data["author_name"],
+ "styles": data["styles"],
+ "evaluate": data["evaluate"],
+ "renewal_time": data["renewal_time"],
+ "hall_icon_text": data["hall_icon_text"],
+ "tags": [tag["name"] for tag in data["tags"]],
+ }
+
+ with open(
+ os.path.join(data["save_path"], "元数据.json"), "w", encoding="utf-8"
+ ) as f:
+ json.dump(meta, f, indent=4, ensure_ascii=False)
diff --git a/src/ui/MyAbout.py b/src/ui/MyAboutUI.py
similarity index 90%
rename from src/ui/MyAbout.py
rename to src/ui/MyAboutUI.py
index f80df89..96af3cb 100644
--- a/src/ui/MyAbout.py
+++ b/src/ui/MyAboutUI.py
@@ -3,7 +3,7 @@
from src.ui.PySide_src.myAbout_ui import Ui_My_about
-class MyAbout(QWidget, Ui_My_about):
+class MyAboutUI(QWidget, Ui_My_about):
"""关于窗口类"""
def __init__(self):
diff --git a/src/ui/PySide_src/imgs/Scan-qr-code.512.png b/src/ui/PySide_src/imgs/Scan-qr-code.512.png
new file mode 100644
index 0000000..55022cf
Binary files /dev/null and b/src/ui/PySide_src/imgs/Scan-qr-code.512.png differ
diff --git a/src/ui/PySide_src/mainWindow.ui b/src/ui/PySide_src/mainWindow.ui
index d2f00ea..a2c6bb8 100644
--- a/src/ui/PySide_src/mainWindow.ui
+++ b/src/ui/PySide_src/mainWindow.ui
@@ -153,8 +153,8 @@
0
0
- 98
- 28
+ 517
+ 191
@@ -210,7 +210,7 @@
-
-
+
6
@@ -252,39 +252,6 @@
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- false
-
-
-
- 100
- 0
-
-
-
- 保存元数据
-
-
-
-
-
@@ -297,7 +264,7 @@
章节详情 (右键确认鼠标框选内容)
-
+
-
-
@@ -378,6 +345,116 @@
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
-
+
+
+ true
+
+
+
+ 80
+ 25
+
+
+
+ B站解析
+
+
+
+ -
+
+
+ true
+
+
+
+ 80
+ 25
+
+
+
+ BiliPlus解析
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ IBeamCursor
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ false
+
+
+
+ 130
+ 25
+
+
+
+ 下载BiliPlus选中章节
+
+
+
+
+
+
+
+
-
@@ -443,7 +520,7 @@
true
- 100
+ 0
true
@@ -502,8 +579,8 @@
0
0
- 98
- 28
+ 1068
+ 554
@@ -531,8 +608,8 @@
0
0
- 98
- 28
+ 61
+ 18
@@ -581,7 +658,7 @@
设置
-
+
-
@@ -605,12 +682,6 @@
0
-
-
- 16777215
- 16777215
-
-
我的Cookie:
@@ -619,6 +690,29 @@
-
+ -
+
+
+
+
+
+
+ :/imgs/Scan-qr-code.512.png:/imgs/Scan-qr-code.512.png
+
+
+
+ 25
+ 25
+
+
+
+ false
+
+
+ false
+
+
+
-
@@ -628,6 +722,54 @@
+ -
+
+
+
+ 6
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
-
+
+
+
+ 110
+ 0
+
+
+
+ BiliPlus Cookie:
+
+
+
+ -
+
+
+ -
+
+
+ 确认
+
+
+
+
+
+
+
+
-
-
@@ -712,7 +854,7 @@
- 110
+ 120
0
diff --git a/src/ui/PySide_src/mainWindow_ui.py b/src/ui/PySide_src/mainWindow_ui.py
index 4aa3ca6..c86aa14 100644
--- a/src/ui/PySide_src/mainWindow_ui.py
+++ b/src/ui/PySide_src/mainWindow_ui.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'mainWindow.ui'
##
-## Created by: Qt User Interface Compiler version 6.5.1
+## Created by: Qt User Interface Compiler version 6.5.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@@ -123,7 +123,7 @@ def setupUi(self, MainWindow):
self.scrollArea_myLibrary.setWidgetResizable(True)
self.scrollAreaWidgetContents_myLibrary = QWidget()
self.scrollAreaWidgetContents_myLibrary.setObjectName(u"scrollAreaWidgetContents_myLibrary")
- self.scrollAreaWidgetContents_myLibrary.setGeometry(QRect(0, 0, 98, 28))
+ self.scrollAreaWidgetContents_myLibrary.setGeometry(QRect(0, 0, 517, 191))
self.v_Layout_myLibrary = QVBoxLayout(self.scrollAreaWidgetContents_myLibrary)
self.v_Layout_myLibrary.setObjectName(u"v_Layout_myLibrary")
self.scrollArea_myLibrary.setWidget(self.scrollAreaWidgetContents_myLibrary)
@@ -187,22 +187,6 @@ def setupUi(self, MainWindow):
self.v_Layout_manga_detail.addWidget(self.label_manga_outline, 0, Qt.AlignTop)
- self.horizontalLayout_3 = QHBoxLayout()
- self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
- self.horizontalSpacer_7 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
-
- self.horizontalLayout_3.addItem(self.horizontalSpacer_7)
-
- self.pushButton_save_mata = QPushButton(self.groupBox_my_manga)
- self.pushButton_save_mata.setObjectName(u"pushButton_save_mata")
- self.pushButton_save_mata.setEnabled(False)
- self.pushButton_save_mata.setMinimumSize(QSize(100, 0))
-
- self.horizontalLayout_3.addWidget(self.pushButton_save_mata)
-
-
- self.v_Layout_manga_detail.addLayout(self.horizontalLayout_3)
-
self.v_Layout_manga_detail.setStretch(4, 1)
self.horizontalLayout_8.addLayout(self.v_Layout_manga_detail)
@@ -286,6 +270,71 @@ def setupUi(self, MainWindow):
self.verticalLayout_4.addLayout(self.h_Layout_chp_detail)
+ self.widget_biliplus_detail = QWidget(self.groupBox_chp_detail)
+ self.widget_biliplus_detail.setObjectName(u"widget_biliplus_detail")
+ self.h_Layout_widget_biliplus_detail = QHBoxLayout(self.widget_biliplus_detail)
+ self.h_Layout_widget_biliplus_detail.setObjectName(u"h_Layout_widget_biliplus_detail")
+ self.h_Layout_widget_biliplus_detail.setContentsMargins(0, 0, 0, 0)
+ self.h_Layout_biliplus_detail = QHBoxLayout()
+ self.h_Layout_biliplus_detail.setObjectName(u"h_Layout_biliplus_detail")
+ self.pushButton_resolve_detail = QPushButton(self.widget_biliplus_detail)
+ self.pushButton_resolve_detail.setObjectName(u"pushButton_resolve_detail")
+ self.pushButton_resolve_detail.setEnabled(True)
+ self.pushButton_resolve_detail.setMaximumSize(QSize(80, 25))
+
+ self.h_Layout_biliplus_detail.addWidget(self.pushButton_resolve_detail)
+
+ self.pushButton_biliplus_resolve_detail = QPushButton(self.widget_biliplus_detail)
+ self.pushButton_biliplus_resolve_detail.setObjectName(u"pushButton_biliplus_resolve_detail")
+ self.pushButton_biliplus_resolve_detail.setEnabled(True)
+ self.pushButton_biliplus_resolve_detail.setMaximumSize(QSize(80, 25))
+
+ self.h_Layout_biliplus_detail.addWidget(self.pushButton_biliplus_resolve_detail)
+
+ self.line_10 = QFrame(self.widget_biliplus_detail)
+ self.line_10.setObjectName(u"line_10")
+ self.line_10.setFrameShape(QFrame.VLine)
+ self.line_10.setFrameShadow(QFrame.Sunken)
+
+ self.h_Layout_biliplus_detail.addWidget(self.line_10)
+
+ self.label_resolve_status = QLabel(self.widget_biliplus_detail)
+ self.label_resolve_status.setObjectName(u"label_resolve_status")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
+ sizePolicy1.setHorizontalStretch(0)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.label_resolve_status.sizePolicy().hasHeightForWidth())
+ self.label_resolve_status.setSizePolicy(sizePolicy1)
+ self.label_resolve_status.setCursor(QCursor(Qt.IBeamCursor))
+ self.label_resolve_status.setAlignment(Qt.AlignCenter)
+
+ self.h_Layout_biliplus_detail.addWidget(self.label_resolve_status)
+
+ self.label_biliplus_empty = QLabel(self.widget_biliplus_detail)
+ self.label_biliplus_empty.setObjectName(u"label_biliplus_empty")
+
+ self.h_Layout_biliplus_detail.addWidget(self.label_biliplus_empty)
+
+ self.line_11 = QFrame(self.widget_biliplus_detail)
+ self.line_11.setObjectName(u"line_11")
+ self.line_11.setFrameShape(QFrame.VLine)
+ self.line_11.setFrameShadow(QFrame.Sunken)
+
+ self.h_Layout_biliplus_detail.addWidget(self.line_11)
+
+ self.pushButton_biliplus_detail_download_selected = QPushButton(self.widget_biliplus_detail)
+ self.pushButton_biliplus_detail_download_selected.setObjectName(u"pushButton_biliplus_detail_download_selected")
+ self.pushButton_biliplus_detail_download_selected.setEnabled(False)
+ self.pushButton_biliplus_detail_download_selected.setMaximumSize(QSize(130, 25))
+
+ self.h_Layout_biliplus_detail.addWidget(self.pushButton_biliplus_detail_download_selected)
+
+
+ self.h_Layout_widget_biliplus_detail.addLayout(self.h_Layout_biliplus_detail)
+
+
+ self.verticalLayout_4.addWidget(self.widget_biliplus_detail)
+
self.listWidget_chp_detail = QListWidget(self.groupBox_chp_detail)
self.listWidget_chp_detail.setObjectName(u"listWidget_chp_detail")
self.listWidget_chp_detail.setAutoFillBackground(True)
@@ -321,7 +370,7 @@ def setupUi(self, MainWindow):
self.progressBar_total_progress = QProgressBar(self.tab_download)
self.progressBar_total_progress.setObjectName(u"progressBar_total_progress")
self.progressBar_total_progress.setEnabled(True)
- self.progressBar_total_progress.setValue(100)
+ self.progressBar_total_progress.setValue(0)
self.progressBar_total_progress.setTextVisible(True)
self.h_Layout_total_progress.addWidget(self.progressBar_total_progress)
@@ -366,7 +415,7 @@ def setupUi(self, MainWindow):
self.scrollArea_processing.setWidgetResizable(True)
self.scrollAreaWidgetContents_processing = QWidget()
self.scrollAreaWidgetContents_processing.setObjectName(u"scrollAreaWidgetContents_processing")
- self.scrollAreaWidgetContents_processing.setGeometry(QRect(0, 0, 98, 28))
+ self.scrollAreaWidgetContents_processing.setGeometry(QRect(0, 0, 1068, 554))
self.verticalLayout_processing = QVBoxLayout(self.scrollAreaWidgetContents_processing)
self.verticalLayout_processing.setObjectName(u"verticalLayout_processing")
self.scrollArea_processing.setWidget(self.scrollAreaWidgetContents_processing)
@@ -388,7 +437,7 @@ def setupUi(self, MainWindow):
self.scrollArea_finished.setWidgetResizable(True)
self.scrollAreaWidgetContents_finished = QWidget()
self.scrollAreaWidgetContents_finished.setObjectName(u"scrollAreaWidgetContents_finished")
- self.scrollAreaWidgetContents_finished.setGeometry(QRect(0, 0, 98, 28))
+ self.scrollAreaWidgetContents_finished.setGeometry(QRect(0, 0, 61, 18))
self.verticalLayout_finished = QVBoxLayout(self.scrollAreaWidgetContents_finished)
self.verticalLayout_finished.setObjectName(u"verticalLayout_finished")
self.scrollArea_finished.setWidget(self.scrollAreaWidgetContents_finished)
@@ -431,7 +480,6 @@ def setupUi(self, MainWindow):
self.label_my_cookie = QLabel(self.tab_setting)
self.label_my_cookie.setObjectName(u"label_my_cookie")
self.label_my_cookie.setMinimumSize(QSize(110, 0))
- self.label_my_cookie.setMaximumSize(QSize(16777215, 16777215))
self.h_Layout_my_cookie.addWidget(self.label_my_cookie)
@@ -440,6 +488,17 @@ def setupUi(self, MainWindow):
self.h_Layout_my_cookie.addWidget(self.lineEdit_my_cookie)
+ self.pushButton_qrcode = QPushButton(self.tab_setting)
+ self.pushButton_qrcode.setObjectName(u"pushButton_qrcode")
+ icon1 = QIcon()
+ icon1.addFile(u":/imgs/Scan-qr-code.512.png", QSize(), QIcon.Normal, QIcon.Off)
+ self.pushButton_qrcode.setIcon(icon1)
+ self.pushButton_qrcode.setIconSize(QSize(25, 25))
+ self.pushButton_qrcode.setAutoRepeat(False)
+ self.pushButton_qrcode.setAutoExclusive(False)
+
+ self.h_Layout_my_cookie.addWidget(self.pushButton_qrcode)
+
self.pushButton_my_cookie = QPushButton(self.tab_setting)
self.pushButton_my_cookie.setObjectName(u"pushButton_my_cookie")
@@ -448,6 +507,36 @@ def setupUi(self, MainWindow):
self.verticalLayout_5.addLayout(self.h_Layout_my_cookie)
+ self.widget_biliplus_cookie = QWidget(self.tab_setting)
+ self.widget_biliplus_cookie.setObjectName(u"widget_biliplus_cookie")
+ self.h_Layout_widget_biliplus_cookie = QHBoxLayout(self.widget_biliplus_cookie)
+ self.h_Layout_widget_biliplus_cookie.setSpacing(6)
+ self.h_Layout_widget_biliplus_cookie.setObjectName(u"h_Layout_widget_biliplus_cookie")
+ self.h_Layout_widget_biliplus_cookie.setContentsMargins(0, 0, 0, 0)
+ self.h_Layout_biliplus_cookie = QHBoxLayout()
+ self.h_Layout_biliplus_cookie.setObjectName(u"h_Layout_biliplus_cookie")
+ self.label_biliplus_cookie = QLabel(self.widget_biliplus_cookie)
+ self.label_biliplus_cookie.setObjectName(u"label_biliplus_cookie")
+ self.label_biliplus_cookie.setMinimumSize(QSize(110, 0))
+
+ self.h_Layout_biliplus_cookie.addWidget(self.label_biliplus_cookie)
+
+ self.lineEdit_biliplus_cookie = QLineEdit(self.widget_biliplus_cookie)
+ self.lineEdit_biliplus_cookie.setObjectName(u"lineEdit_biliplus_cookie")
+
+ self.h_Layout_biliplus_cookie.addWidget(self.lineEdit_biliplus_cookie)
+
+ self.pushButton_biliplus_cookie = QPushButton(self.widget_biliplus_cookie)
+ self.pushButton_biliplus_cookie.setObjectName(u"pushButton_biliplus_cookie")
+
+ self.h_Layout_biliplus_cookie.addWidget(self.pushButton_biliplus_cookie)
+
+
+ self.h_Layout_widget_biliplus_cookie.addLayout(self.h_Layout_biliplus_cookie)
+
+
+ self.verticalLayout_5.addWidget(self.widget_biliplus_cookie)
+
self.h_Layout_save_path = QHBoxLayout()
self.h_Layout_save_path.setObjectName(u"h_Layout_save_path")
self.label_save_path = QLabel(self.tab_setting)
@@ -494,7 +583,7 @@ def setupUi(self, MainWindow):
self.h_Layout_num_thread.setObjectName(u"h_Layout_num_thread")
self.label_num_thread_count = QLabel(self.groupBox)
self.label_num_thread_count.setObjectName(u"label_num_thread_count")
- self.label_num_thread_count.setMinimumSize(QSize(110, 0))
+ self.label_num_thread_count.setMinimumSize(QSize(120, 0))
self.label_num_thread_count.setMaximumSize(QSize(16777215, 16777215))
self.h_Layout_num_thread.addWidget(self.label_num_thread_count)
@@ -684,13 +773,17 @@ def retranslateUi(self, MainWindow):
self.label_manga_style.setText("")
self.label_manga_isFinish.setText("")
self.label_manga_outline.setText("")
- self.pushButton_save_mata.setText(QCoreApplication.translate("MainWindow", u"\u4fdd\u5b58\u5143\u6570\u636e", None))
self.groupBox_chp_detail.setTitle(QCoreApplication.translate("MainWindow", u"\u7ae0\u8282\u8be6\u60c5 (\u53f3\u952e\u786e\u8ba4\u9f20\u6807\u6846\u9009\u5185\u5bb9)", None))
self.label_chp_detail_total_chp.setText(QCoreApplication.translate("MainWindow", u"\u603b\u7ae0\u6570\uff1a", None))
self.label_chp_detail_num_unlocked.setText(QCoreApplication.translate("MainWindow", u"\u5df2\u89e3\u9501\uff1a", None))
self.label_chp_detail_num_downloaded.setText(QCoreApplication.translate("MainWindow", u"\u5df2\u4e0b\u8f7d\uff1a", None))
self.label_chp_detail_num_selected.setText(QCoreApplication.translate("MainWindow", u"\u5df2\u9009\u4e2d\uff1a", None))
self.pushButton_chp_detail_download_selected.setText(QCoreApplication.translate("MainWindow", u"\u4e0b\u8f7d\u9009\u4e2d\u7ae0\u8282", None))
+ self.pushButton_resolve_detail.setText(QCoreApplication.translate("MainWindow", u"B\u7ad9\u89e3\u6790", None))
+ self.pushButton_biliplus_resolve_detail.setText(QCoreApplication.translate("MainWindow", u"BiliPlus\u89e3\u6790", None))
+ self.label_resolve_status.setText("")
+ self.label_biliplus_empty.setText("")
+ self.pushButton_biliplus_detail_download_selected.setText(QCoreApplication.translate("MainWindow", u"\u4e0b\u8f7dBiliPlus\u9009\u4e2d\u7ae0\u8282", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_my_manga), QCoreApplication.translate("MainWindow", u"\u6211\u7684\u6f2b\u753b", None))
self.label_total_progress.setText(QCoreApplication.translate("MainWindow", u"\u603b\u8fdb\u5ea6", None))
self.label_total_progress_speed.setText(QCoreApplication.translate("MainWindow", u"\u603b\u4e0b\u8f7d\u901f\u5ea6:", None))
@@ -700,7 +793,10 @@ def retranslateUi(self, MainWindow):
self.tabWidget_download_list.setTabText(self.tabWidget_download_list.indexOf(self.tab_finished), QCoreApplication.translate("MainWindow", u"\u5df2\u5b8c\u6210", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_download), QCoreApplication.translate("MainWindow", u"\u4e0b\u8f7d\u5217\u8868", None))
self.label_my_cookie.setText(QCoreApplication.translate("MainWindow", u"\u6211\u7684Cookie\uff1a", None))
+ self.pushButton_qrcode.setText("")
self.pushButton_my_cookie.setText(QCoreApplication.translate("MainWindow", u"\u786e\u8ba4", None))
+ self.label_biliplus_cookie.setText(QCoreApplication.translate("MainWindow", u"BiliPlus Cookie\uff1a", None))
+ self.pushButton_biliplus_cookie.setText(QCoreApplication.translate("MainWindow", u"\u786e\u8ba4", None))
self.label_save_path.setText(QCoreApplication.translate("MainWindow", u"\u6f2b\u753b\u4fdd\u5b58\u8def\u5f84\uff1a", None))
self.pushButton_save_path.setText(QCoreApplication.translate("MainWindow", u"\u6d4f\u89c8...", None))
self.groupBox.setTitle(QCoreApplication.translate("MainWindow", u"\u6ce8\u610f\uff1a\u4ee5\u4e0b\u8bbe\u7f6e\u53ea\u5728\u4e0b\u6b21\u542f\u52a8\u65f6\u751f\u6548\uff01", None))
diff --git a/src/ui/PySide_src/myAbout.ui b/src/ui/PySide_src/myAbout.ui
index cfbe068..8fc8875 100644
--- a/src/ui/PySide_src/myAbout.ui
+++ b/src/ui/PySide_src/myAbout.ui
@@ -33,7 +33,7 @@
-
- <html><head/><body><p align="center"><span style=" font-size:16pt; font-weight:700; color:#00aaff;">哔哩哔哩</span><span style=" font-size:16pt; font-weight:700;">漫画下载器 </span><span style=" font-size:16pt; font-weight:700; color:#aa00ff;">v1.2.0</span></p><p align="center"><span style=" font-size:14pt; font-weight:700;">作者:Zeal-L</span></p><p align="center"><span style=" font-size:12pt; font-weight:700;">项目地址:</span><a href="https://github.com/Zeal-L/BiliBili-Manga-Downloader"><span style=" font-size:12pt; text-decoration: underline; color:#0000ff;">https://github.com/Zeal-L/BiliBili-Manga-Downloader</span></a></p><p align="center"><span style=" font-size:12pt; font-weight:700;">本程序仅供学习交流使用,严禁用于商业用途</span></p><p align="center"><span style=" font-size:16pt; font-weight:700; color:#00aa00;">联系方式:</span><span style=" font-size:12pt; font-weight:700;">Q群号:</span><span style=" font-size:12pt; font-weight:700; color:#aa00ff;">244029317</span><span style=" font-size:12pt; font-weight:700;"><br/>欢迎进群讨论程序,漫画,资源分享, 提交问题等等</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt; font-weight:700;">-- LICENSE --</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">BiliBili-Manga-Downloader</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">Copyright (C) 2023 Zeal L</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">You should have received a copy of the GNU Affero General Public License along with this program. If not, see </span><a href="https://www.gnu.org/licenses"><span style=" font-size:12pt; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses</span></a><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">.</span></p><p><br/></p></body></html>
+ <html><head/><body><p align="center"><span style=" font-size:16pt; font-weight:700; color:#00aaff;">哔哩哔哩</span><span style=" font-size:16pt; font-weight:700;">漫画下载器 </span><span style=" font-size:16pt; font-weight:700; color:#aa00ff;">v1.3.0</span></p><p align="center"><span style=" font-size:14pt; font-weight:700;">作者:Zeal-L</span></p><p align="center"><span style=" font-size:12pt; font-weight:700;">项目地址:</span><a href="https://github.com/Zeal-L/BiliBili-Manga-Downloader"><span style=" font-size:12pt; text-decoration: underline; color:#0000ff;">https://github.com/Zeal-L/BiliBili-Manga-Downloader</span></a></p><p align="center"><span style=" font-size:12pt; font-weight:700;">本程序仅供学习交流使用,严禁用于商业用途</span></p><p align="center"><span style=" font-size:16pt; font-weight:700; color:#00aa00;">联系方式:</span><span style=" font-size:12pt; font-weight:700;">Q群号:</span><span style=" font-size:12pt; font-weight:700; color:#aa00ff;">244029317</span><span style=" font-size:12pt; font-weight:700;"><br/>欢迎进群讨论程序,漫画,资源分享, 提交问题等等</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt; font-weight:700;">-- LICENSE --</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">BiliBili-Manga-Downloader</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">Copyright (C) 2023 Zeal L</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.</span></p><p align="center"><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">You should have received a copy of the GNU Affero General Public License along with this program. If not, see </span><a href="https://www.gnu.org/licenses"><span style=" font-size:12pt; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses</span></a><span style=" font-family:'HYWenHei-85W'; font-size:12pt;">.</span></p><p><br/></p></body></html>
true
diff --git a/src/ui/PySide_src/myAbout_ui.py b/src/ui/PySide_src/myAbout_ui.py
index 22c1668..0d74a6d 100644
--- a/src/ui/PySide_src/myAbout_ui.py
+++ b/src/ui/PySide_src/myAbout_ui.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'myAbout.ui'
##
-## Created by: Qt User Interface Compiler version 6.5.1
+## Created by: Qt User Interface Compiler version 6.5.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@@ -55,7 +55,7 @@ def setupUi(self, My_about):
def retranslateUi(self, My_about):
My_about.setWindowTitle(QCoreApplication.translate("My_about", u"Form", None))
self.label.setText("")
- self.outline.setText(QCoreApplication.translate("My_about", u"
\u54d4\u54e9\u54d4\u54e9\u6f2b\u753b\u4e0b\u8f7d\u5668 v1.2.0
\u4f5c\u8005\uff1aZeal-L
\u9879\u76ee\u5730\u5740\uff1ahttps://github.com/Zeal-L/BiliBili-Manga-Downloader
\u672c\u7a0b\u5e8f\u4ec5\u4f9b\u5b66\u4e60\u4ea4\u6d41\u4f7f\u7528\uff0c\u4e25\u7981\u7528\u4e8e\u5546\u4e1a\u7528\u9014
\u8054\u7cfb\u65b9"
+ self.outline.setText(QCoreApplication.translate("My_about", u"
\u54d4\u54e9\u54d4\u54e9\u6f2b\u753b\u4e0b\u8f7d\u5668 v1.3.0
\u4f5c\u8005\uff1aZeal-L
\u9879\u76ee\u5730\u5740\uff1ahttps://github.com/Zeal-L/BiliBili-Manga-Downloader
\u672c\u7a0b\u5e8f\u4ec5\u4f9b\u5b66\u4e60\u4ea4\u6d41\u4f7f\u7528\uff0c\u4e25\u7981\u7528\u4e8e\u5546\u4e1a\u7528\u9014
\u8054\u7cfb\u65b9"
"\u5f0f\uff1aQ\u7fa4\u53f7\uff1a244029317
\u6b22\u8fce\u8fdb\u7fa4\u8ba8\u8bba\u7a0b\u5e8f\uff0c\u6f2b\u753b\uff0c\u8d44\u6e90\u5206\u4eab, \u63d0\u4ea4\u95ee\u9898\u7b49\u7b49
-- LICENSE --
BiliBili-Manga-Downloader
Copyright (C) 2023 Zeal L
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or ("
"at your option) any later version.
This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses.
", None))
# retranslateUi
diff --git a/src/ui/PySide_src/qrCode.ui b/src/ui/PySide_src/qrCode.ui
new file mode 100644
index 0000000..f13cdaa
--- /dev/null
+++ b/src/ui/PySide_src/qrCode.ui
@@ -0,0 +1,62 @@
+
+
+ QrCode
+
+
+
+ 0
+ 0
+ 418
+ 447
+
+
+
+ 二维码登入窗口
+
+
+
+ :/imgs/BiliBili_favicon.ico:/imgs/BiliBili_favicon.ico
+
+
+
+ QLayout::SetFixedSize
+
+ -
+
+
+ Qt::LeftToRight
+
+
+ false
+
+
+ ## 请使用BiliBili手机客户端扫描二维码登入
+
+
+ Qt::MarkdownText
+
+
+ Qt::AlignCenter
+
+
+ -1
+
+
+
+ -
+
+
+
+
+
+ :/imgs/fail_img.jpg
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ui/PySide_src/qrCode_ui.py b/src/ui/PySide_src/qrCode_ui.py
new file mode 100644
index 0000000..dfca7d9
--- /dev/null
+++ b/src/ui/PySide_src/qrCode_ui.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'qrCode.ui'
+##
+## Created by: Qt User Interface Compiler version 6.5.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+ QFont, QFontDatabase, QGradient, QIcon,
+ QImage, QKeySequence, QLinearGradient, QPainter,
+ QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QApplication, QLabel, QLayout, QSizePolicy,
+ QVBoxLayout, QWidget)
+import src.ui.PySide_src.resource_rc
+
+class Ui_QrCode(object):
+ def setupUi(self, QrCode):
+ if not QrCode.objectName():
+ QrCode.setObjectName(u"QrCode")
+ QrCode.resize(418, 447)
+ icon = QIcon()
+ icon.addFile(u":/imgs/BiliBili_favicon.ico", QSize(), QIcon.Normal, QIcon.Off)
+ QrCode.setWindowIcon(icon)
+ self.verticalLayout = QVBoxLayout(QrCode)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.verticalLayout.setSizeConstraint(QLayout.SetFixedSize)
+ self.label = QLabel(QrCode)
+ self.label.setObjectName(u"label")
+ self.label.setLayoutDirection(Qt.LeftToRight)
+ self.label.setAutoFillBackground(False)
+ self.label.setTextFormat(Qt.MarkdownText)
+ self.label.setAlignment(Qt.AlignCenter)
+ self.label.setIndent(-1)
+
+ self.verticalLayout.addWidget(self.label)
+
+ self.label_img = QLabel(QrCode)
+ self.label_img.setObjectName(u"label_img")
+ self.label_img.setPixmap(QPixmap(u":/imgs/fail_img.jpg"))
+
+ self.verticalLayout.addWidget(self.label_img)
+
+ self.verticalLayout.setStretch(1, 1)
+
+ self.retranslateUi(QrCode)
+
+ QMetaObject.connectSlotsByName(QrCode)
+ # setupUi
+
+ def retranslateUi(self, QrCode):
+ QrCode.setWindowTitle(QCoreApplication.translate("QrCode", u"\u4e8c\u7ef4\u7801\u767b\u5165\u7a97\u53e3", None))
+ self.label.setText(QCoreApplication.translate("QrCode", u"## \u8bf7\u4f7f\u7528BiliBili\u624b\u673a\u5ba2\u6237\u7aef\u626b\u63cf\u4e8c\u7ef4\u7801\u767b\u5165", None))
+ self.label_img.setText("")
+ # retranslateUi
+
diff --git a/src/ui/PySide_src/resource.qrc b/src/ui/PySide_src/resource.qrc
index edf9ca3..d0ead14 100644
--- a/src/ui/PySide_src/resource.qrc
+++ b/src/ui/PySide_src/resource.qrc
@@ -1,5 +1,6 @@
+ imgs/Scan-qr-code.512.png
imgs/fail_img.jpg
imgs/blinblin.png
imgs/BiliBili_favicon.ico
diff --git a/src/ui/PySide_src/resource_rc.py b/src/ui/PySide_src/resource_rc.py
index bc99d93..404b227 100644
--- a/src/ui/PySide_src/resource_rc.py
+++ b/src/ui/PySide_src/resource_rc.py
@@ -1,6 +1,6 @@
# Resource object code (Python 3)
# Created by: object code
-# Created by: The Resource Compiler for Qt version 6.5.1
+# Created by: The Resource Compiler for Qt version 6.5.2
# WARNING! All changes made in this file will be lost!
from PySide6 import QtCore
@@ -7118,6 +7118,344 @@
\xcd\xc2.G\x88\x85+D\xb4\x81\x1b\xe9\xe1q\xba\xc6\
J\xe3\xb2F\x99\x94\xbd\xb6f\xfd\xc4Y\xf8\x89\x1b\xf9\
\x09\x1d\xfd\xb5O\xde\x1f~\x98lA\
+\x00\x00\x14\xf1\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x02\x00\x00\x00\x02\x00\x08\x03\x00\x00\x00\xc3\xa6$\xc8\
+\x00\x00\x00\x04gAMA\x00\x00\xb1\x8f\x0b\xfca\x05\
+\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x01\
+\xb3PLTE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00U;AI\x00\x00\x00\x90\
+tRNS\x00\xf4$\x99W\xca#\xfa\xf9\x0d\xfb\xea\
+\xd2\x9a\xeb\x08\x01\xfc\xe9\xfe\x8b1\x09\xd0\xf8\x89\x0e\x8d\
+\xd34\xf090\x8a6k\xee\x19\x9b\x0bH\xe1fT\
+\xe4(7\x22\xc0%\xd5\x06!?\xab\xec\x93\xc5\xa4I\
+\x15\xed}\xa3\xad|\xc9G\x86o\xba\xae\xde.3\xc4\
+\x90\x16\xc2\x0c;=X\x12J\x82]c\xbf\xd9F\xf1\
+\xb1E\xb2\xa6\xaf\xb5\xf2h\x1b\x8c\xef\xcf\x1a\x5c\xce\x04\
+MNZ\x03\x7f\xc1\xcc\x10\xe7B\x98m\xa2\xe2\xcb/\
+\xddjn\xe0\xb9\xc3\x8e\xda\x92\xb8\xb3\x91i\xb7\x14\x11\
+\x8f\x87\xac\xdc\xbe\xc7\xd9\xac\x00\x00\x12@IDAT\
+x\xda\xed\x9diW\xdb\xc8\xb6@\x05\xd8\xd8\x18\x1b\xec\
+\x980\x85\xd0\x19\x80\x00\x0f\x08p\x1b\x02$d\x1e\xbb\
+\xd3\xdd\x99\xe7y\x9e\xe7t\xf7\xed\xb9\xef<_\xfd\xe4\
+\xd7+\xeb\xad\xf5Bb\xa9\xca:*\xcbU\xda\xfb{\
+\xd59:\xde\xb6\xe4\x92T\xc7\xf3\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x22:2m\xd9\xae\
+\x9c/$\xd7\x95m\xcbtP?\xeb\xea\xd7Zj\xf1\
+c\xa3\xa5\xd4\x9a\xb6\x8f\xdf\xf2\xfau\x0f\xe4\xfdX\xc9\
+\xf7\xf4\xa6\xe9\xe3\xb7\xbd~\xedE?v\x8a\xed\xe9\xf9\
+\xfcm\xaf\xdf\xa6u\xbe\x01\xba\xd6\xa7\xe5\xf3\xb7\xbd~\
+\xedF\xf2\xf7\xfd\xce\x94\xfc\x06\xd8^\xbf\xee\xa2o\x88\
+\xa1\xeeT\x9c\xffm\xaf\xdff\xdf\x18=i\x10\xc0\xf6\
+\xfa\xb5\xe6\xcd\x1d@>\x05\xff\x06\xad\xaf\xdf\x98o\x90\
+1\xf7\x05\xb0\xbd~\x1d-&\x0f\xa0\xc5\xf95A\xeb\
+\xeb\x97\xf1\x8d\x92q]\x00\xeb\xebW2{\x00m\xae\
+\x0b`}\xfd\xb2f\x0f \xeb\xba\x00\xd6\xd7\xaf\xd3\xec\
+\x01t\xba.\x80\xf5\xf5\xcb\x99=\x80\x9c\xeb\x02X_\
+?\x1f\x01\x9aY\x00\xdfv\x018\x05\xa4\x5c\x80\xfd\x5c\
+\x04\xa6[\x00\xe7\xff\x06\xb6!\x00\x0bA\x08\xc0R0\
+\x02\xd4\xa6\xe4y\x9c\x03R,\x00\xb7\x83S.\x00\x0f\
+\x84\xa4[\x80b:\x1e\x09\xebC\x00\x1e\x0aE\x80$\
+\x1fkN\x9aM\xeb\x10\xa0\xc6\xef?/\x86\xa4Y\x00\
+^\x0dK\xb5\x00\xbc\x1c\x9a^\x01x=\xdc1\x01<\
+p\xbb\xfe\x08\x80\x00\x08\x80\x00\x08\x80\x00\x08\x80\x00\x08\
+\x80\x00\x08\x80\x00\x08\x80\x00\x08\x80\x00\x08\x80\x00\x08\x80\
+\x00\x08\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\
+\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\
+\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x90^\x01\xbe\xda\xb9\
+{\xcfw\x13#\x05\xbd=\x10\x0a#\x13\xdf\xad\xec\x1e\
+\xdf&<\x92\xc7\x076\xbc\x9c\xea\xaf\x0c\x17W&G\
+\x85S50\x7f\x07\x05\xf8\xc77\x9fG\xda'#\xf7\
+\xeb!\xc1\x07w\xfa\xec{[uU\xae\x9d\x88>S\
+c\xf3wN\x80\x8dG\x04\xbb\xa4\xe4\x8e|\x12\xed(\
+\xca\x93\xabkg\xaa.F\x94\xa9\xd1\xf9;&\xc0\xb1\
+\xc3U\xd9\x968\xd5_6F8\x88\xc1+5\xb6\xa9\
+|\x1ba\xa2\xc6\xe7\xef\x94\x00\x83\xc7\x0b\xbe\x98\xca\x9f\
+\x06\xeb=\x86]\x8fj~\x1dO\xd5\xedQ\x02\xf9\xbb\
+$\xc0\xc6\xff\xc6\xb31\xd6\xc4\x96\xfa\x0e\xa1\xe3U\xc0\
+\x0f\xf2\xce:\x7f\xfd\x93\xc8\xdf!\x01\xb6\xf6\xc7\xb6\xcb\
+\xe4\xd6\xba\x0ea1h\x9e\xe1\xed\xf5L\x93L\xfe\xee\
+\x08p0\xce\xdd\xf16\x97\xf5\x8f\xe0|\xf04\xb3u\
+\x14\x22\xa1\xfc\x9d\x11\xe0\xebx\xf7G,iW\xf0\xf5\
+\x8e\x90i\xfe\xc7k\xf6\xfc]\x11` \xee\x1d2\x07\
+t\x0f\xe0E\xd8,}^\xb3\xe7\xef\x88\x00[\xfd\xd8\
+\xd1<\x8f>\x7f\x13:\xcb'\xcd\x9e\xbf\x1b\x02l\xec\
+\x8f\xbf\x80y\xbdk\xe9\xab\xe1\xb3lh\xf6\xfc\x9d\x10\
+`\xf0\xa8o\x80\x1f\xb4\xfeO\xdf\x0d\x9f\xa4\xaf\xd9\xf3\
+wB\x80\xbf\xfaF8\xae\x13{V\xb18\xfb\xbb&\
+\xcf\xdf\x05\x016\x15\xcc\x14\xb0\xf0\xbdF\xf0)\xc5$\
+\x9f6y\xfe.\x08p\xd87\xc4\x9f5\x82\xab\xce\xde\
+\xeb\x9b<\xff\xc4\x05P\xdc\xfb\xca\xa9g\xd8R5U\
+\xc0\xaa\xc6\x8d\x95\x8aX\x80d\xf3\x97\xd7_Hgx\
+\x02\x9d\xea\x19\x8e\xf8\xc6\xd8\xab\x8e>,>\x05$\x9b\
+\xbf\xbc\xfeB\xb2\xe1\x09\xecWN\xf0E\xce\x5c\x01s\
+\xbb\x94\xe1\x87\xa4\x17\x81\x09\xe7/\xae\xbf\x14E\xef\xe3\
+6\xe5\x04\x87|\x83\xfc\xa4\x0c\x7f=|\x82\xfb\xcd\x9e\
+\xbf\xb8\xfeR2\xe1\x09d\x94\x13|n\xb2\x80_*\
+\xc3\xdf\x96.\x04%\x9c\xbf\xb8\xfeR:B\xbb\x9d\xb5\
+(\xfb\x7f}\x953Y\xc0\xbc\xf2I\xcb;\x15\xd9R\
+p\xd2\xf9K\xebo\xf8\x1cPR\x0e\x1f\xf7\x8d2\xae\
+L\xe0\xa6l!0\xf1\xfc\x85\xf5\x97\xd3\x1a\xd2\xf32\
+\xaf\xee\xff\xb8\xdbl\x01\xf7)\x138Y\x15\xdd\x0eN\
+<\x7fa\xfdc`sp\x02=\xea\xd1+f\x0b\xb8\
+G\x9d\xc1\x8d\xe0\xd1\x17l\xc8_V\xff\x18\xe8\xee\x0b\
+\x8a_\xec\x16\xff\x8d\x94\x92Ug\xf0 \xf0\x89\x90{\
+\xdbm\xc8_V\xff8h\x0f\xe8~\xde\xa9\xd3\xff\xfb\
+\xf7f\x0b\xf8\xb3F\x0a\x97\x02\xae\xe3rg\xec\xc8_\
+T\xffX\xd8T3\x83\xae\xf5:cG\xcc\x16pU\
+'\x87g5\xef\xe6\x14\x1e\xda\x92\xbf\xa4\xfe1\xfd\x06\
+\x14k\xfc\xfe\xe8\xf9W0[@\xbd\xb5\xf0'\x97?\
+\x1ey\xeb\xa9=\xf9\x0b\xea\x1f\xd7u\xc0\xc0\x07\xd7\xa2\
+\xf9\x9e\xdex\xee&J\xd1\xcbbn\xf9\xc3q\xcbs\
+6\xe5\x1f\xbd\xfe\xf1\xfd\x1b,\xbd\xb7\x22\xd1R\xd2\xfe\
+\xff\xd1\x1c\x05\xf4\xca\x9957\x05.\x9e+\xdb\x95\x7f\
+\xe4\xfa\xc7\xb9&\x98i\xcbv\xe5r]\xd9\xb6L\x1d\
+\xebO\xcdR@\xaf\xbc\xb04\xffnU\xb02\xbf\xb4\
+P\xb6/\xff\x88\xf5O\x1ci\x01b} \xa2wz\
+ff\xba\xd7\xde\xfcm\xc4\xf6\x02\x22\x00\x02 \x00\x02\
+ \x00\x02 \x00\x02 \x00\x02 \x00\x02 \x00\x02 \
+\x00\x02 \x00\x02 \x00\x02 \x00\x02 \x00\x02 \x00\
+\x02 \x00\x02 \x00\x02 \x00\x02 \x00\x02 \x00\x02\
+ \x00\x02 \x00\x02 \x00\x02 \x00\x02 \x00\x02 \
+\x00\x02 \x00\x02 \x00\x02 \x00\x02 \x00\x02 \x00\
+\x02 \x00\x02 @\x837Xx|`\xc3\xcb\xa9\xfe\
+\xcapqer\xd4\xc6\xfc\x11@T\xc0\xd3g\xdf\xdb\
+j\xabr\xed\x04\x02\xa4J\x80\xf2\xe4\xea\xdaa\xd5\xc5\
+Q\x04h\x08\x86\xb7Y+h%1x\xe5\xe3\x91\x9d\
+o\xed\xc9\xdff\x0co\xb48\xa2\x93\xc3\xaeG\xb5\x86\
+\xe6N\xd9\x92\xbf\xd5\x18\xdejuB#\x85\x8eW\xb5\
+\xc7\xe6v\xda\x91\xbf\xdd\x18\xdelY\xa7g\xceb\xd0\
+\xe0\xe1\xedV\xe4o7{\xcc\x16\xf0[u\x06\xe7\x83\
+G\xcf\xda\x90\xbf\xe5$\xdep\xe1\xf5\x8e\x90\xe1\x164\
+\x8c\xb0\x9d\x9df\x0bx@\x99\xc0\x8b\xb0\xe1}\xcd\x9f\
+\xbf\xed$\xddt\xe9\xf9\x9b\xd0\x09\x9a\xbei\x94\xfd$\
+\xdcv\xedj\xf8\x04M\xdf6\xce~~2Y\xc0o\
+\x94\xe1\xef\x86O\xd0\xd7\xec\xf9\xdbO\xc2\xadWg\x15\
+34{\xebX\x07\xd8k\xae\x80{\xd5\xd1\xa7\x14S\
+|\xda\xe4\xf9;@\xb2\xed\xd7\xfb\x15s4{\xfbx\
+\x178l\xaa\x80\x7f\xd7\x08^\x11\x0b\x90l\xfe.\xf0\
+\xbd\xa1;j\x85c\x1a\xc1\x87\xc5\xa7\x80d\xf3w\x82\
+\xe3f\x0a\xf8\x07\x9d\xd8C\xd2\x8b\xc0\x84\xf3w\x82\xc1\
+\xa3&\xea\xf7\x83V\xe7\x9c\xeb\xe1\x93\xdco\xf6\xfc\xdd\
+`c\x7f\xfc\xf5\xcbo\xd1\x0a}[\xba\x10\x94p\xfe\
+\x8e\xf0\xb7\xf8\x0b\xb8U/\xf2\x9d\x8al)8\xe9\xfc\
+]\xe1\xdfq\xd7\xef\xa0n\xe4\x9b\xb2\x85\xc0\xc4\xf3w\
+\x85\xaf\xe3\xad_I\xbb\xf3\xdf\xc9\xaa\xe8vp\xe2\xf9\
+;\xc3\xc18\xeb7PG\xfdn\x04Os\xc1\x86\xfc\
+\x9d\xe1\xc7\xd8\xae\xa4\xf2u\x9d?\x1f\x04>\x11ro\
+\xbb\x0d\xf9\xbb\xc3g\x7f\x8c\xa7~G\xeb\xbc~\xbe\x14\
+p;'w\xc6\x8e\xfc\x1dZ\x0f\xd8\x10\xc3\x9aZ\xe1\
+_u\xff\x7f~V3l\xe1\xa1-\xf9;\xc4\xb1\xbf\
+\x08\xef\xacT\x7f\xf9,B\xd8'\x97?\x9e\xe9\xd6S\
+{\xf2w\xea<\xf0\x1f\xc1\xfd\xf5\xdc\xdeO\xa2E\x9d\
+[\xfep\xaa\xe59\x9b\xf2w\x8a\x7f\xfe\xf8k>\xd2\
+\xa5\xd3\x97\x87\xbe\x88\x1c\xb4\x9cYsS\xe0\xe2\xb9\xb2\
+]\xf9;\xc6\xb6\xf1}\xdff'F4\xcf\xa8\x85\xd5\
+\x9f\xb3{\xf6\x8d\x0b\x9f\x9f,/,\xcd\xbf[\x15\xac\
+\xcc/-\x94\xed\xcb\x1fb\xa0wzff\xba\x97:\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\
+\xd2\x91i\xcbv\x89\xfb\xaf\xe4\xba\xb2m\x99H\xdb,\
+=>\xb0\xe1\xe5T\x7fe\xb8\xb829\x1a=\xff\xe4\
+\xe2[Nk\xa9%\xbe}\x16[J\xad\xf5\xc6?}\
+v\xdd\xff\x8f\xaf\x5c;!\xca?\x81\xf8\x96\xd3=\x90\
+\xf7c%\xdfS\xd7F\x1f\xe5\xc9\xd5\x0fv\xebZ\x1c\
+\x15\xe5\xdf\xe0\xf8\xb6\xd3^\x8c\x7f\xb7\xedb\xbb~\xfc\
+\xc1+\x1f\x8f\xef|+\xcb\xbf\x91\xf1mg\xd3:\x13\
+\x0d\x17\xba\xd6\xeb\xc6\xdf\xf5\xa8\xe6\xd5\xc4)Y\xfe\x8d\
+\x8bo\xfd\xf7\xdf\xc8\xe7\xff\xdbwH\xf3;\xd8\xf1*\
+\xe0zr\xa7,\xffF\xc5\xb7\xfe\xfc_\xf4\x0d1\xd4\
+\xad\x95\xc0b\xd0\xf8\xe1\xed\xb2\xfc\x1b\x13\xdfz6\x9b\
+k\xbc\xd8\xa3\x13\xff|\xf0\xf8Ya\xfe\x0d\x89o\xfd\
+\xff\xbf\xbc9\x01\xf2\x1a\xff\xc6^\xef\x905\x8c\x08\xcb\
+\xbf\x11\xf1\xadg\xcc7\xc8\x98:\xfe\x0ba\xcb\x98\xb1\
+\x84\xe3[\xbf\xfe\xd7bR\x80\x16\xe5\x9a\xdc\xf37\xb2\
+\xa6Q\xe1\xf9\x9b\x8fo=\x19\xdf(\x19U\xfc\xab\xc2\
+\xb6q\x99\x84\xe3[O\xc9\xac\x00m\xaa\xf8w\xc3\xc7\
+\xf7\x09\xf37\x1e\xdfz\xb2f\x05\xc8\xaa\xe2\xcf\x0a[\
+\xc7f\x13\x8eo=\x9df\x05\xe8T\xc5\x9fRL\xf0\
+\xa9,\x7f\xe3\xf1\xad'gV\x80\x9c*\xbe\xaa\xd5\xd7\
+zY\xfe\xc6\xe3#\x80\xf0\x03\xa8\x08?\x00U\x02\xa6\
+\xe3s\x0a\x10\xfe\x04\x0f\x0b\x7f\x82\xa5\x02\x0c\xa7\xfd\x14\
+`\xf8\x22p\xbf*\xfe\x90\xf0\x22L*\xc0P\xda/\
+\x02\xdb\x12\xfe\x1bx=|\xfc}\xcf\xb0\x00\xd2\xf8,\
+\x04\x09\x17bn\x0b\x17b\xa4\x02H\xe3\xb3\x14,\x5c\
+\x0a\xbeS\x91-\xc5J\x05\x90\xc6\xe7\x1c\x10JI\x1d\
+\xff\xa6l!N*\x804\xbe\xfd$};\xf8dU\
+t;V,\x800\xbe\x03$\xfd@\xc8\x8d\xe0\xf1\x17\
+<\xf3\x02\x08\xe3;@w\x9f\xa9\xcf\xbf\xa8\xf5H\xd6\
+\x83\xc0'2\xeemo\x84\x00\xb2\xf8.\x90\xf4C\xa1\
+\x97\x02V#sg\xbcF\x08 \x8b\xef\x04I?\x16\
+\xfe\xacf\x93\xdf\xc2C\xaf1\x02\x88\xe2;\xf2\x1b\x90\
+\xf0\x8b!O.\x7f<\xfe\xd6S\xafQ\x02H\xe2\xbb\
+r\x1d\x90\xf0\xabas\xcb\x1fN\xb0<\xe75N\x00\
+A|w\xfe\x0d&\xfbrh9\xb3fQ\xfe\xe29\
+\xdd\x06\xf2\xf1\x08\x10=\xbeKk\x82\xc9\xbe\x1e^^\
+X\x9a\x7f\xb7*W\x99_Z\xd0/\x7fL\x02D\x8e\
+\x0fq\xd2;=33]\xd7\xb9#>\x01\x22\xc6\x87\
+\x84\x89U\x00@\x00@\x00@\x00@\x00@\x00@\x00\
+@\x00@\x00@\x00@\x00@\x00@\x00@\x00@\x00\
+@\x00@\x00@\x00@\x00@\x00@\x00@\x00@\x00\
+@\x00@\x00@\x00@\x00@\x00@\x00@\x00@\x00\
+\xcb\xf8j\xe7\xee=\xdfM\x8c\x14\xf4\xf6\x84(\x8cL\
+|\xb7\xb2{|\x9b0\xe8\xe3\x03\x1b^N\xf5W\x86\
+\x8b+\x93\xa3I\x08\x10-\xbe\x83\xfc\xe3\x9b\xcf#\xed\
+\x13\x92\xfb\xf5\x90\xa0p\xa7\xcf\xbe\xb7UY\xe5\xda\x89\
+F\x0b\x105\xbesl<\x22\xd8%&w$\xe2\xe6\
+\xca\xe5\xc9\xd5\xb53U\x17G\x1b)@\xf4\xf8\x8eq\
+\xecpU\xb6EP\xf5\x97\x8d\x11\xc2\x0e^\xa9\xb1\xcd\
+\xe4\xdb\xc6\x09 \x88\xef\x14\x83\xc7\x0b\xbe\x98\xca\x9f\x06\
+\xeb\x8d\xbb\xebQ\xcd\x9f\x93S\x8d\x12@\x12\xdf\xa9_\
+\xff\xff\xc6\xb3I\xdc\xc4\x96\xfa\xe2v\xbc\x0a8\xa1\xec\
+l\x8c\x00\xa2\xf8\x0e\xb1\xb5\xdf\x8f\x89\xfc\xd6\xba\x02/\
+\x06\xcd3\xdc\x90\xcd\xa2e\xf1\xdd\xe1`\x9c\x1b\x85n\
+\xaec\xa3\xbd\xf3\xc1\xd3\xcc6B\x00Y|g\xf8:\
+\xe6V!\xda\x06\xbc\xde\x91l\xc3\x08a|W\x18\x88\
+{\xaf\xe8\x01\xdd\xc8/\x12n\x19#\x8c\xef\xca\xf9?\
+\xfe\xdd\xc25\xaf\x03\x9e\xbfI\xb6i\x944\xbe#\xd7\
+\xff\xfd\xf1\x0b\x90\xd7\xfb/p5|\x16\xe3m\xe3\xa4\
+\xf1\xdd\xf8\xff\x7f\xd4D\xc3\x88\x1f\xb4\xd6\x03\xee\x86O\
+\xd2gZ\x00i|'\xf8\xab\x99\x961\xc7ub\xcf\
+*\x16\x97M\xb7\x8e\x95\xc6w\x81M\x053\x02\x14\xbe\
+\xd7\x08>\xa5\x98\xc4t\xf3hi|\x178l\xaak\
+\xd8\x9f5\x82\xab\xae>L\xb7\x8f\x97\xc6w\x80-U\
+S\x02T5n\x0cU\x84\x1f\x80\xe2\xdee\xcet|\
+\x078\xe2\x1bc\xaf:\xfa\xb0\xf0'\xb83|x\xa7\
+\xe9\xf8\xf6\xf3E\xce\x9c\x00\xb9]\xca\xf0C\xc2\x8b\xb0\
+l\xf8\xf8\xfd\xa6\xe3\xdb\xcf!\xdf ?)\xc3_\x0f\
+\x9f\xe0\xbej\xbc\xa2\xf7u\x9b\xe9\xf8\xf6\xf3\xb9I\x01\
+\xbeT\x86\xbf-\x5c\x88\xc9\x84\x8f\xcf\x98\x8eo=_\
+\xe5L\x0a\x90W>)z\xa7\x22[\x8a\xed\x08\xedv\
+\xd7\xd2a:\xbe\xf5\x8c\xfbF\x19W&pS\xb8\x10\
+\x17z\x0e(y\xc6\xe3\xdb\xcen\xb3\x02\xecS&p\
+\xb2*\xbb\x1d\xdb\x1a\xd2\xf34\xaf\xd1\xbfR\x1a\xdfv\
+V\xcc\x0a\xb0G\x9d\xc1\x8d\xe0\xd1\x17t\x8e`s\xf0\
+\xf8\x1e\x9d\xf1\xd2\xf8\x96\x935+@V\x9d\xc1\x83\xc0\
+'2\xeei=\x92\xd5\xdd\x174\xbe\xd8\xad3^\x1a\
+\xdfr~oV\x80\x9f5R\xb8\x14p\x1d\x9a;\xa3\
+w\x08\xed\xeb\x02\x16\x814\xfb\x97K\xe3\xdb\xcd\x88Y\
+\x01VurxV\xf3nT\xe1\xa1\xee1l\xaai\
+@\x97\xf6*\xae4\xbe\xd5\x14\xcc\x0a\x90\xd3J\xe2\xc9\
+\xe5\x8fG\xdez\xaa\x7f\x10\xed\xc5\x1a\xbf\xff\xed\xfa\xe3\
+\xa5\xf1m\xc67\x8c^\x16s\xcb\x1f\x8e[\x9e\xab\xe7\
+(\xba\x07>\xf8/\x90\xef\xa9\xab\x07\xb44>\x02\x08\
+\x05\xf0\xca\x995\x8b\xf2\x17\xcf\xd5\xdb\xc0\xbd\xb5\xf4\xde\
+\x8aPK\xa9\xb5\xce\xe1\xe2\xf8\x08 \x13\xe0\xb7\x8f`\
+ai\xfe\xdd\xaa\x5ce~i!J\xf9;2m\xd9\
+\xae\x5c\xae+\xdb\x96\xe9\x880\x5c\x1c\xdfQ\x01L\x8f\
+_C\xef\xf4\xcc\xcctor\xc5H:~\xea\x05\x00\
+\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\
+\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\
+\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\
+\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04H\x03\xd16H\
+h\x9a\x0d\x22\xfe/\x7f\xf1\xa6DQ7\x88\xf0\x1e\x1f\
+\xd8\xf0r\xaa\xbf2\x5c\x5c\x99\x1cm\x5c\xfdc#\xea\
+\x16)\xcd\x22\xc0\x9a\xfc\xa5\xd4\xbfE\x8cw\xfa\xec{\
+[\x8dU\xae\x9dhT\xfdc\x22\xfa&I\xcd!\xc0\
+G\xf9\x8bw\xa9\xaeo\x93\xa8\xf2\xe4\xea\xda\xf1\xd5\xc5\
+\xd1\xc6\xd4?\x1e\x04\xdb\xa4\x19\xde&\xae\x109\x7f)\
+\xf5l\x137x\xa5\xc66\x93o\x1bR\xffX\x90l\
+\x94hx\xa3\xc8\x91\xe8\xf9K\xd1\xdf(r\xd7\xa3\x9a\
+W\x13\xa7\x1aQ\xffX\xbe\xff\x92\xadR\x0do\x15;\
+!\xc8_\x8a\xeeV\xb1\x1d\xaf\x02\xae'w6\xa0\xfe\
+q\x9c\xff\x03\x7f?\x8746K6\xbcY\xf4~I\
+\xfeR\x86\xb46\x8b\xf6\x16\x83\xc6\x0fo7_\xff\x18\
+\x90m\x97\xbe\xc7\xac\x00\xdf\x8a\xf2\x97\xa2\xb5]\xfc\xf9\
+\xe0\xf1\xb3\xe6\xeb\x1f\xc3\xff?Y\xc3\x84\xc4\x1bF\xb4\
+\xe6\xcdE\xd7i\x18\xf1zG\xc8\x04\x0dhX!f\
+,\xac\x02c\xca\xe1;\xcd\x0ap@\x96\xbf\x14\xf5\xf1\
+{/\xc2\xc6\xf7\x19\xaf\xbf|\xfdO\xd84)\xe9\xa6\
+Q\x1d-&\xe3\xab\x8f\xff\xf9\x9b\xd0\x09\x8c7\xad\x12\
+#m\x9b\x96t\xdb\xb8\x8c\xd9_ \xe5\xf1_\x0d\x1f\
+o\xbcm\x9d\x98Rx\x02\xca\xc6\x89\xdeO&\xeb\xff\
+\x8d4\x7f)\xca\xe3\xbf\x1b>\xbe\xcfx\xfd\xa5(\xfe\
+\xc6\xa9{\xf6$\xdc:6\xe9\x9eE\xb3\x8a#\xf8\x9d\
+\xe9\xfaK\x916O\xf6\xbc\xbd\xe6\xca\xbfW\x9c\xbfx\
+1H\x15\x7fJ1\xc1\xa7\xc6\xeb/D\xda>=\xe9\
+\xf6\xf19\xb3\x02(\x8f\xbf_1\xc1z\xe3\xf5\x17\x12\
+\xc3\xdd\xb8\xc3\xa6\xaa\xffw\xaf\xf9\x05\xa8\x08\x05\x88\xef\
+y\x88\xe4\x04\xf8\xde\xd0\x1d\xc1\xc21\xaf\xf9O\x01\xc3\
+\xc2S\x80\x0b\x02x\xc7\xcd\x14\xff\x0f1\x5c\xc4\x1a\xbf\
+\x171$\xbc\x08tB\x80\xc1\xa3&j\xff\x83\xd6\x22\
+H[\xc2\x7f\x03\xaf\x87\x8f\xbf\xef\xa5A\x00oc\x7f\
+\xfc\xa5\xcfo\x89c!\xcb\xf8B\xd0m\xe1B\x90\x1b\
+\x02x\x7f\x8b\xbf\xf4[\xe3X\xca6\xbf\x14|\xa7\x22\
+[\x0avD\x00\xef\xdfq\x97\xfe\xa0\xee\x01\x18=\x07\
+\x94\xd4\xf1o\xcan\x06\xb9\x22\x80\xf7u\xcc\x95\xd7\xee\
+\xbc\x97\xf4\xed\xe0\x93U\xd1\xed`g\x04\xf0\x0e\xc6Y\
+\xf9\x81::/&\xfd@\xc8\x8d\xe0\xf1\x17\xbc\x14\x09\
+\xe0\xfd\x18\xdb\x95`~k=G\xd0\xddg\xea\xf3/\
+j=\x92\xf5 \xf0\x89\x90{\xdbS%\x80\xf7\xd9\x1f\
+\xe3\xa9\xfb\xd1-\xf5\x1dB\xd2\x0f\x85^\x0aX\x8d\xcc\
+\x9d\xf1\xd2%\x807\xb8!\x865\xc1\xc2\xbf\xea~\x08\
+\x22\xe9\xc7\xc2\x9f\xd5<\xec\xc2C/m\x02x\xde\xb1\
+\xbf\x08\xef\x0cU\x7f\xf9,\xc2A$\xfdb\xc8\x93\xcb\
+\x1f\x8f\xbf\xf5\xd4K\xa1\x00\xbf\x9d\x07\xfe#\xb8=\x93\
+\xdb\xfbI\xb4\xa3H\xfa\xd5\xb0\xb9\xe5\x0f'X\x9e\xf3\
+\xd2)\x80\xe7\xfd\xf3\xc7_#}\x1a\xf9/\x0f}\x11\
+\xfd8\x12~9\xb4\x9cYsS\xe0\xe2\xb9\xb2\x97Z\
+\x01~c\xdb\xf8\xbeo\xb3\x13#\x9aW\x04\x85\xd5\x9f\
+\xb3{\xf6\x8do\x13\x1eI\xc2\xaf\x87\x97\x17\x96\xe6\xdf\
+\xad\x0aV\xe6\x97\x16\xca\xc9\xd6?q\x01\xd2J\xef\xf4\
+\xcc\xcct\xaf]\xf5G\x80dA\x00\x04@\x00\x04@\
+\x00\x04@\x00\x04@\x00\x04@\x00\x04@\x00\x04@\x00\
+\x04@\x00\x04@\x00\x04@\x00\x04@\x00\x04@\x00\x04\
+@\x00\x04@\x00\x04@\x00\x04@\x00\x04@\x00\x04@\
+\x00\x04@\x00\x04@\x00\x04@\x00\x04@\x00\x04@\x00\
+\x04@\x00\x04@\x00\x04@\x00\x04@\x00\x04@\x00\x04\
+@\x00\x04\x88)\x81\x86m\xb0`=\xf1lPa\xbd\
+\x00\x11\xb7X\xb1\x9eX\xb7\xa8\xb1^\x80\xba7Y\xb2\
+\x9d\xd87\xa9\xb2^\x80\xfa\xb6Y\xb3\x9dvc\xfd\xab\
+-\x16\xa0\x8e\x8d\x16mg\xd3:\x1f\x01\x04[\xadZ\
+\xff\xfd7\xf8\xf9[-\x80?\xd4\x9d\x86\xcf\xbf\xbb\xe8\
+#@\x00=i\x10`\xb3\x8f\x00\x81\xff\x05R\xf0o\
+\xd0d\xc3\x0a\xeb\x05\xf0\xc7\xdc\x17`\xccG\x80\x90\x15\
+!\xe7\xd7\x04\xcd6\xad\xb2^\x00u\xdb5\xdb1\xdc\
+\xb6\xcez\x01\xda\x5c\x17\xa0\x84\x00\xa1d]\x17 \x8b\
+\x00\xe1\x8bA\xae\x0b\xd0\x89\x00\xe1w\x87]\x17 g\
+\xbb\x009\x04Hw\xfd:9\x05\xa4\xbb~\x86/b\
+\xf6s\x11\xd8\xe4\xf5k3{\x00\xce\xff\x0d\xb4\xbe~\
+\x86\x172X\x08j\xf6\xfa\x99]\xcad)\xb8\xf9\xeb\
+g\xf47\xac\xe4y\x9c\x03\x9a\xbc~&ogr;\
+\xd8\x86\xfa\x19|\xa0\x81\x07Bl\xa8_w\x9f\xb1\x07\
+\x83\xd3\xf1H\x98\xf5\xf53\xf5P#\x0f\x85\xdaR?\
+3\x8f5\xf3X\xb8=\xf53\xf1b\x03/\x86\xd8T\
+\xbf\xd8_m\xe2\xd50\xdb\xea\x17\xeb\xcb\x8d\xbc\x1cj\
+c\xfd\xe2y\xbd\x99\xd7\xc3\xa9\x1f\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00@\xda\xf8_R\xe0|\xe2\
+s\x91\xb0G\x00\x00\x00\x00IEND\xaeB`\x82\
+\
"
qt_resource_name = b"\
@@ -7138,19 +7476,26 @@
\x00B\
\x00i\x00l\x00i\x00B\x00i\x00l\x00i\x00_\x00f\x00a\x00v\x00i\x00c\x00o\x00n\x00.\
\x00i\x00c\x00o\
+\x00\x14\
+\x09\x0b\x12\xe7\
+\x00S\
+\x00c\x00a\x00n\x00-\x00q\x00r\x00-\x00c\x00o\x00d\x00e\x00.\x005\x001\x002\x00.\
+\x00p\x00n\x00g\
"
qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01\x87\xb2\x02\xd0\x5c\
+\x00\x00\x01\x89\xdf\xf3dm\
\x00\x00\x00J\x00\x01\x00\x00\x00\x01\x00\x01\xba\x82\
-\x00\x00\x01\x87\xb2\x02\xd0Z\
+\x00\x00\x01\x89\xdf\xf3dk\
+\x00\x00\x00x\x00\x00\x00\x00\x00\x01\x00\x01\xbc\x12\
+\x00\x00\x01\x89\xdf\xf3\x9f3\
\x00\x00\x00,\x00\x00\x00\x00\x00\x01\x00\x00\xa0<\
-\x00\x00\x01\x87\xb2\x02\xd0[\
+\x00\x00\x01\x89\xdf\xf3dl\
"
def qInitResources():
diff --git a/src/ui/QrCodeUI.py b/src/ui/QrCodeUI.py
new file mode 100644
index 0000000..1389fc4
--- /dev/null
+++ b/src/ui/QrCodeUI.py
@@ -0,0 +1,12 @@
+from PySide6.QtCore import Qt
+from PySide6.QtWidgets import QWidget
+from src.ui.PySide_src.qrCode_ui import Ui_QrCode
+
+
+class QrCodeUI(QWidget, Ui_QrCode):
+ """二维码窗口"""
+
+ def __init__(self):
+ super().__init__()
+ self.setupUi(self)
+ self.setWindowModality(Qt.ApplicationModal)
diff --git a/src/ui/SettingUI.py b/src/ui/SettingUI.py
index e72e036..d592f5f 100644
--- a/src/ui/SettingUI.py
+++ b/src/ui/SettingUI.py
@@ -2,14 +2,19 @@
import os
from functools import partial
+import threading
from typing import TYPE_CHECKING
+from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QFileDialog, QMessageBox, QRadioButton
+from PySide6.QtGui import QPixmap, QImage
+from urllib.parse import urlparse, parse_qs, quote
import requests
from retrying import retry
-from src.ui.MyAbout import MyAbout
+from src.ui.MyAboutUI import MyAboutUI
+from src.ui.QrCodeUI import QrCodeUI
from src.utils import (
log_path,
logger,
@@ -18,17 +23,26 @@
TIMEOUT_SMALL,
check_new_version,
)
+from src.BiliQrCode import QrCode
if TYPE_CHECKING:
from src.ui.MainGUI import MainGUI
-class SettingUI:
+class SettingUI(QObject):
"""设置窗口类,用于管理设置UI"""
+ # ?###########################################################
+ # ? 用于多线程更新我的库存
+ qr_res = Signal(dict)
+
def __init__(self, mainGUI: MainGUI):
+ super().__init__()
+ self.mainGUI = mainGUI
self.clearUserData = False
+ self.init_qrCode(mainGUI)
self.init_cookie(mainGUI)
+ self.init_biliplus_cookie(mainGUI)
self.init_savePath(mainGUI)
self.init_num_thread(mainGUI)
self.init_openLog(mainGUI)
@@ -37,6 +51,74 @@ def __init__(self, mainGUI: MainGUI):
self.init_saveMethod(mainGUI)
self.init_checkUpdate(mainGUI)
self.init_theme(mainGUI)
+ self.qr_ui = QrCodeUI()
+
+ ############################################################
+ def qrCodeCallBack(self, data: dict) -> None:
+ # sourcery skip: extract-method
+
+ if data is None:
+ self.qr_ui.close()
+ return
+
+ # 0:扫码登录成功
+ if data["code"] == 0:
+ self.qr_ui.close()
+
+ parsed_url = urlparse(data["url"])
+ query_params = parse_qs(parsed_url.query)
+ sessdata = quote(query_params["SESSDATA"][0])
+
+ self.mainGUI.updateConfig("cookie", sessdata)
+ self.mainGUI.lineEdit_my_cookie.setText(sessdata)
+ self.qr_ui.label.setText("## 请使用BiliBili手机客户端扫描二维码登入")
+
+ QMessageBox.information(
+ self.mainGUI,
+ "提示",
+ f"扫码登录成功!\n新Cookie为: {sessdata}\n已自动保存!",
+ )
+
+ # 86038:二维码已失效
+ elif data["code"] == 86038:
+ self.qr_ui.close()
+ QMessageBox.warning(self.mainGUI, "警告", "二维码已超时失效!请重新获取二维码!")
+
+ # 86090:二维码已扫码未确认
+ elif data["code"] == 86090:
+ self.qr_ui.label.setText("## 扫码成功!请在手机上确认登录!")
+
+ ############################################################
+ def init_qrCode(self, mainGUI: MainGUI) -> None:
+ """绑定二维码按钮
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ """
+
+ def _():
+ qr = QrCode(mainGUI)
+ img = qr.generate()
+ if img is None:
+ return
+
+ self.qr_ui.label_img.setPixmap(
+ QPixmap.fromImage(QImage.fromData(img)).scaled(400, 400)
+ )
+ self.qr_ui.show()
+
+ # 开一个线程去检测二维码是否扫描成功
+ thread = threading.Thread(
+ target=qr.get_cookie,
+ args=(self.qr_res,),
+ )
+ thread.start()
+
+ # 如果用户把二维码窗口关了,就把线程也关了
+ self.qr_ui.closeEvent = lambda _: setattr(qr, "close_flag", True)
+
+ self.qr_res.connect(self.qrCodeCallBack)
+ mainGUI.pushButton_qrcode.clicked.connect(partial(_))
############################################################
def init_cookie(self, mainGUI: MainGUI) -> None:
@@ -52,6 +134,9 @@ def init_cookie(self, mainGUI: MainGUI) -> None:
def _():
new_cookie = mainGUI.lineEdit_my_cookie.text()
+ if new_cookie == "":
+ QMessageBox.information(mainGUI, "提示", "请输入Cookie!")
+ return
mainGUI.updateConfig("cookie", new_cookie)
mainGUI.lineEdit_my_cookie.clearFocus()
if self.is_cookie_valid(mainGUI, new_cookie):
@@ -109,6 +194,90 @@ def _() -> None:
return False
return True
+ ############################################################
+ def init_biliplus_cookie(self, mainGUI: MainGUI) -> None:
+ """绑定BiliPlus Cookie值
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ """
+ stored_cookie = mainGUI.getConfig("biliplus_cookie")
+ if stored_cookie:
+ mainGUI.lineEdit_biliplus_cookie.setText(stored_cookie)
+ self.is_biliplus_cookie_valid(mainGUI, stored_cookie)
+
+ def _():
+ new_cookie = mainGUI.lineEdit_biliplus_cookie.text()
+ if new_cookie == "":
+ QMessageBox.information(mainGUI, "提示", "请输入Cookie!")
+ return
+ mainGUI.updateConfig("biliplus_cookie", new_cookie)
+ mainGUI.lineEdit_biliplus_cookie.clearFocus()
+ if self.is_biliplus_cookie_valid(mainGUI, new_cookie):
+ QMessageBox.information(mainGUI, "提示", "Cookie有效!")
+
+ mainGUI.lineEdit_biliplus_cookie.returnPressed.connect(_)
+ mainGUI.pushButton_biliplus_cookie.clicked.connect(_)
+
+ ############################################################
+ def is_biliplus_cookie_valid(self, mainGUI: MainGUI, cookie: str) -> bool:
+ """判断BiliPlus Cookie是否有效
+
+ Args:
+ mainGUI (MainGUI): 主窗口类实例
+ cookie (str): Cookie值
+ Returns:
+ bool: Cookie是否有效
+ """
+ # 此处对Cookie是否有效验证使用了硬编码,如果该漫画或该章节变更,需要修改才能继续正常验证
+ main_url = "https://www.biliplus.com/manga/?act=read&mangaid=26551&epid=316882"
+ headers = {
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
+ "cookie": f"login=2;access_key={cookie}",
+ }
+ payload = {}
+
+ @retry(
+ stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
+ )
+ def _() -> None:
+ try:
+ res = requests.post(
+ main_url, data=payload, headers=headers, timeout=TIMEOUT_SMALL
+ )
+ except requests.RequestException as e:
+ logger.warning(f"测试BiliPlus Cookie是否有效失败! 重试中...\n{e}")
+ raise e
+ if res.status_code != 200:
+ logger.warning(
+ f"测试BiliPlus Cookie是否有效失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
+ )
+ raise requests.HTTPError()
+ if "hoz-container" not in res.text:
+ logger.warning("BiliPlus Cookie检测出现故障,暂时无法检测是否有效...")
+ raise ReferenceError
+ elif 'class="comic-single"' not in res.text:
+ logger.warning("BiliPlus Cookie无效!重试中...")
+ raise requests.HTTPError()
+
+ try:
+ _()
+ except requests.RequestException as e:
+ logger.error(f"重复测试Cookie是否有效多次后失败!\n{e}")
+ logger.exception(e)
+ QMessageBox.warning(
+ mainGUI,
+ "警告",
+ "重复测试biliplus Cookie是否有效多次后失败!\n请核对输入的biliplus Cookie值或者检查网络连接!\n\n更多详细信息请查看日志文件",
+ )
+ return False
+ except ReferenceError:
+ QMessageBox.warning(
+ mainGUI, "警告", "BiliPlus Cookie检测功能出现故障!\n暂时无法检测是否有效!\n请自行判断或联系开发者"
+ )
+ return False
+ return True
+
############################################################
def init_savePath(self, mainGUI: MainGUI) -> None:
"""绑定漫画保存路径设置
@@ -180,7 +349,7 @@ def init_about(self, mainGUI: MainGUI) -> None:
Args:
mainGUI (MainGUI): 主窗口类实例
"""
- about_window = MyAbout()
+ about_window = MyAboutUI()
mainGUI.pushButton_about.clicked.connect(partial(about_window.show))
############################################################
@@ -249,7 +418,7 @@ def init_checkUpdate(self, mainGUI: MainGUI) -> None:
)
############################################################
-
+
def init_theme(self, mainGUI: MainGUI) -> None:
"""绑定主题相关设置
diff --git a/src/utils.py b/src/utils.py
index 5683af6..062cec7 100644
--- a/src/utils.py
+++ b/src/utils.py
@@ -1,4 +1,5 @@
from __future__ import annotations
+import hashlib
import typing
import requests
@@ -17,7 +18,7 @@
from ui.MainGUI import MainGUI
__app_name__ = "BiliBili-Manga-Downloader"
-__version__ = "1.2.0"
+__version__ = "1.3.0"
__author__ = "Zeal L"
__copyright__ = "Copyright (C) 2023 Zeal L"
@@ -72,6 +73,19 @@
############################################################
# Helper Functions
############################################################
+
+
+def isCheckSumValid(etag, content) -> tuple[bool, str]:
+ """判断MD5是否有效
+
+ Returns:
+ tuple[bool, str]: (是否有效, MD5)
+ """
+ md5 = hashlib.md5(content).hexdigest()
+ return etag == md5, md5
+
+############################################################
+
def openFolderAndSelectItems(path: str) -> None:
"""读取一个文件的父目录, 如果可能的话,选择该文件。
@@ -332,9 +346,7 @@ def check_new_version(mainGUI: MainGUI):
mainGUI (MainGUI): 主窗口类实例
"""
- url = (
- "https://api.github.com/repos/Zeal-L/BiliBili-Manga-Downloader/releases/latest"
- )
+ url = "https://api.github.com/repos/Zeal-L/BiliBili-Manga-Downloader/releases/latest"
@retry(stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX)
def _() -> dict:
@@ -354,22 +366,22 @@ def _() -> dict:
logger.error(f"重复更新信息多次后失败!\n{e}")
logger.exception(e)
QMessageBox.warning(
- mainGUI, "警告", "重复获取软件版本更新信息多次后失败!\n请检查网络连接或者重启软件!\n因需要访问github,所以请确认拥有外网访问权限(VPN)\n\n更多详细信息请查看日志文件"
+ mainGUI,
+ "警告",
+ "重复获取软件版本更新信息多次后失败!\n请检查网络连接或者重启软件!\n因需要访问github,所以请确认拥有外网访问权限(VPN)\n\n更多详细信息请查看日志文件",
)
return
if data["tag_name"][1:] != __version__:
- msgBox = QMessageBox()
- msgBox.setWindowTitle("更新小助手")
- msgBox.setText(
+ message_box = QMessageBox()
+ message_box.setWindowTitle("更新小助手")
+ message_box.setText(
f"您当前使用的版本为 v{__version__},最新版本为 {data['tag_name']}
请前往 Github 下载最新版本"
)
- msgBox.setTextFormat(Qt.RichText)
- msgBox.setIcon(QMessageBox.Information)
- msgBox.setWindowIcon(QIcon(":/imgs/BiliBili_favicon.ico"))
- msgBox.exec()
+ message_box.setTextFormat(Qt.RichText)
+ message_box.setIcon(QMessageBox.Information)
+ message_box.setWindowIcon(QIcon(":/imgs/BiliBili_favicon.ico"))
+ message_box.exec()
else:
- QMessageBox.information(
- mainGUI, "更新小助手", f"您当前使用的版本为 v{__version__},已经是最新版本了"
- )
+ QMessageBox.information(mainGUI, "更新小助手", f"您当前使用的版本为 v{__version__},已经是最新版本了")
diff --git a/version.txt b/version.txt
index bccc83a..9d0fa54 100644
--- a/version.txt
+++ b/version.txt
@@ -7,8 +7,8 @@ VSVersionInfo(
# filevers 和 prodvers 应该总是一个包含四项的元组:(1, 2, 3, 4)
# 将不需要的项目设置为零。
# 文件版本号
- filevers=(1, 2, 0, 0),
- prodvers=(1, 2, 0, 0),
+ filevers=(1, 3, 0, 0),
+ prodvers=(1, 3, 0, 0),
# 包含指定有效位“flags”的位掩码
mask=0x3f,
# 包含指定文件布尔属性的位掩码。
@@ -32,9 +32,9 @@ VSVersionInfo(
u'040904B0',
# 文件说明
[StringStruct(u'FileDescription', u'哔哩哔哩漫画下载器'),
- StringStruct(u'FileVersion', u'1, 2, 0'),
+ StringStruct(u'FileVersion', u'1, 3, 0'),
# 内部名称
- StringStruct(u'InternalName', u'哔哩哔哩漫画下载器 v1.2.0'),
+ StringStruct(u'InternalName', u'哔哩哔哩漫画下载器 v1.3.0'),
# 版权
StringStruct(u'LegalCopyright', u'Copyright (C) 2023 Zeal L'),
# 原始文件名
@@ -42,7 +42,7 @@ VSVersionInfo(
# 产品名称
StringStruct(u'ProductName', u'BiliBili-Manga-Downloader'),
# 产品版本号
- StringStruct(u'ProductVersion', u'1.2.0')])
+ StringStruct(u'ProductVersion', u'1.3.0')])
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
]