From da7f17b6e6dd42e9aa1caf1cacd5840feb013e24 Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Fri, 2 Feb 2024 20:51:21 -0400 Subject: [PATCH] dev 02022051 --- .gitignore | 2 +- .python-version | 1 + Pipfile | 14 + Pipfile.lock | 249 ++++++++++++++ da_ext_settings.py | 159 +++++++++ da_show_profiles.py | 157 +++++++++ daily_check.qrc | 9 + daily_check_rc.py | 617 ++++++++++++++++++++++++++++++++++ dailycheck.icns | Bin 0 -> 74761 bytes global_vars.py | 42 +++ images/blank_128.png | Bin 0 -> 440 bytes images/browsers/brave_32.png | Bin 0 -> 1406 bytes images/browsers/chrome_32.png | Bin 0 -> 1405 bytes images/browsers/edge_32.png | Bin 0 -> 1654 bytes images/dailycheck_128.png | Bin 0 -> 3692 bytes main.py | 74 ++++ mw_dailycheck.py | 101 ++++++ util_ext.py | 237 +++++++++++++ util_func.py | 66 ++++ wg_basic.py | 57 ++++ wg_extensions.py | 277 +++++++++++++++ wg_software.py | 133 ++++++++ 22 files changed, 2194 insertions(+), 1 deletion(-) create mode 100644 .python-version create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 da_ext_settings.py create mode 100644 da_show_profiles.py create mode 100644 daily_check.qrc create mode 100644 daily_check_rc.py create mode 100644 dailycheck.icns create mode 100644 global_vars.py create mode 100644 images/blank_128.png create mode 100644 images/browsers/brave_32.png create mode 100644 images/browsers/chrome_32.png create mode 100644 images/browsers/edge_32.png create mode 100644 images/dailycheck_128.png create mode 100644 main.py create mode 100644 mw_dailycheck.py create mode 100644 util_ext.py create mode 100644 util_func.py create mode 100644 wg_basic.py create mode 100644 wg_extensions.py create mode 100644 wg_software.py diff --git a/.gitignore b/.gitignore index 68bc17f..2dc53ca 100644 --- a/.gitignore +++ b/.gitignore @@ -157,4 +157,4 @@ cython_debug/ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +.idea/ diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..13efdf9 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12.1 diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..92c3cb1 --- /dev/null +++ b/Pipfile @@ -0,0 +1,14 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +pyside6 = "==6.6.1" +requests = "==2.31.0" +pyinstaller = "==6.3.0" + +[dev-packages] + +[requires] +python_version = "3.12" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..4fc31ac --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,249 @@ +{ + "_meta": { + "hash": { + "sha256": "1f45f6f55ba221223fabb6999af1b051bbfbab5aefdd79ad16108bb071ac8f0d" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.12" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "altgraph": { + "hashes": [ + "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406", + "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff" + ], + "version": "==0.17.4" + }, + "certifi": { + "hashes": [ + "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", + "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + ], + "markers": "python_version >= '3.6'", + "version": "==2024.2.2" + }, + "charset-normalizer": { + "hashes": [ + "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", + "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", + "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", + "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", + "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", + "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", + "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", + "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", + "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", + "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", + "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", + "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", + "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", + "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", + "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", + "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", + "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", + "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", + "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", + "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", + "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", + "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", + "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", + "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", + "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", + "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", + "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", + "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", + "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", + "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", + "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", + "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", + "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", + "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", + "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", + "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", + "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", + "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", + "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", + "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", + "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", + "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", + "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", + "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", + "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", + "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", + "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", + "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", + "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", + "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", + "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", + "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", + "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", + "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", + "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", + "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", + "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", + "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", + "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", + "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", + "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", + "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", + "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", + "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", + "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", + "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", + "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", + "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", + "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", + "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", + "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", + "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", + "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", + "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", + "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", + "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", + "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", + "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", + "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", + "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", + "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", + "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", + "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", + "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", + "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", + "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", + "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", + "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", + "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", + "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.2" + }, + "idna": { + "hashes": [ + "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", + "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + ], + "markers": "python_version >= '3.5'", + "version": "==3.6" + }, + "macholib": { + "hashes": [ + "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30", + "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c" + ], + "markers": "sys_platform == 'darwin'", + "version": "==1.16.3" + }, + "packaging": { + "hashes": [ + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2" + }, + "pyinstaller": { + "hashes": [ + "sha256:0597fb04337695e5cc5250253e0655530bf14f264b7a5b7d219cc65f6889c4bd", + "sha256:156b32ba943e0090bcc68e40ae1cb68fd92b7f1ab6fe0bdf8faf3d3cfc4e12dd", + "sha256:1eadbd1fae84e2e6c678d8b4ed6a232ec5c8fe3a839aea5a3071c4c0282f98cc", + "sha256:41c937fe8f07ae02009b3b5a96ac3eb0800a4f8a97af142d4100060fe2135bb9", + "sha256:75a6f2a6f835a2e6e0899d10e60c10caf5defd25aced38b1dd48fbbabc89de07", + "sha256:886b3b995b674905a20ad5b720b47cc395897d7b391117831027a4c8c5d67a58", + "sha256:914d4c96cc99472e37ac552fdd82fbbe09e67bb592d0717fcffaa99ea74273df", + "sha256:96c37a1ee5b2fd5bb25c098ef510661d6d17b6515d0b86d8fc93727dd2475ba3", + "sha256:abe91106a3bbccc3f3a27af4325676ecdb6f46cb842ac663625002a870fc503b", + "sha256:b721d793a33b6d9946c7dd95d3ea7589c0424b51cf1b9fe580f03c544f1336b2", + "sha256:de25beb176f73a944758553caacec46cc665bf3910ad8a174706d79cf6e95340", + "sha256:e436fcc0ea87c3f132baac916d508c24c84a8f6d8a06c3154fbc753f169b76c7" + ], + "index": "pypi", + "markers": "python_version < '3.13' and python_version >= '3.8'", + "version": "==6.3.0" + }, + "pyinstaller-hooks-contrib": { + "hashes": [ + "sha256:469b5690df53223e2e8abffb2e44d6ee596e7d79d4b1eed9465123b67439875a", + "sha256:a7118c1a5c9788595e5c43ad058a7a5b7b6d59e1eceb42362f6ec1f0b61986b0" + ], + "markers": "python_version >= '3.7'", + "version": "==2024.0" + }, + "pyside6": { + "hashes": [ + "sha256:0a67587c088cb80e90d4ce3023b02466ea858c93a6dc9c4e062b13314e03d464", + "sha256:3593d605175e83e6952cf3b428ecc9c146af97effb36de921ecf3da2752de082", + "sha256:3c348948fe3957b18164c9c7b8942fe065bdb39648b326f212bc114326679fa9", + "sha256:ed3822150f0d7a06b68bf4ceebe287515b5e8309bb256e9b49ae405afd062b18" + ], + "index": "pypi", + "markers": "python_version < '3.13' and python_version >= '3.8'", + "version": "==6.6.1" + }, + "pyside6-addons": { + "hashes": [ + "sha256:5a63a8a943724ce5acd2df72e5ab04982b6906963278cbabb216656b9a26ee18", + "sha256:7cb7af1b050c40f7ac891b0e61c758c1923863173932f5b92dc47bdfb4158b42", + "sha256:a0982da4033319667f9df5ed6fa8eff300a88216aec103a1fff6751a172b19a0", + "sha256:a223575c81e9a13173136c044c3447e25f6d656b462b4d71fc3c6bd9c935a709" + ], + "markers": "python_version < '3.13' and python_version >= '3.8'", + "version": "==6.6.1" + }, + "pyside6-essentials": { + "hashes": [ + "sha256:0c8917b15236956957178a8c9854641b12b11dad79ba0caf26147119164c30cf", + "sha256:13da926e9e9ee3e26e3f66883a9d5e43726ddee70cdabddca02a07aa1ccf9484", + "sha256:a383c3d60298392cfb621ec1a0cf24b4799321e6c5bbafc021d4cc8076ea1315", + "sha256:c7185616083eab6f42eaed598d97d49fac4f60ae2e7415194140d54f58c2b42c" + ], + "markers": "python_version < '3.13' and python_version >= '3.8'", + "version": "==6.6.1" + }, + "requests": { + "hashes": [ + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==2.31.0" + }, + "setuptools": { + "hashes": [ + "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", + "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" + ], + "markers": "python_version >= '3.8'", + "version": "==69.0.3" + }, + "shiboken6": { + "hashes": [ + "sha256:072c35c4fe46ec13b364d9dc47b055bb2277ee3aeaab18c23650280ec362f62a", + "sha256:a605960e72af5eef915991cee7eef4cc72f5cabe63b9ae1a955ceb3d3b0a00b9", + "sha256:d756fd1fa945b787e8eef142f2eb571da0b4c4dc2f2eec1a7c12a474a2cf84e4", + "sha256:fb102e4bc210006f0cdd0ce38e1aaaaf792bd871f02a2b3f01d07922c5cf4c59" + ], + "markers": "python_version < '3.13' and python_version >= '3.8'", + "version": "==6.6.1" + }, + "urllib3": { + "hashes": [ + "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20", + "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224" + ], + "markers": "python_version >= '3.8'", + "version": "==2.2.0" + } + }, + "develop": {} +} diff --git a/da_ext_settings.py b/da_ext_settings.py new file mode 100644 index 0000000..4179456 --- /dev/null +++ b/da_ext_settings.py @@ -0,0 +1,159 @@ +# coding: utf8 +from PySide6 import QtWidgets, QtCore + + +class PushButtonWithId(QtWidgets.QPushButton): + + clicked_with_id = QtCore.Signal(str) + + def __init__(self, ids: str, parent: QtWidgets.QWidget = None, title: str = ""): + super().__init__(title, parent) + self.ids = ids + self.clicked.connect(self.on_self_clicked) + + def on_self_clicked(self): + self.clicked_with_id.emit(self.ids) + + +class DaExtSettings(QtWidgets.QDialog): + + def __init__(self, parent: QtWidgets.QWidget = None): + super().__init__(parent) + self.setWindowTitle("设置") + + self.vly_m = QtWidgets.QVBoxLayout() + self.setLayout(self.vly_m) + + self.gbx_exec = QtWidgets.QGroupBox("执行文件路径", self) + self.vly_m.addWidget(self.gbx_exec) + + self.gly_gbx_exec = QtWidgets.QGridLayout() + self.gbx_exec.setLayout(self.gly_gbx_exec) + + self.lb_exec_chrome = QtWidgets.QLabel("Chrome", self) + self.lb_exec_edge = QtWidgets.QLabel("Edge", self) + self.lb_exec_brave = QtWidgets.QLabel("Brave", self) + self.lne_exec_chrome = QtWidgets.QLineEdit(self) + self.lne_exec_edge = QtWidgets.QLineEdit(self) + self.lne_exec_brave = QtWidgets.QLineEdit(self) + self.pbn_exec_chrome = PushButtonWithId("ChromeExec", self, "选择") + self.pbn_exec_edge = PushButtonWithId("EdgeExec", self, "选择") + self.pbn_exec_brave = PushButtonWithId("BraveExec", self, "选择") + + self.gly_gbx_exec.addWidget(self.lb_exec_chrome, 0, 0) + self.gly_gbx_exec.addWidget(self.lb_exec_edge, 1, 0) + self.gly_gbx_exec.addWidget(self.lb_exec_brave, 2, 0) + self.gly_gbx_exec.addWidget(self.lne_exec_chrome, 0, 1) + self.gly_gbx_exec.addWidget(self.lne_exec_edge, 1, 1) + self.gly_gbx_exec.addWidget(self.lne_exec_brave, 2, 1) + self.gly_gbx_exec.addWidget(self.pbn_exec_chrome, 0, 2) + self.gly_gbx_exec.addWidget(self.pbn_exec_edge, 1, 2) + self.gly_gbx_exec.addWidget(self.pbn_exec_brave, 2, 2) + + self.gbx_data = QtWidgets.QGroupBox("用户数据路径", self) + self.vly_m.addWidget(self.gbx_data) + + self.gly_gbx_data = QtWidgets.QGridLayout() + self.gbx_data.setLayout(self.gly_gbx_data) + + self.lb_data_chrome = QtWidgets.QLabel("Chrome", self) + self.lb_data_edge = QtWidgets.QLabel("Edge", self) + self.lb_data_brave = QtWidgets.QLabel("Brave", self) + self.lne_data_chrome = QtWidgets.QLineEdit(self) + self.lne_data_edge = QtWidgets.QLineEdit(self) + self.lne_data_brave = QtWidgets.QLineEdit(self) + self.pbn_data_chrome = PushButtonWithId("ChromeData", self, "选择") + self.pbn_data_edge = PushButtonWithId("EdgeData", self, "选择") + self.pbn_data_brave = PushButtonWithId("BraveData", self, "选择") + + self.gly_gbx_data.addWidget(self.lb_data_chrome, 0, 0) + self.gly_gbx_data.addWidget(self.lb_data_edge, 1, 0) + self.gly_gbx_data.addWidget(self.lb_data_brave, 2, 0) + self.gly_gbx_data.addWidget(self.lne_data_chrome, 0, 1) + self.gly_gbx_data.addWidget(self.lne_data_edge, 1, 1) + self.gly_gbx_data.addWidget(self.lne_data_brave, 2, 1) + self.gly_gbx_data.addWidget(self.pbn_data_chrome, 0, 2) + self.gly_gbx_data.addWidget(self.pbn_data_edge, 1, 2) + self.gly_gbx_data.addWidget(self.pbn_data_brave, 2, 2) + + self.hly_bot = QtWidgets.QHBoxLayout() + self.pbn_save = QtWidgets.QPushButton("保存", self) + self.pbn_cancel = QtWidgets.QPushButton("取消", self) + + self.hly_bot.addStretch(1) + self.hly_bot.addWidget(self.pbn_save) + self.hly_bot.addWidget(self.pbn_cancel) + + self.vly_m.addLayout(self.hly_bot) + self.vly_m.addStretch(1) + + self.pbn_save.clicked.connect(self.on_pbn_save_clicked) + self.pbn_cancel.clicked.connect(self.on_pbn_cancel_clicked) + + self.pbn_exec_chrome.clicked_with_id.connect(self.on_pbn_exec_n_clicked_with_id) + self.pbn_exec_edge.clicked_with_id.connect(self.on_pbn_exec_n_clicked_with_id) + self.pbn_exec_brave.clicked_with_id.connect(self.on_pbn_exec_n_clicked_with_id) + + self.pbn_data_chrome.clicked_with_id.connect(self.on_pbn_data_n_clicked_with_id) + self.pbn_data_edge.clicked_with_id.connect(self.on_pbn_data_n_clicked_with_id) + self.pbn_data_brave.clicked_with_id.connect(self.on_pbn_data_n_clicked_with_id) + + self.read_settings() + + def sizeHint(self): + return QtCore.QSize(540, 140) + + def read_settings(self): + us = QtCore.QSettings() + chrome_exec = str(us.value("ChromeExec", "")) + edge_exec = str(us.value("EdgeExec", "")) + brave_exec = str(us.value("BraveExec", "")) + + chrome_data = str(us.value("ChromeData", "")) + edge_data = str(us.value("EdgeData", "")) + brave_data = str(us.value("BraveData", "")) + + self.lne_exec_chrome.setText(chrome_exec) + self.lne_exec_edge.setText(edge_exec) + self.lne_exec_brave.setText(brave_exec) + + self.lne_data_chrome.setText(chrome_data) + self.lne_data_edge.setText(edge_data) + self.lne_data_brave.setText(brave_data) + + def on_pbn_exec_n_clicked_with_id(self, ids: str): + filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, f"选择 {ids}") + if len(filename) == 0: + return + if ids == "ChromeExec": + self.lne_exec_chrome.setText(filename) + elif ids == "EdgeExec": + self.lne_exec_edge.setText(filename) + elif ids == "BraveExec": + self.lne_exec_brave.setText(filename) + + def on_pbn_data_n_clicked_with_id(self, ids: str): + dirname = QtWidgets.QFileDialog.getExistingDirectory(self, f"选择 {ids}") + if len(dirname) == 0: + return + if ids == "ChromeData": + self.lne_data_chrome.setText(dirname) + elif ids == "EdgeData": + self.lne_data_edge.setText(dirname) + elif ids == "BraveData": + self.lne_data_brave.setText(dirname) + + def on_pbn_save_clicked(self): + us = QtCore.QSettings() + us.setValue("ChromeExec", self.lne_exec_chrome.text()) + us.setValue("EdgeExec", self.lne_exec_edge.text()) + us.setValue("BraveExec", self.lne_exec_brave.text()) + + us.setValue("ChromeData", self.lne_data_chrome.text()) + us.setValue("EdgeData", self.lne_data_edge.text()) + us.setValue("BraveData", self.lne_data_brave.text()) + + self.accept() + + def on_pbn_cancel_clicked(self): + self.reject() diff --git a/da_show_profiles.py b/da_show_profiles.py new file mode 100644 index 0000000..dadd8b7 --- /dev/null +++ b/da_show_profiles.py @@ -0,0 +1,157 @@ +# coding: utf8 +import os +from pathlib import Path +from PySide6 import QtWidgets, QtCore, QtGui +from util_ext import ProfilesData, DeleteThread, DeleteThreadManager +from global_vars import accept_warning + + +def sort_profiles_id_func(profile_id: str) -> int: + if profile_id == "Default": + return 0 + else: + seq = profile_id.split(" ", 1)[-1] + try: + return int(seq) + except ValueError: + # if the id is weird + return 999 + + +class ProfilesModel(QtCore.QAbstractTableModel): + + def __init__(self, + profiles_data: ProfilesData, + ext_id: str, + profiles: list[str], + parent=None): + super().__init__(parent) + self.ext_id = ext_id + self.profiles = profiles + self.profiles.sort(key=sort_profiles_id_func) + self.profiles_data = profiles_data + + def rowCount(self, parent: QtCore.QModelIndex = ...): + return len(self.profiles) + + def columnCount(self, parent: QtCore.QModelIndex = ...): + return 2 + + def data(self, index: QtCore.QModelIndex, role: int = ...): + row = index.row() + col = index.column() + + if col == 0: + if role == QtCore.Qt.ItemDataRole.DisplayRole: + return self.profiles[row] + elif col == 1: + if role == QtCore.Qt.ItemDataRole.DisplayRole: + return self.profiles_data[self.profiles[row]].name + + def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = ...): + if role == QtCore.Qt.ItemDataRole.DisplayRole: + if section == 0: + return "ID" + if section == 1: + return "名称" + + +class DaShowProfiles(QtWidgets.QDialog): + + def __init__(self, + browser: str, + is_compat: bool, + profiles_data: ProfilesData, + ext_id: str, + ext_name: str, + ext_icon: QtGui.QIcon, + profiles: list[str], + parent: QtWidgets.QWidget = None): + super().__init__(parent) + self.setWindowTitle(ext_name) + self.setWindowIcon(ext_icon) + self.browser = browser + self.is_compat = is_compat + + self.process = QtCore.QProcess(self) + + # ========== UI ============== + + self.vly_m = QtWidgets.QVBoxLayout() + self.setLayout(self.vly_m) + + self.lne_info = QtWidgets.QLineEdit(ext_id, self) + self.lne_info.setReadOnly(True) + self.vly_m.addWidget(self.lne_info) + + self.trv_profiles = QtWidgets.QTreeView(self) + self.trv_profiles.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection) + self.vly_m.addWidget(self.trv_profiles) + + self.pgb_del = QtWidgets.QProgressBar(self) + self.pgb_del.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.vly_m.addWidget(self.pgb_del) + + self.hly_bot = QtWidgets.QHBoxLayout() + self.pbn_delete_selected = QtWidgets.QPushButton("删除所选", self) + self.pbn_open = QtWidgets.QPushButton("打开", self) + self.pbn_cancel = QtWidgets.QPushButton("取消", self) + self.hly_bot.addWidget(self.pbn_delete_selected) + self.hly_bot.addStretch(1) + self.hly_bot.addWidget(self.pbn_open) + self.hly_bot.addWidget(self.pbn_cancel) + self.vly_m.addLayout(self.hly_bot) + + self.profiles_model = ProfilesModel(profiles_data, ext_id, profiles, self) + self.trv_profiles.setModel(self.profiles_model) + + self.pbn_delete_selected.clicked.connect(self.on_pbn_delete_selected_clicked) + self.pbn_open.clicked.connect(self.on_pbn_open_clicked) + self.pbn_cancel.clicked.connect(self.reject) + + def sizeHint(self): + return QtCore.QSize(400, 360) + + def on_pbn_open_clicked(self): + us = QtCore.QSettings() + exec_path = str(us.value(f"{self.browser}Exec", "")) + if len(exec_path) == 0 or not os.path.exists(exec_path): + QtWidgets.QMessageBox.critical(self, "错误", f"无法找到 {self.browser} 浏览器的执行路径") + return + + indexes = self.trv_profiles.selectedIndexes() + cmd = rf'"{exec_path}" --profile-directory="{{0}}"' + for idx in indexes: + if idx.column() != 0: + continue + profile_id = self.profiles_model.data(idx, QtCore.Qt.ItemDataRole.DisplayRole) + # setProgram 不行,不知道为什么,莫名其妙 + self.process.startCommand(cmd.format(profile_id)) + self.process.waitForFinished(10000) + + def on_pbn_delete_selected_clicked(self): + us = QtCore.QSettings() + user_data_path = str(us.value(f"{self.browser}Data", "")) + if self.is_compat: + pref_name = "Preferences" + else: + pref_name = "Secure Preferences" + + indexes = self.trv_profiles.selectedIndexes() + total = len(indexes) // 2 + if accept_warning(self, True, "警告", f"确定要删除这 {total} 项吗?"): + return + + del_thd_mgr = DeleteThreadManager(total, self.pgb_del, self) + + for idx in indexes: + if idx.column() != 0: + continue + profile_id = self.profiles_model.data(idx, QtCore.Qt.ItemDataRole.DisplayRole) + del_thd = DeleteThread( + str(Path(user_data_path, profile_id)), + pref_name, + [self.lne_info.text()], + self + ) + del_thd_mgr.start(del_thd) diff --git a/daily_check.qrc b/daily_check.qrc new file mode 100644 index 0000000..e90314e --- /dev/null +++ b/daily_check.qrc @@ -0,0 +1,9 @@ + + + images/blank_128.png + images/browsers/chrome_32.png + images/browsers/edge_32.png + images/browsers/brave_32.png + images/dailycheck_128.png + + diff --git a/daily_check_rc.py b/daily_check_rc.py new file mode 100644 index 0000000..e8f7a41 --- /dev/null +++ b/daily_check_rc.py @@ -0,0 +1,617 @@ +# Resource object code (Python 3) +# Created by: object code +# Created by: The Resource Compiler for Qt version 6.6.1 +# WARNING! All changes made in this file will be lost! + +from PySide6 import QtCore + +qt_resource_data = b"\ +\x00\x00\x01\xb8\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3>a\xcb\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x04gAMA\x00\x00\xb1\x8f\x0b\xfca\x05\x00\x00\x00\ +\x09pHYs\x00\x00\x0e\xc1\x00\x00\x0e\xc1\x01\xb8\x91\ +k\xed\x00\x00\x01MIDATx^\xed\xd21\x01\ +\x00 \x0c\xc0\xb0\x81\x7f\xcf\xe3\xc1E\x9a\xa7\x06zv\ +w\xe2\xba\xbfA5\x00\xae\x01p\x0d\x80k\x00\x5c\x03\ +\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\x00\xae\x01p\x0d\x80k\ +\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\x00\xae\x01p\ +\x0d\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\x00\ +\xae\x01p\x0d\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\ +\xc05\x00\xae\x01p\x0d\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\ +\x00\xb8\x06\xc05\x00\xae\x01p\x0d\x80k\x00\x5c\x03\xe0\ +\x1a\x00\xd7\x00\xb8\x06\xc05\x00\xae\x01p\x0d\x80k\x00\ +\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\x00\xae\x01p\x0d\ +\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\x00\xae\ +\x01p\x0d\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc0\ +5\x00\xae\x01p\x0d\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\ +\xb8\x06\xc05\x00\xae\x01p\x0d\x80k\x00\x5c\x03\xe0\x1a\ +\x00\xd7\x00\xb8\x06\xc05\x00\xae\x01p\x0d\x80k\x00\x5c\ +\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\x00\xae\x01p\x0d\x80\ +k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\x00\xae\x01\ +p\x0d\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\x06\xc05\ +\x00\xae\x01p\x0d\x80k\x00\x5c\x03\xe0\x1a\x00\xd7\x00\xb8\ +\x06\xc05\x00\xae\x01p\x0d\x80k\x00\x5c\x03\xe0\x1a\x80\ +6\xf3\x00\xedw\x03\xfd\xcd\xd11\xb4\x00\x00\x00\x00I\ +END\xaeB`\x82\ +\x00\x00\x0el\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x80\x00\x00\x00\x80\x08\x03\x00\x00\x00\xf4\xe0\x91\xf9\ +\x00\x00\x03\x00PLTEGpL\xd3\xb0\x22\xfb\xd1\ +*\xe5\xbf%\xd3\xc1'\xf9\xd1(\xdf\xba$\xe8\xca*\ +\xd7\xc4)\xd8\xc2'\xd8\xb4$\xd2\xaf#\xfa\xd1'\xfd\ +\xd4-\xf4\xcd&\xd1\xaf#\xcf\xad#\xd0\xae\x22\xf9\xcf\ +'\xfa\xd0(\xf6\xcf&\xca\xb0#\xcd\xab\x1f>\xb56\ +\xfa\xd1'\xfb\xd1'\xfb\xd2)\xfa\xd0&\xd3\xb0#\xd0\ +\xae&\xf8\xce%\xf9\xcf'\xf8\xcf&\xf5\xcb#O\xcc\ +?\xd0\xae\x22\xd5\xb2%\xd3\xb0&\xcf\xac!\xfb\xd1(\ +\xfb\xd1(\xfd\xd3+\xfb\xd2)\xfd\xd4-\xf7\xcd\x22\xf9\ +\xcf%A\xbe9\xd3\xb0$I\xca@O\xbf7\xfd\xd3\ +,\xf6\xcc \xf7\xce(\xfa\xd1'\xd1\xaf#\xd3\xb0%\ +\xcf\xad \xd3\xb0#\xd1\xaf'\xd3\xb0&@\xbc9\xfb\ +\xd1(\xf9\xcf$\xfd\xd3,\xf8\xce\x22\xda\xb7'\xd4\xb2\ +'\xd8\xb5&\xd3\xb1'\xd0\xae\x22\xcc\xaa\x1e\xca\xb3\x22\ +\xfe\xd4-\xf3\xca#\xfd\xd4,\xfd\xd3,U\xdeK\xe2\ +\xbd(\xfd\xd4-P\xd7F\xe0\xba%S\xdcHZ\xdc\ +J=\xb46D\xc4;=\xb75<\xb25\xf7\xcd!\ +L\xd6B\xef\xc6 T\xddJO\xdbF\xf6\xcc \xd9\ +\xb5$C\xc0;A\xbc:\xf3\xc9!\xf7\xcd\x22\xd8\xb5\ +&<\xb35W\xdfM\xd6\xb4*X\xdfN\xdd\xba*\ +\xf1\xc8$C\xc1;\xf7\xcd\x22V\xddJ\xb7\xbd(\xfd\ +\xd4-G\xc7>>\xb56V\xddKd\xdcF\xed\xc4\ +\x1f\xff\xcf'\xff\xcf'\xfb\xd1)\xfb\xd2*\xff\xff\xff\ +\xf9\xcf&\xfa\xd0'\xfa\xd1(\xfc\xd3,\xf7\xcd#\xfc\ +\xd3+\xfc\xd2+\xf7\xcd\x22\xf8\xce$\xf6\xcc!\xf5\xca\ +\x1e\xfa\xd0(\xf6\xcb\x1f\xf9\xcf%\xf9\xd0'T\xddJ\ +\xf5\xcb\x1f\xf4\xca\x1d\xfd\xd4-\xf4\xc9\x1c\xf6\xcc \xf8\ +\xcf%P\xdcGW\xdfNV\xdeLK\xd9AI\xd8\ +?\xf3\xc8\x1a\xf8\xce#S\xddIR\xdcHE\xd6<\ +U\xdeKP\xdbFF\xd7=G\xd7>D\xd6;O\ +\xdbEH\xd8?\xf4\xc9\x1dN\xdbEC\xd5:B\xd5\ +9\xfd\xd3,\xfd\xd4.\xf7\xcc\x22\xf7\xcc!L\xdaC\ +\xd1\xaf'\xfd\xd3-G\xd7=C\xd6:\xcb\xa9\x1eM\ +\xdaD\xfe\xd5.M\xdaCY\xe0OY\xdfO\xcf\xac\ +!@\xd47A\xd58\xdf\xba&\xf5\xcc&F\xca>\ +A\xca8\xfe\xd4.\xeb\xc4'\xda\xb6$\xd9\xb4\x1e=\ +\xb65\xd4\xb0\x1e\xfc\xfe\xfc\xe6\xc0(\xe9\xc1\x1d\xef\xc5\ +\x1cK\xd6BC\xd0:\xdf\xb8\x1f\xef\xc8$\xd4\xb1&\ +\xfa\xfc\xfa\xf0\xc9)N\xc9F\x8d\xd36H\xd1?\xe2\ +\xbb\x1eB\xc58\xe7\xce%\xed\xed\xed\x9c\xeb\x97z\xe4\ +s\xe2\xe6\xe2\xf7\xf7\xf7>\xc06\xc2\xf2\xbe\x9b\xd69\ +\xd3\xd0*Y\xc9R\xbe\xd8\xbd\xf4\xf4\xf4\xf1\xfc\xf1\xc8\ +\xd2.\xdd\xf8\xdby\xdbD`\xddI\xf6\xce)z\xcb\ +u\xae\xd4\xab\x88\xcd\x83\xfe\xd5/\x87\xe7\x81\xb4\xd31\ +\xdf\xcd%\x9c\xc3+\xcb\xdb\xcae\xc9^\xa1\xd1\x9e\xaf\ +\xef\xab\xbf\xd2/j\xdbDm\xe2ec\xdeZ\xcd\xc4\ +!\xd8\xe0\xd7q\xcbk\xb6\xef\xb2\x84\xe2}X\xd7P\ +\x98\xd0\x94[\xc16\x8b\xb6+l\xc97\x8e\xe7\x88o\ +\xb0.\xfb2\x02\xfb2\x02\x90\x0aZ\x1e\x00\x00\x01\x00\ +tRNS\x00!s\x17\x05\xcf\x0b\x07\x02\x01\x13n\ +!\xf3\x1b\xd6\xcc\x8bH6S-^\xb8\x10\xab\xb9\xa1\ +\x98\xf4h/@{\x0c\x81K\xb3R\x5c\xf0\xc0\x0e\xfa\ +\xf0\xb1Dd\x1f\x15\x83\xfb(\xfa\xc0vD4\xfa\xed\ +\x8a\xe0\xc7\xd8\xf6\x8d\xe3X\xa3\xaa\xe9@\xeab\xdd\xe6\ +\x93\xfc\x92(\xc6L\xcd\xc9vR\xd2\xe8\xaf\xa1\xea\xab\ +\xe5\xf3\xa5\x96\x90\xdd:\xec\xe5\xc4\xf5\xf9\xc2\xe8\x90d\ +\xfe\xdc\xda\xf1\xd7\xb8\xf7\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ +\xff\xffss\xaa\x1e4\xff\x00\x00\x0a\x1bIDAT\ +x\xda\xbd\x9byX\x14G\x1a\xc6\x9bc`\x86C\x06\ +\x04\xb9QNAP\xc1\x03T\xf0\xbeWQ\xe3\xb9f\ +\xe3\x15s'\xee\xf5A\x83\x18Y\xf1\ +X\xa9[\xc0=(\xc8\xcbK\xe8\xbd0`\xbc\xadJ\ +|\xfc\xac\xb1\xe3e\xb2\x84\xf87\xa5A6N&\x1b\ +;6>~d\xe7u\x88\x172\x09\x1f\xf9wq\xb4\ +7\x9a25\x06\x8d&\xd3\xd4\xb8Yd\xd5\xb1\xa8\xf5\ +R\xb08u\x93\x81d\xa0\xd1\x8b\xf3\x80\xd8Oq\x8b\ +\x17Q\xbfBC\x89\x86\xa7\xfazN\x8e\x89\xe9\x97\x16\ +\xa6\x1cC\x92\x0d\xa6v\x11\x01\xc6\xf1\x0d\xf8\xff\x0b\xcc\ +:\x13I\xa6\x87\x8dr'\x14\x1dX\xdc\xc7M\x1dC\ +Y\xd8\x0c\x8f\xc1\xdfO\x09\x05\xd7ml 'y\xb2\ +\xdf\xaf\x94\x0f\x17\xdfp\xd2P\x01\x0e\xc2\xdbOq\x8f\ +\xff\x1b\x10=9&\x1a\xf9zw\x99B64B\xa3\ +\x84p\xa7\x00?\xb8\xbe\xcfh\xa1\x89$.\x9d\xac\x07\ +\x86\x19\xc9}\x0eB\xc1\xfa\xb1\x83\x84\xa72'\x1f\x12\ +\xda\x0639\x1b1\xc0\x1e\xa8'\xa7\xd8{\xb7+<\ +\x94\x0d\x15\xb0H\x9c=\xad\x01\x9bAT4\xc4b\x96\ +\xb9\x1e>\x86u\xa0P#Y\xe3H\xb1\x12f@\xa3\ +\xc4\xae1\x9d\xd2M\xb0X\xfe\xec\xd4\xa3b\x1d\x80\xfa\ +p'\xfc+-\x86\x04\xc5\xda\x1e\xc6\xaa\xe5k\x80\xd4\ +2\x80\x16XS4\x10\x03\x1a_v\xc3\x85\x93\xa6\xed\ +\xd8\x06P\x82\xf69<\xc2\xf17Sa 9\x0f\xf3\ +\xa8I$\xb6\x114\xc0\xec:\xda\x84\xd3\xd7\x93\xa4/\ +\xcf\xf7T\x92\xd4\xdb\xad\xb5\xc1\x07\x98\xdby,\xc3\xdc\ +\xbe\x86LG\xad\xd5&\xa7\x93\x9a\x8a\xb7\x84\x81/\xb1\ +\xa7\xd8\x0b\xf3\x96\xbe\x81\x8cE'E.\xb1d\x83^\ +\xb8\x22|\x93#\xc6N\x14\xea\xf6\xc3\x87\x0a5\xa5b\ +h\xb8\x9dF\x98\x07\xdf\xe0\xce\x14\xd4\xafo S\xed\ +=\xcbN\xa9dC\xfdv4\x22\xd67\xf3\x04Bd\ +S\xb7\x9ff\xffQ\x92\xa7\x8d\xa1\x1aa\x03\x0a\x11k\ +\xfc\x89\xc8\x00\x1b\xa8\xdbW\x06\xe0wF\x94\xa4\x06U\ +;\xbb?\xdc\xc0L\xa4~\x05\x95I@\x96\xa9\xae\xd1\ +\x06\xa4\x01\xf86\x8f\xdc\x0f\xdd\x00\xc2\x99\x04\x87Hd\ +}\x11\xbb\x1c\x03\x90\x01\x92<\xa0\xf5\xfd\x91\xf5\xdd\xbb\ +k`\x15t\x91\xda\x7f\x15\xb2\xbe\x88\xc3\x17t\x17l\ +x\x0dt\x0f\xf2\xc8\x09\xe8\xea\x22v{\x07\xa2#l\ +\x90\x01\x06\xb2\xd7\xb8=\x02\xf8\xc1\x0dD\x0a\xc5\x98\x10\ +\x89y\xa1*\x22&\x08\xd5\xdd#\xe2x:X0\xc8\ +\x9eq^vw\xe6B\xb2\x85\x11q4\xfa\x9c\x9d0\ +\x13\x22\x84\xc7\xe2\xc0$;\x15\xb3\x93\xa0{]\x8a\x11\ +\xf6\xc2d\x7f\x10\x22p\xce\xed\x12\x9cm\x1f\xf0 \x88\ +\xb4\x1f''\x09y\xa0\xea\xbf\x04\xa3\x9f\x1d\x0c\x9d\x08\ +W\xe1\x22\xe5\x04\xbb\xf0\xcf(\xd7c\x19\xee\x05\x9c\xc7\ +\xa8\xef\xe6\x9c\xb9\xf4\x15\xc5\xa5\xbb9\xe8XK8'\ +y\xee\xb2\xf5\x00Ba\x0d {\xd0v\xa3\xec\xb3N\ +\xcan\xb4\xdd9\x83\x88\x95\xc4n\x83\x08\x88\xfe\xfal\ +\xc0~W\xd4\xeb\xf3iq\x9a\x1b\x08\x0f\xac\xa7Z\xbe\ +\x14d`\x9b\x0c7\x97&\xcf~\xa9\x0cM\xdb]v\ +\xac\x1c\xf6\xc2dj\xce\x07 ^\xb3\x7f\xf7\xb3_\xda\ +)HY\xdb\x19f$}\x1a{c\xbc\xe6C\x183\ +\xed\xe8?\xf3\xc2N{\x94\xdd|\xc0\x08T\xc7\xce\x0c\ +=\x0c90\x86\xfb\x0b\x1e6\xcf\xde\x89\xa5\xa9\x9e\x0e\ +\xe4\xc3\xa9\x9e\x9a\x07u \xd0\x06\xc9\xf3\xf1\xfa;?\ +{x\xd7\x1a%\xaf>\x9a{8Q\x93\x03e%j\ +J\x9e\xfb\xc2.\x08e7/Y\x83h\xb8\xc9\xa9\x8b\ +\x01l g\x1c\xef\xad\xae\x98\xfb\xec. V\x07\x1f\ +\xfa\xf0n!5o\x1b\x98\xe1K9\xaf\x93d\xb0~\ +\x87\x03*B=omJx\xd6\xc0\x0dP#!t\ +@Wf\xa1\x88\xfa\xf3;\x22xxf\xdb\xb6\xd3\xfc\ +\xfc\xd8\xc9\xb0M\x1cKB#\xfa\xbaP\xafv\xd7>\ +\xd3\xff\xf2\x8e(n\xe4\xe5\xa1\x0eQ\x94\xa7\xf36\x89\ +'i\xc2\xa6Mwr\xc5\xb1\xab\xcd\xe0\x8b:\xa4+\ +\xaf\xaa\xb3`0TVVuP^\xf9\x1e\xc4\xc3\xdd\ +\x9b\xb9by\x03\xb5@S\x84\x95\xf3\xa8\x01\xe8\xe74\ +\x89\xd6\xcf\x9d\x8f\x9eKF\xa7EG{z\x0e\xed\x17\ +\x17\x173}z@\x80\x93\xd3\xe4\xbf\x02\x0c\x5cz\x1b\ +\xc6\xe3s\xe7m\x7f\xee\xcd}\x06\x92\xd9u\x1cZ\xe5\ +a\xd9x\x03$\x9f\xfb\xe8\x9a\xaa\xfa[\xda\xc1|`\ +r\xb5\x0ao\xe0\xd2^\x10\xe7\xaf\xa9T\x94\x03\xfaz\ +\x08\xec\xb7\x5cx\xfdMMp}\x95\xea\xe4O\x9d\xd7\ +o\xff\x01d`%\xde@}.H\xff\xa4\xca\xca\xc9\ +\xf3\xb6\xa2\x14Hr\xf7\xdcF,\x0fv\x00\xf8\xd6\xa6\ +O9xd)\xd9\xbb\xe3u\xc8\x1a\x17\xaf\xbf\xb1I\ +\x9c\xbe\xaa\xfa\xa7\xceBH\x1f,\x05\x18x\xb8\x0f\xcb\ +\x7f\xab\x19\xfa\xf7~\xb6\x16\x96<\x8b\xdf,pK\xc2\ +\xeb\x9f\xc1\xeb\x9fc\xe8\x9f\xbcw\xb9\xd4V>\x17\xbf\ +\xbe\xc0\xebo\xfd\xaa\x84\xc1\xbeG\xbbJx\x9cS1\ +\xf4\xaf\x5c>A\x7f\x80\x9f\x8b\x06o\xc1s\x87!U\ +v]u\xed\x8c\x5c>\xb5\xd0\xc6\ +w\xcc\xa0\xcd\xa7\xbe?\x0b\xd4\xdf\xbd\x02v\x04\x19\xab\ +.\xaf\xa1dj\xaa\xd4S\xddX\x0bI\x9b\x81'\xcd\ +,\x07\xda[\x17X\xddp\xf6\x96\xf6\x00R\xbf\x19\x96\ +\x95\x12\x0aOj\xde\xa9\xacR\xab\xd9\x87\x96Nut\ +\x13\xfcz\x80I\xb1\xf6\xfe=F7\x5c\xb8\xa5->\ +\x80\xe4U\xf0o\x1c\x03|\xd4j\xf54\xce/\x02\x15\ +>]}\xc0Q\xa8et\xc3\x85\x1f\x84\xf4\x0fd\x10\ +`\x5cc<\xe3x\xc7E\xbef\x9b\x81\x1am1\x9b\ +f\xed\xed\xcen\xe8\xd0\x17@\x9b,\xe6g\xe6\xa8\xe1\ +y\x9an\x82\xdf\x8a8\xc1\xdf\xb7vC\xf5\x85\xfb\x82\ +\xfaE\xcb\x89n\xe2\xba\x8c6p\xb7\xe5c\x0e\xfbk\ +O}}\xf6\xea\xd3\xfb\xda\x8f\x85h\x99\xdb]\x03\xc4\ +Ts\xd7(\xa8\xdd\xcf\xa1\xb8V{\xeb\xf6e^\xb1\ +\x8d\xa2\xe6\x15\xdd\xd6'\xfau=\x07\xe6_\x8b\xf8\x1a\ +:\x9d\xa0\xfe\xfe\xa2W\xa3\xbao\xc0\x83\x9e\xa2\x0a\xcd\ +OZ\x8ax\x14\x17\x09\xd32\x84\x90\x00j\x9e.\xaf\ +\xaa\xaa\xb2l\xa6\xfc\xd6R$\x02]\x86\x14\xfa\x0a\xd7\ +hu\x17\xff\xd3\xbd\x0bF\x17(\xd5?\xc8\xba\x8d\x1e\ +\x15\xd7\x8f\x22nz@J \xd8\x81nA\x14!=\ +\xf2\xa8@\xdd' t\x0bR\x88\x1e!*\xb0\xf5\xd0\ +\xfbX\x0e\xb5\x04F\x11=\x84<\xc3X\x8b\xd3\xafm\ +]\xd1\x93\xff\x9e\xbchu\xcb\xe7\x87\xec\xd1\xf2\xa7E\ +D\x8f\x92\xb2\xdc\xa8\x13\x96\xd7\x19\x03\x93\x89\x9ef\xc8\ +\x02\xa3\xees$:\xe3\xe2!Do0$\xd0\xd8\xaa\ +;\xce\x16?\xaek5\x06.R\x10\xbdD\xf2\xc2\x05\ +Fck\x8b\xae\xf68E\xad\xae\xa5\xd5h\x5c\xbc0\ +\x99\xe8UR\x16e\x04.^m\xa4X\xbd80c\ +Q\x0aa\xe7\xee\xff\x0fO2\xbfP\x8b\xfe4z\x00\ +\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x05~\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x03\x00\x00\x00D\xa4\x8a\xc6\ +\x00\x00\x00\x09pHYs\x00\x00\x0e\xc4\x00\x00\x0e\xc4\ +\x01\x95+\x0e\x1b\x00\x00\x02\xbePLTEGpL\ +\xd7`*\x17\x0a\x04\xa0G\x1fO#\x0f\x04\x01\x00\xf7\ +q4\xf6n0\xdfd,\x00\x00\x00M\x22\x0f\x14\x09\ +\x04\x02\x01\x00\x9eG\x1f\xd8a*\xddc+-\x14\x08\ +Q$\x10\xb5Q#\x22\x0f\x06\x06\x02\x01\x17\x0a\x04\xa1\ +H\x1f\xf7}E\xdbb+\xf6n0\xf5n0N#\ +\x0f\xafN\x22\x15\x09\x04_*\x12\x02\x01\x00\xa9L!\ +\xe4f-X'\x11}8\x182\x16\x09&\x11\x07\xe0\ +d,\x9fG\x1f\x09\x03\x01\xe3f-\x0c\x05\x02b,\ +\x13\xb8R$m1\x15Q$\x10b+\x13z7\x18\ +\x04\x01\x00W'\x11\xf8}E\xf4\x85S\xf7\x86R\xa1\ +H\x1f\xa7K!\xbeiB \x0e\x06)\x12\x08\xd5u\ +I\xd3_)\xd5`*W'\x11\xcdrH\xc6mD\ +\xf2\x82O\xf7~G\xa0G\x1f\xf7x>\xb6e@\xcc\ +\x5c(\x98D\x1e\xf8\x7fHK!\x0e\xe6|K\x97R\ +4\xf7w=\xcf])\xf6\x83O\xf7|C\xf7v;\ +\xf8\x80I\xee\x82Q\xf7|D\xe8\x7fO\xf7\x7fG\xd0\ +tI\xe4~O\xe8h.\xddxI\xf7u:\xdf{\ +N\xe9i.\xf7y@\xf7y@\xf7o1\xff\xff\xff\ +\xf8}E\xf6n0\xf5n0\xfe\xfe\xfe\xfe\xf0\xea\xea\ +i.\xf7p2\xfa\xf0\xec\xfc\xf6\xf3\xf7x>\xfe\xf3\ +\xee\xe3{K\xdfg0\xf8\x8d\x5c\xfb\xbd\xa1\xf6\x7fI\ +\xfc\xce\xb9\xf8\xeb\xe5\xfe\xfc\xfb\xf4m0\xe6\x83V\xe3\ +\x81T\xe3\x81U\xfb\xf5\xf2\xf9\x9cr\xe2\x89`\xfb\xf5\ +\xf3\xfb\xc9\xb2\xf1\xa8\x86\xefm1\xf0\xd4\xc7\xfc\xf5\xf1\ +\xe5r>\xfd\xf9\xf8\xf9\xf0\xeb\xe6\x82U\xe5\x90i\xfc\ +\xd8\xc8\xf6o1\xe5r=\xf6n1\xf1\xd6\xc9\xf9\x9a\ +n\xfd\xfa\xf8\xf1\xa5\x82\xe4\x91j\xf0k/\xe2\x89a\ +\xf0l1\xfb\xc7\xaf\xe9\xba\xa4\xf0l/\xe3\x97t\xe2\ +|M\xfc\xd6\xc5\xe4g/\xf7\xe8\xe1\xf8\xeb\xe6\xf9\xc2\ +\xa8\xe2}N\xf8\x81K\xe4\x9ay\xf7v<\xf8\x85Q\ +\xe9\xb8\xa2\xe4g.\xfe\xfa\xf8\xf7v;\xfe\xf7\xf4\xfc\ +\xf7\xf4\xf8\xbd\xa3\xf7\xe7\xe1\xfe\xfa\xf9\xe4\xaa\x8f\xf8\xec\ +\xe6\xfa\xae\x8c\xf7o2\xe5\xac\x92\xfe\xf9\xf7\xf7{C\ +\xfc\xcd\xb8\xfa\xa6\x80\xfa\xb7\x99\xfc\xd2\xbf\xf7zB\xf9\ +\xa3|\xfd\xea\xe1\xf5\xe3\xdb\xfd\xec\xe3\xfc\xd7\xc6\xfd\xdd\ +\xce\xfa\xaf\x8d\xfe\xf2\xed\xfc\xd9\xc9\xfa\xae\x8b\xe1\x96s\ +\xe3\xa9\x8e\xfe\xf2\xec\xdfxH\xfd\xfa\xf9\xe1\x97t\xdf\ +vF\xf6\xe7\xdf\xf9\xa4}\xe3\xa8\x8d\xfa\xf1\xed\xfe\xee\ +\xe7\xe2\x8bc\xfa\xb5\x96\xfe\xfc\xfc\xe2\x8ce\xfe\xed\xe6\ +\xfd\xfb\xfa\xf2\xad\x8d\xfd\xdf\xd1\xfe\xf8\xf6\xfe\xef\xe9\xe2\ +\xa5\x8a\xed\x95l\xf1\x82O\xf4\xc2\xab\xf9\x95g\xf8\x8c\ +Z\xed\x97p\xef\x98q\xe2\xa3\x87\xf8\x8c[\xe0\x89b\ +\xfd\xe0\xd2\xf1\x81N\xf2\xac\x8c\xf9\x96i\xf4\xc3\xad\xfc\ +\xcf\xba\xef\x99q\xfe\xf9\xf6\xe0\x89a\x19\x07\xe4\xa6\x00\ +\x00\x00_tRNS\x00\xe1$\xb1c\x08\xfc\xfe\xe9\ +\x12a#\x07\xaf\xe2\xe2\x03d\xa0\x02\x05%\xb2\xfe\xe1\ +\xfd\xfdb\x94$D\x08\x93\xebC\x89\x06\x05\xea\xb0\x02\ +\xea\x028\xa2CeB\x87\x056\xfeY[\x88\x89\x11\ +\x01\x01\x14\xd7\xd9-;\x13\x5c\xcc~\xe3\x10\xce|\xcf\ ++2\x01\xe4\xcf^\xc5\xf6\xcd9\xc37\xca<.\xe0\ +1\xf7-\xdf\xe8\xe7\xfe\x08\x05\xdf\x00\x00\x01\xfbID\ +AT8\xcbc`\xa0\x220\x11O\x84\x02cSl\ +\xf2!\x01\xf1p\x10\x15\x84.\xeb\x1a\x16\x1d\x17\x8f\x04\ +b\xc3\xed-\x90\xe5\x1d\x02\x97d\xc5\xa3\x80\xac\xf9\x1e\ +\xd6H\x0aB\xe3\xb1\x00'$\x051\xf1\xf1[\xb7\xef\ +\xdb\x9f\xb7mcvv\xe1\x89\xbc=\xbbwn\x88\x8f\ +\x8f@\xc8G\xb2\xc5\xc7oI@\x01\xbb\xd6\xc6\xb3y\ +\xc1\x15\x04\xc7\xc7o\x02\x0a\x16\xa7@e\x8f\x00\x19k\ +\xe2\xe3\xfd\xbd\xa1\xf2\x8e\xe9\xf1s\x97&\x1c?\x9a{\ +\xecdQBB\xd1\xc1\xc3\xb9\x07v$,^\x10\x9f\ +\xee\x07U\xe0\x12\x1f?\x1d\xa4\xf1P~\xc1\xe3\x84\x84\ +K\x05\xf9{A\xbc\xb6\xf8x\x1f\xa8\x02\xb7\xf8\xf8\x06\ +\x88\xd9\x0f\x0b\x13\x12\x9e]\x86\xb03\xdb\xe3}\xa1\x0a\ +\xdc\xe3\xe3[\x9b\xc0\x82O\xaf&$\xa4\xde\x043{\ +\xfa\xe2\xe3\x9d\xa1\x0a<\xd9\xe3\x93\xab*@\xa2wA\ +\xc4s\x10Q=!9\x9e\xdd\x0e\xaa\xc0\xd2&>>\ +\xa9\xac9!!\xe5\xc6\x83{\xd7^>:\x97\x90\x90\ +Q\x9e\x14\x1fok\x05\xf3\xa6\x190\xdc\x92Z\x80\xfa\ +R\xef\xc7\xc7\xdfN\x052J\x81\xf2\xf1\xe6\xf0p0\ +\x02\x85l7\xc8\xe4\x17On]\x01\xd1\x95 \x11m\ +\xb8\x02a\x09 w\x12H\xa2\xf8\xce\xf5\x8b \xba\x06\ +(\xc0/\x80\x08k\x05 \xbf\x17(~\xea|I\xc9\ +\x99\x0c \xa3\x16( \x83\x14Y\xfa@\xfe\xc4\x85\xab\ +\xd7\xe5\x9c\xbdpzs\xce\xaaY\x93\xeb\x80\x02\xbaH\ +\x0aT5\x81\x02S\x16-_\x0f2~\xe5\xec\x19\xfd\ +@\xae\xa2\x0ar\x8a\x11\x029*i\xde2p\x10N\ +\x05y!^\x07%\xc9)I\x81\xc4\x92\xe7\xacHH\ +\x989-\x19\xc4\x96\x94CQ\xa0a\xc0\x0e6\xa3\xa3\ +\xbe\xab\xb1\x13\xc4bW\xd6BM\xb5\x86,\x1c\xe0t\ +\x96\x96\x06\xa6\xd4\xf4D0\x92\xbd\xac:;,5\xb2\ +\x8b\x89b\xcb\x18\xf2\xd2\x10C\xe29\x04Yq\xe4-\ +n^\xa0!\xec\xccL\xb8s\x1f\x0f\x17#\x1f\x0b+\ +\xde\x0c\xca\xc9Ij\x96\x06\x00\xfd\x98\xe6y\x07\xbeQ\ +(\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x05}\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x03\x00\x00\x00D\xa4\x8a\xc6\ +\x00\x00\x02\xe2PLTEGpL\xfc\xceI\xfc\xce\ +I\xec\xc1D\xdcJ=\xdcJ=\x0f\x93S\xfc\xceI\ +\xfc\xceI\xfc\xceI\x9e5,\xdbI<\x0f\x98V\xf4\ +\xc7F\x0cvC\x96{+\xdcJ=\x0buB\xf6\xc9\ +G\x10\x9dY\xdbI<\xcf\xa9<\xdbI<\x10\x9dY\ +\xdcJ=\x9f\x82.\x0ac8\x86-%\x9e5,\x10\ +\x9dY\xbc\x996\xdcJ=\x0f\x99V\xbd\x9b7\x10\x9d\ +Y\x0d\x81I\x0f\x98V\x10\x9dY\xb7=2\xdcJ=\ +\x10\x9dY\xb7=2\xf5\xc8G\x09]5\xdbJ<\xdc\ +J=\xb6=2\xdbI<\xaa\x840\xf0\xa0D\xdaJ\ +<\xb6=2\x0bk=\x10\x9dY\xdcJ=\xc3A6\ +\x5c9(\xdcJ=\x10\x9dY\xc3A6\xdcJ=\x18\ +\x98W\x10\x9dY\xdcJ=\xdcJ=\xf1\xc5E\x0f\x9b\ +W\xf9\xcbH\x10\x9dY\x9d4+\x0ac8\xdcJ=\ +\xd9I<\xc3A6\xd9I<\xc3A6\x9d4+\x10\ +\x9dY\xfc\xceI\x0d\x82J\x0e\x91R\x0d\x80H\x0e\x90\ +R\x0e\x95T\x0ah;\x8f\xcc\xae\xeb\xed\xee\xfc\xceI\ +4\xa1hE~L\x13\x9bX\xa5\xa2\x8c}gC\xa0\ +\x83.`rG\xa8E3\xbdA3\x1d\x96V\xe8\xbd\ +C\xd1\xab<\xa7\x880\xcd\xa8;\xea\xbfC\x0f\x9cX\ +\x0f\x9cX\x94y+\x09\x5c4\xbf\x9c7\xdc\xb4?\x0c\ +wC\x10\x87L\x9a\xa6D\xd9\xb1?\xdcJ=F\x87\ +\xf3\xfc\xceI\x10\x9dY\xfb\xcdH\xc7\xd7\xf1\xe9\xb5\xb0\ +\xddTH\xde\xe5\xf1F\x87\xf2\x0e\x94T\x0f\x9bXG\ +\x85P\xed\x96?\xeb\x94<\xb9WA\xee\x9aB\xdbI\ +<\xf6\xde\x97\xf9\xc9D\xdaH;\xf6\xde\x99M\x8b\xf2\ +\x15\x9e\x5c\x9b]A\xb4\xda\xc8\xdfcX_\x96\xf2\xc1\ +\xd3\xf1\xf6\xc2>\xc0\xd2\xf1\xcf\xdc\xf1\xf8\xd9\x81\xef\xef\ +\xf0\xea\x91:\xe5\x96\x8f\xfb\xd0S\xf8\xd8|\x84\xc8\xa7\ +\x16\x9f]\xd9G:\xcc\xda\xf1/\x8eS\xe9\x908\xe8\ +\xae\xa9\xaa\xc5\xf1\xe8\x8e7\xf2\xba7\xe8\xb0\xa7`\x97\ +\xf2\xcdA5\xe1\xe7\xf1\xf1\xef\xea\xfb\xcfO\xe6\x91I\ +\xe7\x8b4\xad\xc6\xf1\xc2\xd4\xf1\xf0\xef\xed\xef\xd5\x9b\xee\ +\xb45\xe8\xa5\x86\xd8\xe2\xf1\xd0\xdd\xf1J\x89\xf2\xd8F\ +:\xdb\xe3\xf1\xf0\xb73\xf4\xbf>\xe7\x8c5U\x90\xf2\ +\xa1\xbf\xf1\xe6\x8a3\xed\xd2\xd0\xf6\xe0\x9f\xef\xb41\xf8\ +\xc7Bn\xa0\xf2x\xa6\xf2\xf0\xe0\xbd\xc66-\xd7E\ +9\xcc<1\xde\xa6\xa2[\x94\xf2\xd9\x8b\x86\xbf\xd2\xf1\ +G\x88\xf2h\x9c\xf2\xe7\xed\xea\xa0\xbf\xf1\xed\xee\xf0\x1e\ +\xa2b\xf1\xee\xe5\xd9^T\xdd\xa3\x9f\xc6\xd6\xf1\xc99\ +/\x91\xb4M\x1c\x95Q\x0e\x95T[\xb8\x8b\xe8\xc9I\ +\x15\x8cSy\xc3\x9f\x0f\x98V\x10\x8cN\xe1\xe9\xe5\xb7\ +\xcd\xf1{\xc5\xa1\xd2\xdd\xf1\x0d\x8bN\xdf\xe6\xf1L\x9b\ +L\xf2\xdc\x92Z\x93\xf2p\xb4\x93o\xa9M\x0f\x9cX\ +R\xa8~\xd2\xc2J\xb4\xcb\xf1~\xa9\xf2\xda\xe3\xf1\xb4\ +\xb8J\x0e\x8eP\xf7\xcdJ\xbf\xd3\xb3y\xa6\xf2\xf6\xcc\ +I1\x9fS\xb3\xbdMN\xa9TT\xbb$\xa6\x00\x00\ +\x00qtRNS\x00\xb4\xf6l\xde||\xa5\xcc\xdb\ +\x09aZQ\x11\x04\xbe\x10Q\xe6e\x14j\xd6\xe6\x04\ +\x09\x02\x0c\xd5\x0b\xeaa\x0b\xb0\x1be\xb4\x17\xb4\xe1\x11\ +U\x06\xbe\xc4\x17k\x06\xe1Z\x10\x0c\xea\xd6\x22\x02\xd5\ +\xc4\x1b\xb0k\xfc\xc9\xfcUk[\xc9\x11\x11\xfdkH\ +jE\x14\xfd\xb9HkEj[\x14\xfe\xfe\xf8\xfd\xfe\ +\xfe\xfe\xfe\x07\xfe\xfe\xfe\xfeZ8\x096[\xb9\xf8\x07\ +\x096l8\x5cmZFt#+\x00\x00\x01\xd9I\ +DAT8\xcbc` \x05\xf8xz\xb0\xb2zy\ +\xbbb\x97\x95\xd1\xb7w/\x04\x03\x07]\x11.\x0ci\ +i1\xf9B$ \xc1\x8d&\xaf&P\x88\x06\xd45\ +\x91\xe5\xcdY\x0a1\x80\x995B^\x0f\x8b|a\xa1\ +\xa51L\xdeB\xa7\x10+\xb0\x81)\xb0mh\xc2\xae\ +\xc2\x08\x22obZ\xdb\x0a\x15\xe9\x9e2w\xe1\xba\xe5\ +;Wl\x9b?gr}]\xa3\xa1\x01X\x81SI\ +I\xe7L\x90tE\xf9\xa4\xb2y+7\xac^\xb3v\ +\xcf\x96\x05}-\xa5\xa5\xc5\xce`\x05.%%\xb3\x17\ +o\x02\xca\xef*\xeb)\x02\x82}\xeb\x0fl\xdd[Z\ +\x0c\x02~ \xf9\x10\xdf\x92\x92\x92\x98\xc3\x87\x0a\xcb/\ +n,\x02\x83\xed\x9bw\x17C@x\x0aP\x81?P\ +\xbe$1\xe1\xd2\xf93G\x8b\xa0`\xff\xd2\xa9P\x15\ +\xc9@\x05\x01 \x05%q\x07\x8f\x1d\x87\xc9\x17UU\ +N\x84*H\x03*`\x03+\x88\x8a?r\x1a\xae\xa0\ +\xa8\xbf\x0d\xaa\x80\x19\xae\xa0$\xf2\xc2\x0e\x84\x82\xdef\ +$\x05A\x10\x05%\xd1\xab\xe0\xf2'\x96L\x83*H\ +\x02*\x08\x84*\x88\x08[\x04S\xf0\xfa\xdc2\xa8\x82\ +T\xa0\x027;\xa8\x8a\xd0Y\xed\x10\xf9'\x0f\x1fC\ +\xe5\x99bA\x01a\x05U0\xa3k\xc2I\x90\x17>\ +V~x\x0fU\xc0\x08\x0eI\x15\xa8\x82\x92\x8e\xe9\xa7\ +\xee\xbf\xba\xfb\xe6\xce\xd3\xb7P\xf9b-\xb0\x02)a\ +\x98\x8a\x92\xb3\xd7\xee\xdd|q\xe3\x11L\x9eS\x12\x12\ +\x9d\x0a%H\xe0\xd6\x83\xdb/a\x0a\x84`\x09B\x15\ +I\xc1\xd5w\xcf`\xf2\xec\xf0$\xc7'\x8ePP}\ +\xe5:T\x9eC\x11\x91(\x95ea\xf2\xcf\xab/\xc3\ +\xe4E\x91\x93\xb5\xa0\x12TA\xcd\xe7OP\xf3\xe5\xd0\ +r\x06\x8f\x06D\xc1\x17\x88\xfby1\xb3\x9evpz\ +FI\xc9WP\xf81:\xf2c\xcf\x9eY\xb9y\xf9\ +9\x05\xd9\x99$\xe5x\x00\xfe\xa1E\xc6\x0b}\xa2(\ +\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x06v\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x03\x00\x00\x00D\xa4\x8a\xc6\ +\x00\x00\x00\x09pHYs\x00\x00\x0e\xc4\x00\x00\x0e\xc4\ +\x01\x95+\x0e\x1b\x00\x00\x03\x00PLTEGpL\ +C\x96\xbbs\xdeB'W\x9e#[\xa70\x81\xd51\ +\x84\xdb!U\x9f9tr%H\x8c)E\x8c*G\ +\x92`\xbb>'H\x8f.~\xda(E\x87f\xc5D\ +1\x83\xdb5\x83\xbcP\xb1\xe20WuV\xc0\xf03\ +}\xb0 J\x8a N\x94s\xdeBS\xa4Rs\xde\ +C/\x80\xd2,z\xdar\xdaD,E\x901\x84\xd8\ +\x22C\x86o\xd7K+s\xcfX\xc2\xe4,x\xdaY\ +\xb9\x95h\xce{h\xd2\x83d\xcd\x97g\xd0\x8b-y\ +\xc9Z\xbe\xad#O\x96'L\x95P\xb3\xe4$K\x92\ +p\xdaU_\xc8\xbeZ\xb0NU\xa48e\xc39$\ +O\x99d\xcd\x9e,y\xcd0\x81\xdbq\xdaG\x22Q\ +\x9at\xdeAt\xdfBq\xdbO^\xbaZo\xd9Z\ +`\xc2yk\xd4v'K\x92b\xcb\xab-y\xd1V\ +\xbf\xf3(P\x9f!J\x8a)>~t\xdeA(G\ +\x8bV\xbf\xf2'I\x8c+P\x9b*r\xc8\x22J\x8c\ +)H\x91#Q\x9d)H\x91/}\xd1'g\xa6&\ +d\xb4/|\xd1(i\xb8a\xc5~-M\x9f&c\ +\xb1,v\xce0J\xa26\x85\xba&U\xa2^\xc7\xc4\ +!\x5c\xa2V\xbf\xf1?\x90\xa1c\xca\x8e+t\xc1+\ +u\xc1\x5c\xc3\xb9E\x9b\xafV\xbf\xef^\xc3\x9c.|\ +\xdaF\xa1\xcb1j\xb7=\x90\xba-v\xb8V\xbf\xf2\ +K\xa6\xba<\x8e\xc1m\xd6jU\xbb\xdcK\xa8\xd3W\ +\xc0\xed.w\xbaX\xc1\xe71}\xbb,x\xd4W\xc0\ +\xeb>\x93\xc6V\xbc\xe0Q\xb4\xd9 P\x960{\xba\ +T\xb4\xbc$a\xa0n\xd7cY\xc1\xe3%h\xbaS\ +\xb8\xd9[\xc4\xd47\x87\xbfq\xdbM-/qp\xda\ +ST\xbb\xe9Z\xc3\xd83\x86\xdaW\xc0\xecW\xc0\xe9\ +Y\xc2\xdcP\xae\xc3L\xab\xcc;\x8e\xc00~\xc74\ +\x82\xbf,y\xda%Z\xa9(m\xc4!S\x9a'g\ +\xbe'h\xbe+x\xda*r\xd1+x\xda+w\xd9\ +2\x86\xdb3\x88\xdb0\x83\xdb3\x87\xdb\x1fK\x8c2\ +\x85\xdb\x1fN\x93/\x80\xdb\x1fQ\x99t\xdfA L\ +\x8f M\x91\x1fI\x8a\x1fO\x95q\xdbPX\xc1\xe5\ + J\x8b1\x84\xdb\x1fP\x97.\x7f\xda R\x9an\ +\xd8dq\xdcLo\xd9\x5cp\xdaV-|\xdar\xdc\ +J\x1fK\x8dY\xc2\xe1Y\xc3\xddk\xd5tl\xd6n\ +g\xd1\x8aa\xcb\xb0b\xcc\xabd\xce\x9d_\xc9\xb8i\ +\xd3\x82h\xd2\x86m\xd6jc\xcd\xa5`\xca\xb4s\xdd\ +Cp\xd9Y3\x88\xdap\xdaSs\xddFX\xc1\xe9\ +/}\xc8,z\xda3\x87\xdak\xd5rj\xd3|j\ +\xd4xi\xd3~W\xc0\xeff\xd0\x91g\xd0\x8e_\xc8\ +\xbcf\xcf\x94m\xd7ge\xcf\x96c\xcd\xa1s\xdcG\ +^\xc7\xc1n\xd8an\xd8_W\xc0\xea]\xc7\xc7\x5c\ +\xc6\xcc]\xc6\xc9W\xc0\xec\x5c\xc5\xd1\x5c\xc5\xce[\xc4\ +\xd53\x86\xd5Z\xc3\xda[\xc4\xd3/~\xceZ\xc4\xd7\ +1\x83\xd12\x85\xd8e\xce\x99s\xddD R\x9ca\ +\xcb\xa7_\xc8\xbf0\x80\xcd,w\xc4^\xc7\xc4/|\ +\xc5-x\xc01\x83\xd53\x88\xd9.{\xc2|7\x1f\ +\xe1\x00\x00\x00\xa1tRNS\x00\x16\xc1\x1a\xfd\xfe\xfe\ +\xfd\x04\xc12\x8d3\x80\xf8I.\xb7\xfd7\x09\xfd\xfd\ +\xfe\xfc\xcd\x0d\xa8g\xa0\xd9g\xbe\x0fX\xfd\xc9\xfe%\ +H\xfcXhG;\xd8\x9f?\xe3\xf7\xa5B\x1b$\xcc\ +\xf4B\xect\xe7\xb0\xec\xf4P\x84\x91\xe7\xae\xb8N\xac\ +\x91\xf5)\x80_\xe4v[:\xf4\x9a\xdf\x87\xfdF\xfd\ +\xfd\xfc\xf7o\xfc\xfdh\xfd\xbb\xf3\x12\xf2\xf9\xfd\xa2`\ +\xfd\xfc\xec\xfd\xe3\xfdm\xfd\xfd\xb6\xfd\xfd\x89\xfd#\xcd\ +\xfe\xf3\xfd\xfdz\xfc\xfe\xfd\xfd\xfdC\x1f\xf0\x86.\xe8\ +y\xfc\xca\x1f\x9b_\xa2\x9d\x93\xb6\xbdG\x8a\xbc\xcf\xd5\ +\xf5\x99Q\xfd\xba\xfc\xb2\xc9\x8b\xc8u|\x80\xe1\x00\x00\ +\x02oIDAT8\xcbc` \x010\xf6\xf4O\ +PQ\x99\xd8\xdb\xde(\x82MZ\xbf@\xf4\xc5\x85\x0d\ +{\xf7}x\xf7\xeay\x82\x91\x0e\x86n7\xd1\x1bO\ +\x80\xd2o_\xbf|\xf6\xf4\xe1\xed\xa3\x87\x5c\xd4P\xe4\ +\x85}n\xc0\xb5\xff\xfa~\xf4\xd4\xa1\xc3'\xcd5\x91\ +\xe5\x93P\xb5\x1f>y\xff\xc8\xbd\x9bZp\xf9\xd2L\ +t\xedG>\xdf\xb9uPC\x1d*\xcfQ\x86\xac\xfd\ +\xd4\xe1o \xed\x07\x8f\x1f\xbb\xea$\x05QP}a\ +CIN\x91\x90P\x5c^a:H\xfb}\x90\xf6c\ +\xd7\xaf\xed?P\x0c\xf1@EmM\xf9\xff\x8b?~\ +\xfc\xb8\xf8'?\x03\xae\xfd\xda\x95\x03w\x9b\xc1F\xb4\ +\xd4U\xfe\xfe\xf8\xe6\xdf\xbf\xb3\xff>\xfd}\xffS,\ +\x0b\xa8\xfd8H\xfb\x89m\x8fv(\x81\x5c\xd0\xd6p\ +\xf1\xcd\xd9E@\xb0d\xc9\xc2O\xac?\xc5R\xa0\xda\ +\xb7=>\xb3\xb3\x1b\xa8`R\xc7o\xb8\xfcBA\x99\ +\xb4\xd4d\xb0\xf6\xbb\x8fv\x9c9\xb7\xbe\x13\xa8`\xf2\ +\x9f\x8fg\xa1\xd2\xac\xb9 +C#\xc1\xdaw\xec<\ +\xb7~\xb7\x1c\x90?\xe5\xe2'\xa8|H<\xc4W\x8e\ +`\xed;\xd7o\xdf}^\x12\xc8\x9d\xf6\xe3\x1fXz\ +\x19+{\x14D\x81=D\xfb\xf6\x07_NK\x03\xb9\ +S?^\x06\xcb/\x8b\xde\x1a\x0bQ`\x0c\xd1\xfe\xe0\ +\xcb\xaaU _(|\x02Ko\x0a_\xf9\xd5\x1d\xa2\ +\xc0\x01\xa4}\xf7\xf9\xd3\xabV\xc9q\x00\xb9}\x0b\xc1\ +\xf2\x8b#V~\x0d\x02\xf1\x19\x04\x0c\xc1\xda\x81\xf2\xb6\ +\x02 \xbe\x0cHz\xd3\xe2\xc5,[\xb7n\xf5\x03\x09\ +\xf0\xd8A\xb4\xafb2\x05\x1b\xd8\xc4\x06\xd4\x0e\x04\xec\ ++\xb7n\xb5f\x06\x89\x98XI3I\xdax\xf1\xc0\ +\x22[\x01,\xbf\x02\xa8`\xe5J3E,\x89Q\x9b\ +\x0d(\xbdb\x05\xcb\xe6\x95+7o\xd6\xe5\xc2\xa2B\ +\x10$\xbf%l\xdd\xe6\xcd\x9b\xd7\xad\x93\xd0\x83)\x11\ +\x91\xe7\x86\xb2\x98-\x81\xf2[b\xd6\xac\x03\x82\xe5\xcb\ +\xd7\xac1p\xe6\xe6\x0d\x0e\xe4\x0c\x10\xe7\x87\x19a\xc1\ +\xb7e\xcb\x96],k\x96/\x07\xc9\xafY\xbdz\xcf\ +\x9e\xa5\x1b7\x8a\xfb\x22,q\xe5\xdb\xb5kWU\xfd\ +\x9a5\xcbA\xd2\xab\xf7,\x05\xc9\xf3\x22;\xc3?\x1b\ +\xa8BYb\xcf\xea\xd5P\xed\x1b=\xbcQ\x1d\x9a(\ +\xbb\xeb\xd2%e\xf6\x8dKA\x00\xa8\x9d\xd3\x13\xc3/\ +\xad\xb2\xd3UU\xe7\xcc\x12_\xbbv\xad8'?\xd6\ +\xcc\xab8s\xfe\xdc\x05\xf3f\xcf\x90\xef\x22%\xcb\x03\ +\x00/\xab\x8c\xa71\xf3a\xb4\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +" + +qt_resource_name = b"\ +\x00\x06\ +\x07\x03}\xc3\ +\x00i\ +\x00m\x00a\x00g\x00e\x00s\ +\x00\x0d\ +\x06\x0b\xf4\xa7\ +\x00b\ +\x00l\x00a\x00n\x00k\x00_\x001\x002\x008\x00.\x00p\x00n\x00g\ +\x00\x12\ +\x0d,\x1a\xc7\ +\x00d\ +\x00a\x00i\x00l\x00y\x00c\x00h\x00e\x00c\x00k\x00_\x001\x002\x008\x00.\x00p\x00n\ +\x00g\ +\x00\x08\ +\x09n\x91\xb3\ +\x00b\ +\x00r\x00o\x00w\x00s\x00e\x00r\x00s\ +\x00\x0c\ +\x0fTN'\ +\x00b\ +\x00r\x00a\x00v\x00e\x00_\x003\x002\x00.\x00p\x00n\x00g\ +\x00\x0d\ +\x01\x97\x91\x87\ +\x00c\ +\x00h\x00r\x00o\x00m\x00e\x00_\x003\x002\x00.\x00p\x00n\x00g\ +\x00\x0b\ +\x02\xb2\x0c'\ +\x00e\ +\x00d\x00g\x00e\x00_\x003\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\x00\x00\x00\ +\x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x8db\xb8\xc9\xc8\ +\x00\x00\x00\x5c\x00\x02\x00\x00\x00\x03\x00\x00\x00\x05\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x002\x00\x00\x00\x00\x00\x01\x00\x00\x01\xbc\ +\x00\x00\x01\x8df\xb35\xbe\ +\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x15\xae\ +\x00\x00\x01\x8dd\xf15i\ +\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x1b/\ +\x00\x00\x01\x8dd\xf1K\xbc\ +\x00\x00\x00r\x00\x00\x00\x00\x00\x01\x00\x00\x10,\ +\x00\x00\x01\x8dd\xf1\x5c\xbe\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/dailycheck.icns b/dailycheck.icns new file mode 100644 index 0000000000000000000000000000000000000000..b4fdf33eab200ebf6e849af50710718e7b5219cf GIT binary patch literal 74761 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 aLi5puD|ep4{}MyfR~rkXpL^Vq$-e>GI3U^p literal 0 HcmV?d00001 diff --git a/global_vars.py b/global_vars.py new file mode 100644 index 0000000..7c8a4c8 --- /dev/null +++ b/global_vars.py @@ -0,0 +1,42 @@ +# coding: utf8 +import requests +from PySide6 import QtWidgets + +SoftwareStatusRole = 0x0101 +ExtensionStatusRole = 0x0102 +ExtensionIdRole = 0x0103 + + +def accept_warning(widget: QtWidgets.QWidget, condition: bool, + caption: str = "Warning", text: str = "Are you sure to continue?") -> bool: + if condition: + b = QtWidgets.QMessageBox.question(widget, caption, text) + if b == QtWidgets.QMessageBox.StandardButton.No: + return True + return False + + +def get_with_chained_keys(dic: dict, keys: list, default=None): + """ + 调用 get_with_chained_keys(d, ["a", "b", "c"]) + 等同于 d["a"]["b"]["c"] , + 只不过中间任意一次索引如果找不到键,则返回 default + + :param dic: 目标字典 + :param keys: 键列表 + :param default: 找不到键时的默认返回值 + :return: + """ + k = keys[0] + if k not in dic: + return default + if len(keys) == 1: + return dic[k] + return get_with_chained_keys(dic[k], keys[1:], default) + + +def request_content(url: str) -> bytes: + req = requests.get(url) + if req.status_code == 200: + return req.content + return b"" diff --git a/images/blank_128.png b/images/blank_128.png new file mode 100644 index 0000000000000000000000000000000000000000..7eeafdbedff2e509e9221cb4f141a406abdcca80 GIT binary patch literal 440 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBuf-vKbiP>*~8hkxn978JN-d-|fWKiHau%WU3{NsbJvzD_} zm6bo*wcpW{VI5-uZ$mai4D$mihU*MF*ba;eVGW4}v(F4~%bEY4y=b@v7}^Y;u6{1- HoD!MA5S9>1OWi|aWwXBFyCY>0000@A`cV^ z1Ofp7o<|?pVJh8YD=icVQ6vzxQ6nM`1_lBF7YYQSNFVooMcZO4_HHosZZJ+G53f!l z6$u1iDiQ(#0I5tNHN;MCgA{_kTywbV=lXPv~ea-FQj&bvoaBPU&eb_jy3~c|iAXG5`Pn_V^q4s}C{LZ=f>*fCZ z`}A!v=7Uz_fmGvxRr~ew`J8g%iD3Kn^ZUuN@u-IHZ87lF$Ncs2<#Im#`S|(p>*j)0 z<&bIo*vR&8G39bS_HHrp*2(#rZvFcB@uh;~k!tX3FXD+|@N6;r$FJ$Sr0{Gne zd`*o2wsN#K2_<>90ntAtjJotrC>A0fgXDj zTJ4u`@0fAoqlfs6Ti}Ue{ovB^fll(QjQN&n^uw+E&${oKasK)C;E7=w2jr#z003Wf zQchC<;UuwR2>kx(5@90;uj1kZWS{~CC9?kE{rzH;Bt!_4>qChK1?sQ@>H;{TLuEpT z1vdU!TZoAf0Ra@(*)2O0T+Dvs5YBwhD>4D(&tAp$%{jw2$~-RMG50Os=;!_j1>XPw z0sBcrK~y-)V_={nFcD9L0%KEb@*x57a1a%QF6$Z=9T$%TV#Dn%kmVf$mt@7GfUNl* z)<_CMV|I4oiM&0#cW#J}k3h&rvc<=5Nk9R+*2c4W!4(9@ z$8Q1(7N|{|wLeas)xd(P6EM5?w?gv%i5+6Su zr14OG!Q+I4O9lCRLAU>GbnG7JK7APQt6j}N}{=|i=*X5kOaC&pj zs#%lkfC9Qm3RE?L0#g<(Uk@^V#K(3++a*7cGIVx%1GH?)11$iM}2PMfVNrA+Y z=d4Ibm^m#O#FmspQJ`VK4mP8szN@hl#9~+0LQS=XEF9o;mX-#l)bvC!lD(`tJ1jM_ zi-}^(81m8(L*h9ES#jhoZeE}v?95EKa~}^EBOePZ-VDmgNotk`0R5Qec?Z5xC;$Ke M07*qoM6N<$g6w<6>i_@% literal 0 HcmV?d00001 diff --git a/images/browsers/chrome_32.png b/images/browsers/chrome_32.png new file mode 100644 index 0000000000000000000000000000000000000000..f00d8a82c15920dd772ef31d8b255dfcc622e024 GIT binary patch literal 1405 zcmX9+2~<-@6b*p@2}^>N(rRrv7F~H;xrh;K))zpg`CJ zqYzLwZD}g8h!!ItUuAd2%>#p|T3_w&sB#^m*Km-=Jj#(zlTo7n>k!fBWXkO04#rYHs zv@EIAz;dmPqo=b!6Nc8;6{H=din1K}iHs(?O9$CyTSf4E2ld%)Qe*Dk!6u(YDHVS$ z6hv8yJvP!+dd*`(;%k~jCFHQLHqaEm`GVd3a^8cQVAIt>X5UMA;jVa+$DC5aemRJF z84oWEW&FrdRroHIk=jGZ>Z=rR@s+77IvH(@>9aCb<)4pOR!0h>$da)quVX{Mt3W!R z!z*3;9}UCu30SMhSYFmF3cQsSMXN(x?W@%6Cyk%iL@5~F17omLA$OtJbH1hdRu4R1 z=z-k#m=`zluONeDx0yK@US3?4ADk6HbNQ~n^uk>)V9l~>c|@p|xXssJdi4e#nuJ-G zkyn1+<8NV2o6863{<#9Tpkky}3eV=bsD_7DrfZfZL~S4CqzFlFKs3`Gz3vV#>0SdQ z;#5OjL>Z#Uza$-o8M#Q@HDpe;D3Zb|wdU)(7+9@T9Og~lsOcSrWnNAKiT_vShrnNm zxR*aKgDeZUDcv>e9a0c5v!HAngfH~e4o|{n`2nwIVYZNsOq7I|BBv##r<(o2#}8~u zAMRpF`r-6uWb7?0xyLduYrqq7EBwCRY+Vzh~P>k)~SWX2-M@Zn>tc*B`+g6ZPu zcJ#>Ot>XBPvX4RW5i$#lPw~v-^v$2znep`F5u4Z6w4c_%W3&$8o>=#YcC8WCJ;5{b zM7ZDCZ|zYiJq1J~^E~@w`PLY1@_F%{^C=Hvu9QD(OL8*MH;S@wG(C2VsH50ecmA~F z*BzW(!xwG>@$wm^6p_`ktqJjH9h>tJNv= zpUZYjyV03xOZbGzh;UPMy0wn*x}>C}vO5RY?{snxI!h%?vZ5YH#&I%yIS*}!Gs8L; zM!tyu-*7X>Qg#5NXN|EvV^p*)M`jfi6p(Gl)VJg7+vn!_CT?jFHA&5GUHq~|WP@~> zXJ<}*Z-XHdFt*QbPa``k*jaW=w4HIbU9NG20ax?ygmY6SPlWdHY04W4QxSAK@!wFD zRWW3}XiU)F8}VIGvDN zM1I?;`!Bkn^sZ(SlxSFFNb9u9T}>gjR-Ze4-Vc(6aI{2kBvxJ>)}EsC e!YHb2l*y>IT6(WZTHP+tVJL_mKx?7!Gyexht*cZ3 literal 0 HcmV?d00001 diff --git a/images/browsers/edge_32.png b/images/browsers/edge_32.png new file mode 100644 index 0000000000000000000000000000000000000000..f8507c4fa24dae61a00bc231cdbab75073216ed1 GIT binary patch literal 1654 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 o^NSMuZe>|lE4oMPe=eCV ProfilesData: + local_state_path = Path(user_data_path, "Local State") + if not local_state_path.exists(): + return {} + + local_state_data: dict = json.loads(local_state_path.read_text(encoding="utf8")) + info_cache_data: dict = get_with_chained_keys(local_state_data, ["profile", "info_cache"]) + + profiles_data: ProfilesData = {} + + for profile_id in info_cache_data: + profile_data: dict = info_cache_data[profile_id] + profile_node = ProfileNode( + gaia_given_name=profile_data.get("gaia_given_name", ""), + gaia_name=profile_data.get("gaia_name", ""), + name=profile_data.get("name", ""), + shortcut_name=profile_data.get("shortcut_name", ""), + user_name=profile_data.get("user_name"), + ) + profiles_data[profile_id] = profile_node + + return profiles_data + + +@dataclass +class ExtensionNode(object): + # ids: str + icon: str + name: str + # path: str + profiles: list[str] = field(default_factory=list) + + +ExtensionsData = dict[str, ExtensionNode] + + +def get_extension_icon_path(ext_icons: dict[str, str], ext_path: str, profile_path: Path) -> str: + if len(ext_icons) == 0: + return "" + + if "128" in ext_icons: + icon_file = ext_icons["128"] + else: + icon_file = ext_icons[str(max(map(lambda x: int(x), ext_icons.keys())))] + # 如果路径以 / 开头,会被认为是根而忽略其他,因此需要检查一下 + if icon_file.startswith("/"): + icon_file = icon_file[1:] + + full_path = Path(profile_path, "Extensions", ext_path, icon_file) + if not full_path.exists(): + return "" + return str(full_path) + + +def scan_extensions(browser: str, is_compat=False) -> tuple[ExtensionsData, ProfilesData]: + us = QtCore.QSettings() + user_data_path = str(us.value(f"{browser}Data", "")) + if len(user_data_path) == 0 or not Path(user_data_path).exists(): + return {}, {} + + profile_data = scan_profiles(user_data_path) + extensions_data: ExtensionsData = {} + + if is_compat: + pref_file = "Preferences" + else: + pref_file = "Secure Preferences" + + # print(pref_file) + + for profile_id in profile_data: + profile_path = Path(user_data_path, profile_id) + secure_pref_path = Path(profile_path, pref_file) + secure_pref_data: dict = json.loads(secure_pref_path.read_text(encoding="utf8")) + ext_settings_data: dict = get_with_chained_keys(secure_pref_data, ["extensions", "settings"], dict()) + + for ext_id in ext_settings_data: + ext_data: dict = ext_settings_data[ext_id] + # 这里插件有几种情况 + ext_path: str = ext_data.get("path", "") + if len(ext_path) == 0: + # 如果 path 是空,则该插件可能是一些内部插件,不予收集 + continue + elif not (ext_path.startswith(ext_id) or os.path.exists(ext_path)): + # 如果 path 以插件 ID 开头,则为商店安装的插件, + # 如果不是以插件 ID 开头,但是是一个存在的路径,则为离线安装的插件 + # 否则,可能也是内部插件,不予收集 + continue + ext_manifest: dict = ext_data.get("manifest", {}) + if len(ext_manifest) == 0: + # 如果 manifest 为空,则该插件可能是离线插件,需要额外找它的 manifest + ext_manifest_path = Path(ext_path, "manifest.json") + ext_manifest: dict = json.loads(ext_manifest_path.read_text(encoding="utf8")) + + if ext_id not in extensions_data: + ext_node = ExtensionNode( + # ids=ext_id, + icon=get_extension_icon_path(ext_manifest.get("icons", {}), ext_path, profile_path), + name=ext_manifest.get("name", ""), + # path=ext_data.get("path", ""), + profiles=[profile_id], + ) + extensions_data[ext_id] = ext_node + else: + ext_node = extensions_data[ext_id] + ext_node.profiles += [profile_id] + + return extensions_data, profile_data + + +# ================== Deletion ==================== + + +def delete_extensions(profile_path: str, pref_name: str, ext_ids: list[str]) -> tuple[int, int]: + total = len(ext_ids) + + e_pref_path = Path(profile_path, pref_name) + e_pref_data = json.loads(e_pref_path.read_text("utf8")) # type: dict + ext_set_data = get_with_chained_keys(e_pref_data, ["extensions", "settings"]) # type: dict + if ext_set_data is None: + return 0, total + + s_pref_path = Path(profile_path, "Secure Preferences") + pref_path = Path(profile_path, "Preferences") + s_pref_data = json.loads(s_pref_path.read_text("utf8")) # type: dict + pref_data = json.loads(pref_path.read_text("utf8")) # type: dict + + macs = get_with_chained_keys(s_pref_data, ["protection", "macs", "extensions", "settings"]) # type: dict + if macs is None: + return 0, total + + success = 0 + for ids in ext_ids: + c1 = ext_set_data.pop(ids, None) + c2 = macs.pop(ids, None) + if None not in (c1, c2): + success += 1 + + pinned_ext = get_with_chained_keys(pref_data, ["extensions", "pinned_extensions"]) # type: list + if pinned_ext is not None: + for ids in ext_ids: + if ids in pinned_ext: + pinned_ext.remove(ids) + + s_pref_path.write_text(json.dumps(s_pref_data, ensure_ascii=False), "utf8") + pref_path.write_text(json.dumps(pref_data, ensure_ascii=False), "utf8") + + extensions_path_d = Path(profile_path, "Extensions") + for ids in ext_ids: + # 对于离线安装的插件,目录可能不在这个位置,所以就不删了 + ext_folder_path = Path(extensions_path_d, ids) + if ext_folder_path.exists(): + shutil.rmtree(ext_folder_path, ignore_errors=True) + + return success, total + + +class DeleteThread(QtCore.QThread): + + deleted = QtCore.Signal(int, int) + + def __init__(self, + profile_path: str, + pref_name: str, + ext_ids: list[str], + parent: QtCore.QObject = None): + super().__init__(parent) + self.profile_path = profile_path + self.pref_name = pref_name + self.ext_ids = ext_ids + self.finished.connect(self.deleteLater) + + def run(self): + success, total = delete_extensions(self.profile_path, self.pref_name, self.ext_ids) + self.deleted.emit(success, total) + + +class DeleteThreadManager(QtCore.QObject): + + def __init__(self, total: int, progress_bar: QtWidgets.QProgressBar, parent: QtWidgets.QDialog): + super().__init__(parent) + self.deletion_progress = 0 + self.success_deletion = 0 + self.fail_deletion = 0 + self.total_for_deletion = total + self.deletion_info = "成功:{success} 个;失败:{fail} 个;总共 {total} 个。" + self.progress_bar = progress_bar + self.parent = parent + + self.progress_bar.setMaximum(total) + self.progress_bar.setValue(0) + + self.progress_bar.valueChanged.connect(self.on_pgb_del_value_changed) + + def start(self, thread: DeleteThread): + thread.deleted.connect(self.on_del_thd_deleted) + thread.start() + + def on_del_thd_deleted(self, success: int, total: int): + self.success_deletion += success + self.deletion_progress += total + self.fail_deletion += total - success + self.progress_bar.setValue(self.deletion_progress) + + def on_pgb_del_value_changed(self, value: int): + if value == self.total_for_deletion: + QtWidgets.QMessageBox.information( + self.parent, "删除结果", self.deletion_info.format( + success=self.success_deletion, + fail=self.fail_deletion, + total=self.total_for_deletion + ) + ) + self.parent.accept() diff --git a/util_func.py b/util_func.py new file mode 100644 index 0000000..c58f7c4 --- /dev/null +++ b/util_func.py @@ -0,0 +1,66 @@ +# coding: utf8 +import os +import json +from pathlib import Path +import xml.etree.ElementTree as Et + +from global_vars import request_content + + +def get_isp_name() -> str: + try: + data = json.loads(request_content("https://ipinfo.io/")) + return data.get("org", "[Not found]") + except json.JSONDecodeError: + return "[Decode Error]" + + +def get_app_icon_path(info_file: Path) -> str: + try: + tree = Et.parse(info_file) + except Et.ParseError: + return "" + root = tree.getroot() + dic = root[0] + keys = [] + values = [] + for c in dic: + if c.tag == "key": + keys.append(c.text) + else: + values.append(c.text) + + res = {k: v for k, v in zip(keys, values)} + if "CFBundleIconFile" not in res: + return "" + name = res["CFBundleIconFile"] + path = str(info_file.parent / "Resources" / name) + if not path.endswith(".icns"): + path = path + ".icns" + return path + + +def get_mac_installed_software() -> dict[str, str]: + p1 = Path("/Applications") + p2 = Path("/System/Applications") + p3 = Path(os.path.expanduser("~"), "Applications") + + all_soft: list[Path] = [] + + def search(path: Path): + for c in path.glob("*"): + if str(c).endswith(".app"): + if c.is_dir(): + all_soft.append(c) + elif c.is_dir(): + search(c) + + search(p1) + search(p2) + search(p3) + all_soft.sort(key=lambda x: x.name.lower()) + + return { + app.name: get_app_icon_path(Path(app) / "Contents" / "Info.plist") + for app in all_soft + } diff --git a/wg_basic.py b/wg_basic.py new file mode 100644 index 0000000..516484d --- /dev/null +++ b/wg_basic.py @@ -0,0 +1,57 @@ +# coding: utf8 +from PySide6 import QtWidgets, QtCore, QtGui +from util_func import ( + get_isp_name, +) + + +class UiWgBasic(object): + + def __init__(self, window: QtWidgets.QWidget): + self.vly_m = QtWidgets.QVBoxLayout() + window.setLayout(self.vly_m) + + self.gbx_isp = QtWidgets.QGroupBox("网络运营商", window) + self.vly_m.addWidget(self.gbx_isp) + self.vly_gbx_isp = QtWidgets.QVBoxLayout() + self.gbx_isp.setLayout(self.vly_gbx_isp) + + self.lne_isp = QtWidgets.QLineEdit(self.gbx_isp) + self.lne_isp.setReadOnly(True) + self.vly_gbx_isp.addWidget(self.lne_isp) + + self.vly_m.addStretch(1) + + +class WgBasic(QtWidgets.QWidget): + + def __init__(self, parent=None): + super().__init__(parent) + self.ui = UiWgBasic(self) + + self.ui.lne_isp.setText(get_isp_name()) + + def update_safe(self, isp_safe_info: dict): + + def set_palette(is_safe: bool | None, lne_w: QtWidgets.QLineEdit): + pal = lne_w.palette() + if is_safe is True: + pal.setColor(QtGui.QPalette.ColorRole.Text, QtCore.Qt.GlobalColor.blue) + elif is_safe is False: + pal.setColor(QtGui.QPalette.ColorRole.Text, QtCore.Qt.GlobalColor.red) + else: + pal.setColor(QtGui.QPalette.ColorRole.Text, QtCore.Qt.GlobalColor.black) + lne_w.setPalette(pal) + + isp_text = self.ui.lne_isp.text() + if isp_text in isp_safe_info: + is_isp_safe = isp_safe_info[isp_text]["safe"] + set_palette(is_isp_safe, self.ui.lne_isp) + + def export_unknown(self) -> dict: + unknown = {} + text_role = QtGui.QPalette.ColorRole.Text + black = QtCore.Qt.GlobalColor.black + if self.ui.lne_isp.palette().color(text_role) == black: + unknown["isp"] = self.ui.lne_isp.text() + return unknown diff --git a/wg_extensions.py b/wg_extensions.py new file mode 100644 index 0000000..07aa204 --- /dev/null +++ b/wg_extensions.py @@ -0,0 +1,277 @@ +# coding: utf8 +from PySide6 import QtWidgets, QtCore, QtGui +from util_ext import scan_extensions, ExtensionsData, ProfilesData +from global_vars import ( + ExtensionStatusRole, + ExtensionIdRole, +) +from da_ext_settings import DaExtSettings +from da_show_profiles import DaShowProfiles + + +class UiWgExtensions(object): + + def __init__(self, window: QtWidgets.QWidget): + self.vly_m = QtWidgets.QVBoxLayout() + window.setLayout(self.vly_m) + + self.hly_top = QtWidgets.QHBoxLayout() + self.vly_m.addLayout(self.hly_top) + self.cmbx_browsers = QtWidgets.QComboBox(window) + self.cbx_safe = QtWidgets.QCheckBox("安全", window) + self.cbx_unsafe = QtWidgets.QCheckBox("不安全", window) + self.cbx_unknown = QtWidgets.QCheckBox("未知", window) + self.cbx_safe.setChecked(True) + self.cbx_unsafe.setChecked(True) + self.cbx_unknown.setChecked(True) + self.cbx_compat = QtWidgets.QCheckBox("兼容模式", window) + self.pbn_update = QtWidgets.QPushButton("更新", window) + self.pbn_settings = QtWidgets.QPushButton("设置", window) + self.hly_top.addWidget(self.cmbx_browsers) + self.hly_top.addWidget(self.cbx_safe) + self.hly_top.addWidget(self.cbx_unsafe) + self.hly_top.addWidget(self.cbx_unknown) + self.hly_top.addStretch(1) + self.hly_top.addWidget(self.cbx_compat) + self.hly_top.addWidget(self.pbn_update) + self.hly_top.addWidget(self.pbn_settings) + + self.lv_extensions = QtWidgets.QListView(window) + self.vly_m.addWidget(self.lv_extensions) + + +class BaseExtensionsListModel(QtCore.QAbstractListModel): + + def __init__(self, parent=None): + super().__init__(parent) + self.all_profiles = {} # type: ProfilesData + self.all_extensions = {} # type: ExtensionsData + self.names = [] # type: list[tuple[str, str]] + self.icons = {} # type: dict[str, QtGui.QIcon] + self.safe_info = {} # type: dict[str, dict] + self.blank_icon = QtGui.QIcon(":/images/blank_128.png") + + self.last_is_compat = False + + def update(self, is_compat=False): + raise NotImplementedError + + def update_ext(self, browser: str, is_compat=False): + """内部用""" + self.all_profiles.clear() + self.all_extensions.clear() + self.names.clear() + self.icons.clear() + + self.all_extensions, self.all_profiles = scan_extensions(browser, is_compat) + self.last_is_compat = is_compat + for ext_id in self.all_extensions: + name = self.all_extensions[ext_id].name + icon = self.all_extensions[ext_id].icon + self.names.append((ext_id, name)) + if len(icon) == 0: + self.icons[ext_id] = self.blank_icon + else: + self.icons[ext_id] = QtGui.QIcon(icon) + self.names.sort(key=lambda x: x[1].lower()) + + # print("updated " + browser) + + def update_safe_info(self, safe_info: dict): + self.safe_info.clear() + self.safe_info = safe_info + + def rowCount(self, parent: QtCore.QModelIndex = ...): + return len(self.names) + + def data(self, index: QtCore.QModelIndex, role: int = ...): + row = index.row() + ext_id, name = self.names[row] + + if role == QtCore.Qt.ItemDataRole.DisplayRole: + return name + if role == QtCore.Qt.ItemDataRole.DecorationRole: + return self.icons[ext_id] + if role == QtCore.Qt.ItemDataRole.BackgroundRole: + is_safe = self.data(index, ExtensionStatusRole) + if is_safe is True: + return QtGui.QBrush(QtGui.QColor("lightgreen")) + elif is_safe is False: + return QtGui.QBrush(QtGui.QColor("lightpink")) + else: + return QtGui.QBrush(QtCore.Qt.BrushStyle.NoBrush) + if role == ExtensionStatusRole: + if ext_id not in self.safe_info: + return None + else: + return self.safe_info[ext_id]["safe"] + if role == ExtensionIdRole: + return ext_id + + +class ChromeExtensionsListModel(BaseExtensionsListModel): + + def update(self, is_compat=False): + super().update_ext("Chrome", is_compat) + + +class EdgeExtensionsListModel(BaseExtensionsListModel): + + def update(self, is_compat=False): + super().update_ext("Edge", is_compat) + + +class BraveExtensionsListModel(BaseExtensionsListModel): + + def update(self, is_compat=False): + super().update_ext("Brave", is_compat) + + +class BrowsersListModel(QtCore.QAbstractListModel): + + def __init__(self, parent=None): + super().__init__(parent) + self.browsers = ["Chrome", "Edge", "Brave"] + self.icons = [ + QtGui.QIcon(":/images/browsers/chrome_32.png"), + QtGui.QIcon(":/images/browsers/edge_32.png"), + QtGui.QIcon(":/images/browsers/brave_32.png"), + ] + + def rowCount(self, parent: QtCore.QModelIndex = ...): + return len(self.browsers) + + def data(self, index: QtCore.QModelIndex, role: int = ...): + row = index.row() + + if role == QtCore.Qt.ItemDataRole.DisplayRole: + return self.browsers[row] + if role == QtCore.Qt.ItemDataRole.DecorationRole: + return self.icons[row] + + +class WgExtensions(QtWidgets.QWidget): + + def __init__(self, parent=None): + super().__init__(parent) + self.ui = UiWgExtensions(self) + + self.browsers_list_model = BrowsersListModel(self) + self.ui.cmbx_browsers.setModel(self.browsers_list_model) + + self.ext_list_models: dict[str, BaseExtensionsListModel] = { + "Chrome": ChromeExtensionsListModel(self), + "Edge": EdgeExtensionsListModel(self), + "Brave": BraveExtensionsListModel(self), + } + self.model_is_initial = { + "Chrome": True, + "Edge": True, + "Brave": True, + } + self.switch_model(self.get_current_browser()) + + self.ui.cbx_compat.clicked.connect(self.on_cbx_compat_clicked) + self.ui.cmbx_browsers.currentTextChanged.connect(self.on_cmbx_browsers_current_text_changed) + self.ui.cbx_safe.clicked.connect(self.on_cbx_safe_clicked) + self.ui.cbx_unsafe.clicked.connect(self.on_cbx_unsafe_clicked) + self.ui.cbx_unknown.clicked.connect(self.on_cbx_unknown_clicked) + self.ui.pbn_update.clicked.connect(self.on_pbn_update_clicked) + self.ui.pbn_settings.clicked.connect(self.on_pbn_settings_clicked) + self.ui.lv_extensions.doubleClicked.connect(self.on_lv_extensions_double_clicked) + + def on_pbn_settings_clicked(self): + da_es = DaExtSettings(self) + da_es.exec() + + def get_current_browser(self) -> str: + return self.ui.cmbx_browsers.currentData(QtCore.Qt.ItemDataRole.DisplayRole) + + def show_all_rows(self): + # 在 update 之前调用 + self.filters_clicked(True, True) + self.filters_clicked(False, True) + self.filters_clicked(None, True) + + def apply_rows_hidden(self): + # 在 update 之后调用 + self.filters_clicked(True, self.ui.cbx_safe.isChecked()) + self.filters_clicked(False, self.ui.cbx_unsafe.isChecked()) + self.filters_clicked(None, self.ui.cbx_unknown.isChecked()) + + def update_model(self, browser: str): + model = self.ext_list_models[browser] + self.show_all_rows() + model.update(is_compat=self.ui.cbx_compat.isChecked()) + self.apply_rows_hidden() + + def switch_model(self, browser: str): + if self.model_is_initial[browser] is True: + self.update_model(browser) + self.model_is_initial[browser] = False + + model = self.ext_list_models[browser] + self.show_all_rows() + self.ui.lv_extensions.setModel(model) + self.apply_rows_hidden() + # 单纯的切换浏览器不一定会导致更新数据,所以需要同步兼容模式的设置 + self.ui.cbx_compat.setChecked(model.last_is_compat) + + def on_cbx_compat_clicked(self): + self.update_model(self.get_current_browser()) + + def on_cmbx_browsers_current_text_changed(self, text: str): + self.switch_model(text) + + def filters_clicked(self, safe_mark: bool | None, checked: bool): + model = self.ext_list_models[self.get_current_browser()] + for row in range(model.rowCount()): + idx = model.index(row) + is_safe = model.data(idx, ExtensionStatusRole) + if is_safe is safe_mark: + self.ui.lv_extensions.setRowHidden(row, not checked) + + def on_cbx_safe_clicked(self, checked: bool): + self.filters_clicked(True, checked) + + def on_cbx_unsafe_clicked(self, checked: bool): + self.filters_clicked(False, checked) + + def on_cbx_unknown_clicked(self, checked: bool): + self.filters_clicked(None, checked) + + def on_pbn_update_clicked(self): + self.update_model(self.get_current_browser()) + + def on_lv_extensions_double_clicked(self, index: QtCore.QModelIndex): + model = self.ext_list_models[self.get_current_browser()] + ext_id = model.data(index, ExtensionIdRole) + node = model.all_extensions[ext_id] + da_sp = DaShowProfiles( + self.get_current_browser(), + self.ui.cbx_compat.isChecked(), + model.all_profiles, + ext_id, + node.name, + model.icons[ext_id], + node.profiles, + self + ) + da_sp.exec() + + def update_safe(self, safe_info: dict): + for browser in self.ext_list_models: + self.ext_list_models[browser].update_safe_info(safe_info) + + def export_unknown(self) -> dict[str, dict]: + unknown_ext = {} + for browser in self.ext_list_models: + model = self.ext_list_models[browser] + for row in range(model.rowCount()): + idx = model.index(row) + is_safe = model.data(idx, ExtensionStatusRole) + if is_safe is None: + ext_id = model.data(idx, ExtensionIdRole) + name = model.data(idx, QtCore.Qt.ItemDataRole.DisplayRole) + unknown_ext[ext_id] = {"name": name} + return unknown_ext diff --git a/wg_software.py b/wg_software.py new file mode 100644 index 0000000..e918849 --- /dev/null +++ b/wg_software.py @@ -0,0 +1,133 @@ +# coding: utf8 +import os.path + +from PySide6 import QtWidgets, QtCore, QtGui +from util_func import ( + get_mac_installed_software, +) +from global_vars import ( + SoftwareStatusRole, +) + + +class UiWgSoftware(object): + + def __init__(self, window: QtWidgets.QWidget): + self.vly_m = QtWidgets.QVBoxLayout() + window.setLayout(self.vly_m) + + self.hly_top = QtWidgets.QHBoxLayout() + self.vly_m.addLayout(self.hly_top) + self.cbx_safe = QtWidgets.QCheckBox("安全", window) + self.cbx_unsafe = QtWidgets.QCheckBox("不安全", window) + self.cbx_unknown = QtWidgets.QCheckBox("未知", window) + self.cbx_safe.setChecked(True) + self.cbx_unsafe.setChecked(True) + self.cbx_unknown.setChecked(True) + self.hly_top.addWidget(self.cbx_safe) + self.hly_top.addWidget(self.cbx_unsafe) + self.hly_top.addWidget(self.cbx_unknown) + self.hly_top.addStretch(1) + + self.lv_software = QtWidgets.QListView(window) + self.vly_m.addWidget(self.lv_software) + + +class SoftwareListModel(QtCore.QAbstractListModel): + + def __init__(self, parent=None): + super().__init__(parent) + self.all_software = {} # type: dict[str, str] + self.names = [] # type: list[str] + self.icons = {} # type: dict[str, QtGui.QIcon] + self.safe_info = {} + self.blank_icon = QtGui.QIcon(":/images/blank_128.png") + self.update() + + def update(self): + self.all_software.clear() + self.names.clear() + self.icons.clear() + + self.all_software = get_mac_installed_software() + for s in self.all_software: + self.names.append(s) + ic = self.all_software[s] + if len(ic) == 0 or not os.path.exists(ic): + self.icons[s] = self.blank_icon + else: + self.icons[s] = QtGui.QIcon(ic) + self.names.sort(key=lambda x: x.lower()) + + def update_safe_info(self, safe_info: dict): + self.safe_info.clear() + self.safe_info = safe_info + + def rowCount(self, parent: QtCore.QModelIndex = ...): + return len(self.names) + + def data(self, index: QtCore.QModelIndex, role: int = ...): + row = index.row() + name = self.names[row] + + if role == QtCore.Qt.ItemDataRole.DisplayRole: + return name + if role == QtCore.Qt.ItemDataRole.DecorationRole: + return self.icons[name] + if role == QtCore.Qt.ItemDataRole.BackgroundRole: + is_safe = self.data(index, SoftwareStatusRole) + if is_safe is True: + return QtGui.QBrush(QtGui.QColor("lightgreen")) + elif is_safe is False: + return QtGui.QBrush(QtGui.QColor("lightpink")) + else: + return QtGui.QBrush(QtCore.Qt.BrushStyle.NoBrush) + if role == SoftwareStatusRole: + if name not in self.safe_info: + return None + else: + return self.safe_info[name]["safe"] + + +class WgSoftware(QtWidgets.QWidget): + + def __init__(self, parent=None): + super().__init__(parent) + self.ui = UiWgSoftware(self) + + self.software_list_model = SoftwareListModel(self) + self.ui.lv_software.setModel(self.software_list_model) + + self.ui.cbx_safe.clicked.connect(self.on_cbx_safe_clicked) + self.ui.cbx_unsafe.clicked.connect(self.on_cbx_unsafe_clicked) + self.ui.cbx_unknown.clicked.connect(self.on_cbx_unknown_clicked) + + def filters_clicked(self, safe_mark: bool | None, checked: bool): + for row in range(self.software_list_model.rowCount()): + idx = self.software_list_model.index(row) + is_safe = self.software_list_model.data(idx, SoftwareStatusRole) + if is_safe is safe_mark: + self.ui.lv_software.setRowHidden(row, not checked) + + def on_cbx_safe_clicked(self, checked: bool): + self.filters_clicked(True, checked) + + def on_cbx_unsafe_clicked(self, checked: bool): + self.filters_clicked(False, checked) + + def on_cbx_unknown_clicked(self, checked: bool): + self.filters_clicked(None, checked) + + def update_safe(self, safe_info: dict): + self.software_list_model.update_safe_info(safe_info) + + def export_unknown(self) -> list[str]: + unknown_software = [] + for row in range(self.software_list_model.rowCount()): + idx = self.software_list_model.index(row) + is_safe = self.software_list_model.data(idx, SoftwareStatusRole) + if is_safe is None: + name = self.software_list_model.data(idx, QtCore.Qt.ItemDataRole.DisplayRole) + unknown_software.append(name) + + return unknown_software