bcmd 0.6.5__py3-none-any.whl → 0.6.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bcmd might be problematic. Click here for more details.
- {bcmd-0.6.5.dist-info → bcmd-0.6.6.dist-info}/METADATA +1 -1
- bcmd-0.6.6.dist-info/RECORD +6 -0
- bcmd-0.6.6.dist-info/entry_points.txt +2 -0
- bcmd-0.6.6.dist-info/top_level.txt +1 -0
- bcmd-0.6.5.dist-info/RECORD +0 -29
- bcmd-0.6.5.dist-info/entry_points.txt +0 -2
- bcmd-0.6.5.dist-info/top_level.txt +0 -1
- bcmdx/__init__.py +0 -0
- bcmdx/common/__init__.py +0 -0
- bcmdx/common/func.py +0 -19
- bcmdx/common/password.py +0 -35
- bcmdx/resources/project/main.py +0 -1
- bcmdx/tasks/__init__.py +0 -16
- bcmdx/tasks/bin.py +0 -104
- bcmdx/tasks/code.py +0 -132
- bcmdx/tasks/crypto.py +0 -105
- bcmdx/tasks/debian.py +0 -78
- bcmdx/tasks/download.py +0 -74
- bcmdx/tasks/image.py +0 -304
- bcmdx/tasks/json.py +0 -25
- bcmdx/tasks/lib.py +0 -93
- bcmdx/tasks/math.py +0 -97
- bcmdx/tasks/mirror.py +0 -46
- bcmdx/tasks/pdf.py +0 -43
- bcmdx/tasks/proxy.py +0 -55
- bcmdx/tasks/time.py +0 -81
- bcmdx/tasks/upgrade.py +0 -22
- bcmdx/tasks/wasabi.py +0 -94
- bcmdx/utils/__init__.py +0 -0
- bcmdx/utils/tkUtil.py +0 -130
- /bcmdx/main.py → /bcmd/__init__.py +0 -0
- {bcmd-0.6.5.dist-info → bcmd-0.6.6.dist-info}/WHEEL +0 -0
bcmdx/tasks/time.py
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from datetime import datetime as Datetime
|
|
3
|
-
from datetime import timezone
|
|
4
|
-
from typing import Final
|
|
5
|
-
from zoneinfo import ZoneInfo
|
|
6
|
-
|
|
7
|
-
import typer
|
|
8
|
-
from beni import bcolor, btask
|
|
9
|
-
from beni.bfunc import syncCall, textToAry
|
|
10
|
-
from beni.btype import Null
|
|
11
|
-
|
|
12
|
-
app: Final = btask.app
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@app.command('time')
|
|
16
|
-
@syncCall
|
|
17
|
-
async def showtime(
|
|
18
|
-
args: list[str] = typer.Argument(None),
|
|
19
|
-
):
|
|
20
|
-
'''
|
|
21
|
-
格式化时间戳\n
|
|
22
|
-
beni time\n
|
|
23
|
-
beni time 1632412740\n
|
|
24
|
-
beni time 1632412740.1234\n
|
|
25
|
-
beni time 2021-9-23\n
|
|
26
|
-
beni time 2021-9-23 09:47:00\n
|
|
27
|
-
'''
|
|
28
|
-
args = args or []
|
|
29
|
-
btask.assertTrue(len(args) <= 2, '参数过多')
|
|
30
|
-
value1: str | None = args[0] if len(args) >= 1 else None
|
|
31
|
-
value2: str | None = args[1] if len(args) >= 2 else None
|
|
32
|
-
timestamp: float = Null
|
|
33
|
-
if not value1:
|
|
34
|
-
timestamp = time.time()
|
|
35
|
-
else:
|
|
36
|
-
try:
|
|
37
|
-
timestamp = float(value1)
|
|
38
|
-
except:
|
|
39
|
-
try:
|
|
40
|
-
if value2:
|
|
41
|
-
timestamp = Datetime.strptime(f'{value1} {value2}', '%Y-%m-%d %H:%M:%S').timestamp()
|
|
42
|
-
else:
|
|
43
|
-
timestamp = Datetime.strptime(f'{value1}', '%Y-%m-%d').timestamp()
|
|
44
|
-
except:
|
|
45
|
-
pass
|
|
46
|
-
if not timestamp:
|
|
47
|
-
bcolor.printRed('参数无效\n')
|
|
48
|
-
bcolor.printRed('使用示例:')
|
|
49
|
-
msgAry = textToAry(str(showtime.__doc__))[1:]
|
|
50
|
-
bcolor.printRed('\n'.join(msgAry))
|
|
51
|
-
return
|
|
52
|
-
print()
|
|
53
|
-
bcolor.printMagenta(timestamp)
|
|
54
|
-
print()
|
|
55
|
-
# localtime = time.localtime(timestamp)
|
|
56
|
-
# tzname = time.tzname[(time.daylight and localtime.tm_isdst) and 1 or 0]
|
|
57
|
-
# bcolor.printx(time.strftime('%Y-%m-%d %H:%M:%S %z', localtime), tzname, colors=[Fore.YELLOW])
|
|
58
|
-
# print()
|
|
59
|
-
datetime_utc = Datetime.fromtimestamp(timestamp, tz=timezone.utc)
|
|
60
|
-
tzname_list = [
|
|
61
|
-
'Australia/Sydney',
|
|
62
|
-
'Asia/Tokyo',
|
|
63
|
-
'Asia/Shanghai',
|
|
64
|
-
'Asia/Kolkata',
|
|
65
|
-
'Africa/Cairo',
|
|
66
|
-
'Europe/London',
|
|
67
|
-
'America/Sao_Paulo',
|
|
68
|
-
'America/New_York',
|
|
69
|
-
'America/Chicago',
|
|
70
|
-
'America/Los_Angeles',
|
|
71
|
-
]
|
|
72
|
-
for tzname in tzname_list:
|
|
73
|
-
datetime_tz = datetime_utc.astimezone(ZoneInfo(tzname))
|
|
74
|
-
dstStr = ''
|
|
75
|
-
dst = datetime_tz.dst()
|
|
76
|
-
if dst:
|
|
77
|
-
dstStr = f'(DST+{dst})'
|
|
78
|
-
if tzname == 'Asia/Shanghai':
|
|
79
|
-
bcolor.printYellow(f'{datetime_tz} {tzname} {dstStr}')
|
|
80
|
-
else:
|
|
81
|
-
print(f'{datetime_tz} {tzname} {dstStr}')
|
bcmdx/tasks/upgrade.py
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
from typing import Final
|
|
2
|
-
|
|
3
|
-
import pyperclip
|
|
4
|
-
import typer
|
|
5
|
-
from beni import bcolor, btask
|
|
6
|
-
from beni.bfunc import syncCall
|
|
7
|
-
|
|
8
|
-
app: Final = btask.app
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@app.command()
|
|
12
|
-
@syncCall
|
|
13
|
-
async def upgrade(
|
|
14
|
-
name: str = typer.Argument('bcmdx', help='要更新的包名'),
|
|
15
|
-
):
|
|
16
|
-
'使用 pipx 官方源更新指定包到最新版本'
|
|
17
|
-
|
|
18
|
-
cmd = f'pipx upgrade {name} -i https://pypi.org/simple'
|
|
19
|
-
pyperclip.copy(cmd + '\n')
|
|
20
|
-
bcolor.printGreen(cmd)
|
|
21
|
-
bcolor.printGreen('已复制到剪贴板(需要手动执行)')
|
|
22
|
-
bcolor.printGreen('OK')
|
bcmdx/tasks/wasabi.py
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import getpass
|
|
2
|
-
import stat
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Final
|
|
5
|
-
|
|
6
|
-
import typer
|
|
7
|
-
from beni import bcolor, bcrypto, bfile, bpath, btask, bzip
|
|
8
|
-
from beni.bfunc import shuffleSequence, syncCall
|
|
9
|
-
from beni.binput import genPassword
|
|
10
|
-
|
|
11
|
-
app: Final = btask.newSubApp('Wasabi 工具')
|
|
12
|
-
|
|
13
|
-
SEP = f'{chr(852)}{chr(322)}{chr(470)}'.encode()
|
|
14
|
-
MAX_ENCRYPT_SIZE = 199 * 1024
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
@app.command()
|
|
18
|
-
@syncCall
|
|
19
|
-
async def unzip(
|
|
20
|
-
target: Path = typer.Argument(Path.cwd(), help='加密文件'),
|
|
21
|
-
password: str = typer.Option('', '--password', '-p', help='密码'),
|
|
22
|
-
):
|
|
23
|
-
'解压缩加密文件成目录'
|
|
24
|
-
assert target.is_file(), f'不是文件 {target}'
|
|
25
|
-
password = password or getpass.getpass('请输入密码: ')
|
|
26
|
-
with bpath.useTempFile() as tempFile:
|
|
27
|
-
data = await bfile.readBytes(target)
|
|
28
|
-
if SEP not in data:
|
|
29
|
-
data = bcrypto.decrypt(data, password)
|
|
30
|
-
else:
|
|
31
|
-
partA, partB = data.split(SEP)
|
|
32
|
-
partA = bcrypto.decrypt(partA, password)
|
|
33
|
-
data = partA + partB
|
|
34
|
-
data = shuffleSequence(data)
|
|
35
|
-
await bfile.writeBytes(tempFile, data)
|
|
36
|
-
tempPath = target.with_suffix('.tmp')
|
|
37
|
-
await bzip.sevenUnzip(tempFile, tempPath)
|
|
38
|
-
|
|
39
|
-
# 调整文件权限,完全擦除
|
|
40
|
-
target.chmod(stat.S_IWRITE)
|
|
41
|
-
await bpath.removeSecure(target)
|
|
42
|
-
|
|
43
|
-
bpath.move(tempPath, target)
|
|
44
|
-
bcolor.printGreen('OK')
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@app.command()
|
|
48
|
-
@syncCall
|
|
49
|
-
async def zip(
|
|
50
|
-
target: Path = typer.Argument(Path.cwd(), help='输出目录'),
|
|
51
|
-
password: str = typer.Option('', '--password', '-p', help='密码'),
|
|
52
|
-
):
|
|
53
|
-
'将目录压缩成加密文件'
|
|
54
|
-
target = target.absolute()
|
|
55
|
-
assert target.is_dir(), f'不是目录 {target}'
|
|
56
|
-
password = password or genPassword()
|
|
57
|
-
with bpath.useTempFile() as tempFile:
|
|
58
|
-
await bzip.sevenZipFolder(tempFile, target)
|
|
59
|
-
data = await bfile.readBytes(tempFile)
|
|
60
|
-
bpath.remove(tempFile) # 为了安全所以立即删除
|
|
61
|
-
data = shuffleSequence(data)
|
|
62
|
-
if len(data) < MAX_ENCRYPT_SIZE:
|
|
63
|
-
data = bcrypto.encrypt(data, password)
|
|
64
|
-
else:
|
|
65
|
-
partA, partB = data[:MAX_ENCRYPT_SIZE], data[MAX_ENCRYPT_SIZE:]
|
|
66
|
-
partA = bcrypto.encrypt(partA, password)
|
|
67
|
-
data = partA + SEP + partB
|
|
68
|
-
tempZipFile = target.with_suffix('.tmp')
|
|
69
|
-
await bfile.writeBytes(tempZipFile, data)
|
|
70
|
-
|
|
71
|
-
# 调整目录权限,完全擦除
|
|
72
|
-
target.chmod(stat.S_IWRITE)
|
|
73
|
-
for file in target.glob('**/*'):
|
|
74
|
-
file.chmod(stat.S_IWRITE)
|
|
75
|
-
await bpath.removeSecure(target)
|
|
76
|
-
|
|
77
|
-
bpath.move(tempZipFile, target)
|
|
78
|
-
|
|
79
|
-
bcolor.printGreen('OK')
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
@app.command()
|
|
83
|
-
@syncCall
|
|
84
|
-
async def change_pass(
|
|
85
|
-
file: Path = typer.Argument(Path.cwd(), help='加密文件'),
|
|
86
|
-
password: str = typer.Option('', '--password', '-p', help='密码'),
|
|
87
|
-
new_password: str = typer.Option('', '--new-password', '-n', help='新密码'),
|
|
88
|
-
):
|
|
89
|
-
with bpath.useTempPath() as tempPath:
|
|
90
|
-
target = tempPath / file.name
|
|
91
|
-
bpath.copy(file, target)
|
|
92
|
-
unzip(target, password)
|
|
93
|
-
zip(target, new_password)
|
|
94
|
-
bpath.copy(target, file)
|
bcmdx/utils/__init__.py
DELETED
|
File without changes
|
bcmdx/utils/tkUtil.py
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import tkinter as tk
|
|
2
|
-
from tkinter.scrolledtext import ScrolledText
|
|
3
|
-
from typing import Callable
|
|
4
|
-
from uuid import uuid4
|
|
5
|
-
|
|
6
|
-
# version 2026-0621
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class TkForm(tk.Tk):
|
|
10
|
-
|
|
11
|
-
_row = -1
|
|
12
|
-
_initFocusItem: tk.Widget | None = None
|
|
13
|
-
|
|
14
|
-
RADIO_NOTHING = uuid4().hex
|
|
15
|
-
|
|
16
|
-
def __init__(self):
|
|
17
|
-
super().__init__()
|
|
18
|
-
self.resizable(False, False)
|
|
19
|
-
self.bind("<Map>", self._onMap)
|
|
20
|
-
|
|
21
|
-
def _onMap(self, event: tk.Event):
|
|
22
|
-
if self._initFocusItem:
|
|
23
|
-
self._initFocusItem.focus_set()
|
|
24
|
-
self._initFocusItem = None
|
|
25
|
-
|
|
26
|
-
def add(self, desc: str, widget: tk.Widget):
|
|
27
|
-
self._row += 1
|
|
28
|
-
tk.Label(text=desc).grid(row=self._row, column=0, padx=10, pady=5, sticky='n')
|
|
29
|
-
widget.grid(row=self._row, column=1, padx=10, pady=5, sticky='w')
|
|
30
|
-
|
|
31
|
-
def addFrame(self, frame: tk.Frame):
|
|
32
|
-
self._row += 1
|
|
33
|
-
frame.grid(row=self._row, column=0, columnspan=2, padx=10, pady=5)
|
|
34
|
-
|
|
35
|
-
def run(self):
|
|
36
|
-
self.center()
|
|
37
|
-
self.mainloop()
|
|
38
|
-
|
|
39
|
-
def center(self):
|
|
40
|
-
self.withdraw() # 先隐藏窗口,避免闪动
|
|
41
|
-
self.update_idletasks() # 确保获取正确的窗口尺寸
|
|
42
|
-
width = self.winfo_width() # 获取窗口宽度
|
|
43
|
-
height = self.winfo_height() # 获取窗口高度
|
|
44
|
-
screen_width = self.winfo_screenwidth() # 屏幕宽度
|
|
45
|
-
screen_height = self.winfo_screenheight() # 屏幕高度
|
|
46
|
-
x = (screen_width - width) // 2 # 水平居中
|
|
47
|
-
y = (screen_height - height) // 2 # 垂直居中
|
|
48
|
-
self.geometry(f"+{x}+{y}") # 设置窗口位置
|
|
49
|
-
self.deiconify() # 恢复显示窗口
|
|
50
|
-
|
|
51
|
-
def addLabel(self, desc: str, text: str):
|
|
52
|
-
self.add(desc, tk.Label(text=text))
|
|
53
|
-
|
|
54
|
-
def addBtn(self, label: str, command: Callable[..., None], *, width: int = 20, focus: bool = False):
|
|
55
|
-
frame = tk.Frame(self)
|
|
56
|
-
self.addFrame(frame)
|
|
57
|
-
btn = tk.Button(frame, text=label, width=width, command=command)
|
|
58
|
-
btn.pack(side="left", expand=True, padx=15)
|
|
59
|
-
if focus:
|
|
60
|
-
self._initFocusItem = btn
|
|
61
|
-
|
|
62
|
-
def addRadioBtn(self, desc: str, selectionList: list[str], *, selectedIndex: int | None = None, focusIndex: int | None = None):
|
|
63
|
-
frame = tk.Frame()
|
|
64
|
-
self.add(desc, frame)
|
|
65
|
-
var = tk.StringVar(value=selectionList[selectedIndex] if selectedIndex is not None else self.RADIO_NOTHING)
|
|
66
|
-
radioBtnList: list[tk.Radiobutton] = []
|
|
67
|
-
for version in selectionList:
|
|
68
|
-
radioBtn = tk.Radiobutton(frame, text=version, variable=var, value=version)
|
|
69
|
-
radioBtn.pack(side="left", padx=(0, 15))
|
|
70
|
-
radioBtnList.append(radioBtn)
|
|
71
|
-
if focusIndex is not None:
|
|
72
|
-
self._initFocusItem = radioBtnList[focusIndex]
|
|
73
|
-
return var
|
|
74
|
-
|
|
75
|
-
def addEntry(self, desc: str, text: str = '', *, width: int = 60, focus: bool = False):
|
|
76
|
-
entry = tk.Entry(self, width=30)
|
|
77
|
-
entry.insert(0, text)
|
|
78
|
-
self.add(desc, entry)
|
|
79
|
-
if focus:
|
|
80
|
-
self._initFocusItem = entry
|
|
81
|
-
return entry
|
|
82
|
-
|
|
83
|
-
def addScrolledText(self, desc: str, text: str = '', *, width: int = 60, height: int = 20, focus: bool = False):
|
|
84
|
-
scrolledText = ScrolledText(self, width=width, height=height)
|
|
85
|
-
scrolledText.insert("1.0", text)
|
|
86
|
-
self.add(desc, scrolledText)
|
|
87
|
-
if focus:
|
|
88
|
-
self._initFocusItem = scrolledText
|
|
89
|
-
return scrolledText
|
|
90
|
-
|
|
91
|
-
def addCheckBox(self, text: str, value: bool = False):
|
|
92
|
-
remember_var = tk.BooleanVar(value=value)
|
|
93
|
-
check_btn = tk.Checkbutton(text=text, variable=remember_var)
|
|
94
|
-
self.add("", check_btn)
|
|
95
|
-
return remember_var
|
|
96
|
-
|
|
97
|
-
def addPasswordInput(self, desc: str, *, width: int = 60, command: Callable[..., None] | None = None):
|
|
98
|
-
password_entry = tk.Entry(self, show="*", width=width) # 使用 show="*" 隐藏输入内容
|
|
99
|
-
if command:
|
|
100
|
-
password_entry.bind('<Return>', lambda event: command())
|
|
101
|
-
self.add(desc, password_entry)
|
|
102
|
-
return password_entry
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
''' 例子
|
|
106
|
-
app = TkForm()
|
|
107
|
-
app.title('更新版本信息')
|
|
108
|
-
app.addLabel('当前版本号', '3.11.8')
|
|
109
|
-
app.addLabel('上次更新时间', '2025-06-16 16:00:00')
|
|
110
|
-
version_var = app.addRadioBtn(
|
|
111
|
-
'请选择新版本',
|
|
112
|
-
['3.11.8', '3.11.9', '3.11.10'],
|
|
113
|
-
2,
|
|
114
|
-
)
|
|
115
|
-
log_text = app.addScrolledText('更新日志', '123\n23454asd这个')
|
|
116
|
-
vara = app.addCheckBox('记住密码', False)
|
|
117
|
-
varb = app.addCheckBox('阿萨德法师大润发', True)
|
|
118
|
-
passwordInput = app.addPasswordInput('密码', command=lambda: onBtn())
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def onBtn():
|
|
122
|
-
print(version_var.get())
|
|
123
|
-
print(log_text.get('1.0', "end-1c").split('\n'))
|
|
124
|
-
app.destroy()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
app.addBtn('确定', onBtn)
|
|
128
|
-
app.bind("<Visibility>", lambda e: passwordInput.focus_set())
|
|
129
|
-
app.run()
|
|
130
|
-
'''
|
|
File without changes
|
|
File without changes
|