Загрузка данных
# -*- coding: utf-8 -*-
import sys
import time
import socket
import threading
import io
import struct
# Automatic check and installation of missing libraries
try:
import mss
from PIL import Image
import pyautogui
except ImportError:
print("[Demirast] Установка недостающих библиотек (mss, pillow, pyautogui)...")
import subprocess
subprocess.check_call([sys.executable, "-m", "pip", "install", "mss", "pillow", "pyautogui"])
import mss
from PIL import Image
import pyautogui
pyautogui.FAILSAFE = False
pyautogui.PAUSE = 0.0 # Removing PyAutoGUI delay for fast streaming and inputs!
def main():
print("=====================================================")
print(" DEMIRAST MULTI-CONNECTION PC CLIENT v2.1 ")
print("=====================================================")
print("Выберите способ подключения:")
print("1. Wi-Fi - Телефон как СЕРВЕР (Рекомендуется)")
print("2. Wi-Fi - ПК как СЕРВЕР")
print("3. USB Кабель (через ADB порт-форвардинг)")
print("4. Bluetooth - Телефон как СЕРВЕР")
print("5. Bluetooth - ПК как СЕРВЕР")
print("=====================================================")
choice = input("Введите номер (1-5): ").strip()
if choice not in ["1", "2", "3", "4", "5"]:
print("[Demirast] Неверный выбор.")
input("\nНажмите Enter для выхода...")
return
state = {
"delay": 1.0 / 60,
"monitor_index": 0,
"current_monitor": None
}
client_socket = None
server_socket = None
if choice == "1":
ip = input("Введите IP-адрес телефона (отображается в приложении): ").strip()
port_str = input("Введите порт (по умолчанию 12345): ").strip()
port = int(port_str) if port_str else 12345
print(f"\n[Demirast] Ожидание запуска Wi-Fi сервера на телефоне ({ip}:{port})...")
print("Пожалуйста, запустите сервер на Android в приложении.")
print("Для выхода нажмите Ctrl+C.")
while True:
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.settimeout(2.0)
client_socket.connect((ip, port))
client_socket.settimeout(None)
print("[Demirast] Подключение к Wi-Fi серверу установлено!")
break
except (socket.timeout, ConnectionRefusedError, OSError):
time.sleep(1.0)
except KeyboardInterrupt:
print("\n[Demirast] Подключение отменено пользователем.")
return
elif choice == "2":
port_str = input("Введите порт для сервера на ПК (по умолчанию 12345): ").strip()
port = int(port_str) if port_str else 12345
try:
print(f"[Demirast] Запуск TCP сервера на ПК на порту {port}...")
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("0.0.0.0", port))
server_socket.listen(1)
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
pc_ip = s.getsockname()[0]
s.close()
except:
pc_ip = "127.0.0.1"
print(f"[Demirast] Сервер запущен. На телефоне введите IP: {pc_ip} и нажмите 'Подключиться'")
client_socket, addr = server_socket.accept()
print(f"[Demirast] Подключено мобильное устройство: {addr}")
except Exception as e:
print(f"[Demirast] Ошибка TCP сервера: {e}")
input("\nНажмите Enter для выхода...")
return
elif choice == "3":
port_str = input("Введите порт (по умолчанию 12345): ").strip()
port = int(port_str) if port_str else 12345
print("\n=== НАСТРОЙКА USB ПОДКЛЮЧЕНИЯ ===")
print("1. Подключите телефон к ПК по USB кабелю.")
print("2. Включите 'Отладка по USB' в настройках телефона.")
print("3. Выполните на ПК в командной строке (CMD / PowerShell):")
print(f" adb forward tcp:{port} tcp:{port}")
print("4. Нажмите 'Запустить Сервер на Android' в приложении телефона.")
input("\nКогда выполните шаги, нажмите ENTER для начала ожидания подключения...")
print(f"\n[Demirast] Ожидание запуска сервера на телефоне через порт USB (127.0.0.1:{port})...")
print("Для выхода нажмите Ctrl+C.")
while True:
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.settimeout(2.0)
client_socket.connect(("127.0.0.1", port))
client_socket.settimeout(None)
print("[Demirast] Подключение по USB кабелю установлено успешно!")
break
except (socket.timeout, ConnectionRefusedError, OSError):
time.sleep(1.0)
except KeyboardInterrupt:
print("\n[Demirast] Подключение отменено пользователем.")
return
elif choice == "4":
if not hasattr(socket, "AF_BLUETOOTH"):
print("[Demirast] Ошибка: Ваша версия Python или ОС не поддерживает AF_BLUETOOTH напрямую.")
print("Рекомендуется использовать Wi-Fi или USB-Кабель подключение (варианты 1, 2, 3)!")
input("\nНажмите Enter для выхода...")
return
addr = input("Введите MAC-адрес телефона (например, AA:BB:CC:DD:EE:FF): ").strip()
print(f"\n[Demirast] Ожидание запуска Bluetooth сервера на телефоне ({addr})...")
print("Для выхода нажмите Ctrl+C.")
while True:
try:
client_socket = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
client_socket.connect((addr, 1))
print("[Demirast] Успешно подключено по Bluetooth!")
break
except Exception:
time.sleep(1.5)
except KeyboardInterrupt:
print("\n[Demirast] Подключение отменено пользователем.")
return
elif choice == "5":
if not hasattr(socket, "AF_BLUETOOTH"):
print("[Demirast] Ошибка: Ваша версия Python или ОС не поддерживает AF_BLUETOOTH напрямую.")
print("Рекомендуется использовать Wi-Fi или USB-Кабель подключение (варианты 1, 2, 3)!")
input("\nНажмите Enter для выхода...")
return
try:
print("[Demirast] Запуск Bluetooth RFCOMM сервера на ПК...")
server_socket = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
server_socket.bind(("", 1))
server_socket.listen(1)
print("[Demirast] Сервер запущен. Нажмите в приложении 'Подключиться к ПК' (Клиент) через Bluetooth.")
client_socket, client_info = server_socket.accept()
print(f"[Demirast] Мобильный клиент подключился: {client_info}")
except Exception as e:
print(f"[Demirast] Ошибка Bluetooth сервера: {e}")
input("\nНажмите Enter для выхода...")
return
# Background thread to receive touch input, mouse clicks, and configuration from Android
def receive_inputs():
try:
while True:
cmd = client_socket.recv(1)
if not cmd:
break
if cmd == b'M': # Move
coords = client_socket.recv(8)
if len(coords) == 8:
x_ratio, y_ratio = struct.unpack('!ff', coords)
mon = state["current_monitor"]
if mon:
monitor_left = mon.get("left", 0)
monitor_top = mon.get("top", 0)
monitor_width = mon.get("width", 1920)
monitor_height = mon.get("height", 1080)
target_x = monitor_left + int(x_ratio * monitor_width)
target_y = monitor_top + int(y_ratio * monitor_height)
else:
screen_w, screen_h = pyautogui.size()
target_x = int(x_ratio * screen_w)
target_y = int(y_ratio * screen_h)
pyautogui.moveTo(target_x, target_y)
elif cmd == b'C': # Click
pyautogui.click()
elif cmd == b'F': # Frame rate configuration
fps_data = client_socket.recv(4)
if len(fps_data) == 4:
fps = struct.unpack('!i', fps_data)[0]
if 1 <= fps <= 144:
state["delay"] = 1.0 / fps
print(f"[Demirast] Частота трансляции изменена на {fps} Гц (интервал: {state['delay']:.4f} с)")
elif cmd == b'D': # Monitor Index configuration
mon_index_bytes = client_socket.recv(1)
if len(mon_index_bytes) == 1:
state["monitor_index"] = int(mon_index_bytes[0])
print(f"[Demirast] Выбранный экран изменен на: Экран {state['monitor_index'] + 1}")
except Exception as e:
print(f"[Demirast] Поток ввода остановлен: {e}")
threading.Thread(target=receive_inputs, daemon=True).start()
# Screen frames streaming loop
print("[Demirast] Запуск трансляции экрана...")
try:
with mss.MSS() as sct:
while True:
# Dynamic monitor selection
monitors = sct.monitors
idx = state["monitor_index"] + 1 # individual monitors start at 1
if idx < len(monitors):
monitor = monitors[idx]
else:
monitor = monitors[-1]
state["current_monitor"] = monitor
# Capture frame
sct_img = sct.grab(monitor)
img = Image.frombytes("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX")
# Compress screen size if it's too large
if img.width > 1280:
img = img.resize((1280, int(1280 * img.height / img.width)), Image.Resampling.BILINEAR)
# Compress image into highly optimized JPEG bytes
out_bytes = io.BytesIO()
img.save(out_bytes, format="JPEG", quality=55)
jpeg_data = out_bytes.getvalue()
# Send length header (4 bytes) + image bytes
length_prefix = len(jpeg_data).to_bytes(4, byteorder='big')
client_socket.sendall(length_prefix + jpeg_data)
# Sleep to match frame rate
time.sleep(state["delay"])
except Exception as e:
print(f"[Demirast] Трансляция завершена: {e}")
finally:
try:
client_socket.close()
except:
pass
if server_socket:
try:
server_socket.close()
except:
pass
print("[Demirast] Сессия завершена. Спасибо за использование!")
input("\nНажмите Enter для выхода...")
if __name__ == "__main__":
main()