149 lines
4.9 KiB
Python
149 lines
4.9 KiB
Python
import os
|
|
import random
|
|
import string
|
|
from configparser import ConfigParser, DuplicateSectionError, NoOptionError
|
|
|
|
|
|
def moonlight_config_dir() -> str:
|
|
return os.path.join(
|
|
os.path.expanduser("~"), ".config", "Moonlight Game Streaming Project"
|
|
)
|
|
|
|
|
|
def moonlight_state_file() -> str:
|
|
return os.path.join(moonlight_config_dir(), "Moonlight.conf")
|
|
|
|
|
|
def load_state() -> ConfigParser | None:
|
|
try:
|
|
with open(moonlight_state_file()) as file:
|
|
config = ConfigParser()
|
|
config.read_file(file)
|
|
print(config.sections())
|
|
return config
|
|
except FileNotFoundError:
|
|
print("Sunshine state file not found.")
|
|
return None
|
|
|
|
|
|
# prepare the string for the config file
|
|
# this is how qt handles byte arrays
|
|
def convert_string_to_bytearray(data: str) -> str:
|
|
byte_array = '"@ByteArray('
|
|
byte_array += data.replace("\n", "\\n")
|
|
byte_array += ')"'
|
|
return byte_array
|
|
|
|
|
|
def convert_bytearray_to_string(byte_array: str) -> str:
|
|
if byte_array.startswith('"@ByteArray(') and byte_array.endswith(')"'):
|
|
byte_array = byte_array[12:-2]
|
|
return byte_array.replace("\\n", "\n")
|
|
|
|
|
|
# this must be created before moonlight is first run
|
|
def init_state(certificate: str, key: str) -> None:
|
|
print("Initializing moonlight state.")
|
|
os.makedirs(moonlight_config_dir(), exist_ok=True)
|
|
print("Initialized moonlight config directory.")
|
|
|
|
print("Writing moonlight state file.")
|
|
# write the initial bootstrap config file
|
|
with open(moonlight_state_file(), "w") as file:
|
|
config = ConfigParser()
|
|
# bytearray ojbects are not supported by ConfigParser,
|
|
# so we need to adjust them ourselves
|
|
config.add_section("General")
|
|
config.set("General", "certificate", convert_string_to_bytearray(certificate))
|
|
config.set("General", "key", convert_string_to_bytearray(key))
|
|
config.set("General", "latestsupportedversion-v1", "99.99.99.99")
|
|
config.add_section("gcmapping")
|
|
config.set("gcmapping", "size", "0")
|
|
|
|
config.write(file)
|
|
|
|
|
|
def write_state(data: ConfigParser) -> bool:
|
|
with open(moonlight_state_file(), "w") as file:
|
|
data.write(file)
|
|
|
|
|
|
def add_sunshine_host_to_parser(
|
|
config: ConfigParser, hostname: str, manual_host: str, certificate: str, uuid: str
|
|
) -> bool:
|
|
try:
|
|
config.add_section("hosts")
|
|
except DuplicateSectionError:
|
|
pass
|
|
|
|
# amount of hosts
|
|
try:
|
|
no_hosts = int(config.get("hosts", "size"))
|
|
except NoOptionError:
|
|
no_hosts = 0
|
|
|
|
new_host = no_hosts + 1
|
|
|
|
config.set("hosts", f"{new_host}\srvcert", convert_string_to_bytearray(certificate))
|
|
config.set("hosts", "size", str(new_host))
|
|
config.set("hosts", f"{new_host}\\uuid", uuid)
|
|
config.set("hosts", f"{new_host}\hostname", hostname)
|
|
config.set("hosts", f"{new_host}\\nvidiasv", "false")
|
|
config.set("hosts", f"{new_host}\customname", "false")
|
|
config.set("hosts", f"{new_host}\manualaddress", manual_host)
|
|
config.set("hosts", f"{new_host}\manualport", "47989")
|
|
config.set("hosts", f"{new_host}\\remoteport", "0")
|
|
config.set("hosts", f"{new_host}\\remoteaddress", "")
|
|
config.set("hosts", f"{new_host}\localaddress", "")
|
|
config.set("hosts", f"{new_host}\localport", "0")
|
|
config.set("hosts", f"{new_host}\ipv6port", "0")
|
|
config.set("hosts", f"{new_host}\ipv6address", "")
|
|
config.set(
|
|
"hosts", f"{new_host}\mac", convert_string_to_bytearray("\\xceop\\x8d\\xfc{")
|
|
)
|
|
add_app(config, "Desktop", new_host, 1, 881448767)
|
|
add_app(config, "Low Res Desktop", new_host, 2, 303580669)
|
|
add_app(config, "Steam Big Picture", new_host, 3, 1093255277)
|
|
|
|
print(config.items("hosts"))
|
|
return True
|
|
|
|
|
|
# set default apps for the host for now
|
|
# TODO: do this dynamically
|
|
def add_app(
|
|
config: ConfigParser, name: str, host_id: int, app_id: int, app_no: int
|
|
) -> None:
|
|
identifier = f"{host_id}\\apps\{app_id}\\"
|
|
config.set("hosts", f"{identifier}appcollector", "false")
|
|
config.set("hosts", f"{identifier}directlaunch", "false")
|
|
config.set("hosts", f"{identifier}hdr", "false")
|
|
config.set("hosts", f"{identifier}hidden", "false")
|
|
config.set("hosts", f"{identifier}id", f"{app_no}")
|
|
config.set("hosts", f"{identifier}name", f"{name}")
|
|
|
|
|
|
def get_moonlight_certificate() -> str:
|
|
config = load_state()
|
|
if config is None:
|
|
raise FileNotFoundError("Moonlight state file not found.")
|
|
certificate = config.get("General", "certificate")
|
|
certificate = convert_bytearray_to_string(certificate)
|
|
return certificate
|
|
|
|
|
|
def gen_pin() -> str:
|
|
return "".join(random.choice(string.digits) for _ in range(4))
|
|
|
|
|
|
def add_sunshine_host(
|
|
hostname: str, manual_host: str, certificate: str, uuid: str
|
|
) -> bool:
|
|
config = load_state()
|
|
if config is None:
|
|
return False
|
|
hostname = "test"
|
|
add_sunshine_host_to_parser(config, hostname, manual_host, certificate, uuid)
|
|
write_state(config)
|
|
return True
|