溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

基于Python怎么編寫微信清理工具

發(fā)布時間:2022-05-19 13:49:10 來源:億速云 閱讀:101 作者:iii 欄目:開發(fā)技術(shù)

這篇“基于Python怎么編寫微信清理工具”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“基于Python怎么編寫微信清理工具”文章吧。

主要功能

它可以自動刪除 PC 端微信自動下載的大量文件、視頻、圖片等數(shù)據(jù)內(nèi)容,釋放幾十 G 的空間占用,而且不會刪除文字的聊天記錄,可以放心使用。

工作以后,微信的群聊實在太多了,動不動就被拉入一個群中,然后群聊里大部分都是與自己無關(guān)的各大群聊中的文件、視頻、圖片等內(nèi)容,會非常占用存儲空間。

  • 自動識別微信賬號,支持用戶選擇自定義路徑;

  • 同時管理多個賬號,保留配置參數(shù),打開即用;

  • 自由設(shè)置想要刪除的文件類型,包括圖片類緩存、文件、圖片、視頻;

  • 自由設(shè)置需要刪除的文件的距離時間,默認 365 天;

  • 刪除后的文件放置在回收站中,檢查后自行清空,防止刪錯文件;

  • 支持刪除進度的顯示;

工具的主界面如下

基于Python怎么編寫微信清理工具

運行環(huán)境

Windows,后續(xù)可能會支持 Mac。

核心代碼

import sys

from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsDropShadowEffect, QListWidgetItem, QListView, QWidget, \
    QLabel, QHBoxLayout, QFileDialog
from PyQt5.QtCore import Qt, QPropertyAnimation, QEasingCurve, QThread, pyqtSignal, QMutex, QSize, QEvent, QPoint
from PyQt5.QtGui import QMouseEvent, QCursor, QColor
from PyQt5.uic import loadUi

from pathlib import Path, PureWindowsPath
from dateutil import relativedelta
import utils.resources
import os, datetime, time, re, math, shutil, json

from utils.deleteThread import *
from utils.multiDeleteThread import multiDeleteThread
from utils.selectVersion import *
from utils.selectVersion import check_dir, existing_user_config

working_dir = os.path.split(os.path.realpath(__file__))[0]


# 主窗口
class Window(QMainWindow):
    def mousePressEvent(self, event):
        # 重寫一堆方法使其支持拖動
        if event.button() == Qt.LeftButton:
            self.m_drag = True
            self.m_DragPosition = event.globalPos() - self.pos()
            event.accept()
            # self.setCursor(QCursor(Qt.OpenHandCursor))

    def mouseMoveEvent(self, QMouseEvent):
        try:
            if Qt.LeftButton and self.m_drag:
                self.move(QMouseEvent.globalPos() - self.m_DragPosition)
                QMouseEvent.accept()
        except:
            pass

    def mouseReleaseEvent(self, QMouseEvent):
        self.m_drag = False
        # self.setCursor(QCursor(Qt.ArrowCursor))

    def _frame(self):
        # 邊框
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        # 陰影
        effect = QGraphicsDropShadowEffect(blurRadius=12, xOffset=0, yOffset=0)
        effect.setColor(QColor(25, 25, 25, 170))
        self.mainFrame.setGraphicsEffect(effect)

    def doFadeIn(self):
        # 動畫
        self.animation = QPropertyAnimation(self, b'windowOpacity')
        # 持續(xù)時間250ms
        self.animation.setDuration(250)
        try:
            # 嘗試先取消動畫完成后關(guān)閉窗口的信號
            self.animation.finished.disconnect(self.close)
        except:
            pass
        self.animation.stop()
        # 透明度范圍從0逐漸增加到1
        self.animation.setEasingCurve(QEasingCurve.InOutCubic)
        self.animation.setStartValue(0)
        self.animation.setEndValue(1)
        self.animation.start()

    def doFadeOut(self):
        self.animation.stop()
        # 動畫完成則關(guān)閉窗口
        self.animation.finished.connect(self.close)
        # 透明度范圍從1逐漸減少到0s
        self.animation.setEasingCurve(QEasingCurve.InOutCubic)
        self.animation.setStartValue(1)
        self.animation.setEndValue(0)
        self.animation.start()

    def setWarninginfo(self, text):
        self.lab_info.setStyleSheet("""
            .QLabel {
                border:1px solid #ffccc7;
                border-radius:3px;
                line-height: 140px;
                padding: 5px;
                color: #434343;
                background: #fff2f0;
            }
            """)
        self.lab_info.setText(text)

    def setSuccessinfo(self, text):
        self.lab_info.setStyleSheet("""
            .QLabel {
                border:1px solid #b7eb8f;
                border-radius:3px;
                line-height: 140px;
                padding: 5px;
                color: #434343;
                background: #f6ffed;
            }
            """)
        self.lab_info.setText(text)


