├── .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 | ![](https://markdown-pic-blackboxo.oss-cn-shanghai.aliyuncs.com/banner.png) 4 | 5 | [![](https://img.shields.io/badge/platform-win64-lightgrey)](https://github.com/blackboxo/AutoDeleteFileOnPCWechat/releases) [![](https://img.shields.io/github/v/release/blackboxo/AutoDeleteFileOnPCWechat)](https://github.com/blackboxo/AutoDeleteFileOnPCWechat/releases) [![](https://img.shields.io/github/downloads/blackboxo/AutoDeleteFileOnPCWechat/total)](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 | ![](https://markdown-pic-blackboxo.oss-cn-shanghai.aliyuncs.com/20200929151623.jpg) 34 | 35 | ## 微信现状 36 | 37 | 下载两年时间,微信一个软件就占用多达 33.5 G 存储空间。其中大部分都是与自己无关的各大群聊中的文件、视频、图片等内容,且很久以前的文件仍旧存在电脑中。 38 | 39 | ![](https://markdown-pic-blackboxo.oss-cn-shanghai.aliyuncs.com/20200213142805.png) 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 | [![Stargazers over time](https://starchart.cc/blackboxo/CleanMyWechat.svg)](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 ([],[]) --------------------------------------------------------------------------------