"""Patch pymumble deps for Python 3.13+ / musl (Alpine). 1. pymumble: ssl.wrap_socket was removed in 3.13 2. opuslib: ctypes.util.find_library fails on musl-based distros 3. pymumble: close stale socket on reconnect """ import pathlib import sysconfig site = sysconfig.get_path("purelib") # -- pymumble: replace ssl.wrap_socket with SSLContext -- p = pathlib.Path(f"{site}/pymumble_py3/mumble.py") src = p.read_text() old = """\ try: self.control_socket = ssl.wrap_socket(std_sock, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_TLS) except AttributeError: self.control_socket = ssl.wrap_socket(std_sock, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_TLSv1) try:""" new = """\ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE if self.certfile: ctx.load_cert_chain(certfile=self.certfile, keyfile=self.keyfile) self.control_socket = ctx.wrap_socket(std_sock, server_hostname=self.host) try:""" assert old in src, "pymumble ssl patch target not found" p.write_text(src.replace(old, new)) print("pymumble ssl patch applied") # -- opuslib: find_library fails on musl, use direct CDLL fallback -- p = pathlib.Path(f"{site}/opuslib/api/__init__.py") src = p.read_text() old_opus = "lib_location = find_library('opus')" new_opus = "lib_location = find_library('opus') or 'libopus.so.0'" assert old_opus in src, "opuslib find_library patch target not found" p.write_text(src.replace(old_opus, new_opus)) print("opuslib musl patch applied") # -- pymumble: close old socket before reconnecting -- # init_connection() drops control_socket reference without closing it. # The lingering TCP connection causes Murmur to kick the new session # with "You connected to the server from another device". p = pathlib.Path(f"{site}/pymumble_py3/mumble.py") src = p.read_text() old_init = """\ self.connected = PYMUMBLE_CONN_STATE_NOT_CONNECTED self.control_socket = None""" new_init = """\ self.connected = PYMUMBLE_CONN_STATE_NOT_CONNECTED if getattr(self, 'control_socket', None) is not None: try: self.control_socket.close() except Exception: pass self.control_socket = None""" assert old_init in src, "pymumble init_connection socket patch target not found" src = src.replace(old_init, new_init) print("pymumble reconnect socket patch applied") p.write_text(src)