class ConfigWindow(Window):
    Signal_OneParameter = pyqtSignal(int)

    config = {}

    def _connect(self):
        self.combo_user.currentIndexChanged.connect(self.refresh_ui)
        self.btn_close.clicked.connect(self.save_config)
        self.btn_file.clicked.connect(self.open_file)

    def open_file(self):
        openfile_path = QFileDialog.getExistingDirectory(self, '選擇微信數(shù)據(jù)目錄', '')
        if not openfile_path or openfile_path == '':
            return False
        if check_dir(openfile_path) == 0:
            self.setSuccessinfo('讀取路徑成功!')
            list_ = os.listdir(openfile_path)
            user_list = [
                elem for elem in list_
                if elem != 'All Users' and elem != 'Applet'
            ]
            # 如果已有用戶配置,那么寫入新的用戶配置,否則默認寫入新配置
            dir_list = []
            user_config = []
            existing_user_config_dic = existing_user_config()
            for user_wx_id in user_list:
                dir_list.append(os.path.join(openfile_path, user_wx_id))
                if user_wx_id in existing_user_config_dic:
                    user_config.append(existing_user_config_dic[user_wx_id])
                else:
                    user_config.append({
                        "wechat_id": user_wx_id,
                        "clean_days": "365",
                        "is_clean": False,
                        "clean_pic_cache": True,
                        "clean_file": False,
                        "clean_pic": True,
                        "clean_video": True,
                        "is_timer": True,
                        "timer": "0h"
                    })

            config = {"data_dir": dir_list, "users": user_config}

            with open(
                    working_dir + "/config.json", "w", encoding="utf-8") as f:
                json.dump(config, f)
            self.load_config()
        else:
            self.setWarninginfo('請選擇正確的文件夾!一般是WeChat Files文件夾。')

    def save_config(self):
        self.update_config()
        self.doFadeOut()

    def check_wechat_exists(self):
        self.selectVersion = selectVersion()
        self.version_scan = self.selectVersion.getAllPath()[0]
        self.users_scan = self.selectVersion.getAllPath()[1]
        if len(self.version_scan) == 0:
            return False
        else:
            return True

    def load_config(self):
        fd = open(working_dir + "/config.json", encoding="utf-8")
        self.config = json.load(fd)

        self.combo_user.clear()
        for value in self.config["users"]:
            self.combo_user.addItem(value["wechat_id"])

        self.line_gobackdays.setText(
            str(self.config["users"][0]["clean_days"]))
        self.check_is_clean.setChecked(self.config["users"][0]["is_clean"])
        self.check_picdown.setChecked(self.config["users"][0]["clean_pic"])
        self.check_files.setChecked(self.config["users"][0]["clean_file"])
        self.check_video.setChecked(self.config["users"][0]["clean_video"])
        self.check_picscache.setChecked(
            self.config["users"][0]["clean_pic_cache"])
        self.setSuccessinfo("加載配置文件成功")

    def refresh_ui(self):
        self.config = open(working_dir + "/config.json", encoding="utf-8")
        self.config = json.load(self.config)

        for value in self.config["users"]:
            if value["wechat_id"] == self.combo_user.currentText():
                self.line_gobackdays.setText(str(value["clean_days"]))
                self.check_is_clean.setChecked(value["is_clean"])
                self.check_picdown.setChecked(value["clean_pic"])
                self.check_files.setChecked(value["clean_file"])
                self.check_video.setChecked(value["clean_video"])
                self.check_picscache.setChecked(value["clean_pic_cache"])

    def create_config(self):
        true = True
        if not os.path.exists(working_dir + "/config.json"):
            if not self.check_wechat_exists():
                self.setWarninginfo("默認位置沒有微信,請自定義位置")
                return

            self.config = {"data_dir": self.version_scan, "users": []}
            for value in self.users_scan:
                self.config["users"].append({
                    "wechat_id": value,
                    "clean_days": 365,
                    "is_clean": False,
                    "clean_pic_cache": true,
                    "clean_file": False,
                    "clean_pic": true,
                    "clean_video": true,
                    "is_timer": true,
                    "timer": "0h"
                })
            with open(
                    working_dir + "/config.json", "w", encoding="utf-8") as f:
                json.dump(self.config, f)
            self.load_config()
            self.setSuccessinfo("加載配置文件成功")
        else:
            self.setSuccessinfo("加載配置文件成功")
            self.load_config()

    def update_config(self):
        if not len(self.config):
            return
        else:
            for value in self.config["users"]:
                if value["wechat_id"] == self.combo_user.currentText():
                    try:
                        days = int(self.line_gobackdays.text())
                        if days < 0:
                            value["clean_days"] = "0"
                        else:
                            value["clean_days"] = self.line_gobackdays.text()
                    except ValueError:
                        value["clean_days"] = "0"
                    value["is_clean"] = self.check_is_clean.isChecked()
                    value["clean_pic"] = self.check_picdown.isChecked()
                    value["clean_file"] = self.check_files.isChecked()
                    value["clean_video"] = self.check_video.isChecked()
                    value["clean_pic_cache"] = self.check_picscache.isChecked()

            with open(working_dir + "/config.json", "w", encoding="utf-8") as f:
                json.dump(self.config, f)
            self.setSuccessinfo("更新配置文件成功")
            self.Signal_OneParameter.emit(1)

    def __init__(self):
        super().__init__()
        loadUi(working_dir + "/images/config.ui", self)

        self._frame()
        self._connect()

        self.doFadeIn()
        self.create_config()

        self.show()


