There are multiple possible methods:
Method 1:
@DanielB does give the simplest answer. Put a loop around your script.
Method 2:
The more elegant would be to make a launchd .plist file and put it in (not link it in) /Library/LaunchDaemons
.
An elementary .plist
would look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.jvc.streambaby</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/your/script</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>StandardOutPath</key>
<string>/dev/null</string>
</dict>
</plist>
You can load up the plist with sudo launchctl load -w /Library/LaunchDaemons/com.jvc.streambaby.plist
if you have named your .plist file as com.jvc.streambaby.plist
, of course!
Note: Please change /dev/null
to some real file path if you need to save the error and output streams as logs.
Method 3:
The most disguisting and visual method would be to use Automator to execute your script. There must be a way to restart your script somewhere in there. But who in their right mind uses a GUI when you can script anyway!
There may be other methods, but I am not an Apple guy anyway so don't know.
Method 4:
Here is a small script:
Be sure to change the variables, especially the streambaby root directory and run it with python3 (made with Python 3.9.x on linux).
#!/usr/bin/env python3
# set the path to the streambaby directory
# do not add a trailing slash (/)
streambaby_home = "/home/<username>/streambaby"
import subprocess
import signal
import sys
import os
from pathlib import Path
# variable to keep track if the app should restart
# True by default
should_run = True
# everything should be made visible immediately
os.environ["PYTHONUNBUFFERED"] = "1"
# copy the current environment
proc_env = os.environ.copy()
# is this really necessary, but was in the batch file so....
proc_env["LAUNCHDIR"] = str(Path.home())
# split the whole command into a list
exec_cmd = [
'java',
'-Djava.net.preferIPv4Stack=true',
'-Xmx256m', # don't know why this argument is added twice
'-Xmx256m',
'-jar',
'{0}/jbin/streambaby.jar'.format(streambaby_home)
]
# put the subprocess execution in a function for cleanliness
# return the process handle
def runapp(cmd, env):
return subprocess.Popen(
cmd, # the command to execute
env=env, # setup the environment variables
shell=False, # not using a shell, change to True if doesn't work
stdout = subprocess.PIPE, # pipe the console output so we can read it
stderr = subprocess.STDOUT, # somethings pop up on stderr, we send them to stdout anyway
start_new_session=True # using a session makes the whole set of processes easier to kill
# works only on *nix type systems
)
# now we start the program in a loop and poll() the hell out of it
while should_run:
proc = runapp(exec_cmd, proc_env)
while True:
stdout_string = str(proc.stdout.readline())
if proc.poll() is not None: # poll returns None while the process is executing
break
if stdout_string != '':
print(stdout_string) # if someone wants to see the output anyway
if "run() exception" in stdout_string.strip(): # only checking for those 2 words
# we have hit a snag; kill it
# ...(evil laugh)...
# SIGKILL is my favorite type of signal
# sounds badass
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
elif " Could not create the Java Virtual Machine" in stdout_string:
# if the Java VM fails to start, there is no point in trying anymore
should_run = False
# get the return code
return_code = proc.poll()
print("The process exited with exit_code ( {0} )".format(return_code))
# a normal process which terminates properly should return 0
# I think we may need to change this
# don't know what streambaby should be returning
if return_code == 0 and should_run:
# if the process exits normally, don't restart the process
should_run = False
until
. if the app you are running returns a non-success ( not zero) return code,until
will run the command again. linuxize.com/post/bash-until-loop