Files
2026-09-26 12:00:41 +02:00

228 lines
6.8 KiB
Python

# https://git.krzak.org/N0VA/ESharePy/raw/branch/main/main.py
import sys
import os
import socket
import struct
import time
# Standard KeyCodes
KEY_MAP = {
'w': (19, "DPAD_UP"),
's': (20, "DPAD_DOWN"),
'a': (21, "DPAD_LEFT"),
'd': (22, "DPAD_RIGHT"),
' ': (23, "DPAD_CENTER (OK)"),
'e': (23, "DPAD_CENTER (OK)"),
'\r': (23, "DPAD_CENTER (OK)"),
'\n': (23, "DPAD_CENTER (OK)"),
'b': (4, "BACK"),
'h': (3, "HOME"),
'+': (24, "VOLUME_UP"),
'=': (24, "VOLUME_UP"),
'-': (25, "VOLUME_DOWN"),
'_': (25, "VOLUME_DOWN"),
'0': (164, "VOLUME_MUTE"),
}
def get_broadcast_addresses():
broadcasts = {'255.255.255.255'}
try:
with open('/proc/net/route') as f:
for line in f.readlines()[1:]:
fields = line.strip().split()
dest = fields[1]
mask = fields[7]
if dest == '00000000':
continue
d = int(dest, 16)
m = int(mask, 16)
b = (d & m) | (~m & 0xFFFFFFFF)
broadcasts.add(socket.inet_ntoa(struct.pack('<I', b)))
except Exception:
pass
return list(broadcasts)
def discover(timeout=2.5):
print("Searching for compatible TVs on the local network (UDP 48689)...")
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
try:
sock.bind(('', 48689))
except Exception as e:
print(f"Warning: Could not bind to port 48689 ({e})")
sock.settimeout(timeout)
packet = bytearray(50)
magic = b"FindECloudBox"
struct.pack_into(">IIIII", packet, 0, 0, 0, 0, len(magic), 0)
packet[20:20 + len(magic)] = magic
for bcast in get_broadcast_addresses():
try:
sock.sendto(packet, (bcast, 48689))
except Exception:
pass
t_end = time.time() + timeout
found_devices = []
while time.time() < t_end:
try:
data, addr = sock.recvfrom(1024)
reply = data.decode("utf-8", errors="ignore")
if reply.startswith("ECloudBox"):
parts = reply.split(":")
name = parts[1] if len(parts) > 1 else "Unknown"
port = int(parts[2]) if len(parts) > 2 and parts[2].isdigit() else 8121
device = (addr[0], port, name)
if device not in found_devices:
found_devices.append(device)
print(f"Found TV: '{name}' at {addr[0]}:{port}")
except socket.timeout:
break
except Exception:
pass
sock.close()
return found_devices
def connect(ip, port=8121):
print(f"Connecting to {ip}:{port}...")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
sock.connect((ip, port))
sock.sendall(b"getServerInfo\r\neshare\r\n\r\n")
try:
resp = sock.recv(1024).decode("utf-8", errors="ignore")
if resp.strip():
print(f"Server response: {resp.strip()[:100]}")
except socket.timeout:
pass
sock.sendall(b"GETPASSWORDCONFIG\r\neshare\r\n\r\n")
try:
resp = sock.recv(1024).decode("utf-8", errors="ignore")
except socket.timeout:
pass
sock.sendall(b"sayHello\r\nEShareClient\r\n\r\n")
print("Handshake complete! Connected.")
return sock
def send_key(sock, keycode):
cmd = f"KEYEVENT\r\n{keycode}\r\n\r\n".encode("utf-8")
sock.sendall(cmd)
def send_text(sock, text):
escaped = text.replace("\\", "\\\\").replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t")
cmd = f"CONTENT\r\n1\r\n{escaped}\r\n\r\n".encode("utf-8")
sock.sendall(cmd)
def getch():
if not sys.stdin.isatty():
line = sys.stdin.readline()
return line[0] if line else 'q'
import tty, termios
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
if ch == '\x1b':
ch2 = sys.stdin.read(1)
if ch2 == '[':
ch3 = sys.stdin.read(1)
arrows = {'A': 'w', 'B': 's', 'C': 'd', 'D': 'a'}
return arrows.get(ch3, '')
return ch
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
def print_help():
print("\n--- Controls ---")
print(" [W / ↑] Up [S / ↓] Down")
print(" [A / ←] Left [D / →] Right")
print(" [Space/E/Enter] OK [B] Back")
print(" [H] Home [0] Mute")
print(" [+] Vol Up [-] Vol Down")
print(" [T] Type text [Q] Quit")
print("----------------\n")
def main():
tv_ip = None
tv_port = 8121
if len(sys.argv) > 1:
tv_ip = sys.argv[1]
if len(sys.argv) > 2:
tv_port = int(sys.argv[2])
else:
devices = discover()
if not devices:
print("No TVs discovered.")
tv_ip = input("Enter TV IP address manually: ").strip()
elif len(devices) == 1:
tv_ip, tv_port, name = devices[0]
print(f"Auto-selected TV: '{name}' ({tv_ip}:{tv_port})")
else:
print(f"\nFound {len(devices)} TVs:")
for idx, (ip, port, name) in enumerate(devices, 1):
print(f" [{idx}] {name} ({ip}:{port})")
choice = input(f"Select TV [1-{len(devices)}] (default 1): ").strip()
idx = int(choice) - 1 if choice.isdigit() and 1 <= int(choice) <= len(devices) else 0
tv_ip, tv_port, name = devices[idx]
print(f"Selected TV: '{name}' ({tv_ip}:{tv_port})")
if not tv_ip:
print("No IP provided. Exiting.")
return
sock = connect(tv_ip, tv_port)
print_help()
try:
while True:
ch = getch()
if not ch:
continue
lower_ch = ch.lower()
if lower_ch == 'q' or ch == '\x03':
print("\nExiting...")
break
if lower_ch == 't':
print()
text = input("Enter text to send to TV (keyboard input): ")
if text:
send_text(sock, text)
print(f"Sent text: {repr(text)}")
continue
if lower_ch in KEY_MAP:
keycode, name = KEY_MAP[lower_ch]
send_key(sock, keycode)
print(f"Sent: {name} (code {keycode})", flush=True)
else:
print(f"Unknown key: {repr(ch)} (type 'q' to quit)", flush=True)
except KeyboardInterrupt:
print("\nInterrupted.")
except Exception as e:
print(f"\nConnection error: {e}")
finally:
try:
sock.close()
except:
pass
if __name__ == "__main__":
main()