代码拉取完成,页面将自动刷新
同步操作将从 火柴/AppXManager 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import json
import os
import subprocess
import sys
import time
import PySimpleGUI as sg
import pyperclip
from concurrent.futures import ThreadPoolExecutor
rec_list = []
try:
with open('rec_uninstall.json', 'r', encoding='utf-8') as file:
rec_list = json.load(file)
except IOError:
print('无法加载rec_uninstall.json')
warn_list = []
try:
with open('warn_list.json', 'r', encoding='utf-8') as file:
warn_list = json.load(file)
except IOError:
print('无法加载warn_list.json')
name_dict = {}
try:
with open('cn_name.json', 'r', encoding='utf-8') as file:
name_dict = json.load(file)
except IOError:
print('无法加载cn_name.json')
# 修复高DPI感知
if sys.platform == 'win32':
try:
import ctypes
ctypes.OleDLL('shcore').SetProcessDpiAwareness(1)
except (ImportError, AttributeError, OSError):
pass
def uninstall(sel_app, threads=False):
try:
uninstall_command = f"Get-AppxPackage -Name '*{sel_app}*' | Remove-AppxPackage"
result = subprocess.run(["powershell", uninstall_command], capture_output=True, text=True)
if result.returncode == 0:
print(f"卸载命令执行成功!{sel_app}")
else:
print(f'命令执行失败{sel_app},参考:')
print(result.stderr)
if not threads:
print('已卸载!', sel_app)
window[sel_app].update(text_color='red')
# if notfoundAppx(sel_app):
# print('已卸载!', sel_app)
# window[sel_app].update(text_color='red')
# else:
# print('应用还存在,似乎未卸载成功')
except Exception as e:
print(f"卸载应用时出现错误: {e}")
def notfoundAppx(app_name): # 检查指定的应用程序是否不存在
command = f"Get-AppxPackage -Name '*{app_name}*'" # 定义一个命令,用于搜索指定应用程序
# print(command)
try:
# 使用PowerShell运行命令,并将输出捕获到check_result中
check_result = subprocess.run(["powershell", command], capture_output=True, text=True)
if check_result.stdout.strip() == "": # 如果输出为空,则表示应用程序不存在
return True
else:
return False
except Exception as e:
print(f"异常: {e}")
def getColor(curr_name):
if curr_name in warn_list:
return 'purple'
elif curr_name in rec_list:
return '#006600'
elif curr_name in dev_list:
return 'blue'
else:
return ''
def getName(name): # 获取推荐列表中的名字
# 判断name是否在recom_dict中
if name in name_dict.keys():
# 如果在,返回recom_dict中的值
return name_dict[name]
else:
# 如果不在,返回name
return name
def tidy(name_list):
recom = []
noml = []
dev = []
warn = []
for x in name_list:
if x in rec_list:
recom.append(x)
elif x in warn_list:
warn.append(x)
elif x in dev_list:
dev.append(x)
else:
noml.append(x)
recom.sort()
noml.sort()
dev.sort()
warn.sort()
print('推荐卸载', len(recom))
print('第三方', len(dev))
print('不建议卸载', len(warn))
return recom + noml + dev + warn
print("正在获取包信息,等待系统响应...")
getapp_pscmd = 'powershell "Get-AppxPackage | Select-Object -Property Name, IsFramework, NonRemovable, SignatureKind,PackageFullName"'
echo = ""
try:
echo = subprocess.check_output(getapp_pscmd).decode("utf-8")
except Exception as e:
print(f"获取包信息时出现错误: {e}\n请检查是否安装powershell")
echo_list = list(filter(None, echo.split("\r\n\r\n")))
num = len(echo_list)
if num > 0:
print(f"包数量: {num}")
else:
print("没有找到任何包,请检查是否以管理员权限运行")
# 创建一个空列表,用于存储包的信息
pkg_list = [] # 包列表
name_list = []
dev_list = []
# 遍历echo_list中的每个元素(即每个包的信息)
for echo_item in echo_list:
# 将字符串按照换行符进行分割,得到一个列表
lines = str(echo_item).split("\n")
# 创建一个空字典,用于存储当前包的信息
appinfdic = {}
# 遍历lines中的每个元素(即当前包的一行信息)
for x in lines:
# 如果当前行包含冒号,说明该行是一个键值对
if ":" in x:
# 使用split方法将字符串按照冒号进行分割,得到一个列表,其中第一个元素为键,第二个元素为值
k, v = x.split(":", 1)
# 将键和值去除首尾空格后存入字典
appinfdic[k.strip()] = v.strip()
# 只添加"NonRemovable"为"False"的包到包列表中
if appinfdic.get("NonRemovable") == "False" and appinfdic.get("IsFramework") == "False":
pkg_list.append(appinfdic) # 将一个包字典存入包列表
name_list.append(appinfdic.get('Name'))
if appinfdic.get("SignatureKind") == "Developer":
dev_list.append(appinfdic.get('Name'))
name_list = tidy(name_list)
print("可卸载的非框架应用", len(name_list))
# 界面布局
sg.set_options(font=('微软雅黑', 8))
sg.theme('Default1')
# sg.theme('GreenMono')
# sg.theme('LightBlue6')
# sg.theme('DarkAmber')
# sg.theme('BlueMono')
# sg.theme('LightBrown10')
# sg.theme('LightGrey')
row_cap = 4 if len(name_list) > 33 else 3
frame_layout = []
row_layout = []
for i, capp in enumerate(name_list):
if i % row_cap == 0: # 如果当前是新行的开始
row_layout = []
column_layout = [[ # 创建单个应用的Column布局
sg.Checkbox(getName(capp), size=(30, 1), key=capp, text_color=getColor(capp)),
sg.Button('详情', key=f'btinfo-{capp}'),
sg.Button('卸载', key=f'button-{capp}')
]]
row_layout.append(sg.Column(column_layout)) # 将该Column添加到当前行布局
# 当达到每行的最大元素数或者处理到最后一个应用时,将当前行布局添加到主布局中
if len(row_layout) == row_cap or i == len(name_list) - 1:
frame_layout.append(row_layout)
layout = [ # 创建一个表格布局,其中包含表格布局和提交和取消按钮
[sg.Frame('可卸载的非框架应用', frame_layout)],
[
sg.Button('全选'),
sg.Button('反选'),
sg.Button('全不选'),
sg.Button('复制名称', button_color=('WHITE', '#CA7508')),
# sg.Button('显示信息'),
sg.Button('推荐卸载', button_color=('white', 'springgreen4')),
sg.Button('一键卸载', button_color=('white', 'firebrick3')),
sg.Checkbox('多线程', key='threads', default=False),
# sg.Button('检查存在状态', button_color=('white', '#132843')),
sg.Button('退出'),
sg.Text('第三方', text_color='blue'),
sg.Text('不推荐卸载', text_color='purple'),
sg.Text('已卸载', text_color='red'),
]
]
# sg.theme('SystemDefaultForReal')
window = sg.Window('WinAppsUninstaller 240724', layout)
while True: # 添加事件循环
event, values = window.read()
if event in (sg.WIN_CLOSED, '退出'):
break
if event.startswith('button-'):
app_name = event.split('-')[1]
uninstall(app_name)
if event.startswith('btinfo-'):
app_name = event.split('-')[1]
powershell_command = f"Get-AppxPackage {app_name} | Select-Object Name, PackageFullName, Version, InstallLocation, Dependencies"
echo = subprocess.check_output(["powershell", powershell_command]).decode("utf-8")
print(echo)
if event == '全选':
for aapp in name_list:
window[aapp].update(value=True)
if event == '反选':
for app in name_list:
window[app].update(value=not window[app].get())
if event == '全不选':
for app in name_list:
window[app].update(value=False)
if event == '一键卸载':
selected_apps = [app for app in name_list if window[app].get()]
if sg.popup_yes_no(f'确定要卸载选中的{len(selected_apps)}个应用吗?') == 'Yes':
start_time = time.time()
# 如果key=threads的值为1,则使用单线程执行任务
if not values['threads']:
print('单线程模式')
for app in selected_apps:
uninstall(app)
else:
print('多线程模式')
with ThreadPoolExecutor() as executor:
futures = [executor.submit(uninstall, app, True) for app in selected_apps]
for future in futures: # 等待所有任务完成
future.result()
for x in selected_apps:
window[x].update(text_color='red')
print('默认线程数:', os.cpu_count())
end_time = time.time()
print(f'卸载时间: {end_time - start_time:.2f}秒')
sg.popup('卸载完成', f'已卸载{len(selected_apps)}个应用')
if event == '复制名称':
selected_apps = [app for app in name_list if window[app].get()]
pyperclip.copy('\n'.join(selected_apps))
print(selected_apps)
print('已复制到剪切板', len(selected_apps), '个应用')
if event == '推荐卸载':
for app in name_list:
if app in rec_list:
window[app].update(value=True)
if event == '检查存在状态':
uninstalled_apps = []
selected_apps = [app for app in name_list if window[app].get()]
for app in selected_apps:
if notfoundAppx(app):
uninstalled_apps.append(app)
print(app, '确认已卸载!')
else:
print(app, '存在!')
for app in uninstalled_apps:
window[app].update(text_color='red')
window.close()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。