class MainWindow(Window):

    def deal_emit_slot(self, set_status):
        if set_status and not self.config_exists:
            self.setSuccessinfo("已經(jīng)準備好,可以開始了!")
            self.config_exists = True

    def closeEvent(self, event):
        sys.exit(0)

    def eventFilter(self, object, event):
        if event.type() == QEvent.MouseButtonPress:
            if object == self.lab_close:
                self.doFadeOut()
                return True
            elif object == self.lab_clean:
                try:
                    self.setSuccessinfo("正在清理中...")
                    self.justdoit()
                except:
                    self.setWarninginfo("清理失敗,請檢查配置文件后重試")
                return True
            elif object == self.lab_config:
                cw = ConfigWindow()
                cw.Signal_OneParameter.connect(self.deal_emit_slot)
                return True
        return False

    def _eventfilter(self):
        # 事件過濾
        self.lab_close.installEventFilter(self)
        self.lab_clean.installEventFilter(self)
        self.lab_config.installEventFilter(self)

    def get_fileNum(self, path, day, picCacheCheck, fileCheck, picCheck,
                    videoCheck, file_list, dir_list):
        dir_name = PureWindowsPath(path)
        # Convert path to the right format for the current operating system
        correct_path = Path(dir_name)
        now = datetime.datetime.now()
        if picCacheCheck:
            path_one = correct_path / 'Attachment'
            path_two = correct_path / 'FileStorage/Cache'
            self.getPathFileNum(now, day, path_one, path_two, file_list,
                                dir_list)
        if fileCheck:
            path_one = correct_path / 'Files'
            path_two = correct_path / 'FileStorage/File'
            self.getPathFileNum(now, day, path_one, path_two, file_list,
                                dir_list)
        if picCheck:
            path_one = correct_path / 'Image/Image'
            path_two = correct_path / 'FileStorage/Image'
            self.getPathFileNum(now, day, path_one, path_two, file_list,
                                dir_list)
        if videoCheck:
            path_one = correct_path / 'Video'
            path_two = correct_path / 'FileStorage/Video'
            self.getPathFileNum(now, day, path_one, path_two, file_list,
                                dir_list)

    def pathFileDeal(self, now, day, path, file_list, dir_list):
        if os.path.exists(path):
            filelist = [
                f for f in os.listdir(path)
                if os.path.isfile(os.path.join(path, f))
            ]
            for i in range(0, len(filelist)):
                file_path = os.path.join(path, filelist[i])
                if os.path.isdir(file_path):
                    continue
                timestamp = datetime.datetime.fromtimestamp(
                    os.path.getmtime(file_path))
                diff = (now - timestamp).days
                if diff >= day:
                    file_list.append(file_path)

    def getPathFileNum(self, now, day, path_one, path_two, file_list,
                       dir_list):
        # caculate path_one
        self.pathFileDeal(now, day, path_one, file_list, dir_list)
        td = datetime.datetime.now() - datetime.timedelta(days=day)
        td_year = td.year
        td_month = td.month
        # caculate path_two
        if os.path.exists(path_two):
            osdir = os.listdir(path_two)
            dirlist = []
            for i in range(0, len(osdir)):
                file_path = os.path.join(path_two, osdir[i])
                if os.path.isdir(file_path):
                    dirlist.append(osdir[i])
            for i in range(0, len(dirlist)):
                file_path = os.path.join(path_two, dirlist[i])
                if os.path.isfile(file_path):
                    continue
                if re.match('\d{4}(\-)\d{2}', dirlist[i]) != None:
                    cyear = int(dirlist[i].split('-', 1)[0])
                    cmonth = int(dirlist[i].split('-', 1)[1])
                    if self.__before_deadline(cyear, cmonth, td_year,
                                              td_month):
                        dir_list.append(file_path)
                    else:
                        if cmonth == td_month:
                            self.pathFileDeal(now, day, file_path, file_list,
                                              dir_list)

    def __before_deadline(self, cyear, cmonth, td_year, td_month):
        if cyear < td_year:
            return True
        elif cyear > td_year:
            return False
        elif cyear == td_year:
            return cmonth < td_month

    def callback(self, v):
        value = v / int((self.total_file + self.total_dir)) * 100
        self.bar_progress.setValue(value)
        if value == 100:
            out = "本次共清理文件" + str(self.total_file) + "個,文件夾" + str(
                self.total_dir) + "個。請前往回收站檢查并清空。"
            self.setSuccessinfo(out)
            return

    def justdoit(self):  # 這個Api設(shè)計的太腦殘了,其實dir可以直接放在user里的... 有時間改吧
        fd = open(working_dir + "/config.json", encoding="utf-8")
        self.config = json.load(fd)
        i = 0
        need_clean = False
        thread_list = []
        total_file = 0
        total_dir = 0
        share_thread_arr = [0]
        for value in self.config["users"]:
            file_list = []
            dir_list = []
            if value["is_clean"]:
                self.get_fileNum(self.config["data_dir"][i],
                                 int(value["clean_days"]),
                                 value["clean_pic_cache"], value["clean_file"],
                                 value["clean_pic"], value["clean_video"],
                                 file_list, dir_list)

            if len(file_list) + len(dir_list) != 0:
                need_clean = True
                total_file += len(file_list)
                total_dir += len(dir_list)
                thread_list.append(
                    multiDeleteThread(file_list, dir_list, share_thread_arr))
                thread_list[-1].delete_process_signal.connect(self.callback)
            i = i + 1

        if not need_clean:
            self.setWarninginfo("沒有需要清理的文件")
        else:
            self.total_file = total_file
            self.total_dir = total_dir
            for thread in thread_list:
                thread.run()

    def __init__(self):
        super().__init__()
        loadUi(working_dir + "/images/main.ui", self)

        self._frame()
        self._eventfilter()
        self.doFadeIn()
        self.config_exists = True

        # 判斷配置文件是否存在
        if not os.path.exists(working_dir + "/config.json"):
            self.setWarninginfo("配置文件不存在!請單擊“設(shè)置”創(chuàng)建配置文件")
            self.config_exists = False

        self.show()


if __name__ == '__main__':
    app = QApplication([])
    win = MainWindow()
    app.exec_()

以上就是關(guān)于“基于Python怎么編寫微信清理工具”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI