<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前幾天網上找了一款 PC 端微信自動清理工具,用了一下,電腦釋放了 30GB 的儲存空間,而且不會刪除文字的聊天記錄,很好用,感覺很多人都用得到,就在此分享一下,而且是用 Python 寫的,喜歡 Python 的小夥伴可以探究一下。
它可以自動刪除 PC 端微信自動下載的大量檔案、視訊、圖片等資料內容,釋放幾十 G 的空間佔用,而且不會刪除文字的聊天記錄,可以放心使用。
工作以後,微信的群聊實在太多了,動不動就被拉入一個群中,然後群聊裡大部分都是與自己無關的各大群聊中的檔案、視訊、圖片等內容,會非常佔用儲存空間。
工具的主介面如下
Windows,後續可能會支援 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') # 持續時間250ms self.animation.setDuration(250) try: # 嘗試先取消動畫完成後關閉視窗的訊號 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() # 動畫完成則關閉視窗 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, '選擇微信資料目錄', '') 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("已經準備好,可以開始了!") 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設計的太腦殘了,其實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("組態檔不存在!請單擊「設定」建立組態檔") self.config_exists = False self.show() if __name__ == '__main__': app = QApplication([]) win = MainWindow() app.exec_()
原始碼獲取地址 提取碼:vuud
到此這篇關於基於Python編寫微信清理工具的範例程式碼的文章就介紹到這了,更多相關Python微信清理工具內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45