├── .gitignore
├── LICENSE
├── images
├── arrow-down.png
├── config.ui
├── gen.bat
├── icon.ico
├── icon.png
├── main.ui
├── resources.qrc
├── wechat.png
├── 全局_反馈.svg
├── 复选.svg
├── 复选1.svg
├── 微信.svg
├── 用户_体力.svg
└── 顶部_退出.svg
├── main.py
├── readme.md
├── requirements.txt
└── utils
├── __pycache__
├── deleteThread.cpython-38.pyc
├── multiDeleteThread.cpython-38.pyc
├── resources.cpython-38.pyc
└── selectVersion.cpython-38.pyc
├── deleteThread.py
├── loadPath.py
├── multiDeleteThread.py
├── resources.py
└── selectVersion.py
/.gitignore:
--------------------------------------------------------------------------------
1 | config.json
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 blackboxo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/images/arrow-down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/images/arrow-down.png
--------------------------------------------------------------------------------
/images/config.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 650
10 | 416
11 |
12 |
13 |
14 | Config
15 |
16 |
17 | Qt::LeftToRight
18 |
19 |
20 |
21 | -
22 |
23 |
24 | Qt::Horizontal
25 |
26 |
27 |
28 | 40
29 | 20
30 |
31 |
32 |
33 |
34 | -
35 |
36 |
37 | Qt::Vertical
38 |
39 |
40 |
41 | 20
42 | 40
43 |
44 |
45 |
46 |
47 | -
48 |
49 |
50 | .QFrame {
51 | background: rgb(245, 245, 245);
52 | border-radius: 3px;
53 | }
54 |
55 |
56 | QFrame::StyledPanel
57 |
58 |
59 | QFrame::Raised
60 |
61 |
62 |
-
63 |
64 |
65 |
66 | 0
67 | 40
68 |
69 |
70 |
71 |
72 | 微软雅黑
73 |
74 |
75 |
76 | .QLabel {
77 | border:1px solid #b7eb8f;
78 | border-radius:3px;
79 | line-height: 140px;
80 | padding: 5px;
81 | color: #434343;
82 | background: #f6ffed;
83 | }
84 |
85 |
86 | 一切都准备好!
87 |
88 |
89 | Qt::AlignCenter
90 |
91 |
92 |
93 | -
94 |
95 |
96 | 5
97 |
98 |
99 | QLayout::SetDefaultConstraint
100 |
101 |
-
102 |
103 |
104 |
105 | 70
106 | 35
107 |
108 |
109 |
110 |
111 | 16777215
112 | 16777215
113 |
114 |
115 |
116 |
117 | 微软雅黑
118 |
119 |
120 |
121 | .QComboBox {
122 | border:1px solid #d9d9d9;
123 | border-radius:3px;
124 | line-height: 140px;
125 | padding:5px 20px;
126 | color: #434343;
127 | }
128 | .QComboBox::drop-down {
129 | width: 20px;
130 | border-left: 1px solid #d9d9d9;
131 | }
132 | .QComboBox::down-arrow {
133 | image: url(:/icon/arrow-down.png)
134 | }
135 |
136 |
137 |
138 | -
139 |
140 |
141 |
142 | 0
143 | 0
144 |
145 |
146 |
147 |
148 | 0
149 | 35
150 |
151 |
152 |
153 |
154 | 微软雅黑
155 | -1
156 |
157 |
158 |
159 | .QPushButton {
160 | height: 24px;
161 | padding: 0px 10px;
162 | font-size: 14px;
163 | border-radius: 3px;
164 | color: rgba(0,0,0,.65);
165 | background-color: #fff;
166 | border: 1px solid #d9d9d9;
167 | }
168 |
169 | .QPushButton:hover {
170 | height: 24px;
171 | padding: 0px 10px;
172 | font-size: 14px;
173 | border-radius: 3px;
174 | color: #40a9ff;
175 | background-color: #fff;
176 | border: 1px solid #40a9ff;
177 | }
178 |
179 |
180 |
181 | +自定义路径
182 |
183 |
184 |
185 | -
186 |
187 |
188 |
189 | 0
190 | 0
191 |
192 |
193 |
194 |
195 | 0
196 | 35
197 |
198 |
199 |
200 |
201 | 微软雅黑
202 | -1
203 |
204 |
205 |
206 | .QPushButton {
207 | height: 24px;
208 | padding: 0px 10px;
209 | font-size: 14px;
210 | border-radius: 3px;
211 | color: rgba(0,0,0,.65);
212 | background-color: #fff;
213 | border: 1px solid #d9d9d9;
214 | }
215 |
216 | .QPushButton:hover {
217 | height: 24px;
218 | padding: 0px 10px;
219 | font-size: 14px;
220 | border-radius: 3px;
221 | color: #40a9ff;
222 | background-color: #fff;
223 | border: 1px solid #40a9ff;
224 | }
225 |
226 |
227 |
228 | 保存
229 |
230 |
231 |
232 |
233 |
234 | -
235 |
236 |
237 | Qt::Vertical
238 |
239 |
240 |
241 | 20
242 | 40
243 |
244 |
245 |
246 |
247 | -
248 |
249 |
-
250 |
251 |
252 | Qt::Horizontal
253 |
254 |
255 | QSizePolicy::Maximum
256 |
257 |
258 |
259 | 80
260 | 20
261 |
262 |
263 |
264 |
265 | -
266 |
267 |
268 |
269 | 0
270 | 0
271 |
272 |
273 |
274 |
275 | 微软雅黑
276 | 50
277 | false
278 |
279 |
280 |
281 | QCheckBox::indicator::unchecked {
282 | image: url(:/icon/复选.svg);
283 | }
284 |
285 | QCheckBox::indicator::checked {
286 | image: url(:/icon/复选1.svg);
287 | }
288 |
289 |
290 | 是否清理该账号
291 |
292 |
293 |
294 | -
295 |
296 |
297 | Qt::Horizontal
298 |
299 |
300 |
301 | 40
302 | 20
303 |
304 |
305 |
306 |
307 |
308 |
309 | -
310 |
311 |
-
312 |
313 |
314 | Qt::Horizontal
315 |
316 |
317 | QSizePolicy::Maximum
318 |
319 |
320 |
321 | 80
322 | 20
323 |
324 |
325 |
326 |
327 | -
328 |
329 |
330 |
331 | 微软雅黑
332 | 50
333 | false
334 |
335 |
336 |
337 | QCheckBox::indicator::unchecked {
338 | image: url(:/icon/复选.svg);
339 | }
340 |
341 | QCheckBox::indicator::checked {
342 | image: url(:/icon/复选1.svg);
343 | }
344 |
345 |
346 | 图片
347 |
348 |
349 |
350 | -
351 |
352 |
353 | Qt::Horizontal
354 |
355 |
356 |
357 | 40
358 | 20
359 |
360 |
361 |
362 |
363 |
364 |
365 | -
366 |
367 |
-
368 |
369 |
370 | Qt::Horizontal
371 |
372 |
373 | QSizePolicy::Maximum
374 |
375 |
376 |
377 | 80
378 | 20
379 |
380 |
381 |
382 |
383 | -
384 |
385 |
386 |
387 | 微软雅黑
388 |
389 |
390 |
391 | QCheckBox::indicator::unchecked {
392 | image: url(:/icon/复选.svg);
393 | }
394 |
395 | QCheckBox::indicator::checked {
396 | image: url(:/icon/复选1.svg);
397 | }
398 |
399 |
400 | 接受的文件(PPT、Doc 等)
401 |
402 |
403 |
404 | -
405 |
406 |
407 | Qt::Horizontal
408 |
409 |
410 |
411 | 40
412 | 20
413 |
414 |
415 |
416 |
417 |
418 |
419 | -
420 |
421 |
-
422 |
423 |
424 | Qt::Horizontal
425 |
426 |
427 | QSizePolicy::Maximum
428 |
429 |
430 |
431 | 80
432 | 20
433 |
434 |
435 |
436 |
437 | -
438 |
439 |
440 |
441 | 微软雅黑
442 |
443 |
444 |
445 | QCheckBox::indicator::unchecked {
446 | image: url(:/icon/复选.svg);
447 | }
448 |
449 | QCheckBox::indicator::checked {
450 | image: url(:/icon/复选1.svg);
451 | }
452 |
453 |
454 | 视频(视频文件和视频的封面图)
455 |
456 |
457 |
458 | -
459 |
460 |
461 | Qt::Horizontal
462 |
463 |
464 |
465 | 40
466 | 20
467 |
468 |
469 |
470 |
471 |
472 |
473 | -
474 |
475 |
-
476 |
477 |
478 | Qt::Horizontal
479 |
480 |
481 | QSizePolicy::Maximum
482 |
483 |
484 |
485 | 80
486 | 20
487 |
488 |
489 |
490 |
491 | -
492 |
493 |
494 |
495 | 微软雅黑
496 |
497 |
498 |
499 | QCheckBox::indicator::unchecked {
500 | image: url(:/icon/复选.svg);
501 | }
502 |
503 | QCheckBox::indicator::checked {
504 | image: url(:/icon/复选1.svg);
505 | }
506 |
507 |
508 | 图片缓存(来自小程序、公众号等)
509 |
510 |
511 |
512 | -
513 |
514 |
515 | Qt::Horizontal
516 |
517 |
518 |
519 | 40
520 | 20
521 |
522 |
523 |
524 |
525 |
526 |
527 | -
528 |
529 |
-
530 |
531 |
532 | Qt::Horizontal
533 |
534 |
535 | QSizePolicy::Maximum
536 |
537 |
538 |
539 | 80
540 | 20
541 |
542 |
543 |
544 |
545 | -
546 |
547 |
548 |
549 | Microsoft YaHei
550 |
551 |
552 |
553 | 需要删除多久以前的文件:
554 |
555 |
556 |
557 | -
558 |
559 |
560 |
561 | 70
562 | 35
563 |
564 |
565 |
566 |
567 | 60
568 | 16777215
569 |
570 |
571 |
572 |
573 | 微软雅黑
574 |
575 |
576 |
577 | .QLineEdit {
578 | border:1px solid #d9d9d9;
579 | border-radius:3px;
580 | line-height: 140px;
581 | padding: 5px;
582 | color: #434343;
583 | }
584 |
585 | .QLineEdit:hover {
586 | border:1px solid #40a9ff;
587 | border-radius:3px;
588 | line-height: 140px;
589 | padding: 5px;
590 | color: #434343;
591 | }
592 |
593 |
594 |
595 |
596 |
597 | 天数
598 |
599 |
600 |
601 | -
602 |
603 |
604 |
605 | Microsoft YaHei
606 |
607 |
608 |
609 | 天
610 |
611 |
612 |
613 | -
614 |
615 |
616 | Qt::Horizontal
617 |
618 |
619 |
620 | 40
621 | 20
622 |
623 |
624 |
625 |
626 |
627 |
628 | -
629 |
630 |
631 | Qt::Vertical
632 |
633 |
634 |
635 | 20
636 | 40
637 |
638 |
639 |
640 |
641 | -
642 |
643 |
644 |
645 | 微软雅黑
646 |
647 |
648 |
649 | .QLabel {
650 | color: #434343;
651 | }
652 |
653 |
654 | Clean My Wechat - 设置页面
655 |
656 |
657 | Qt::AlignCenter
658 |
659 |
660 |
661 |
662 |
663 |
664 | -
665 |
666 |
667 | Qt::Vertical
668 |
669 |
670 |
671 | 20
672 | 40
673 |
674 |
675 |
676 |
677 | -
678 |
679 |
680 | Qt::Horizontal
681 |
682 |
683 |
684 | 40
685 | 20
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
--------------------------------------------------------------------------------
/images/gen.bat:
--------------------------------------------------------------------------------
1 | pyrcc5 -o resources.py resources.qrc
--------------------------------------------------------------------------------
/images/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/images/icon.ico
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/images/icon.png
--------------------------------------------------------------------------------
/images/main.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 499
10 | 466
11 |
12 |
13 |
14 | Wechat Cleaner
15 |
16 |
17 | false
18 |
19 |
20 | * {
21 | font: 9pt "微软雅黑";
22 | }
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | -
31 |
32 |
33 | Qt::Horizontal
34 |
35 |
36 |
37 | 40
38 | 20
39 |
40 |
41 |
42 |
43 | -
44 |
45 |
46 | Qt::Horizontal
47 |
48 |
49 |
50 | 40
51 | 20
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 | Qt::Vertical
60 |
61 |
62 |
63 | 20
64 | 40
65 |
66 |
67 |
68 |
69 | -
70 |
71 |
72 | Qt::Vertical
73 |
74 |
75 |
76 | 20
77 | 40
78 |
79 |
80 |
81 |
82 | -
83 |
84 |
85 |
86 | 3
87 | 3
88 |
89 |
90 |
91 | .QFrame {
92 | background: rgb(245, 245, 245);
93 | border-radius: 3px;
94 | }
95 |
96 |
97 | QFrame::StyledPanel
98 |
99 |
100 | QFrame::Raised
101 |
102 |
103 |
-
104 |
105 |
106 |
107 | 0
108 | 40
109 |
110 |
111 |
112 | .QLabel {
113 | border:1px solid #b7eb8f;
114 | border-radius:3px;
115 | line-height: 140px;
116 | padding: 5px;
117 | color: #434343;
118 | background: #f6ffed;
119 | }
120 |
121 |
122 | <html><head/><body><p>已经准备好,可以开始了!</p></body></html>
123 |
124 |
125 | Qt::AlignCenter
126 |
127 |
128 |
129 | -
130 |
131 |
132 | Qt::Vertical
133 |
134 |
135 |
136 | 20
137 | 40
138 |
139 |
140 |
141 |
142 | -
143 |
144 |
-
145 |
146 |
147 | Qt::Horizontal
148 |
149 |
150 |
151 | 40
152 | 20
153 |
154 |
155 |
156 |
157 | -
158 |
159 |
160 |
161 | 200
162 | 200
163 |
164 |
165 |
166 | .QLabel {
167 | image: url(:/icon/wechat.png);
168 | }
169 |
170 |
171 |
172 |
173 |
174 | Qt::AlignCenter
175 |
176 |
177 |
178 | -
179 |
180 |
181 | Qt::Horizontal
182 |
183 |
184 |
185 | 40
186 | 20
187 |
188 |
189 |
190 |
191 |
192 |
193 | -
194 |
195 |
196 | Qt::Vertical
197 |
198 |
199 |
200 | 20
201 | 40
202 |
203 |
204 |
205 |
206 | -
207 |
208 |
-
209 |
210 |
211 | Qt::Horizontal
212 |
213 |
214 | QSizePolicy::Fixed
215 |
216 |
217 |
218 | 40
219 | 20
220 |
221 |
222 |
223 |
224 | -
225 |
226 |
227 |
228 | 0
229 | 0
230 |
231 |
232 |
233 |
234 | 16777215
235 | 16777215
236 |
237 |
238 |
239 | Qt::LeftToRight
240 |
241 |
242 | .QProgressBar {
243 | background: #fff;
244 | border:1px solid #d9d9d9;
245 | border-radius: 13px;
246 | color: black;
247 | }
248 | QProgressBar::chunk {
249 | background-color: #1890ff;
250 | border-radius:12px;
251 | }
252 |
253 |
254 | 0
255 |
256 |
257 | Qt::AlignCenter
258 |
259 |
260 | true
261 |
262 |
263 | Qt::Horizontal
264 |
265 |
266 | false
267 |
268 |
269 |
270 | -
271 |
272 |
273 | Qt::Horizontal
274 |
275 |
276 | QSizePolicy::Fixed
277 |
278 |
279 |
280 | 40
281 | 20
282 |
283 |
284 |
285 |
286 |
287 |
288 | -
289 |
290 |
291 | 0
292 |
293 |
-
294 |
295 |
296 | Qt::Horizontal
297 |
298 |
299 | QSizePolicy::Fixed
300 |
301 |
302 |
303 | 100
304 | 20
305 |
306 |
307 |
308 |
309 | -
310 |
311 |
312 | .QLabel {
313 | color: rgba(0,0,0,.65);
314 | background-color: #fff;
315 | border: 1px solid #d9d9d9;
316 | border-right: 0px;
317 | height: 24px;
318 | font-size: 14px;
319 | padding: 0px 10px;
320 | }
321 | .QLabel:hover {
322 | color: #40a9ff;
323 | background-color: #fff;
324 | border: 1px solid #40a9ff;
325 | height: 24px;
326 | font-size: 14px
327 | }
328 |
329 |
330 | <html><head/><body><p>开始</p></body></html>
331 |
332 |
333 | Qt::AlignCenter
334 |
335 |
336 |
337 | -
338 |
339 |
340 |
341 | 0
342 | 35
343 |
344 |
345 |
346 | .QLabel {
347 | color: rgba(0,0,0,.65);
348 | background-color: #fff;
349 | border: 1px solid #d9d9d9;
350 | border-right: 0px;
351 | height: 24px;
352 | font-size: 14px;
353 | padding: 0px 10px;
354 | }
355 | .QLabel:hover {
356 | color: #40a9ff;
357 | background-color: #fff;
358 | border: 1px solid #40a9ff;
359 | height: 24px;
360 | font-size: 14px
361 | }
362 |
363 |
364 | <html><head/><body><p>设置</p></body></html>
365 |
366 |
367 | Qt::AlignCenter
368 |
369 |
370 |
371 | -
372 |
373 |
374 |
375 | 0
376 | 30
377 |
378 |
379 |
380 | .QLabel {
381 | color: rgba(0,0,0,.65);
382 | background-color: #fff;
383 | border: 1px solid #d9d9d9;
384 | height: 24px;
385 | font-size: 14px;
386 | padding: 0px 10px;
387 | }
388 |
389 | .QLabel:hover {
390 | color: #40a9ff;
391 | background-color: #fff;
392 | border: 1px solid #40a9ff;
393 | height: 24px;
394 | font-size: 14px
395 | }
396 |
397 |
398 | <html><head/><body><p>退出</p></body></html>
399 |
400 |
401 | Qt::AlignCenter
402 |
403 |
404 |
405 | -
406 |
407 |
408 | Qt::Horizontal
409 |
410 |
411 | QSizePolicy::Fixed
412 |
413 |
414 |
415 | 100
416 | 20
417 |
418 |
419 |
420 |
421 |
422 |
423 | -
424 |
425 |
426 | Qt::Vertical
427 |
428 |
429 |
430 | 20
431 | 40
432 |
433 |
434 |
435 |
436 | -
437 |
438 |
439 | .QLabel {
440 | color: #434343;
441 | }
442 |
443 |
444 | Clean My Wechat - 清除微信无用数据
445 |
446 |
447 | Qt::AlignCenter
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
--------------------------------------------------------------------------------
/images/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | 微信.svg
4 | 全局_反馈.svg
5 | 用户_体力.svg
6 | 顶部_退出.svg
7 | arrow-down.png
8 | 复选.svg
9 | 复选1.svg
10 | wechat.png
11 |
12 |
13 |
--------------------------------------------------------------------------------
/images/wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/images/wechat.png
--------------------------------------------------------------------------------
/images/全局_反馈.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/复选.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/复选1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/微信.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/用户_体力.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/顶部_退出.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsDropShadowEffect, QListWidgetItem, QListView, QWidget, \
4 | QLabel, QHBoxLayout, QFileDialog
5 | from PyQt5.QtCore import Qt, QPropertyAnimation, QEasingCurve, QThread, pyqtSignal, QMutex, QSize, QEvent, QPoint
6 | from PyQt5.QtGui import QMouseEvent, QCursor, QColor
7 | from PyQt5.uic import loadUi
8 |
9 | from pathlib import Path, PureWindowsPath
10 | from dateutil import relativedelta
11 | import utils.resources
12 | import os, datetime, time, re, math, shutil, json
13 |
14 | from utils.deleteThread import *
15 | from utils.multiDeleteThread import multiDeleteThread
16 | from utils.selectVersion import *
17 | from utils.selectVersion import check_dir, existing_user_config
18 |
19 |
20 | # determine if application is a script file or frozen exe
21 | if getattr(sys, 'frozen', False):
22 | working_dir = os.path.dirname(os.path.realpath(sys.executable))
23 | elif __file__:
24 | working_dir = os.path.split(os.path.realpath(__file__))[0]
25 |
26 | # 主窗口
27 | class Window(QMainWindow):
28 | def mousePressEvent(self, event):
29 | # 重写一堆方法使其支持拖动
30 | if event.button() == Qt.LeftButton:
31 | self.m_drag = True
32 | self.m_DragPosition = event.globalPos() - self.pos()
33 | event.accept()
34 | # self.setCursor(QCursor(Qt.OpenHandCursor))
35 |
36 | def mouseMoveEvent(self, QMouseEvent):
37 | try:
38 | if Qt.LeftButton and self.m_drag:
39 | self.move(QMouseEvent.globalPos() - self.m_DragPosition)
40 | QMouseEvent.accept()
41 | except:
42 | pass
43 |
44 | def mouseReleaseEvent(self, QMouseEvent):
45 | self.m_drag = False
46 | # self.setCursor(QCursor(Qt.ArrowCursor))
47 |
48 | def _frame(self):
49 | # 边框
50 | self.setWindowFlags(Qt.FramelessWindowHint)
51 | self.setAttribute(Qt.WA_TranslucentBackground, True)
52 | # 阴影
53 | effect = QGraphicsDropShadowEffect(blurRadius=12, xOffset=0, yOffset=0)
54 | effect.setColor(QColor(25, 25, 25, 170))
55 | self.mainFrame.setGraphicsEffect(effect)
56 |
57 | def doFadeIn(self):
58 | # 动画
59 | self.animation = QPropertyAnimation(self, b'windowOpacity')
60 | # 持续时间250ms
61 | self.animation.setDuration(250)
62 | try:
63 | # 尝试先取消动画完成后关闭窗口的信号
64 | self.animation.finished.disconnect(self.close)
65 | except:
66 | pass
67 | self.animation.stop()
68 | # 透明度范围从0逐渐增加到1
69 | self.animation.setEasingCurve(QEasingCurve.InOutCubic)
70 | self.animation.setStartValue(0)
71 | self.animation.setEndValue(1)
72 | self.animation.start()
73 |
74 | def doFadeOut(self):
75 | self.animation.stop()
76 | # 动画完成则关闭窗口
77 | self.animation.finished.connect(self.close)
78 | # 透明度范围从1逐渐减少到0s
79 | self.animation.setEasingCurve(QEasingCurve.InOutCubic)
80 | self.animation.setStartValue(1)
81 | self.animation.setEndValue(0)
82 | self.animation.start()
83 |
84 | def setWarninginfo(self, text):
85 | self.lab_info.setStyleSheet("""
86 | .QLabel {
87 | border:1px solid #ffccc7;
88 | border-radius:3px;
89 | line-height: 140px;
90 | padding: 5px;
91 | color: #434343;
92 | background: #fff2f0;
93 | }
94 | """)
95 | self.lab_info.setText(text)
96 |
97 | def setSuccessinfo(self, text):
98 | self.lab_info.setStyleSheet("""
99 | .QLabel {
100 | border:1px solid #b7eb8f;
101 | border-radius:3px;
102 | line-height: 140px;
103 | padding: 5px;
104 | color: #434343;
105 | background: #f6ffed;
106 | }
107 | """)
108 | self.lab_info.setText(text)
109 |
110 |
111 | class ConfigWindow(Window):
112 | Signal_OneParameter = pyqtSignal(int)
113 |
114 | config = {}
115 |
116 | def _connect(self):
117 | self.combo_user.currentIndexChanged.connect(self.refresh_ui)
118 | self.btn_close.clicked.connect(self.save_config)
119 | self.btn_file.clicked.connect(self.open_file)
120 |
121 | def open_file(self):
122 | openfile_path = QFileDialog.getExistingDirectory(self, '选择微信数据目录', '')
123 | if not openfile_path or openfile_path == '':
124 | return False
125 | if check_dir(openfile_path) == 0:
126 | self.setSuccessinfo('读取路径成功!')
127 | list_ = os.listdir(openfile_path)
128 | user_list = [
129 | elem for elem in list_
130 | if elem != 'All Users' and elem != 'Applet'
131 | ]
132 | # 如果已有用户配置,那么写入新的用户配置,否则默认写入新配置
133 | dir_list = []
134 | user_config = []
135 | existing_user_config_dic = existing_user_config()
136 | for user_wx_id in user_list:
137 | dir_list.append(os.path.join(openfile_path, user_wx_id))
138 | if user_wx_id in existing_user_config_dic:
139 | user_config.append(existing_user_config_dic[user_wx_id])
140 | else:
141 | user_config.append({
142 | "wechat_id": user_wx_id,
143 | "clean_days": "365",
144 | "is_clean": False,
145 | "clean_pic_cache": True,
146 | "clean_file": False,
147 | "clean_pic": True,
148 | "clean_video": True,
149 | "is_timer": True,
150 | "timer": "0h"
151 | })
152 |
153 | config = {"data_dir": dir_list, "users": user_config}
154 |
155 | with open(
156 | working_dir + "/config.json", "w", encoding="utf-8") as f:
157 | json.dump(config, f)
158 | self.load_config()
159 | else:
160 | self.setWarninginfo('请选择正确的文件夹!一般是WeChat Files文件夹。')
161 |
162 | def save_config(self):
163 | self.update_config()
164 | self.doFadeOut()
165 |
166 | def check_wechat_exists(self):
167 | self.selectVersion = selectVersion()
168 | self.version_scan = self.selectVersion.getAllPath()[0]
169 | self.users_scan = self.selectVersion.getAllPath()[1]
170 | if len(self.version_scan) == 0:
171 | return False
172 | else:
173 | return True
174 |
175 | def load_config(self):
176 | fd = open(working_dir + "/config.json", encoding="utf-8")
177 | self.config = json.load(fd)
178 |
179 | self.combo_user.clear()
180 | for value in self.config["users"]:
181 | self.combo_user.addItem(value["wechat_id"])
182 |
183 | self.line_gobackdays.setText(
184 | str(self.config["users"][0]["clean_days"]))
185 | self.check_is_clean.setChecked(self.config["users"][0]["is_clean"])
186 | self.check_picdown.setChecked(self.config["users"][0]["clean_pic"])
187 | self.check_files.setChecked(self.config["users"][0]["clean_file"])
188 | self.check_video.setChecked(self.config["users"][0]["clean_video"])
189 | self.check_picscache.setChecked(
190 | self.config["users"][0]["clean_pic_cache"])
191 | self.setSuccessinfo("加载配置文件成功")
192 |
193 | def refresh_ui(self):
194 | self.config = open(working_dir + "/config.json", encoding="utf-8")
195 | self.config = json.load(self.config)
196 |
197 | for value in self.config["users"]:
198 | if value["wechat_id"] == self.combo_user.currentText():
199 | self.line_gobackdays.setText(str(value["clean_days"]))
200 | self.check_is_clean.setChecked(value["is_clean"])
201 | self.check_picdown.setChecked(value["clean_pic"])
202 | self.check_files.setChecked(value["clean_file"])
203 | self.check_video.setChecked(value["clean_video"])
204 | self.check_picscache.setChecked(value["clean_pic_cache"])
205 |
206 | def create_config(self):
207 | true = True
208 | if not os.path.exists(working_dir + "/config.json"):
209 | if not self.check_wechat_exists():
210 | self.setWarninginfo("默认位置没有微信,请自定义位置")
211 | return
212 |
213 | self.config = {"data_dir": self.version_scan, "users": []}
214 | for value in self.users_scan:
215 | self.config["users"].append({
216 | "wechat_id": value,
217 | "clean_days": 365,
218 | "is_clean": False,
219 | "clean_pic_cache": true,
220 | "clean_file": False,
221 | "clean_pic": true,
222 | "clean_video": true,
223 | "is_timer": true,
224 | "timer": "0h"
225 | })
226 | with open(
227 | working_dir + "/config.json", "w", encoding="utf-8") as f:
228 | json.dump(self.config, f)
229 | self.load_config()
230 | self.setSuccessinfo("加载配置文件成功")
231 | else:
232 | self.setSuccessinfo("加载配置文件成功")
233 | self.load_config()
234 |
235 | def update_config(self):
236 | if not len(self.config):
237 | return
238 | else:
239 | for value in self.config["users"]:
240 | if value["wechat_id"] == self.combo_user.currentText():
241 | try:
242 | days = int(self.line_gobackdays.text())
243 | if days < 0:
244 | value["clean_days"] = "0"
245 | else:
246 | value["clean_days"] = self.line_gobackdays.text()
247 | except ValueError:
248 | value["clean_days"] = "0"
249 | value["is_clean"] = self.check_is_clean.isChecked()
250 | value["clean_pic"] = self.check_picdown.isChecked()
251 | value["clean_file"] = self.check_files.isChecked()
252 | value["clean_video"] = self.check_video.isChecked()
253 | value["clean_pic_cache"] = self.check_picscache.isChecked()
254 |
255 | with open(working_dir + "/config.json", "w", encoding="utf-8") as f:
256 | json.dump(self.config, f)
257 | self.setSuccessinfo("更新配置文件成功")
258 | self.Signal_OneParameter.emit(1)
259 |
260 | def __init__(self):
261 | super().__init__()
262 | loadUi(working_dir + "/images/config.ui", self)
263 |
264 | self._frame()
265 | self._connect()
266 |
267 | self.doFadeIn()
268 | self.create_config()
269 |
270 | self.show()
271 |
272 |
273 | class MainWindow(Window):
274 |
275 | def deal_emit_slot(self, set_status):
276 | if set_status and not self.config_exists:
277 | self.setSuccessinfo("已经准备好,可以开始了!")
278 | self.config_exists = True
279 |
280 | def closeEvent(self, event):
281 | sys.exit(0)
282 |
283 | def eventFilter(self, object, event):
284 | if event.type() == QEvent.MouseButtonPress:
285 | if object == self.lab_close:
286 | self.doFadeOut()
287 | return True
288 | elif object == self.lab_clean:
289 | try:
290 | self.setSuccessinfo("正在清理中...")
291 | self.justdoit()
292 | except:
293 | self.setWarninginfo("清理失败,请检查配置文件后重试")
294 | return True
295 | elif object == self.lab_config:
296 | cw = ConfigWindow()
297 | cw.Signal_OneParameter.connect(self.deal_emit_slot)
298 | return True
299 | return False
300 |
301 | def _eventfilter(self):
302 | # 事件过滤
303 | self.lab_close.installEventFilter(self)
304 | self.lab_clean.installEventFilter(self)
305 | self.lab_config.installEventFilter(self)
306 |
307 | def get_fileNum(self, path, day, picCacheCheck, fileCheck, picCheck,
308 | videoCheck, file_list, dir_list):
309 | dir_name = PureWindowsPath(path)
310 | # Convert path to the right format for the current operating system
311 | correct_path = Path(dir_name)
312 | now = datetime.datetime.now()
313 | if picCacheCheck:
314 | path_one = correct_path / 'Attachment'
315 | path_two = correct_path / 'FileStorage/Cache'
316 | self.getPathFileNum(now, day, path_one, path_two, file_list,
317 | dir_list)
318 | if fileCheck:
319 | path_one = correct_path / 'Files'
320 | path_two = correct_path / 'FileStorage/File'
321 | self.getPathFileNum(now, day, path_one, path_two, file_list,
322 | dir_list)
323 | if picCheck:
324 | path_one = correct_path / 'Image/Image'
325 | path_two = correct_path / 'FileStorage/Image'
326 | self.getPathFileNum(now, day, path_one, path_two, file_list,
327 | dir_list)
328 | if videoCheck:
329 | path_one = correct_path / 'Video'
330 | path_two = correct_path / 'FileStorage/Video'
331 | self.getPathFileNum(now, day, path_one, path_two, file_list,
332 | dir_list)
333 |
334 | def pathFileDeal(self, now, day, path, file_list, dir_list):
335 | if os.path.exists(path):
336 | filelist = [
337 | f for f in os.listdir(path)
338 | if os.path.isfile(os.path.join(path, f))
339 | ]
340 | for i in range(0, len(filelist)):
341 | file_path = os.path.join(path, filelist[i])
342 | if os.path.isdir(file_path):
343 | continue
344 | timestamp = datetime.datetime.fromtimestamp(
345 | os.path.getmtime(file_path))
346 | diff = (now - timestamp).days
347 | if diff >= day:
348 | file_list.append(file_path)
349 |
350 | def getPathFileNum(self, now, day, path_one, path_two, file_list,
351 | dir_list):
352 | # caculate path_one
353 | self.pathFileDeal(now, day, path_one, file_list, dir_list)
354 | td = datetime.datetime.now() - datetime.timedelta(days=day)
355 | td_year = td.year
356 | td_month = td.month
357 | # caculate path_two
358 | if os.path.exists(path_two):
359 | osdir = os.listdir(path_two)
360 | dirlist = []
361 | for i in range(0, len(osdir)):
362 | file_path = os.path.join(path_two, osdir[i])
363 | if os.path.isdir(file_path):
364 | dirlist.append(osdir[i])
365 | for i in range(0, len(dirlist)):
366 | file_path = os.path.join(path_two, dirlist[i])
367 | if os.path.isfile(file_path):
368 | continue
369 | if re.match('\d{4}(\-)\d{2}', dirlist[i]) != None:
370 | cyear = int(dirlist[i].split('-', 1)[0])
371 | cmonth = int(dirlist[i].split('-', 1)[1])
372 | if self.__before_deadline(cyear, cmonth, td_year,
373 | td_month):
374 | dir_list.append(file_path)
375 | else:
376 | if cmonth == td_month:
377 | self.pathFileDeal(now, day, file_path, file_list,
378 | dir_list)
379 |
380 | def __before_deadline(self, cyear, cmonth, td_year, td_month):
381 | if cyear < td_year:
382 | return True
383 | elif cyear > td_year:
384 | return False
385 | elif cyear == td_year:
386 | return cmonth < td_month
387 |
388 | def callback(self, v):
389 | value = v / int((self.total_file + self.total_dir)) * 100
390 | self.bar_progress.setValue(value)
391 | if value == 100:
392 | out = "本次共清理文件" + str(self.total_file) + "个,文件夹" + str(
393 | self.total_dir) + "个。请前往回收站检查并清空。"
394 | self.setSuccessinfo(out)
395 | return
396 |
397 | def justdoit(self):
398 | fd = open(working_dir + "/config.json", encoding="utf-8")
399 | self.config = json.load(fd)
400 | i = 0
401 | need_clean = False
402 | thread_list = []
403 | total_file = 0
404 | total_dir = 0
405 | share_thread_arr = [0]
406 | for value in self.config["users"]:
407 | file_list = []
408 | dir_list = []
409 | if value["is_clean"]:
410 | self.get_fileNum(self.config["data_dir"][i],
411 | int(value["clean_days"]),
412 | value["clean_pic_cache"], value["clean_file"],
413 | value["clean_pic"], value["clean_video"],
414 | file_list, dir_list)
415 |
416 | if len(file_list) + len(dir_list) != 0:
417 | need_clean = True
418 | total_file += len(file_list)
419 | total_dir += len(dir_list)
420 | thread_list.append(
421 | multiDeleteThread(file_list, dir_list, share_thread_arr))
422 | thread_list[-1].delete_process_signal.connect(self.callback)
423 | i = i + 1
424 |
425 | if not need_clean:
426 | self.setWarninginfo("没有需要清理的文件")
427 | else:
428 | self.total_file = total_file
429 | self.total_dir = total_dir
430 | for thread in thread_list:
431 | thread.run()
432 |
433 | def __init__(self):
434 | super().__init__()
435 | loadUi(working_dir + "/images/main.ui", self)
436 |
437 | self._frame()
438 | self._eventfilter()
439 | self.doFadeIn()
440 | self.config_exists = True
441 |
442 | # 判断配置文件是否存在
443 | if not os.path.exists(working_dir + "/config.json"):
444 | self.setWarninginfo("配置文件不存在!请单击“设置”创建配置文件")
445 | self.config_exists = False
446 |
447 | self.show()
448 |
449 |
450 | if __name__ == '__main__':
451 | app = QApplication([])
452 | win = MainWindow()
453 | app.exec_()
454 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Clean My PC Wechat
2 |
3 | 
4 |
5 | [](https://github.com/blackboxo/AutoDeleteFileOnPCWechat/releases) [](https://github.com/blackboxo/AutoDeleteFileOnPCWechat/releases) [](https://github.com/blackboxo/AutoDeleteFileOnPCWechat/releases)
6 |
7 | 自动删除 PC 端微信自动下载的大量文件、视频、图片等数据内容,解放一年几十 G 的空间占用。
8 |
9 | 该工具不会删除文字的聊天记录,请放心使用。请给个 **Star** 吧,非常感谢!
10 |
11 | **现已经支持 Windows 系统中的所有微信版本。**
12 |
13 | [国内地址 - 点击下载](
14 | https://www.lanzoux.com/iamuhh1owmb)
15 |
16 | [Github Release - 点击下载](
17 | https://github.com/blackboxo/CleanMyWechat/releases/download/v2.0/CleanMyWechat.zip)
18 |
19 | **碰到无法清理的,请记得勾选第一个选项,勾选后才会清理该账号下的内容。**
20 |
21 | ### [请我喝咖啡:coffee:](https://dun.mianbaoduo.com/@blackboxo)
22 |
23 | ## 特性
24 | 1. 自动识别微信账号,支持用户选择自定义路径;
25 | 2. 同时管理多个账号,保留配置参数,打开即用;
26 | 3. 自由设置想要删除的文件类型,包括图片类缓存、文件、图片、视频;
27 | 4. 自由设置需要删除的文件的距离时间,默认 365 天;
28 | 5. 删除后的文件放置在回收站中,检查后自行清空,防止删错需要的文件;
29 | 6. 支持删除进度的显示;
30 |
31 | ## 运行截图
32 |
33 | 
34 |
35 | ## 微信现状
36 |
37 | 下载两年时间,微信一个软件就占用多达 33.5 G 存储空间。其中大部分都是与自己无关的各大群聊中的文件、视频、图片等内容,且很久以前的文件仍旧存在电脑中。
38 |
39 | 
40 |
41 | ## 待改进
42 |
43 | 欢迎 PR!
44 |
45 | - [ ] Bug:由于微信文件保存路径更改等导致的空配置文件 config.json 引起的闪退,可以考虑读取注册表,详见此 [Issue](https://github.com/blackboxo/CleanMyWechat/issues/45)
46 | - [ ] 界面逻辑优化 [Issue](https://github.com/blackboxo/CleanMyWechat/issues/31)
47 | - [ ] Mac 版本的开发,微信 Mac 版存在缓存大量占用问题
48 | - [ ] 增加企业微信的支持
49 | - [ ] Windows XP 系统的支持
50 | - [ ] 有用户有每日定时删除的需求,考虑让应用开机自启动并常驻后台,或者“将选项变成参数加到快捷方式里运行自动执行”
51 | - [ ] 增加应用打包后的签名
52 | - [x] ~~自动识别出的多个微信账号的路径,让用户选择哪几个账号的需要删除,并记录参数~~
53 | - [x] ~~更改为以天为单位~~
54 | - [x] ~~增加多个微信路径的支持,支持保存路径~~
55 | - [x] ~~支持 Microsoft Store 下载的微信 for Windows 版本~~
56 | - [x] ~~支持 Microsoft Store 下载的微信 UWP 版本~~
57 |
58 | 其他需求详见 Issue
59 |
60 | ## 打包 EXE 方式
61 |
62 | 执行 pyinstaller -F -i images/icon.ico -w main.py, 会生成 dist 文件夹
63 |
64 | 将 images 文件夹拷贝到 dist 文件夹下,运行 dist/main.exe 即可执行。
65 |
66 | ## 致谢
67 |
68 | [@mylittlefox](https://www.mylittlefox.art):图标及 Banner 设计
69 |
70 | [@Gears](https://refun.eu.org):提供微信 for Windows 版本的文件目录树及测试支持
71 |
72 | @SongJee:版本 1.1 的主要开发者,增加进度条,支持多个微信版本,自动识别路径
73 |
74 | [@LenmoisLemon](https://github.com/LenmoisLemon):版本 2.0 的主要开发者,全新 UI 设计,增加多用户配置
75 |
76 | [@Louhwz](https://github.com/Louhwz):版本 2.0 的主要开发者,增加多用户支持、多线程删除、自定义路径等
77 |
78 | ## 开发者
79 |
80 | 微博:@BlackBoXo
81 |
82 | 邮箱:bwu18@fudan.edu.cn
83 |
84 | Blog:https://www.blackboxo.top/
85 |
86 | ## 项目 Star 数
87 |
88 | [](https://starchart.cc/blackboxo/CleanMyWechat)
89 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Send2Trash==1.5.0
2 | PyQt5==5.13.0
3 | python_dateutil==2.7.5
4 |
--------------------------------------------------------------------------------
/utils/__pycache__/deleteThread.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/utils/__pycache__/deleteThread.cpython-38.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/multiDeleteThread.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/utils/__pycache__/multiDeleteThread.cpython-38.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/resources.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/utils/__pycache__/resources.cpython-38.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/selectVersion.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OscarMCY/CleanMyWechat/d4afddbc2b56446d23ac966da3328bed3a6ead9d/utils/__pycache__/selectVersion.cpython-38.pyc
--------------------------------------------------------------------------------
/utils/deleteThread.py:
--------------------------------------------------------------------------------
1 | import os, datetime, time, re
2 | import shutil
3 |
4 | from send2trash import send2trash
5 |
6 | from PyQt5.QtCore import QThread, pyqtSignal, QMutex
7 |
8 |
9 | ##################################################################
10 | #删除线程
11 | ##################################################################
12 | qmut = QMutex()
13 | class deleteThread(QThread):
14 | delete_proess_signal = pyqtSignal(int) #创建信号
15 |
16 | def __init__(self, fileList, dirList):
17 | super(deleteThread, self).__init__()
18 | self.fileList = fileList
19 | self.dirList = dirList
20 | self.fileNum = len(fileList) + len(dirList)
21 | self.tempNum = 0
22 |
23 | def run(self):
24 | qmut.lock()
25 | try:
26 | for file_path in self.fileList:
27 | send2trash(file_path)
28 | self.tempNum = self.tempNum + 1
29 | proess = self.tempNum / int(self.fileNum) * 100
30 | self.delete_proess_signal.emit(int(proess))
31 |
32 | for file_path in self.dirList:
33 | send2trash(file_path)
34 | self.tempNum = self.tempNum + 1
35 | proess = self.tempNum / int(self.fileNum) * 100
36 | self.delete_proess_signal.emit(int(proess))
37 |
38 | qmut.unlock()
39 | self.exec_() #关闭线程
40 | except Exception as e:
41 | print(e)
--------------------------------------------------------------------------------
/utils/loadPath.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | from pathlib import Path
4 |
5 |
6 | class loadPath():
7 |
8 | def load(self):
9 | syspath = sys.prefix
10 | correct_syspath = Path(syspath)
11 | filepath = correct_syspath / 'path_file.txt'
12 | if os.path.exists(filepath):
13 | with open('path_file.txt', 'r') as f:
14 | self.path = f.readline()
15 | return self.path
16 | else:
17 | return ''
18 |
19 | def storage(self, path):
20 | syspath = sys.prefix
21 | correct_syspath = Path(syspath)
22 | filepath = correct_syspath / 'path_file.txt'
23 | with open(filepath, 'w') as f:
24 | f.write(path)
--------------------------------------------------------------------------------
/utils/multiDeleteThread.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QThread, pyqtSignal, QMutex
2 | from send2trash import send2trash
3 |
4 | ##################################################################
5 | # 删除线程,支持多进程
6 | ##################################################################
7 | qmut = QMutex()
8 |
9 |
10 | class multiDeleteThread(QThread):
11 | delete_process_signal = pyqtSignal(int) # 创建信号
12 |
13 | def __init__(self, fileList, dirList, share_thread_arr):
14 | super(multiDeleteThread, self).__init__()
15 | self.fileList = fileList
16 | self.dirList = dirList
17 | self.share_thread_arr = share_thread_arr
18 |
19 |
20 | def run(self):
21 | try:
22 | for file_path in self.fileList:
23 | send2trash(file_path)
24 | qmut.lock()
25 | self.share_thread_arr[0] += 1
26 | self.delete_process_signal.emit(self.share_thread_arr[0])
27 | qmut.unlock()
28 |
29 | for file_path in self.dirList:
30 | send2trash(file_path)
31 | qmut.lock()
32 | self.share_thread_arr[0] += 1
33 | self.delete_process_signal.emit(self.share_thread_arr[0])
34 | qmut.unlock()
35 |
36 | # self.exec_() # 关闭线程
37 | print('一个线程执行结束了')
38 | except Exception as e:
39 | print(e)
40 |
--------------------------------------------------------------------------------
/utils/selectVersion.py:
--------------------------------------------------------------------------------
1 |
2 | import getpass
3 | import json
4 | import os
5 |
6 | working_dir = os.path.split(os.path.realpath(__file__))[0]
7 |
8 | def check_dir(file_path):
9 | list_ = os.listdir(file_path)
10 | if 'All Users' in list_ or 'Applet' in list_:
11 | return 0
12 | else:
13 | return 1
14 |
15 |
16 | def existing_user_config():
17 | if os.path.exists(working_dir + "/config.json"):
18 | fd = open(working_dir+"/config.json", encoding="utf-8")
19 | config = json.load(fd)
20 | user_config = config['users']
21 | result = {}
22 | for uc in user_config:
23 | wechat_id = uc['wechat_id']
24 | result[wechat_id] = uc
25 | return result
26 | else:
27 | return {}
28 |
29 | class selectVersion:
30 |
31 | def getAllPath(self):
32 | user = getpass.getuser()
33 | dic = {
34 | 'pc': 'C:\\Users\\' + user + '\\Documents\\WeChat Files',
35 | 'forwin10': 'C:\\Users\\' + user + '\\AppData\\Local\\Packages\\TencentWeChatLimited.forWindows10_sdtnhv12zgd7a\\LocalCache\\Roaming\\Tencent\\WeChatAppStore\\WeChatAppStore Files',
36 | 'foruwp': 'C:\\Users\\' + user + '\\AppData\\Local\\Packages\\TencentWeChatLimited.WeChatUWP_sdtnhv12zgd7a\\LocalCache\\Roaming\\Tencent\\WeChatAppStore\\WeChatAppStore Files'
37 | }
38 | dirlist = []
39 | for key in dic:
40 | if os.path.exists(dic[key]):
41 | list_ = os.listdir(dic[key])
42 | # 换用lambda 表达式更安全,remove函数如果不存在对象会抛出异常
43 | list_ = [element for element in list_ if element != 'All Users' and element != 'Applet']
44 | for i in range(0, len(list_)):
45 | file_path = os.path.join(dic[key], list_[i])
46 | if os.path.isdir(file_path):
47 | dirlist.append(file_path)
48 | return (dirlist,list_)
49 | else:
50 | return ([],[])
--------------------------------------------------------------------------------