Commit e4128d53 authored by Aral Balkan's avatar Aral Balkan
Browse files

Add --owncast integration to enable command

parent 09901417
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
const os = require('os') const os = require('os')
const fs = require('fs') const fs = require('fs-extra')
const path = require('path') const path = require('path')
const childProcess = require('child_process') const childProcess = require('child_process')
...@@ -78,14 +78,23 @@ function enable (args) { ...@@ -78,14 +78,23 @@ function enable (args) {
const sourceDirectory = path.resolve(__dirname, '..', '..') const sourceDirectory = path.resolve(__dirname, '..', '..')
const executable = runtime.isBinary ? binaryExecutable : `${childProcess.execSync('which node').toString().trim()} ${path.join(sourceDirectory, 'bin/site.js')}` const executable = runtime.isBinary ? binaryExecutable : `${childProcess.execSync('which node').toString().trim()} ${path.join(sourceDirectory, 'bin/site.js')}`
// It is a common mistake to start the server in a .dynamic folder (or subfolder) let pathToServe = args.positional[0]
// or a .hugo folder or subfolder. In these cases, try to recover and do the right thing.
let pathToServe
let absolutePathToServe let absolutePathToServe
if (args.positional[0].startsWith(':')) {
if (args.named['owncast']) {
console.log(' 💮️ ❨site.js❩ Owncast setup requested.')
// This is going to be a proxy server for Owncast (at its default port).
// Override any setting that might have been passed (it should not have been).
pathToServe = ':8080'
}
if (pathToServe.startsWith(':')) {
// This is a proxy server, leave as is. // This is a proxy server, leave as is.
absolutePathToServe = args.positional[0] absolutePathToServe = pathToServe
} else { } else {
// It is a common mistake to start the server in a .dynamic folder (or subfolder)
// or a .hugo folder or subfolder. In these cases, try to recover and do the right thing.
const paths = Util.magicallyRewritePathToServeIfNecessary(args.positional[0], _pathToServe) const paths = Util.magicallyRewritePathToServeIfNecessary(args.positional[0], _pathToServe)
pathToServe = paths.pathToServe pathToServe = paths.pathToServe
absolutePathToServe = paths.absolutePathToServe absolutePathToServe = paths.absolutePathToServe
...@@ -205,9 +214,89 @@ function enable (args) { ...@@ -205,9 +214,89 @@ function enable (args) {
} }
// //
// Save the systemd service unit. // Save the Site.js systemd service unit.
//
const systemdServicesDirectory = path.join('/', 'etc', 'systemd', 'system')
const siteJsServiceFilePath = path.join(systemdServicesDirectory, 'site.js.service')
fs.writeFileSync(siteJsServiceFilePath, unit, 'utf-8')
//
// Owncast integration. If the --owncast flag is supplied, also:
// - (a) install owncast if it doesn’t already exist.
// - (b) create and install the systemd unit for owncast if it doesn’t already exist.
// //
fs.writeFileSync('/etc/systemd/system/site.js.service', unit, 'utf-8') if (args.named['owncast']) {
console.log(' 💮️ ❨site.js❩ Setting up to serve your Owncast instance.')
// Is Owncast installed? If so, just use it.
// Otherwise, install it.
// Note: we expect Owncast to be installed in ~/owncast.
const owncastDirectory = path.join(Util.unprivilegedHomeDirectory(), 'owncast')
const owncastBinaryPath = path.join(owncastDirectory, 'owncast')
try {
fs.accessSync(owncastBinaryPath, fs.constants.X_OK)
} catch (error) {
// The Owncast binary is not where we expect it to be.
// Install Owncast there.
console.log(` 💮️ ❨site.js❩ Owncast installation not found at ${owncastDirectory}, running installation script…`)
// Ensure that the directory is empty and exists.
if (fs.existsSync(owncastDirectory)) {
console.log(` 💮️ ❨site.js❩ Owncast directory exists at ${owncastDirectory}, removing it before installation.`)
fs.removeSync(owncastDirectory)
}
try {
const owncastInstallationScript = path.resolve(path.join(__dirname, '..', 'sh', 'install-owncast.sh'))
childProcess.execSync(`OWNCAST_INSTALL_DIRECTORY=${owncastDirectory} ${owncastInstallationScript}`, {env: process.env, stdio: 'pipe'})
console.log(` 💮️ ❨site.js❩ Owncast installed at ${owncastDirectory}.`)
} catch (error) {
console.log(error, `\n ❌ ${clr('❨site.js❩ Error:', 'red')} Could not install Owncast.\n`)
process.exit(1)
}
}
console.log(' 💮️ ❨site.js❩ Owncast installation is OK.')
// Is the Owncast service installed? If so, leave it be.
// Otherwise, install it.
const owncastServiceFilePath = path.join(systemdServicesDirectory, 'owncast.service')
if (!fs.existsSync(owncastServiceFilePath)) {
// Create Owncast service unit based on template at
// https://github.com/owncast/owncast/blob/develop/examples/owncast-sample.service
const owncastUnit = `
[Unit]
Description=Owncast
[Service]
Type=simple
WorkingDirectory=${owncastDirectory}
ExecStart=${owncastBinaryPath}
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
`
fs.writeFileSync(owncastServiceFilePath, owncastUnit, 'utf-8')
}
console.log(' 💮️ ❨site.js❩ Owncast service unit is installed.')
// Also start the Owncast service.
try {
// Start.
childProcess.execSync('sudo systemctl start owncast', {env: process.env, stdio: 'pipe'})
console.log(` 💮️ ❨site.js❩ Owncast launched as daemon.`)
// Enable.
childProcess.execSync('sudo systemctl enable owncast', {env: process.env, stdio: 'pipe'})
console.log(` 💮️ ❨site.js❩ Owncast daemon installed for auto-launch at startup.`)
} catch (error) {
console.log(error, `\n ❌ ${clr('❨site.js❩ Error:', 'red')} Could not enable Owncast server.\n`)
process.exit(1)
}
}
// Pre-flight check: run the server normally and ensure that it starts up properly // Pre-flight check: run the server normally and ensure that it starts up properly
// before installing it as a daemon. If there are any issues we want to catch it here // before installing it as a daemon. If there are any issues we want to catch it here
...@@ -230,7 +319,7 @@ function enable (args) { ...@@ -230,7 +319,7 @@ function enable (args) {
// //
// Enable and start systemd service. // Enable and start the Site.js systemd service.
// //
try { try {
// Start. // Start.
......
#!/usr/bin/env bash
# shellcheck disable=SC2059
set -o errexit
set -o nounset
set -o pipefail
# Install configuration
if ! [ "${OWNCAST_VERSION:-}" ]; then
OWNCAST_VERSION="0.0.6"
fi
if ! [ "${OWNCAST_INSTALL_DIRECTORY:-}" ]; then
OWNCAST_INSTALL_DIRECTORY="$(pwd)/owncast"
fi
INSTALL_TEMP_DIRECTORY="$(mktemp -d)"
# Set up an exit handler so we can print a help message on failures.
_success=false
shutdown () {
if [ $_success = false ]; then
printf "Your Owncast installation did not complete successfully.\n"
printf "Please report your issue at https://github.com/owncast/owncast/issues\n"
fi
rm -rf "$INSTALL_TEMP_DIRECTORY"
}
trap shutdown INT TERM ABRT EXIT
# Formatting escape codes.
RED='\033[0;31m'
PURPLE='\033[0;35m'
BLUE='\033[1;34m'
GREEN='\033[1;32m'
BOLD='\033[1m'
UNDERLINE='\033[4m'
NC='\033[0m' # No Color
# Activity spinner for background processes.
spinner() {
local -r delay='0.3'
local spinstr='\|/-'
local temp
while ps -p "$1" >> /dev/null; do
temp="${spinstr#?}"
printf " [${BLUE}%c${NC}] " "${spinstr}"
spinstr=${temp}${spinstr%"${temp}"}
sleep "${delay}"
printf "\b\b\b\b\b\b"
done
printf "\r"
}
# Print an error message and exit the program.
errorAndExit() {
printf "${RED}ERROR:${NC} %s" "$1"
exit 1;
}
# Check for a required tool, or exit
requireTool() {
which "$1" >> /dev/null && EC=$? || EC=$?
if [ $EC != 0 ]; then
errorAndExit "Could not locate \"$1\", which is required for installation. Please it install it on your system."
fi
}
# Backup the existing install
backupInstall() {
BACKUP_STAGING="$(mktemp -d)"
mkdir ${BACKUP_STAGING}/backup
BACKUP_DIR="backup"
TIMESTAMP=$(date +%s)
BACKUP_FILE="${TIMESTAMP}-v${OWNCAST_VERSION}".tar.gz
printf "${BLUE}Backing up${NC} your files before upgrading to v${OWNCAST_VERSION}"
FILE_LIST=(
"webroot/*.html"
"webroot/styles/"
"webroot/js"
"webroot/img"
"data/"
"*.yaml"
)
# Make backup directory if it doesn't exist
[[ -d $BACKUP_DIR ]] || mkdir $BACKUP_DIR
for i in "${FILE_LIST[@]}"
do
:
cp -r ${FILE_LIST[@]} ${BACKUP_STAGING}/backup
done
pushd ${BACKUP_STAGING} >> /dev/null
tar zcf ${BACKUP_FILE} backup & >> /dev/null
spinner $!
popd >> /dev/null
mv ${BACKUP_STAGING}/${BACKUP_FILE} backup/
rm -rf ${BACKUP_STAGING}
printf "${BLUE}Backed up${NC} your files before upgrading to v${OWNCAST_VERSION} [${GREEN}${NC}]\n"
}
main () {
printf "${PURPLE}${BOLD}Owncast Installer v%s ${NC}\n\n" "$OWNCAST_VERSION"
requireTool "curl"
requireTool "unzip"
requireTool "tar"
requireTool "which"
# Determine operating system & architecture
case $(uname -s) in
"Darwin")
OWNCAST_ARCH="64bit"
PLATFORM="macOS"
FFMPEG_VERSION="4.3.1"
FFMPEG_DOWNLOAD_URL="https://evermeet.cx/ffmpeg/ffmpeg-${FFMPEG_VERSION}.zip"
FFMPEG_TARGET_FILE="${INSTALL_TEMP_DIRECTORY}/ffmpeg.zip"
;;
"Linux")
case "$(uname -m)" in
"x86_64")
FFMPEG_ARCH="linux-x64"
OWNCAST_ARCH="64bit"
;;
i?86)
FFMPEG_ARCH="linux-ia32"
OWNCAST_ARCH="32bit"
;;
armv7?)
FFMPEG_ARCH="linux-arm"
OWNCAST_ARCH="arm7"
;;
*)
errorAndExit "Unsupported CPU architecture $(uname -m)"
;;
esac
PLATFORM="linux"
FFMPEG_VERSION="b4.3.1"
FFMPEG_DOWNLOAD_URL="https://github.com/eugeneware/ffmpeg-static/releases/download/${FFMPEG_VERSION}/${FFMPEG_ARCH}"
FFMPEG_TARGET_FILE="${OWNCAST_INSTALL_DIRECTORY}/ffmpeg"
;;
*)
errorAndExit "Unsupported operating system $(uname -s)"
;;
esac
# Build release download URL
OWNCAST_URL="https://github.com/owncast/owncast/releases/download/v${OWNCAST_VERSION}/owncast-${OWNCAST_VERSION}-${PLATFORM}-${OWNCAST_ARCH}.zip"
OWNCAST_TARGET_FILE="${INSTALL_TEMP_DIRECTORY}/owncast-${OWNCAST_VERSION}-${PLATFORM}-${OWNCAST_ARCH}.zip"
# If the install directory exists already then cd into it and upgrade
if [[ -d "$OWNCAST_INSTALL_DIRECTORY" && -x "$OWNCAST_INSTALL_DIRECTORY/owncast" ]]; then
printf "${BLUE}Existing install found${NC} in ${OWNCAST_INSTALL_DIRECTORY}. Will update it to v${OWNCAST_VERSION}. If this is incorrect remove the directory and rerun the installer.\n"
cd $OWNCAST_INSTALL_DIRECTORY
OWNCAST_INSTALL_DIRECTORY="./"
backupInstall
# If the owncast binary exists then upgrade
elif [ -x ./owncast ]; then
printf "${BLUE}Existing install found${NC} in this directory. Will update it to v${OWNCAST_VERSION}. If this is incorrect remove the directory and rerun the installer.\n"
backupInstall
OWNCAST_INSTALL_DIRECTORY="./"
else
# Create target directory
mkdir -p "$OWNCAST_INSTALL_DIRECTORY"
printf "${GREEN}Created${NC} directory [${GREEN}${NC}]\n"
fi
# Download release
printf "${BLUE}Downloading${NC} Owncast v${OWNCAST_VERSION} for ${PLATFORM}"
curl -s -L ${OWNCAST_URL} --output "${OWNCAST_TARGET_FILE}" &
spinner $!
printf "${GREEN}Downloaded${NC} Owncast v${OWNCAST_VERSION} for ${PLATFORM} [${GREEN}${NC}]\n"
# Unzip release
unzip -oq "$OWNCAST_TARGET_FILE" -d "$OWNCAST_INSTALL_DIRECTORY"
# Delete release zip file
rm "$OWNCAST_TARGET_FILE"
# Check for ffmpeg
which ffmpeg >> /dev/null && EC=$? || EC=$?
if [ $EC -ne 0 ]; then
# Download ffmpeg
printf "${BLUE}Downloading${NC} ffmpeg v${FFMPEG_VERSION} "
curl -s -L ${FFMPEG_DOWNLOAD_URL} --output "${FFMPEG_TARGET_FILE}" &
spinner $!
printf "${GREEN}Downloaded${NC} ffmpeg because it was not found on your system [${GREEN}${NC}]\n"
if [[ "$FFMPEG_TARGET_FILE" == *.zip ]]; then
unzip -oq "$FFMPEG_TARGET_FILE" -d "$OWNCAST_INSTALL_DIRECTORY"
rm "$FFMPEG_TARGET_FILE"
fi
chmod u+x "${OWNCAST_INSTALL_DIRECTORY}/ffmpeg"
fi
_success=true
printf "\n"
printf "${GREEN}Success!${NC} Run owncast by changing to the ${BOLD}owncast${NC} directory and run ${BOLD}./owncast${NC}.\n"
printf "The default port is ${BOLD}8080${NC} and the default streaming key is ${BOLD}abc123${NC}.\n"
printf "Visit ${UNDERLINE}https://owncast.online/docs/configuration/${NC} to learn how to configure your new Owncast server."
printf "\n\n"
}
main
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment