absfuyu 5.8.0__py3-none-any.whl → 5.10.0__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 absfuyu might be problematic. Click here for more details.
- absfuyu/__init__.py +1 -1
- absfuyu/__main__.py +2 -2
- absfuyu/cli/__init__.py +2 -2
- absfuyu/cli/color.py +2 -2
- absfuyu/cli/config_group.py +2 -2
- absfuyu/cli/do_group.py +2 -2
- absfuyu/cli/game_group.py +20 -2
- absfuyu/cli/tool_group.py +2 -2
- absfuyu/config/__init__.py +2 -2
- absfuyu/core/__init__.py +2 -2
- absfuyu/core/baseclass.py +2 -2
- absfuyu/core/baseclass2.py +2 -2
- absfuyu/core/decorator.py +2 -2
- absfuyu/core/docstring.py +2 -2
- absfuyu/core/dummy_cli.py +2 -2
- absfuyu/core/dummy_func.py +2 -2
- absfuyu/dxt/__init__.py +2 -2
- absfuyu/dxt/dictext.py +2 -2
- absfuyu/dxt/dxt_support.py +2 -2
- absfuyu/dxt/intext.py +2 -2
- absfuyu/dxt/listext.py +13 -18
- absfuyu/dxt/strext.py +2 -2
- absfuyu/extra/__init__.py +2 -2
- absfuyu/extra/beautiful.py +2 -2
- absfuyu/extra/da/__init__.py +37 -3
- absfuyu/extra/da/dadf.py +2 -2
- absfuyu/extra/da/dadf_base.py +2 -2
- absfuyu/extra/da/df_func.py +2 -2
- absfuyu/extra/da/mplt.py +2 -2
- absfuyu/extra/data_analysis.py +2 -2
- absfuyu/extra/pdf.py +2 -2
- absfuyu/extra/rclone.py +253 -0
- absfuyu/extra/xml.py +2 -2
- absfuyu/fun/__init__.py +2 -2
- absfuyu/fun/rubik.py +2 -2
- absfuyu/fun/tarot.py +2 -2
- absfuyu/game/__init__.py +2 -2
- absfuyu/game/game_stat.py +2 -2
- absfuyu/game/schulte.py +78 -0
- absfuyu/game/sudoku.py +2 -2
- absfuyu/game/tictactoe.py +2 -2
- absfuyu/game/wordle.py +2 -2
- absfuyu/general/__init__.py +2 -2
- absfuyu/general/content.py +2 -2
- absfuyu/general/human.py +2 -2
- absfuyu/general/shape.py +2 -2
- absfuyu/logger.py +2 -2
- absfuyu/pkg_data/__init__.py +2 -2
- absfuyu/pkg_data/deprecated.py +2 -2
- absfuyu/pkg_data/logo.py +2 -2
- absfuyu/sort.py +2 -2
- absfuyu/tools/__init__.py +2 -2
- absfuyu/tools/checksum.py +2 -2
- absfuyu/tools/converter.py +2 -2
- absfuyu/tools/generator.py +2 -2
- absfuyu/tools/inspector.py +2 -2
- absfuyu/tools/keygen.py +2 -2
- absfuyu/tools/obfuscator.py +2 -2
- absfuyu/tools/passwordlib.py +2 -2
- absfuyu/tools/shutdownizer.py +2 -2
- absfuyu/tools/sw.py +76 -5
- absfuyu/tools/web.py +2 -2
- absfuyu/typings.py +2 -2
- absfuyu/util/__init__.py +31 -2
- absfuyu/util/api.py +2 -2
- absfuyu/util/gui.py +91 -0
- absfuyu/util/json_method.py +2 -2
- absfuyu/util/lunar.py +2 -2
- absfuyu/util/path.py +2 -2
- absfuyu/util/performance.py +2 -2
- absfuyu/util/shorten_number.py +2 -2
- absfuyu/util/text_table.py +2 -2
- absfuyu/util/zipped.py +2 -2
- absfuyu/version.py +2 -2
- {absfuyu-5.8.0.dist-info → absfuyu-5.10.0.dist-info}/METADATA +4 -1
- absfuyu-5.10.0.dist-info/RECORD +84 -0
- absfuyu-5.8.0.dist-info/RECORD +0 -81
- {absfuyu-5.8.0.dist-info → absfuyu-5.10.0.dist-info}/WHEEL +0 -0
- {absfuyu-5.8.0.dist-info → absfuyu-5.10.0.dist-info}/entry_points.txt +0 -0
- {absfuyu-5.8.0.dist-info → absfuyu-5.10.0.dist-info}/licenses/LICENSE +0 -0
absfuyu/extra/rclone.py
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Absfuyu: Rclone decrypt
|
|
3
|
+
-----------------------
|
|
4
|
+
Rclone decryptor
|
|
5
|
+
|
|
6
|
+
Version: 5.10.0
|
|
7
|
+
Date updated: 23/09/2025 (dd/mm/yyyy)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Module level
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
__all__ = ["RcloneEncryptDecrypt", "DirectoryRcloneDEMixin"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Library
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
import os
|
|
18
|
+
import shutil
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Literal, Self
|
|
21
|
+
|
|
22
|
+
from rclone import Crypt
|
|
23
|
+
|
|
24
|
+
from absfuyu.core.baseclass import AutoREPRMixin
|
|
25
|
+
from absfuyu.logger import LogLevel, logger
|
|
26
|
+
from absfuyu.util.path import DirectoryBase
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Class
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
class RcloneEncryptDecrypt(AutoREPRMixin):
|
|
32
|
+
"""
|
|
33
|
+
Rclone Decrypt/Encrypt Module
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, crypt: Crypt) -> None:
|
|
37
|
+
"""
|
|
38
|
+
This will encrypt/decrypt with rclone style
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
crypt : Crypt
|
|
43
|
+
``rclone.Crypt`` object | Encrypt/Decrypt engine
|
|
44
|
+
"""
|
|
45
|
+
self._crypt = crypt
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_passwd_salt(cls, passwd: str, salt: str | None = None) -> Self:
|
|
49
|
+
"""
|
|
50
|
+
Create Rclone Decrypt/Encrypt object from password and salt
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
passwd : str
|
|
55
|
+
Custom password
|
|
56
|
+
|
|
57
|
+
salt : str | None, optional
|
|
58
|
+
Custom salt, by default None
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
Self
|
|
63
|
+
Rclone Decrypt/Encrypt object
|
|
64
|
+
"""
|
|
65
|
+
if salt is None:
|
|
66
|
+
crypt: Crypt = Crypt(passwd=passwd)
|
|
67
|
+
else:
|
|
68
|
+
crypt: Crypt = Crypt(passwd=passwd, salt=salt)
|
|
69
|
+
return cls(crypt)
|
|
70
|
+
|
|
71
|
+
# Support
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _directory_validator(path: Path) -> Path:
|
|
74
|
+
"""Validate if directory exists, then return the path"""
|
|
75
|
+
path = Path(path)
|
|
76
|
+
if not path.exists():
|
|
77
|
+
raise ValueError("Path does not exist")
|
|
78
|
+
return path
|
|
79
|
+
|
|
80
|
+
def _modify_name(self, name_to_modify: str, mode: Literal["encrypt", "decrypt"]) -> str:
|
|
81
|
+
if mode == "decrypt":
|
|
82
|
+
return self._crypt.Name.standard_decrypt(name_to_modify)
|
|
83
|
+
if mode == "encrypt":
|
|
84
|
+
return self._crypt.Name.standard_encrypt(name_to_modify)
|
|
85
|
+
|
|
86
|
+
def _decrypt_encrypt_operation(
|
|
87
|
+
self,
|
|
88
|
+
mode: Literal["encrypt", "decrypt"],
|
|
89
|
+
root_dir: Path | str, # type: ignore
|
|
90
|
+
delete_when_complete: bool = False,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Base operation to decrypt, encrypt
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
mode : Literal["encrypt", "decrypt"]
|
|
98
|
+
Encrypt or decrypt
|
|
99
|
+
|
|
100
|
+
root_dir : Path | str
|
|
101
|
+
Directory location
|
|
102
|
+
|
|
103
|
+
delete_when_complete : bool
|
|
104
|
+
Delete directory when completed, defaults to False
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
logger.info(f"Begin operation: {mode.title()}")
|
|
108
|
+
root_dir = Path(root_dir)
|
|
109
|
+
FILE_MODE = False
|
|
110
|
+
|
|
111
|
+
# Make Base folder
|
|
112
|
+
if root_dir.is_file():
|
|
113
|
+
# Get name of parent dir and make name
|
|
114
|
+
temp = self._modify_name(root_dir.parent.name, "encrypt" if mode == "decrypt" else "decrypt")
|
|
115
|
+
# Create sub dir
|
|
116
|
+
base_dir = root_dir.parent.joinpath(temp)
|
|
117
|
+
base_dir.mkdir(exist_ok=True, parents=True)
|
|
118
|
+
# Move file to that dir
|
|
119
|
+
new_path = root_dir.rename(base_dir.joinpath(root_dir.name))
|
|
120
|
+
root_dir = base_dir # Make root dir
|
|
121
|
+
FILE_MODE = True
|
|
122
|
+
else:
|
|
123
|
+
root_dir: Path = self._directory_validator(root_dir)
|
|
124
|
+
base_name: str = self._modify_name(root_dir.name, mode=mode)
|
|
125
|
+
base_dir: Path = root_dir.parent.joinpath(base_name)
|
|
126
|
+
base_dir.mkdir(exist_ok=True, parents=True)
|
|
127
|
+
|
|
128
|
+
_ljust: int = 17 # Logger ljust value
|
|
129
|
+
|
|
130
|
+
# Decrypt / Encrypt
|
|
131
|
+
for path in root_dir.glob("**/*"):
|
|
132
|
+
rel_path: Path = path.relative_to(root_dir)
|
|
133
|
+
rel_path_splited: list[str] = str(rel_path).split(os.sep)
|
|
134
|
+
rel_path_modified: list[str] = [self._modify_name(x, mode=mode) for x in rel_path_splited]
|
|
135
|
+
new_path: Path = base_dir.joinpath(*rel_path_modified)
|
|
136
|
+
|
|
137
|
+
if path.is_dir():
|
|
138
|
+
logger.debug(f"{mode.title()}ing Dir:".ljust(_ljust) + f"{path}")
|
|
139
|
+
new_path.mkdir(exist_ok=True, parents=True)
|
|
140
|
+
logger.debug(f"{mode.title()}ed Dir:".ljust(_ljust) + f"{new_path}")
|
|
141
|
+
else:
|
|
142
|
+
logger.debug(f"{mode.title()}ing File:".ljust(_ljust) + f"{path}")
|
|
143
|
+
if mode == "decrypt":
|
|
144
|
+
self._crypt.File.file_decrypt(path, new_path) # type: ignore
|
|
145
|
+
if mode == "encrypt":
|
|
146
|
+
self._crypt.File.file_encrypt(path, new_path) # type: ignore
|
|
147
|
+
logger.debug(f"{mode.title()}ed File:".ljust(_ljust) + f"{new_path}")
|
|
148
|
+
logger.info(f"Operation: {mode.title()} COMPLETED")
|
|
149
|
+
|
|
150
|
+
# File mode
|
|
151
|
+
if FILE_MODE:
|
|
152
|
+
new_path.rename(root_dir.parent.joinpath(new_path.name)) # type: ignore
|
|
153
|
+
shutil.rmtree(root_dir)
|
|
154
|
+
|
|
155
|
+
# Delete when completed
|
|
156
|
+
if delete_when_complete:
|
|
157
|
+
logger.debug(f"Deleting {root_dir}")
|
|
158
|
+
shutil.rmtree(root_dir)
|
|
159
|
+
logger.debug(f"Deleting {root_dir}...DONE")
|
|
160
|
+
|
|
161
|
+
# Decrypt/Encrypt
|
|
162
|
+
def decrypt(self, root_dir: Path, delete_when_complete: bool = False) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Decrypt encrypted directory.
|
|
165
|
+
|
|
166
|
+
This will decrypt the directory itself and
|
|
167
|
+
create a decrypted directory next to the original
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
root_dir : Path
|
|
172
|
+
Directory location
|
|
173
|
+
|
|
174
|
+
delete_when_complete : bool, optional
|
|
175
|
+
Delete directory when completed, by default False
|
|
176
|
+
"""
|
|
177
|
+
self._decrypt_encrypt_operation(mode="decrypt", root_dir=root_dir, delete_when_complete=delete_when_complete)
|
|
178
|
+
|
|
179
|
+
def encrypt(self, root_dir: Path, delete_when_complete: bool = False) -> None:
|
|
180
|
+
"""
|
|
181
|
+
Encrypt entire directory.
|
|
182
|
+
|
|
183
|
+
This will encrypt the directory itself and
|
|
184
|
+
create an encrypted directory next to the original
|
|
185
|
+
|
|
186
|
+
Parameters
|
|
187
|
+
----------
|
|
188
|
+
root_dir : Path
|
|
189
|
+
Directory location
|
|
190
|
+
|
|
191
|
+
delete_when_complete : bool, optional
|
|
192
|
+
Delete directory when completed, by default False
|
|
193
|
+
"""
|
|
194
|
+
self._decrypt_encrypt_operation(mode="encrypt", root_dir=root_dir, delete_when_complete=delete_when_complete)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class DirectoryRcloneDEMixin(DirectoryBase):
|
|
198
|
+
"""
|
|
199
|
+
Directory - Rclone encrypt/decrypt
|
|
200
|
+
|
|
201
|
+
Extension for ``absfuyu.util.path.Directory``
|
|
202
|
+
|
|
203
|
+
- Decrypt
|
|
204
|
+
- Encrypt
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def rclone_encrypt(self, passwd: str, salt: str | None = None, delete_when_complete: bool = False) -> None:
|
|
208
|
+
"""
|
|
209
|
+
Encrypt entire directory.
|
|
210
|
+
|
|
211
|
+
This will encrypt the directory itself and
|
|
212
|
+
create an encrypted directory next to the original
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
passwd : str
|
|
217
|
+
Custom password
|
|
218
|
+
|
|
219
|
+
salt : str | None, optional
|
|
220
|
+
Custom salt, by default None
|
|
221
|
+
|
|
222
|
+
delete_when_complete : bool, optional
|
|
223
|
+
Delete directory when completed, by default False
|
|
224
|
+
"""
|
|
225
|
+
engine = RcloneEncryptDecrypt.from_passwd_salt(passwd=passwd, salt=salt)
|
|
226
|
+
engine.encrypt(self.source_path, delete_when_complete=delete_when_complete)
|
|
227
|
+
|
|
228
|
+
def rclone_decrypt(self, passwd: str, salt: str | None = None, delete_when_complete: bool = False) -> None:
|
|
229
|
+
"""
|
|
230
|
+
Decrypt encrypted directory.
|
|
231
|
+
|
|
232
|
+
This will decrypt the directory itself and
|
|
233
|
+
create a decrypted directory next to the original
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
passwd : str
|
|
238
|
+
Custom password
|
|
239
|
+
|
|
240
|
+
salt : str | None, optional
|
|
241
|
+
Custom salt, by default None
|
|
242
|
+
|
|
243
|
+
delete_when_complete : bool, optional
|
|
244
|
+
Delete directory when completed, by default False
|
|
245
|
+
"""
|
|
246
|
+
engine = RcloneEncryptDecrypt.from_passwd_salt(passwd=passwd, salt=salt)
|
|
247
|
+
engine.decrypt(self.source_path, delete_when_complete=delete_when_complete)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# Run
|
|
251
|
+
# -----------------------------------------------------------------------------------------------
|
|
252
|
+
if __name__ == "__main__":
|
|
253
|
+
logger.setLevel(LogLevel.DEBUG)
|
absfuyu/extra/xml.py
CHANGED
absfuyu/fun/__init__.py
CHANGED
absfuyu/fun/rubik.py
CHANGED
absfuyu/fun/tarot.py
CHANGED
absfuyu/game/__init__.py
CHANGED
absfuyu/game/game_stat.py
CHANGED
absfuyu/game/schulte.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Game: Schulte
|
|
3
|
+
-------------
|
|
4
|
+
|
|
5
|
+
Version: 5.10.0
|
|
6
|
+
Date updated: 25/09/2025 (dd/mm/yyyy)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# Module level
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
__all__ = ["SchulteTable"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Library
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
from absfuyu.core.baseclass import BaseClass
|
|
17
|
+
from absfuyu.dxt import ListExt
|
|
18
|
+
from absfuyu.util.text_table import BoxStyle, get_box_drawing_character
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Function
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
def draw_grid(data: list[list[int]], style: BoxStyle = "normal"):
|
|
24
|
+
chars = get_box_drawing_character(style=style)
|
|
25
|
+
rows = len(data)
|
|
26
|
+
cols = len(data[0])
|
|
27
|
+
|
|
28
|
+
# find max width for padding
|
|
29
|
+
cell_width = max(len(str(x)) for row in data for x in row) + 2
|
|
30
|
+
|
|
31
|
+
def horizontal_border(left: str, middle: str, right: str) -> str:
|
|
32
|
+
return left + (chars.HORIZONTAL * cell_width + middle) * (cols - 1) + chars.HORIZONTAL * cell_width + right
|
|
33
|
+
|
|
34
|
+
# top border
|
|
35
|
+
print(horizontal_border(chars.UPPER_LEFT_CORNER, chars.HORIZONTAL_DOWN, chars.UPPER_RIGHT_CORNER))
|
|
36
|
+
|
|
37
|
+
for i, row in enumerate(data):
|
|
38
|
+
# content line
|
|
39
|
+
line = chars.VERTICAL + "".join(f"{str(val):^{cell_width}}" + chars.VERTICAL for val in row)
|
|
40
|
+
print(line)
|
|
41
|
+
|
|
42
|
+
# middle or bottom border
|
|
43
|
+
if i < rows - 1:
|
|
44
|
+
print(horizontal_border(chars.VERTICAL_RIGHT, chars.CROSS, chars.VERTICAL_LEFT))
|
|
45
|
+
else:
|
|
46
|
+
print(horizontal_border(chars.LOWER_LEFT_CORNER, chars.HORIZONTAL_UP, chars.LOWER_RIGHT_CORNER))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Class
|
|
50
|
+
# ---------------------------------------------------------------------------
|
|
51
|
+
class SchulteTable(BaseClass):
|
|
52
|
+
"""
|
|
53
|
+
A Schulte Table is a cognitive training tool consisting of a grid filled
|
|
54
|
+
with randomly placed numbers. The task is to find and select all the numbers
|
|
55
|
+
in ascending order as quickly as possible. This exercise helps improve
|
|
56
|
+
visual attention, focus, processing speed, mental flexibility,
|
|
57
|
+
and peripheral vision.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(self, size: int = 5) -> None:
|
|
61
|
+
self.size = max(size, 1)
|
|
62
|
+
|
|
63
|
+
def make_table(self) -> None:
|
|
64
|
+
data = ListExt(range(1, self.size**2 + 1)).shuffle().split_chunk(self.size)
|
|
65
|
+
draw_grid(data)
|
|
66
|
+
|
|
67
|
+
# def play(self):
|
|
68
|
+
# """GUI"""
|
|
69
|
+
# from absfuyu.util.gui import CustomTkinterApp
|
|
70
|
+
|
|
71
|
+
# class Schulte(CustomTkinterApp):
|
|
72
|
+
# def __init__(self, title: str | None = None, size: tuple[int, int] | None = None) -> None:
|
|
73
|
+
# super().__init__(title=title, size=size)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
t = SchulteTable(5)
|
|
78
|
+
print(t)
|
absfuyu/game/sudoku.py
CHANGED
absfuyu/game/tictactoe.py
CHANGED
absfuyu/game/wordle.py
CHANGED
absfuyu/general/__init__.py
CHANGED
absfuyu/general/content.py
CHANGED
absfuyu/general/human.py
CHANGED
absfuyu/general/shape.py
CHANGED
absfuyu/logger.py
CHANGED
absfuyu/pkg_data/__init__.py
CHANGED
absfuyu/pkg_data/deprecated.py
CHANGED
absfuyu/pkg_data/logo.py
CHANGED
absfuyu/sort.py
CHANGED
absfuyu/tools/__init__.py
CHANGED
absfuyu/tools/checksum.py
CHANGED
absfuyu/tools/converter.py
CHANGED
absfuyu/tools/generator.py
CHANGED
absfuyu/tools/inspector.py
CHANGED
absfuyu/tools/keygen.py
CHANGED
absfuyu/tools/obfuscator.py
CHANGED
absfuyu/tools/passwordlib.py
CHANGED