Last active
March 26, 2025 02:41
-
-
Save udance4ever/9fbd6f2044e1daac388b875e67c7fd4b to your computer and use it in GitHub Desktop.
macOS (& Linux) RPCS3 launcher that handles .ps3.squashfs & PSN dev mounts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse | |
import os | |
import atexit | |
import platform | |
import re | |
# boolean: https://stackoverflow.com/a/52403318/9983389 | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--tmpmount", help='mount in /tmp', default=False, action='store_true') | |
parser.add_argument("--app", help='specify custom executable') | |
parser.add_argument("file") | |
parser.add_argument("--devmount", help='mount in dev_hdd0/game', default=False, action='store_true') | |
parser.add_argument("--intel", help='use Intel executable', default=False, action='store_true') | |
args = parser.parse_args() | |
mount = None | |
def exit_handler(): | |
if mount: | |
if os.path.exists(mount): | |
if os.path.ismount(mount): | |
print("Unmounting and removing:", mount) | |
os.system('umount "{}"'.format(mount)) | |
os.rmdir(mount) | |
atexit.register(exit_handler) | |
file = args.file | |
if not os.path.exists(file): | |
print(file, "not found. Exiting.") | |
exit(1) | |
devpath = "/Users/Shared/system/configs/rpcs3/dev_hdd0/game/" | |
devmount = False | |
rompath = file | |
if file.endswith(".squashfs"): | |
(mount, ext) = os.path.splitext(file) | |
# https://stackoverflow.com/a/8569258/9983389 | |
serial = None | |
m = re.search(r"\[hdd0,([A-Za-z0-9_]+)\]", mount) | |
if m: | |
serial = m.group(1) | |
print("Found serial:", serial) | |
# $$ hack to redirect mount to dev_hdd0/game if "[hdd0,<serial>]" in filename | |
if args.devmount or serial: | |
devmount = True | |
if devmount: | |
if not serial: | |
print("no serial in filename to mount in dev_hdd0/game. Exiting") | |
exit(1) | |
mount = devpath + serial | |
# https://stackoverflow.com/a/2113511/9983389 | |
if (not os.access(os.path.dirname(os.path.realpath(mount)), os.W_OK)) or args.tmpmount: | |
mount = "/tmp/ps3Launch.{}.ps3".format(os.getpid()) | |
print("Using mount:", mount) | |
if not os.path.exists(mount): | |
os.mkdir(mount) | |
elif os.path.ismount(mount): | |
print("unmounting:", mount) | |
os.system("umount '{}'".format(mount)) | |
cmd = '/usr/local/bin/squashfuse "{}" "{}"'.format(file, mount) | |
print("cmd:", cmd) | |
status = os.system(cmd) | |
if status != 0: | |
print("Failed to mount:", file) | |
exit(1) | |
# https://learnpython.com/blog/python-if-in-one-line/ | |
r = "r" if os.access(mount, os.R_OK) else "-" | |
w = "w" if os.access(mount, os.W_OK) else "-" | |
x = "x" if os.access(mount, os.X_OK) else "-" | |
print("permissions: {}{}{}".format(r,w,x)) | |
if not os.access(mount, os.R_OK | os.X_OK): | |
print("Mounted file system inaccessible ({}{}{}):".format(r,w,x), mount) | |
print(" You may need to run `mksquashfs source FILESYSTEM -all-root`") | |
exit(1) | |
# override | |
rompath = mount | |
# --- | |
if rompath.endswith(".psn"): | |
handle = open(rompath, "r") | |
serial = handle.read() | |
rompath = devpath + serial.rstrip() | |
elif not rompath.endswith(".ps3") and not devmount: | |
print(rompath, "not .ps3 folder. Exiting.") | |
exit(1) | |
app = None | |
if args.app: | |
app = args.app | |
elif platform.uname().system == "Linux": | |
app = '/mnt/dev/bin/rpcs3' | |
else: | |
if args.intel: | |
app = '/Applications/#emu/RPCS3 (Intel).app/Contents/MacOS/rpcs3' | |
else: | |
app = '/Applications/#emu/RPCS3.app/Contents/MacOS/rpcs3' | |
if not os.path.exists(app): | |
print("app '{}' does not exist. Exiting.".format(app)) | |
exit(1) | |
cmd = '"{}" --no-gui "{}"'.format(app, rompath) | |
# --- | |
print("cmd:", cmd) | |
status = os.system(cmd) | |
if status != 0: | |
print("{} failed to exit cleanly (status={})".format(cmd.split()[0], status)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment