zhmiscellany 6.2.3__py3-none-any.whl → 6.2.5__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.
- zhmiscellany/__init__.py +2 -2
- zhmiscellany/_discord_supportfuncs.py +7 -10
- zhmiscellany/_fileio_supportfuncs.py +1 -2
- zhmiscellany/_misc_supportfuncs.py +248 -147
- zhmiscellany/_processing_supportfuncs.py +29 -13
- zhmiscellany/_py_resources.py +1 -1
- zhmiscellany/dict.py +1 -3
- zhmiscellany/discord.py +45 -23
- zhmiscellany/fileio.py +70 -29
- zhmiscellany/gui.py +19 -12
- zhmiscellany/image.py +7 -8
- zhmiscellany/list.py +1 -2
- zhmiscellany/macro.py +40 -44
- zhmiscellany/math.py +3 -3
- zhmiscellany/misc.py +43 -18
- zhmiscellany/netio.py +11 -13
- zhmiscellany/pastebin.py +9 -8
- zhmiscellany/pipes.py +13 -15
- zhmiscellany/processing.py +25 -8
- zhmiscellany/rust.py +3 -1
- zhmiscellany/string.py +3 -3
- {zhmiscellany-6.2.3.dist-info → zhmiscellany-6.2.5.dist-info}/METADATA +1 -1
- zhmiscellany-6.2.5.dist-info/RECORD +27 -0
- zhmiscellany-6.2.3.dist-info/RECORD +0 -27
- {zhmiscellany-6.2.3.dist-info → zhmiscellany-6.2.5.dist-info}/WHEEL +0 -0
- {zhmiscellany-6.2.3.dist-info → zhmiscellany-6.2.5.dist-info}/top_level.txt +0 -0
zhmiscellany/gui.py
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import threading
|
|
2
1
|
import sys
|
|
3
2
|
|
|
4
|
-
# Windows-specific imports
|
|
5
3
|
if sys.platform == "win32":
|
|
6
|
-
|
|
7
|
-
import ctypes
|
|
8
|
-
from ctypes import wintypes
|
|
9
|
-
import win32gui
|
|
10
|
-
WIN32_AVAILABLE = True
|
|
11
|
-
except ImportError:
|
|
12
|
-
WIN32_AVAILABLE = False
|
|
13
|
-
print("Warning: Windows modules not available - GUI functionality disabled")
|
|
4
|
+
WIN32_AVAILABLE = True
|
|
14
5
|
else:
|
|
15
6
|
WIN32_AVAILABLE = False
|
|
16
7
|
|
|
@@ -26,6 +17,7 @@ class StateIndicator:
|
|
|
26
17
|
|
|
27
18
|
def __init__(self, colour=(255, 0, 0), opacity=0.8, corner='topright', offset=(10, 10), size=_DEFAULT_SIZE):
|
|
28
19
|
import tkinter as tk
|
|
20
|
+
import threading
|
|
29
21
|
self.tk = tk
|
|
30
22
|
self._colour = colour
|
|
31
23
|
self._opacity = opacity
|
|
@@ -80,6 +72,9 @@ class StateIndicator:
|
|
|
80
72
|
if not WIN32_AVAILABLE:
|
|
81
73
|
print("Click-through only supported on Windows")
|
|
82
74
|
return
|
|
75
|
+
else:
|
|
76
|
+
import ctypes
|
|
77
|
+
from ctypes import wintypes
|
|
83
78
|
|
|
84
79
|
try:
|
|
85
80
|
# Get the window handle
|
|
@@ -144,6 +139,9 @@ class StateIndicator:
|
|
|
144
139
|
"""Update the layered window attributes for proper transparency with click-through"""
|
|
145
140
|
if not WIN32_AVAILABLE:
|
|
146
141
|
return
|
|
142
|
+
else:
|
|
143
|
+
import ctypes
|
|
144
|
+
from ctypes import wintypes
|
|
147
145
|
|
|
148
146
|
try:
|
|
149
147
|
hwnd = ctypes.windll.user32.GetParent(self._root.winfo_id())
|
|
@@ -199,29 +197,38 @@ class StateIndicator:
|
|
|
199
197
|
self._root.after(0, self._update_size_internal)
|
|
200
198
|
|
|
201
199
|
if WIN32_AVAILABLE:
|
|
202
|
-
user32 = ctypes.windll.user32
|
|
203
|
-
|
|
204
200
|
def get_focused_window():
|
|
205
201
|
"""Return the window that currently has the keyboard focus."""
|
|
202
|
+
import ctypes
|
|
203
|
+
from ctypes import wintypes
|
|
204
|
+
user32 = ctypes.windll.user32
|
|
206
205
|
return user32.GetForegroundWindow()
|
|
207
206
|
|
|
208
207
|
def get_window_rect(hwnd):
|
|
209
208
|
"""Return the bounding rectangle of a window."""
|
|
209
|
+
import ctypes
|
|
210
|
+
from ctypes import wintypes
|
|
210
211
|
HWND = wintypes.HWND
|
|
211
212
|
RECT = wintypes.RECT
|
|
212
213
|
rect = RECT()
|
|
214
|
+
user32 = ctypes.windll.user32
|
|
213
215
|
user32.GetWindowRect(hwnd, ctypes.byref(rect))
|
|
214
216
|
return rect
|
|
215
217
|
|
|
216
218
|
def set_window_pos(hwnd, x: int, y: int, w: int, h: int):
|
|
217
219
|
"""Move (and optionally resize) a window."""
|
|
218
220
|
# 0x0040 == SWP_NOACTIVATE | 0x0020 == SWP_SHOWWINDOW
|
|
221
|
+
import ctypes
|
|
222
|
+
user32 = ctypes.windll.user32
|
|
219
223
|
user32.SetWindowPos(hwnd, 0, x, y, w, h, 0x0040 | 0x0020)
|
|
220
224
|
|
|
221
225
|
|
|
222
226
|
def find_window_by_title_fuzzy(title_query, threshold=70):
|
|
223
227
|
from fuzzywuzzy import process
|
|
224
228
|
from fuzzywuzzy import fuzz
|
|
229
|
+
import ctypes
|
|
230
|
+
from ctypes import wintypes
|
|
231
|
+
import win32gui
|
|
225
232
|
def enum_windows_callback(hwnd, windows):
|
|
226
233
|
if win32gui.IsWindowVisible(hwnd):
|
|
227
234
|
window_title = win32gui.GetWindowText(hwnd)
|
zhmiscellany/image.py
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from PIL import Image, ImageDraw, ImageFont
|
|
3
|
-
import math
|
|
4
|
-
|
|
5
|
-
|
|
6
1
|
def image_diff(img1, img2):
|
|
2
|
+
import numpy as np
|
|
7
3
|
img1 = img1.resize((100, 100))
|
|
8
4
|
img2 = img2.resize((100, 100))
|
|
9
5
|
|
|
@@ -19,6 +15,8 @@ def image_diff(img1, img2):
|
|
|
19
15
|
|
|
20
16
|
class Canvas:
|
|
21
17
|
def __init__(self, width, height, colour=(0, 0, 0, 255)):
|
|
18
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
19
|
+
self.ImageFont = ImageFont
|
|
22
20
|
self.width = width
|
|
23
21
|
self.height = height
|
|
24
22
|
self.image = Image.new("RGBA", (self.width, self.height), color=colour)
|
|
@@ -62,6 +60,7 @@ class Canvas:
|
|
|
62
60
|
|
|
63
61
|
def annotate(self, pixel_xy, text, text_scale=1.0, line_thickness=1,
|
|
64
62
|
text_colour=None, line_colour=None, auto_contrast=False, background_colour=None):
|
|
63
|
+
import math
|
|
65
64
|
x, y = pixel_xy
|
|
66
65
|
if not (0 <= x < self.width and 0 <= y < self.height):
|
|
67
66
|
return
|
|
@@ -83,11 +82,11 @@ class Canvas:
|
|
|
83
82
|
line_colour = default_color
|
|
84
83
|
|
|
85
84
|
try:
|
|
86
|
-
font = ImageFont.truetype("consola.ttf", int(12 * text_scale))
|
|
85
|
+
font = self.ImageFont.truetype("consola.ttf", int(12 * text_scale))
|
|
87
86
|
except IOError:
|
|
88
|
-
font = ImageFont.load_default()
|
|
87
|
+
font = self.ImageFont.load_default()
|
|
89
88
|
if hasattr(font, "size"):
|
|
90
|
-
font = ImageFont.load_default().font_variant(size=int(12 * text_scale))
|
|
89
|
+
font = self.ImageFont.load_default().font_variant(size=int(12 * text_scale))
|
|
91
90
|
text_bbox = self.draw.textbbox((0, 0), text, font=font)
|
|
92
91
|
text_width = text_bbox[2] - text_bbox[0]
|
|
93
92
|
text_height = text_bbox[3] - text_bbox[1]
|
zhmiscellany/list.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from itertools import chain
|
|
2
|
-
|
|
3
1
|
def remove_duplicates(l_list):
|
|
4
2
|
return list(dict.fromkeys(l_list))
|
|
5
3
|
|
|
@@ -52,6 +50,7 @@ def split_into_sublists(lst, n):
|
|
|
52
50
|
|
|
53
51
|
|
|
54
52
|
def flatten(an_iterable):
|
|
53
|
+
from itertools import chain
|
|
55
54
|
return list(chain.from_iterable(an_iterable))
|
|
56
55
|
|
|
57
56
|
|
zhmiscellany/macro.py
CHANGED
|
@@ -1,32 +1,19 @@
|
|
|
1
|
-
import math
|
|
2
|
-
import random
|
|
3
|
-
import threading
|
|
4
1
|
import sys
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
import zhmiscellany.misc
|
|
8
|
-
import zhmiscellany.math
|
|
9
|
-
import zhmiscellany.string
|
|
10
|
-
import zhmiscellany.processing
|
|
11
|
-
|
|
12
|
-
# Windows-specific imports
|
|
13
|
-
if sys.platform == "win32":
|
|
14
|
-
try:
|
|
15
|
-
import win32api, win32con, ctypes
|
|
16
|
-
WIN32_AVAILABLE = True
|
|
17
|
-
except ImportError:
|
|
18
|
-
WIN32_AVAILABLE = False
|
|
19
|
-
print("Warning: Windows modules not available - macro functionality disabled")
|
|
20
|
-
else:
|
|
21
|
-
WIN32_AVAILABLE = False
|
|
22
|
-
|
|
23
|
-
import keyboard, kthread
|
|
24
|
-
import time
|
|
25
|
-
|
|
26
|
-
get_mouse_xy = get_mouse_xy
|
|
3
|
+
IS_WINDOWS = sys.platform == "win32"
|
|
27
4
|
|
|
5
|
+
_last_press_time_map = {} # Stores the last press timestamp for each key
|
|
28
6
|
|
|
29
7
|
def click_pixel(x=None, y=None, click_duration=None, right_click=False, middle_click=False, shift=False, ctrl=False, act_start=True, act_end=True, click_end_duration=None, double_click=False, animation_time=None, animation_fps=60, animation_easing=True, relative=False, ensure_movement=True, pre_click_duration=None, pre_click_wiggle=True, click=True):
|
|
8
|
+
import random
|
|
9
|
+
import math
|
|
10
|
+
from ._misc_supportfuncs import move_mouse, mouse_down, mouse_up, get_mouse_xy
|
|
11
|
+
import zhmiscellany.math
|
|
12
|
+
if IS_WINDOWS:
|
|
13
|
+
import win32api
|
|
14
|
+
import win32con
|
|
15
|
+
import ctypes
|
|
16
|
+
|
|
30
17
|
if not click:
|
|
31
18
|
act_start=False;act_end=False
|
|
32
19
|
if right_click and middle_click:
|
|
@@ -115,7 +102,7 @@ def click_pixel(x=None, y=None, click_duration=None, right_click=False, middle_c
|
|
|
115
102
|
for point in animation_points:
|
|
116
103
|
click_pixel((round(point[0]), round(point[1])), act_start=False, act_end=False, click_end_duration=1/animation_fps, relative=relative)
|
|
117
104
|
|
|
118
|
-
if
|
|
105
|
+
if IS_WINDOWS:
|
|
119
106
|
if ctrl:
|
|
120
107
|
win32api.keybd_event(win32con.VK_CONTROL, 0, 0, 0)
|
|
121
108
|
keys_down.append(win32con.VK_CONTROL)
|
|
@@ -187,7 +174,7 @@ def click_pixel(x=None, y=None, click_duration=None, right_click=False, middle_c
|
|
|
187
174
|
if act_end:
|
|
188
175
|
mouse_up(1)
|
|
189
176
|
|
|
190
|
-
if
|
|
177
|
+
if IS_WINDOWS:
|
|
191
178
|
for key in keys_down:
|
|
192
179
|
win32api.keybd_event(key, 0, win32con.KEYEVENTF_KEYUP, 0)
|
|
193
180
|
|
|
@@ -197,13 +184,13 @@ def click_pixel(x=None, y=None, click_duration=None, right_click=False, middle_c
|
|
|
197
184
|
if double_click:
|
|
198
185
|
click_pixel(x, y, click_duration, right_click, shift, ctrl, act_start, act_end, middle_click, click_end_duration, pre_click_duration=pre_click_duration, pre_click_wiggle=pre_click_wiggle)
|
|
199
186
|
|
|
200
|
-
|
|
201
187
|
def press_key_directinput(key, shift=False, act_start=True, act_end=True, key_hold_time=0):
|
|
202
|
-
if not
|
|
188
|
+
if not IS_WINDOWS:
|
|
203
189
|
print("press_key_directinput() only supports Windows! Functionality disabled")
|
|
204
190
|
return
|
|
205
191
|
|
|
206
192
|
import pydirectinput
|
|
193
|
+
import zhmiscellany.misc
|
|
207
194
|
pydirectinput.PAUSE = 0
|
|
208
195
|
pydirectinput.FAILSAFE = False
|
|
209
196
|
if shift: pydirectinput.keyDown('shift')
|
|
@@ -212,12 +199,15 @@ def press_key_directinput(key, shift=False, act_start=True, act_end=True, key_ho
|
|
|
212
199
|
if act_end: pydirectinput.keyUp(key)
|
|
213
200
|
if shift: pydirectinput.keyUp('shift')
|
|
214
201
|
|
|
215
|
-
|
|
216
202
|
def press_key(vk_code, shift=False, act_start=True, act_end=True, key_hold_time=0):
|
|
217
|
-
if not
|
|
203
|
+
if not IS_WINDOWS:
|
|
218
204
|
print("press_key() only supports Windows! Functionality disabled")
|
|
219
205
|
return
|
|
220
206
|
|
|
207
|
+
import win32api
|
|
208
|
+
import win32con
|
|
209
|
+
import zhmiscellany.misc
|
|
210
|
+
|
|
221
211
|
if shift:
|
|
222
212
|
win32api.keybd_event(win32con.VK_SHIFT, 0, 0, 0)
|
|
223
213
|
if act_start:
|
|
@@ -229,8 +219,8 @@ def press_key(vk_code, shift=False, act_start=True, act_end=True, key_hold_time=
|
|
|
229
219
|
if shift:
|
|
230
220
|
win32api.keybd_event(win32con.VK_SHIFT, 0, win32con.KEYEVENTF_KEYUP, 0)
|
|
231
221
|
|
|
232
|
-
|
|
233
222
|
def type_string(text=None, delay=None, key_hold_time=None, vk_codes=None, combine=False):
|
|
223
|
+
import zhmiscellany.misc
|
|
234
224
|
# Dictionary mapping characters to their virtual key codes and shift state
|
|
235
225
|
char_to_vk = {
|
|
236
226
|
'a': (0x41, False), 'b': (0x42, False), 'c': (0x43, False), 'd': (0x44, False),
|
|
@@ -287,24 +277,27 @@ def type_string(text=None, delay=None, key_hold_time=None, vk_codes=None, combin
|
|
|
287
277
|
for vk_code in vk_codes:
|
|
288
278
|
press_key(vk_code, False, act_start=False, act_end=True, key_hold_time=key_hold_time)
|
|
289
279
|
|
|
290
|
-
|
|
291
280
|
def is_key_pressed_async(vk_code):
|
|
292
281
|
"""
|
|
293
282
|
Async check if a key is currently pressed
|
|
294
283
|
vk_code: Virtual Key code (e.g., 0x41 for 'A', 0x1B for ESC)
|
|
295
284
|
Returns: True if pressed, False otherwise
|
|
296
285
|
"""
|
|
297
|
-
if not
|
|
286
|
+
if not IS_WINDOWS:
|
|
298
287
|
print("is_key_pressed_async() only supports Windows! Returning False")
|
|
299
288
|
return False
|
|
289
|
+
import win32api
|
|
290
|
+
import ctypes
|
|
300
291
|
return win32api.GetAsyncKeyState(vk_code) & 0x8000 != 0
|
|
301
292
|
|
|
302
|
-
|
|
303
293
|
def scroll(amount, delay=None, post_scroll_delay=None):
|
|
304
|
-
if not
|
|
294
|
+
if not IS_WINDOWS:
|
|
305
295
|
print("scroll() only supports Windows! Functionality disabled")
|
|
306
296
|
return
|
|
307
297
|
|
|
298
|
+
import zhmiscellany.misc
|
|
299
|
+
import ctypes
|
|
300
|
+
|
|
308
301
|
def raw_scroll(amount):
|
|
309
302
|
# Constants for mouse input
|
|
310
303
|
INPUT_MOUSE = 0
|
|
@@ -354,13 +347,14 @@ def scroll(amount, delay=None, post_scroll_delay=None):
|
|
|
354
347
|
if post_scroll_delay:
|
|
355
348
|
zhmiscellany.misc.high_precision_sleep(post_scroll_delay)
|
|
356
349
|
|
|
357
|
-
|
|
358
350
|
def get_mouse_buttons():
|
|
359
351
|
"""Returns a list of booleans [M1, M2, M3] indicating which mouse buttons are held down."""
|
|
360
|
-
if not
|
|
352
|
+
if not IS_WINDOWS:
|
|
361
353
|
print("get_mouse_buttons() only supports Windows! Returning [False, False, False]")
|
|
362
354
|
return [False, False, False]
|
|
363
355
|
|
|
356
|
+
import ctypes
|
|
357
|
+
|
|
364
358
|
VK_LBUTTON = 0x01 # Left mouse button (M1)
|
|
365
359
|
VK_RBUTTON = 0x02 # Right mouse button (M2)
|
|
366
360
|
VK_MBUTTON = 0x04 # Middle mouse button (M3)
|
|
@@ -373,10 +367,11 @@ def get_mouse_buttons():
|
|
|
373
367
|
bool(GetAsyncKeyState(VK_MBUTTON) & 0x8000)
|
|
374
368
|
]
|
|
375
369
|
|
|
376
|
-
|
|
377
|
-
_last_press_time_map = {} # Stores the last press timestamp for each key
|
|
378
|
-
|
|
379
370
|
def better_wait_for(key):
|
|
371
|
+
import threading
|
|
372
|
+
import keyboard
|
|
373
|
+
import time
|
|
374
|
+
|
|
380
375
|
key_name = key.lower()
|
|
381
376
|
press_event = threading.Event() # Event to signal when the key is pressed
|
|
382
377
|
_last_press_time_map.setdefault(key_name, 0) # Initialize last press time for this key
|
|
@@ -391,8 +386,11 @@ def better_wait_for(key):
|
|
|
391
386
|
press_event.wait() # Block execution until the press_event is set
|
|
392
387
|
keyboard.unhook(hook_id) # Clean up the listener after key is detected
|
|
393
388
|
|
|
394
|
-
|
|
395
389
|
def toggle_function(func, key='f8', blocking=True):
|
|
390
|
+
import kthread
|
|
391
|
+
import threading
|
|
392
|
+
# better_wait_for is in the same module, no import needed
|
|
393
|
+
|
|
396
394
|
def atom():
|
|
397
395
|
while True:
|
|
398
396
|
better_wait_for(key)
|
|
@@ -407,7 +405,6 @@ def toggle_function(func, key='f8', blocking=True):
|
|
|
407
405
|
t.start()
|
|
408
406
|
return t
|
|
409
407
|
|
|
410
|
-
|
|
411
408
|
def record_actions_to_code(RECORD_MOUSE_MOVEMENT=False, STOP_KEY='f9'):
|
|
412
409
|
import time
|
|
413
410
|
import pynput
|
|
@@ -653,7 +650,6 @@ def record_actions_to_code(RECORD_MOUSE_MOVEMENT=False, STOP_KEY='f9'):
|
|
|
653
650
|
# Generate the replay script
|
|
654
651
|
return generate_code(events, start_time)
|
|
655
652
|
|
|
656
|
-
|
|
657
653
|
KEY_CODES = {
|
|
658
654
|
'None': 0,
|
|
659
655
|
'LeftMouseButton': 1,
|
|
@@ -797,4 +793,4 @@ KEY_CODES = {
|
|
|
797
793
|
'StartApplication2': 183,
|
|
798
794
|
'Equals': 187,
|
|
799
795
|
'Minus': 189,
|
|
800
|
-
}
|
|
796
|
+
}
|
zhmiscellany/math.py
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
def smart_percentage(things, total_things):
|
|
5
2
|
if total_things == 0:
|
|
6
3
|
return total_things
|
|
@@ -25,6 +22,7 @@ def clamp(value, minimum, maximum):
|
|
|
25
22
|
|
|
26
23
|
|
|
27
24
|
def generate_grid(top_left, bottom_right, rows, cols, int_coords=True, row_major=True):
|
|
25
|
+
import numpy as np
|
|
28
26
|
x = np.linspace(top_left[0], bottom_right[0], cols)
|
|
29
27
|
y = np.linspace(top_left[1], bottom_right[1], rows)
|
|
30
28
|
grid = np.array(np.meshgrid(x, y)).T.reshape(-1, 2)
|
|
@@ -44,6 +42,7 @@ def generate_grid(top_left, bottom_right, rows, cols, int_coords=True, row_major
|
|
|
44
42
|
|
|
45
43
|
|
|
46
44
|
def generate_eased_points(p1, p2, num_points):
|
|
45
|
+
import numpy as np
|
|
47
46
|
def ease_in_out(t):
|
|
48
47
|
return t * t * (3 - 2 * t) # Smoothstep formula
|
|
49
48
|
x1, y1 = p1
|
|
@@ -65,6 +64,7 @@ def generate_eased_points(p1, p2, num_points):
|
|
|
65
64
|
|
|
66
65
|
|
|
67
66
|
def generate_linear_points(p1, p2, num_points):
|
|
67
|
+
import numpy as np
|
|
68
68
|
x1, y1 = p1
|
|
69
69
|
x2, y2 = p2
|
|
70
70
|
|
zhmiscellany/misc.py
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import zhmiscellany.math
|
|
3
|
-
import zhmiscellany.string
|
|
4
|
-
import zhmiscellany.processing
|
|
1
|
+
import sys
|
|
5
2
|
import zhmiscellany.macro
|
|
6
|
-
import
|
|
7
|
-
import time, hashlib, ctypes
|
|
8
|
-
import random, string, copy
|
|
9
|
-
import builtins, inspect
|
|
3
|
+
import types
|
|
10
4
|
|
|
11
5
|
WIN32_AVAILABLE = False
|
|
12
6
|
if sys.platform == "win32":
|
|
13
|
-
|
|
14
|
-
import win32gui, win32con, win32process
|
|
15
|
-
WIN32_AVAILABLE = True
|
|
16
|
-
except ImportError:
|
|
17
|
-
print("Warning: pywin32 not available, Windows-specific features disabled")
|
|
18
|
-
|
|
19
|
-
import psutil
|
|
20
|
-
|
|
21
|
-
import types
|
|
7
|
+
WIN32_AVAILABLE = True
|
|
22
8
|
|
|
23
9
|
# support backwards compatibility
|
|
24
10
|
click_pixel = zhmiscellany.macro.click_pixel
|
|
@@ -29,6 +15,7 @@ KEY_CODES = zhmiscellany.macro.KEY_CODES
|
|
|
29
15
|
|
|
30
16
|
|
|
31
17
|
def get_actual_screen_resolution():
|
|
18
|
+
import ctypes
|
|
32
19
|
if not WIN32_AVAILABLE:
|
|
33
20
|
print("get_actual_screen_resolution only supports Windows! Returning (0, 0)")
|
|
34
21
|
return (0, 0)
|
|
@@ -40,9 +27,14 @@ def get_actual_screen_resolution():
|
|
|
40
27
|
|
|
41
28
|
|
|
42
29
|
def focus_window(process_name: str, interval=0):
|
|
30
|
+
import time
|
|
31
|
+
import psutil
|
|
32
|
+
import ctypes
|
|
43
33
|
if not WIN32_AVAILABLE:
|
|
44
34
|
print("focus_window only supports Windows!")
|
|
45
35
|
return
|
|
36
|
+
else:
|
|
37
|
+
import win32gui, win32con, win32process
|
|
46
38
|
|
|
47
39
|
# Import user32.dll for additional window handling
|
|
48
40
|
user32 = ctypes.windll.user32
|
|
@@ -130,9 +122,12 @@ def focus_window(process_name: str, interval=0):
|
|
|
130
122
|
|
|
131
123
|
|
|
132
124
|
def setup_console_window(xy=(0, 0), wh=(400, 100), always_on_top=True):
|
|
125
|
+
import ctypes
|
|
133
126
|
if not WIN32_AVAILABLE:
|
|
134
127
|
print("setup_console_window only supports Windows!")
|
|
135
128
|
return
|
|
129
|
+
else:
|
|
130
|
+
import win32gui, win32con, win32process
|
|
136
131
|
|
|
137
132
|
# Get the console window handle
|
|
138
133
|
hwnd = ctypes.windll.kernel32.GetConsoleWindow()
|
|
@@ -150,10 +145,13 @@ def setup_console_window(xy=(0, 0), wh=(400, 100), always_on_top=True):
|
|
|
150
145
|
|
|
151
146
|
|
|
152
147
|
def die():
|
|
148
|
+
import os
|
|
149
|
+
import signal
|
|
153
150
|
os.kill(os.getpid(), signal.SIGTERM)
|
|
154
151
|
|
|
155
152
|
|
|
156
153
|
def show_progress(things, total_things, extra_data='', smart_ratelimit=False, max_prints=1000):
|
|
154
|
+
import zhmiscellany.math
|
|
157
155
|
do_print = True
|
|
158
156
|
|
|
159
157
|
if smart_ratelimit:
|
|
@@ -182,6 +180,8 @@ def smart_every_nth(number, n, total):
|
|
|
182
180
|
|
|
183
181
|
|
|
184
182
|
def calculate_eta(timestamps, total_timestamps):
|
|
183
|
+
import time
|
|
184
|
+
import zhmiscellany.string
|
|
185
185
|
if not timestamps:
|
|
186
186
|
return "Not enough data to calculate ETA."
|
|
187
187
|
|
|
@@ -211,6 +211,8 @@ def decide(options, text):
|
|
|
211
211
|
|
|
212
212
|
|
|
213
213
|
def import_module_from_path(path, module_name=None):
|
|
214
|
+
import importlib
|
|
215
|
+
import zhmiscellany.string
|
|
214
216
|
if not module_name:
|
|
215
217
|
module_name = zhmiscellany.string.get_universally_unique_string()
|
|
216
218
|
spec = importlib.util.spec_from_file_location(module_name, path)
|
|
@@ -220,14 +222,18 @@ def import_module_from_path(path, module_name=None):
|
|
|
220
222
|
|
|
221
223
|
|
|
222
224
|
def base62_hash(anything):
|
|
225
|
+
import hashlib
|
|
226
|
+
import zhmiscellany.string
|
|
223
227
|
return zhmiscellany.string.convert_to_base62(int(int(hashlib.md5(anything if isinstance(anything, bytes) else str(anything).encode()).hexdigest(), 16)**0.5))
|
|
224
228
|
|
|
225
229
|
|
|
226
230
|
def md5_int_hash(anything):
|
|
231
|
+
import hashlib
|
|
227
232
|
return int(hashlib.md5(anything if isinstance(anything, bytes) else str(anything).encode()).hexdigest(), 16)
|
|
228
233
|
|
|
229
234
|
|
|
230
235
|
def high_precision_sleep(duration):
|
|
236
|
+
import time
|
|
231
237
|
start_time = time.perf_counter()
|
|
232
238
|
while True:
|
|
233
239
|
elapsed_time = time.perf_counter() - start_time
|
|
@@ -241,6 +247,7 @@ def high_precision_sleep(duration):
|
|
|
241
247
|
|
|
242
248
|
|
|
243
249
|
def is_admin():
|
|
250
|
+
import ctypes
|
|
244
251
|
if not WIN32_AVAILABLE:
|
|
245
252
|
print("is_admin only supports Windows! Returning False")
|
|
246
253
|
return False
|
|
@@ -251,6 +258,8 @@ def is_admin():
|
|
|
251
258
|
|
|
252
259
|
|
|
253
260
|
def die_on_key(key='f9', show_message=False):
|
|
261
|
+
import zhmiscellany.macro
|
|
262
|
+
import zhmiscellany.processing
|
|
254
263
|
def _die_on_key(key):
|
|
255
264
|
zhmiscellany.macro.better_wait_for(key)
|
|
256
265
|
if show_message:
|
|
@@ -259,10 +268,19 @@ def die_on_key(key='f9', show_message=False):
|
|
|
259
268
|
zhmiscellany.processing.start_daemon(target=_die_on_key, args=(key,))
|
|
260
269
|
|
|
261
270
|
if WIN32_AVAILABLE:
|
|
262
|
-
|
|
271
|
+
def get_temp_folder():
|
|
272
|
+
import os
|
|
273
|
+
temp_folder = os.popen(r'echo %TEMP%').read().replace('\n', '')
|
|
274
|
+
return temp_folder
|
|
263
275
|
|
|
264
276
|
def obfuscate_python(python_code_string, do_not_obfuscate_indent_block_comment='# DNO', remove_prints=True, remove_comments=True, add_lines=True, new_line_ratio=10):
|
|
265
277
|
import keyword
|
|
278
|
+
import copy
|
|
279
|
+
import random
|
|
280
|
+
import string
|
|
281
|
+
import builtins
|
|
282
|
+
import inspect
|
|
283
|
+
import zhmiscellany.string
|
|
266
284
|
|
|
267
285
|
obf = python_code_string
|
|
268
286
|
dno_sig = do_not_obfuscate_indent_block_comment
|
|
@@ -697,6 +715,10 @@ _CYAN = '\033[96m'
|
|
|
697
715
|
_RESET = '\033[0m'
|
|
698
716
|
|
|
699
717
|
def time_it(action=False, clock=0):
|
|
718
|
+
import time
|
|
719
|
+
import inspect
|
|
720
|
+
import zhmiscellany.math
|
|
721
|
+
import sys
|
|
700
722
|
global _start
|
|
701
723
|
try:
|
|
702
724
|
a = _start
|
|
@@ -718,6 +740,8 @@ def time_it(action=False, clock=0):
|
|
|
718
740
|
|
|
719
741
|
|
|
720
742
|
def here(*args):
|
|
743
|
+
import inspect
|
|
744
|
+
import sys
|
|
721
745
|
frame = inspect.currentframe().f_back # Get caller frame
|
|
722
746
|
filename = frame.f_code.co_filename
|
|
723
747
|
lineno = frame.f_lineno
|
|
@@ -769,6 +793,7 @@ l = types.FunctionType(
|
|
|
769
793
|
|
|
770
794
|
|
|
771
795
|
def wait_for_vsync():
|
|
796
|
+
import ctypes
|
|
772
797
|
if not WIN32_AVAILABLE:
|
|
773
798
|
print("wait_for_vsync only supports Windows!")
|
|
774
799
|
return
|
zhmiscellany/netio.py
CHANGED
|
@@ -1,23 +1,12 @@
|
|
|
1
|
-
import os, requests
|
|
2
|
-
import zhmiscellany.string
|
|
3
|
-
import urllib.parse
|
|
4
1
|
import sys
|
|
5
|
-
from urllib3.exceptions import InsecureRequestWarning
|
|
6
|
-
import urllib3
|
|
7
|
-
|
|
8
|
-
urllib3.disable_warnings(InsecureRequestWarning)
|
|
9
2
|
|
|
10
3
|
WIN32_AVAILABLE = False
|
|
11
4
|
if sys.platform == "win32":
|
|
12
|
-
|
|
13
|
-
from zhmiscellany._misc_supportfuncs import patch_rhg
|
|
14
|
-
from random_header_generator import HeaderGenerator
|
|
15
|
-
WIN32_AVAILABLE = True
|
|
16
|
-
except ImportError:
|
|
17
|
-
print("Warning: random_header_generator not available, Windows-specific features disabled")
|
|
5
|
+
WIN32_AVAILABLE = True
|
|
18
6
|
|
|
19
7
|
|
|
20
8
|
def resolve_file(url, destination_folder="."):
|
|
9
|
+
import urllib.parse
|
|
21
10
|
file_name = urllib.parse.unquote(url.split("/")[-1])
|
|
22
11
|
file_name = file_name.split('?')[0]
|
|
23
12
|
destination_path = f"{destination_folder}/{file_name}"
|
|
@@ -27,6 +16,11 @@ def resolve_file(url, destination_folder="."):
|
|
|
27
16
|
|
|
28
17
|
|
|
29
18
|
def download_file(url, destination_folder=".", just_return_path=False, headers=None, file_path=None):
|
|
19
|
+
import os, requests
|
|
20
|
+
from urllib3.exceptions import InsecureRequestWarning
|
|
21
|
+
import urllib3
|
|
22
|
+
urllib3.disable_warnings(InsecureRequestWarning)
|
|
23
|
+
|
|
30
24
|
if file_path:
|
|
31
25
|
destination_path = file_path
|
|
32
26
|
else:
|
|
@@ -54,9 +48,12 @@ def download_file(url, destination_folder=".", just_return_path=False, headers=N
|
|
|
54
48
|
|
|
55
49
|
|
|
56
50
|
def generate_headers(url):
|
|
51
|
+
import urllib.parse
|
|
57
52
|
headers = {}
|
|
58
53
|
|
|
59
54
|
if WIN32_AVAILABLE:
|
|
55
|
+
from zhmiscellany._misc_supportfuncs import _
|
|
56
|
+
from random_header_generator import HeaderGenerator
|
|
60
57
|
generator = HeaderGenerator()
|
|
61
58
|
for k, v in generator().items():
|
|
62
59
|
headers[k] = v
|
|
@@ -68,6 +65,7 @@ def generate_headers(url):
|
|
|
68
65
|
|
|
69
66
|
|
|
70
67
|
def is_internet():
|
|
68
|
+
import os, requests
|
|
71
69
|
urls = [
|
|
72
70
|
"http://1.1.1.1",
|
|
73
71
|
"https://www.google.com",
|
zhmiscellany/pastebin.py
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
import requests
|
|
3
|
-
|
|
4
1
|
# PasteBin API Class - Developed by acidvegas in Python, modernized for use in zhmiscellany package. (https://git.acid.vegas/pastebin)
|
|
5
2
|
class PasteBin:
|
|
6
3
|
def __init__(self, api_dev_key, api_user_key=None):
|
|
4
|
+
import requests
|
|
5
|
+
self.requests = requests
|
|
7
6
|
self.api_dev_key = api_dev_key
|
|
8
7
|
self.api_user_key = api_user_key
|
|
9
8
|
|
|
10
9
|
def api_call(self, method, params):
|
|
11
10
|
'''Make a call to the PasteBin API.'''
|
|
12
11
|
url = f'https://pastebin.com/api/{method}'
|
|
13
|
-
response = requests.post(url, data=params, timeout=10)
|
|
12
|
+
response = self.requests.post(url, data=params, timeout=10)
|
|
14
13
|
try:
|
|
15
14
|
response.raise_for_status() # Raise an exception for HTTP errors
|
|
16
15
|
except:
|
|
@@ -102,6 +101,8 @@ class PasteBin:
|
|
|
102
101
|
|
|
103
102
|
class Pasteee:
|
|
104
103
|
def __init__(self, api_key):
|
|
104
|
+
import requests
|
|
105
|
+
self.requests = requests
|
|
105
106
|
self.api_key = api_key
|
|
106
107
|
self.base_url = "https://api.paste.ee/v1/pastes"
|
|
107
108
|
|
|
@@ -111,15 +112,15 @@ class Pasteee:
|
|
|
111
112
|
url = f"{self.base_url}{endpoint}"
|
|
112
113
|
|
|
113
114
|
if method == 'POST':
|
|
114
|
-
response = requests.post(url, headers=headers, json=json_data, params=params, timeout=10)
|
|
115
|
+
response = self.requests.post(url, headers=headers, json=json_data, params=params, timeout=10)
|
|
115
116
|
elif method == 'GET':
|
|
116
|
-
response = requests.get(url, headers=headers, params=params, timeout=10)
|
|
117
|
+
response = self.requests.get(url, headers=headers, params=params, timeout=10)
|
|
117
118
|
elif method == 'DELETE':
|
|
118
|
-
response = requests.delete(url, headers=headers, params=params, timeout=10)
|
|
119
|
+
response = self.requests.delete(url, headers=headers, params=params, timeout=10)
|
|
119
120
|
|
|
120
121
|
try:
|
|
121
122
|
response.raise_for_status()
|
|
122
|
-
except requests.exceptions.RequestException as e:
|
|
123
|
+
except self.requests.exceptions.RequestException as e:
|
|
123
124
|
raise Exception(f'ERROR {response.status_code}: {response.text}') from e
|
|
124
125
|
|
|
125
126
|
return response.json()
|