From 3da3fabe793f48a28de18513f5e361c27f117536 Mon Sep 17 00:00:00 2001
From: milk <53408947@qq.com>
Date: Tue, 21 Oct 2025 15:43:02 +0800
Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8DiOS=E9=AB=98=E7=89=88?=
=?UTF-8?q?=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/workspace.xml | 9 +-
Entity/Variables.py | 7 +-
Entity/__pycache__/Variables.cpython-312.pyc | Bin 3125 -> 3125 bytes
Module/DeviceInfo.py | 23 +-
Module/IOSActivator.py | 300 ++++++++++++++++++
Module/Main.py | 2 +-
Module/__pycache__/DeviceInfo.cpython-312.pyc | Bin 16720 -> 17147 bytes
Module/__pycache__/Main.cpython-312.pyc | Bin 3192 -> 3192 bytes
Utils/LogManager.py | 2 +-
Utils/__pycache__/LogManager.cpython-312.pyc | Bin 14685 -> 14663 bytes
10 files changed, 332 insertions(+), 11 deletions(-)
create mode 100644 Module/IOSActivator.py
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index a47552f..cc1eb4b 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,7 +4,14 @@
-
+
+
+
+
+
+
+
+
diff --git a/Entity/Variables.py b/Entity/Variables.py
index 069994e..a24f720 100644
--- a/Entity/Variables.py
+++ b/Entity/Variables.py
@@ -3,8 +3,11 @@ from typing import Dict, Any
from Entity.AnchorModel import AnchorModel
# wda apple bundle id
-WdaAppBundleId = "com.yolozsAgent.wda.xctrunner"
-
+WdaAppBundleId = "com.yolojtAgent.wda.xctrunner"
+# wda投屏端口
+wdaScreenPort = 9567
+# wda功能端口
+wdaFunctionPort = 8567
# 全局主播列表
anchorList: list[AnchorModel] = []
# 线程锁
diff --git a/Entity/__pycache__/Variables.cpython-312.pyc b/Entity/__pycache__/Variables.cpython-312.pyc
index eff3e48af091940bea93857d47f4a94e63ead65d..33bcf4cb5cfc453dc0c39188107d431c09a89e72 100644
GIT binary patch
delta 28
icmdlgu~mZmG%qg~0}yCyeA>t@&B&BhvRQ+Xmm2_PHU@?O
delta 28
icmdlgu~mZmG%qg~0}#mGy1bEFnvtohc(Vp0FE;>f_XipP
diff --git a/Module/DeviceInfo.py b/Module/DeviceInfo.py
index 6867093..92ad39d 100644
--- a/Module/DeviceInfo.py
+++ b/Module/DeviceInfo.py
@@ -1,17 +1,21 @@
import os
import signal
import subprocess
+import sys
+import threading
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
from typing import Dict, Optional, List
import tidevice
+import usb
import wda
from tidevice import Usbmux, ConnectionType
from tidevice._device import BaseDevice
from Entity.DeviceModel import DeviceModel
-from Entity.Variables import WdaAppBundleId
+from Entity.Variables import WdaAppBundleId, wdaFunctionPort, wdaScreenPort
from Module.FlaskSubprocessManager import FlaskSubprocessManager
+from Module.IOSActivator import IOSActivator
from Utils.LogManager import LogManager
import socket
@@ -36,7 +40,6 @@ class DeviceInfo:
orphan_gc_tick = 0
while True:
online = {d.udid for d in Usbmux().device_list() if d.conn_type == ConnectionType.USB}
-
# 拔掉——同步
for udid in list(self._models):
if udid not in online:
@@ -107,8 +110,16 @@ class DeviceInfo:
print("进入启动wda方法")
try:
dev = tidevice.Device(udid)
- print("获取tidevice对象成功,准备启动wda")
- dev.app_start(WdaAppBundleId)
+ systemVersion = int(dev.product_version.split(".")[0])
+ # 判断运行wda的逻辑
+ if systemVersion > 17:
+ ios = IOSActivator()
+ threading.Thread(
+ target=ios.activate,
+ args=(udid,)
+ ).start()
+ else:
+ dev.app_start(WdaAppBundleId)
print("启动wda成功")
time.sleep(3)
return True
@@ -118,7 +129,7 @@ class DeviceInfo:
def _screen_info(self, udid: str):
try:
- c = wda.USBClient(udid, 8100)
+ c = wda.USBClient(udid, wdaFunctionPort)
c.home()
size = c.window_size()
scale = c.scale
@@ -139,7 +150,7 @@ class DeviceInfo:
flags = subprocess.CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP
return subprocess.Popen(
- [self._iproxy_path, "-u", udid, str(port), "9100"],
+ [self._iproxy_path, "-u", udid, str(port), wdaScreenPort],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
creationflags=flags
diff --git a/Module/IOSActivator.py b/Module/IOSActivator.py
new file mode 100644
index 0000000..90f6812
--- /dev/null
+++ b/Module/IOSActivator.py
@@ -0,0 +1,300 @@
+
+import os
+import random
+import re
+import socket
+import sys
+import subprocess
+from typing import Optional
+
+from Entity.Variables import WdaAppBundleId
+
+
+class IOSActivator:
+ """
+ 轻量 iOS 激活器(仅代码调用):
+ 1) 启动 `pymobiledevice3 remote tunneld`(基于传入 UDID)
+ 2) 自动挂载 Developer Disk Image
+ 3) 设备隧道就绪后启动 WDA:
+ - 优先使用 `--rsd ` 直连(支持 IPv6)
+ - 失败再用 `PYMOBILEDEVICE3_TUNNEL=127.0.0.1:` 作为退路(仅 IPv4)
+ """
+
+ def __init__(self, python_executable: Optional[str] = None):
+ self.python = python_executable or sys.executable
+
+ # --------------------------
+ # 内部工具
+ # --------------------------
+ def _auto_mount_developer_disk(self, udid: str, retries: int = 3, backoff_seconds: float = 2.0) -> None:
+ """使用 `pymobiledevice3 mounter auto-mount` 为指定 UDID 挂载开发者镜像(带重试)。"""
+ env = os.environ.copy()
+ env["PYMOBILEDEVICE3_UDID"] = udid
+
+ max_attempts = max(1, int(retries))
+ last_err = None
+ for i in range(max_attempts):
+ try:
+ out = subprocess.check_output(
+ [self.python, "-m", "pymobiledevice3", "mounter", "auto-mount"],
+ text=True,
+ stderr=subprocess.STDOUT,
+ env=env,
+ )
+ if out:
+ for line in out.splitlines():
+ print(f"[mounter] {line}")
+ print("[mounter] Developer disk image mounted.")
+ return
+ except subprocess.CalledProcessError as exc:
+ lowered = (exc.output or "").lower()
+ if "already mounted" in lowered:
+ print("[mounter] Developer disk image already mounted.")
+ return
+ last_err = exc
+ if i < max_attempts - 1:
+ print(f"[mounter] attempt {i+1}/{max_attempts} failed, retrying in {backoff_seconds}s ...")
+ try:
+ import time as _t
+ _t.sleep(backoff_seconds)
+ except Exception:
+ pass
+
+ msg = last_err.output if isinstance(last_err, subprocess.CalledProcessError) else str(last_err)
+ raise RuntimeError(f"Auto-mount failed after {max_attempts} attempts: {msg}")
+
+ def _is_ipv4_host(self, host: str) -> bool:
+ return bool(re.match(r"^\d{1,3}(\.\d{1,3}){3}$", host))
+
+ def _wait_for_rsd_ready(self, rsd_host: str, rsd_port: str, retries: int = 5, delay: float = 3.0) -> bool:
+ """
+ 探测 RSD 通道是否就绪:直接尝试 TCP 连接。
+ """
+ port_int = int(rsd_port)
+ for i in range(1, retries + 1):
+ print(f"[rsd] Probing RSD {rsd_host}:{rsd_port} (attempt {i}/{retries}) ...")
+ try:
+ with socket.create_connection((rsd_host, port_int), timeout=2):
+ print("[rsd] ✅ RSD is reachable and ready.")
+ return True
+ except (socket.timeout, ConnectionRefusedError, OSError) as e:
+ print(f"[rsd] Not ready yet ({e}). Retrying...")
+ import time as _t
+ _t.sleep(delay)
+ print("[rsd] ❌ RSD did not become ready after retries.")
+ return False
+
+ def _launch_wda_via_rsd(self, bundle_id: str, rsd_host: str, rsd_port: str, udid: str) -> None:
+ """
+ 使用 `--rsd ` 直连设备隧道来启动 WDA(推荐路径,IPv4/IPv6 都 OK)。
+ 不设置 PYMOBILEDEVICE3_TUNNEL,避免 IPv6 解析问题。
+ """
+ print(f"[wda] Launch via RSD {rsd_host}:{rsd_port}, bundle: {bundle_id}")
+ env = os.environ.copy()
+ env["PYMOBILEDEVICE3_UDID"] = udid
+
+ args = [
+ self.python, "-m", "pymobiledevice3",
+ "developer", "dvt", "launch", bundle_id,
+ "--rsd", rsd_host, rsd_port,
+ ]
+ try:
+ out = subprocess.check_output(args, text=True, stderr=subprocess.STDOUT, env=env)
+ except subprocess.CalledProcessError as exc:
+ raise RuntimeError(f"WDA launch via RSD failed: {exc.output}") from exc
+
+ if out:
+ for line in out.splitlines():
+ print(f"[wda] {line}")
+ print("[wda] Launch via RSD completed.")
+
+ def _launch_wda_via_http_tunnel(self, bundle_id: str, http_host: str, http_port: str, udid: str) -> None:
+ """
+ 退路:通过 HTTP 网关端口设置 PYMOBILEDEVICE3_TUNNEL(仅 IPv4)。
+ """
+ if not self._is_ipv4_host(http_host):
+ raise RuntimeError(f"HTTP tunnel host must be IPv4, got {http_host}")
+
+ tunnel_endpoint = f"{http_host}:{http_port}"
+ print(f"[wda] Launch via HTTP tunnel {tunnel_endpoint}, bundle: {bundle_id}")
+ env = os.environ.copy()
+ env["PYMOBILEDEVICE3_TUNNEL"] = tunnel_endpoint
+ env["PYMOBILEDEVICE3_UDID"] = udid
+
+ args = [self.python, "-m", "pymobiledevice3", "developer", "dvt", "launch", bundle_id]
+ try:
+ out = subprocess.check_output(args, text=True, stderr=subprocess.STDOUT, env=env)
+ except subprocess.CalledProcessError as exc:
+ raise RuntimeError(f"WDA launch via HTTP tunnel failed: {exc.output}") from exc
+
+ if out:
+ for line in out.splitlines():
+ print(f"[wda] {line}")
+ print("[wda] Launch via HTTP tunnel completed.")
+
+ def _pick_available_port(self, base=49151, step=10) -> int:
+ """挑选一个可用端口(避免重复)"""
+ for i in range(0, 1000, step):
+ port = base + i
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+ if s.connect_ex(("127.0.0.1", port)) != 0:
+ return port
+ raise RuntimeError("No free port found for tunneld")
+
+ # --------------------------
+ # 对外方法
+ # --------------------------
+ def activate(
+ self,
+ udid: str,
+ wda_bundle_id: Optional[str] = WdaAppBundleId,
+ ready_timeout_sec: float = 120.0,
+ mount_retries: int = 3,
+ backoff_seconds: float = 2.0,
+ rsd_probe_retries: int = 5,
+ rsd_probe_delay_sec: float = 3.0,
+ ) -> str:
+ """
+ 执行:开隧道 -> (等待 RSD 就绪)-> 挂载镜像 -> 启动 WDA
+ - 优先用 `--rsd` 启动(先做 dvt list 探测)
+ - 失败再用 HTTP 端口作为退路
+ """
+ if not udid or not isinstance(udid, str):
+ raise ValueError("udid is required and must be a non-empty string")
+
+ print(f"[activate] UDID = {udid}")
+ env = os.environ.copy()
+ env["PYMOBILEDEVICE3_UDID"] = udid
+
+ # 1) 开隧道(子进程常驻)
+ port = self._pick_available_port()
+ cmd = [self.python, "-m", "pymobiledevice3", "remote", "tunneld", "--port", str(port)]
+
+ proc = subprocess.Popen(
+ cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ env=env,
+ )
+
+ captured: list[str] = []
+ http_host: Optional[str] = None
+ http_port: Optional[str] = None
+ rsd_host: Optional[str] = None
+ rsd_port: Optional[str] = None
+ device_tunnel_ready = False
+ wda_started = False
+ mount_done = False
+
+ import time as _t
+ start_ts = _t.time()
+
+ HTTP_RE = re.compile(r"http://([0-9.]+):(\d+)")
+ RSD_CREATED_RE = re.compile(r"Created tunnel\s+--rsd\s+([^\s]+)\s+(\d+)")
+
+ try:
+ assert proc.stdout is not None
+ for line in proc.stdout:
+ captured.append(line)
+ print(f"[tunneld] {line}", end="")
+
+ if proc.poll() is not None:
+ break
+
+ # 捕获 HTTP 网关端口
+ if http_port is None:
+ m = HTTP_RE.search(line)
+ if m:
+ http_host, http_port = m.group(1), m.group(2)
+ print(f"[tunneld] Tunnel API: {http_host}:{http_port}")
+
+ # 捕获设备 RSD(可能 IPv6)
+ m = RSD_CREATED_RE.search(line)
+ if m:
+ rsd_host, rsd_port = m.group(1), m.group(2)
+ device_tunnel_ready = True
+ print(f"[tunneld] Device-level tunnel ready (RSD {rsd_host}:{rsd_port}).")
+
+ # 条件满足后推进
+ if (not wda_started) and wda_bundle_id and device_tunnel_ready:
+ try:
+ if not mount_done:
+ self._auto_mount_developer_disk(
+ udid, retries=mount_retries, backoff_seconds=backoff_seconds
+ )
+ mount_done = True
+
+ # 先做 RSD 就绪探测,再走 RSD 启动
+ rsd_ok = False
+ if rsd_host and rsd_port:
+ rsd_ok = self._wait_for_rsd_ready(
+ rsd_host, rsd_port,
+ retries=rsd_probe_retries,
+ delay=rsd_probe_delay_sec,
+ )
+ if rsd_ok:
+ self._launch_wda_via_rsd(
+ bundle_id=wda_bundle_id,
+ rsd_host=rsd_host, # type: ignore[arg-type]
+ rsd_port=rsd_port, # type: ignore[arg-type]
+ udid=udid,
+ )
+ else:
+ # RSD 不就绪或失败,回退到 HTTP 网关(必须是 IPv4)
+ if http_host and http_port:
+ self._launch_wda_via_http_tunnel(
+ bundle_id=wda_bundle_id,
+ http_host=http_host,
+ http_port=http_port,
+ udid=udid,
+ )
+ else:
+ raise RuntimeError("No valid tunnel endpoint for fallback.")
+
+ wda_started = True
+
+ except RuntimeError as exc:
+ print(str(exc), file=sys.stderr)
+ proc.terminate()
+ try:
+ proc.wait(timeout=5)
+ except subprocess.TimeoutExpired:
+ proc.kill()
+ raise
+
+ # 超时保护(仍未启动 WDA)
+ if (not wda_started) and ready_timeout_sec > 0 and (_t.time() - start_ts > ready_timeout_sec):
+ print(f"[tunneld] Timeout waiting for device tunnel ({ready_timeout_sec}s). Aborting.")
+ proc.terminate()
+ try:
+ proc.wait(timeout=5)
+ except subprocess.TimeoutExpired:
+ proc.kill()
+ break
+
+ # 等待子进程结束(若已结束)
+ try:
+ return_code = proc.wait(timeout=5)
+ except subprocess.TimeoutExpired:
+ proc.kill()
+ return_code = proc.returncode or -9
+
+ output = "".join(captured)
+ if return_code != 0 and not wda_started:
+ raise RuntimeError(f"tunneld exited with code {return_code}.\n{output}")
+
+ print("[activate] Done.")
+ return output
+
+ except KeyboardInterrupt:
+ print("\n[activate] Interrupted, cleaning up ...", file=sys.stderr)
+ try:
+ proc.terminate()
+ proc.wait(timeout=5)
+ except Exception:
+ try:
+ proc.kill()
+ except Exception:
+ pass
+ raise
diff --git a/Module/Main.py b/Module/Main.py
index 8b8a9f3..a964353 100644
--- a/Module/Main.py
+++ b/Module/Main.py
@@ -36,7 +36,7 @@ def main(arg):
if __name__ == "__main__":
# 获取启动时候传递的参数
- main(sys.argv)
+ # main(sys.argv)
# 添加iOS开发包到电脑上
deployer = DevDiskImageDeployer(verbose=True)
diff --git a/Module/__pycache__/DeviceInfo.cpython-312.pyc b/Module/__pycache__/DeviceInfo.cpython-312.pyc
index f2ddf59848a9f66b5c158c1cfdfbfff6be49e800..a12092b86fde72293d2ccfa2c41b0d36e7560915 100644
GIT binary patch
delta 3272
zcmZuzYiv}<6`r|w?|OH=Z@<>B_4>`)*g(v~2^&ld4uyar;gN7tx>3&Mj=%Zkf=)4^Z_L)=-Mu%6x66c>XJw(&{mx@YX_5d
zrTy-iGv~}XbLN~gbN(58=K%J8=<&D^`;9l<+P1xY)Eg4qcyw0t2-a+}Ern88lVpi~
z1juDcZhH%vPDUiKU!3u8JMwCQq
zT_&UT&?r9PcCTE!{-LC)?n;=M+*w>F;sCv7+lec48>KrU4$()Q#W+m+ob#}s9(O)c
zThCUqycv?+mPp6@lW|i`?yzvmvS-qonpVht)aGiz4RnqxY;R_=MvAU?b%}osRncRv
z8-)vyujmV_Wa}3r6`Y&%Kewc=Qf5A=kj&HIHlr1rv$&xidN%0-3rt#It
zCdP=0Q)__s76yjMAQFiXzTSM=5(wihbYg-}+dm-KFu4+$-u%Fj)er~V0M@-pvEN3n(Ha&SBo1G%|
z+Gx$I8QDYH)-!N{zf
zp5I=@yeOhe9fc!9j(TK?2yCP=?xS~m8<
z2JI+bG~y?Zu{q0Oswricnp7!B=VW8FhOR^w48}-HqJ=`;UzJE2LbqT+DGo5rzJ8EERQi{n2Nq>%ATlZ
z4AR5o4Lbvt9qgA+khN?)T$FcqWx6lZ&aFJ2O6VZ{7K43g+~GOzZT!g5G${m}<>SGM
zV{=C5ywY$n*nD`|cva0S;-x1d9Ty@Umm>FHh}?gw{$gawsht-h4_&P4KD_3tuj)AY
zqpxeVw`lJ2@ho&-Uu
zPfPSqotDHHGY)G5{Y6DJ{vN$t@f+LM*%Un&ETzA!{5%|I0}^Erb+CL=h_0p+refI!
z6D-R*>F=wW+IXh{rF#lK!5G8-nLC8`@>;I8x){d}!K#M=pfE`t0|P2+Ds|Q~a=3J+
zZbH*C$#^zH%s1%HaI3uu)V9#q!q0cU$jGRTKn1g~v*yRDD6?EmGWTF+sv+?PHnSmZ
zqUoAy{8sMSnp4;gB}Sg3t7_|TJ=JS#>UoQ+V%&QVsZUL(;wr1T-9zutH)~DYlxwJa
zNm&0wFkX<{^*p1KSPB-os>|lVj(G{~|bsQ*h#3=lnm2
zBdtufpZ(eIYFE^oZ^gB2l)saI22=uow`Vw60vjMJ0lrdEaDkHz45E&^UBD94nL*2)
zR(6|lD5yaedZ=4|yIb^NXP9|(vU4sD=l;~$g!6lvof96A1RSM~*us$*NY?;#0PyUR
zSib5;-V1m|5kJ6LfPXNE7UUh64UE47@Jxbw%y%Urv%@H0Bi@asFOLTpW4LZ+2S{#H
zlJs;eh?mmyv7eVg1BeQ}>UpLb#pDARV$w=aJlHbQ$OhzLfad@f0?cP%*|xG*9qENJ
z+)f0#aK5jD1LWHP&jLW?^09_iMBD&8q|g$G1Av#)VxZ0d@RK+MRAeb2j|A+Wz*c^Y
z2soU-7>j@cs9=9%0Y+#)x+yrNZhSLTB~?r=p$C?C8r9&e{YuM{RQ`%=dVM+dN;NQr4j?un4)4wMF
zZp|i0Rzs5+Y$0
zA+|eYY-TViVvNU-a}0ULP+$zX#*lvu6<$GI6DV{AHD5r@W5~z(t}Cc@0yR&dmI)x1
bPN3OrcnuVT6R4i8aLcyKhFfnUKyLfLSEw--
delta 2773
zcmZWr3v5%@8NTOUU%%}*j$=D<{76h5c0z*Fv}IW(O3|vF|2SFF
z&QiYnpYuP@fByeJx&JhpeF`~$<8W9x`m;noJYicuwk`Zwk
zE+Z(WoLMq6+Mrl+R>_*PNw%C_va>y;I3x#^LyA*!(yypEaurfV&Lz1R->6jP+>)Eo
zCZ#IpkvxnxE7du#kS723;Nz*diu^VR|JV#yd?seW
z4Zuo}yUv6Wtm7`yUJ*ds$nJ{2phmLZwK%{IAQTHlyaz0Z$x~THVb<_Lx)BqWZGiS+
z3aUUM5{Y1D?*VeSGK3^@y7FOrBW37DENi1UPa+X7`MC0IPY>OU@vAmeNa~9A2&E^h
z*5o0n;Zd5LOqyJEA3;`Pt=j28REYgD{8dDD`$D{CCOw{@Pq@0wLY!t>5jtrnDRb2U
z!zyn=jB=WDg};u&-ZO%>YSj3ouyWCeJ4EZ_jPNyK!c_i_p)qb;IK+*in3=rq2_#0_
zsG)`De>i{fMJ-#t?fGjzUij{-A5Fh7|LiOO{ONP^=bxFsa(@1WYxB>(F_uXYOLfnb
z8Go6o>E;y`-B>=eZb=o3NmWZ>4Lhg=?gQutV0kmF=1mu2nKyY{7ynT~I+`@r2iz3ryGa@IX~!#?y!
zd&R|(3nQ1?Z`fnxMQ@*PsCp>MU5{F}^1}5t`_N|L`eu>Rq(0~^edg^){FN~2_a_fL
zNS)|HHm~7bl)}3K!T@jxcJ!EW%}G#NH>lZ38G~N=NJdJ*kyZ}1kNm@5hsKDl<`R-h
zuh)DZ35g9G$dSM<@Oa=Q09x{MicE&b4}(x%sqT48%Ot(7Zix${`#u8rm(`FkXY
zUN4#Ie}s%socJvHRYL=vRtpW`@~8+9N3;&TN#aorHI`n9UgoCv{!zyMx4$pwCmjN^ipP~q!CXYAOp@+!xO`EGBHM$7es*Z|G2fs{iH+h-A}^J
ze&TL!L_a9?HlO2-U<0?2U&i{wY)%Tu95RisAC{)3D|I
zN;W4KMz!JbViwC8d>%NgLzkx`_`%<%@cHRjBKO+Xp}A6MeLYO
z38Hrd(E|CT<2{ouvN|O1ZumFV{8^%Fm{rCERnqPINAntuXc*%HjxAUFJ7Du&0Ej~u
zHJp_*>KCeglJs_l(Gq#2Gg~gCSn1cDcHa1N&}$(de(7ip97`9|NGr%lt|e27QW&Gjht6Uzkxu@zF+?M(+q3~yl}0u-AscIsRw|I@
z$-hKT>Fa%W5NaV)o4Zf;fm#Tl6M&VInAPN*S`Oz=uv-D}7Qo*q(28K!1qShL09I7c
zOy#-47fz`rx?+=SWp-^O;VsRmi|p9)mJi~I@q4qgR4Rt>+pt79PTT|WsdZpx7~m{G
z7r+A)bi-qXf`Z{~#4z0PK7b+s_`**DOaVZ)%K6<7lpTPjF#wbq09pla0w@8n?6bs&
zhhWVP4M)WrDSV5=EP?E0cf&3K)ScQ*r_niXiMNPb(ULzX)-Dbra(|#zw23u~wWM|M
zZXHtvg;)cA29z%VuxR_p&Y>Mfs1&S_OG6V=u7g@uQQP+vj*pc8Unyt)7gR#GozS#m
zds@lL^g;Q6?W7BeBB!-%A+KT=Sb;`m!QneV{V(cI&HcGTW>k^4;JcJTgXUC7go71*LsUI7?u$7&l
diff --git a/Module/__pycache__/Main.cpython-312.pyc b/Module/__pycache__/Main.cpython-312.pyc
index d403ad4cc35a3f924c07827dba175d8a61b97c25..cdb3f1866ce0592f294df1bbeb4235f85506d199 100644
GIT binary patch
delta 20
acmew%@k4_9G%qg~0}#Aa__UEbmj?hwR0c}`
delta 20
acmew%@k4_9G%qg~0}#y9xw(-$mj?hu5(V=B
diff --git a/Utils/LogManager.py b/Utils/LogManager.py
index 3981133..0c8bb94 100644
--- a/Utils/LogManager.py
+++ b/Utils/LogManager.py
@@ -26,7 +26,7 @@ def _force_utf8_everywhere():
except Exception:
pass
-_force_utf8_everywhere()
+# _force_utf8_everywhere()
class LogManager:
"""
diff --git a/Utils/__pycache__/LogManager.cpython-312.pyc b/Utils/__pycache__/LogManager.cpython-312.pyc
index f1c24fa8cf2633d72cb0fb068463d03ef2a9cd36..3e4d8a68a682cc662ceec83ac79617aad49e18ca 100644
GIT binary patch
delta 54
zcmcaxbi9c7G%qg~0}x0le#+3B$ScWMG*LZq