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

Owncast installation script is now native Node.js

Removes need for curl and unzip dependencies.
parent 3be6eb11
......@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [16.4.1] - 2021-04-17
### Fixed
- Owncast installation no longer requires the server to have any dependencies. Previously, it would fail if the server didn’t have curl and unzip installed.
## [16.4.0] - 2021-04-15
### Added
......
......@@ -232,9 +232,6 @@ const resources = [
// Not sure if this is a different regression in Nexe 4’s resolve dependencies.
// Afaik, it was being included correctly before.
'node_modules/@small-tech/instant/client/bundle.js',
// Bundle the Owncast installation script.
'bin/sh/install-owncast.sh',
]
const input = 'bin/site.js'
......
......@@ -21,6 +21,7 @@ const status = require('../lib/status')
const runtime = require('../lib/runtime')
const ensure = require('../lib/ensure')
const clr = require('../../lib/clr')
const installOwncast = require('../lib/install-owncast')
const Util = require('../../lib/Util')
const Site = require('../../index')
......@@ -61,7 +62,7 @@ function enable (args) {
// is already in use and, if it is, refuse to install and activate the
// service. This is should provide the least amount of surprise in usage.
tcpPortUsed.check(443)
.then(inUse => {
.then(async inUse => {
if (inUse) {
console.log(`\n ❌ ${clr('❨site.js❩ Error:', 'red')} Cannot start daemon. Port 443 is already in use.\n`)
process.exit(1)
......@@ -246,23 +247,10 @@ function enable (args) {
} 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)
}
console.log(` 💮️ ❨site.js❩ Owncast installation not found at ${owncastDirectory}.`)
try {
// Copy the installation script to our settings directory
// and run it from there (for when we’re running from within a Nexe bundle).
const internalOwncastInstallationScriptPath = path.resolve(path.join(__dirname, '..', 'sh', 'install-owncast.sh'))
const installationScript = fs.readFileSync(internalOwncastInstallationScriptPath, 'utf-8')
const externalOwncastInstallationScriptPath = path.join(Site.settingsDirectory, 'install-owncast.sh')
fs.writeFileSync(externalOwncastInstallationScriptPath, installationScript, {encoding: 'utf-8', mode: 0o755})
childProcess.execSync(`OWNCAST_INSTALL_DIRECTORY=${owncastDirectory} ${externalOwncastInstallationScriptPath}`, {env: process.env, stdio: 'pipe'})
console.log(` 💮️ ❨site.js❩ Owncast installed at ${owncastDirectory}.`)
await installOwncast(owncastDirectory)
} catch (error) {
console.log(error, `\n ❌ ${clr('❨site.js❩ Error:', 'red')} Could not install Owncast.\n`)
process.exit(1)
......
////////////////////////////////////////////////////////////////////////////////
//
// Node.js version of the Owncast installation script.
// (With minor differences.)
//
// Copyright (C) 2021-present Aral Balkan, Small Technology Foundation
// Released under AGPL version 3.0
//
////////////////////////////////////////////////////////////////////////////////
const os = require('os')
const fs = require('fs-extra')
const path = require('path')
const process = require('process')
const fetch = require('node-fetch')
const unzip = require('extract-zip')
async function installOwncast(owncastInstallDirectory) {
const owncastVersion = '0.0.6'
const tempDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'owncast-'))
console.log(` 💮️ ❨site.js❩ Installing Owncast version ${owncastVersion}…`)
let owncastArch, owncastPlatform
let ffmpegArch, ffmpegVersion, ffmpegDownloadUrl, ffmpegTargetFile
const platform = os.platform()
switch (platform) {
case 'darwin':
owncastArch = '64bit'
owncastPlatform = 'macOS'
ffmpegVersion = '4.3.1'
ffmpegDownloadUrl = `https://evermeet.cx/ffmpeg/ffmpeg-${ffmpegVersion}.zip`
ffmpegTargetFile = `${tempDirectory}/ffmpeg.zip`
break;
case 'linux':
switch (process.arch) {
case 'x64':
ffmpegArch = 'linux-x64'
owncastArch = '64bit'
break
case 'ia86':
ffmpegArch = 'linux-ia32'
owncastArch = '32bit'
break
case 'arm':
if (process.config.variables.arm_version === '7') {
ffmpegArch = 'linux-arm'
owncastArch = 'arm7'
}
break
default:
throw new Error(`Architecture ${process.arch}${process.config.variables.arm_version !== undefined ? `v${process.config.variables.arm_version}`: ''} is not supported by Owncast.`)
break
}
owncastPlatform = 'linux'
ffmpegVersion = 'b4.3.1'
ffmpegDownloadUrl = `https://github.com/eugeneware/ffmpeg-static/releases/download/${ffmpegVersion}/${ffmpegArch}`
ffmpegTargetFile = path.join(owncastInstallDirectory, 'ffmpeg')
break
default:
throw new Error(`Platform ${platform} is not supported by Owncast.`)
}
// Build release download URL
const owncastDownloadUrl = `https://github.com/owncast/owncast/releases/download/v${owncastVersion}/owncast-${owncastVersion}-${owncastPlatform}-${owncastArch}.zip`
const owncastTargetFile = `${tempDirectory}/owncast-${owncastVersion}-${owncastPlatform}-${owncastArch}.zip`
// Backup existing Owncast folder, if it exists
if (fs.existsSync(owncastInstallDirectory)) {
console.log(' 💮️ ❨site.js❩ Found existing Owncast directory. Backing it up…')
const backup = `${owncastInstallDirectory}-backup-${Date.now()}`
fs.moveSync(owncastInstallDirectory, backup)
}
// Make the installation directory.
fs.ensureDirSync(owncastInstallDirectory)
// Download Owncast release.
console.log(' 💮️ ❨site.js❩ Downloading Owncast release binary (zip)…')
const owncastZip = await (await fetch(owncastDownloadUrl)).buffer()
fs.writeFileSync(owncastTargetFile, owncastZip, {encoding: 'binary'})
// Unzip Owncast release.
console.log(' 💮️ ❨site.js❩ Unzipping Owncast release binary…')
await unzip(owncastTargetFile, {dir: owncastInstallDirectory})
// Download ffmpeg.
console.log(` 💮️ ❨site.js❩ Downloading Owncast dependency ffmpeg (version ${ffmpegVersion})…`)
const ffmpeg = await (await fetch(ffmpegDownloadUrl)).buffer()
fs.writeFileSync(ffmpegTargetFile, ffmpeg, {encoding: 'binary', mode: 755})
console.log(` 💮️ ❨site.js❩ Owncast installed at ${owncastInstallDirectory}.`)
}
module.exports = installOwncast
#!/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
{
"name": "@small-tech/site.js",
"version": "16.4.0",
"version": "16.4.1",
"description": "Small Web construction set.",
"keywords": [
"web server",
......@@ -69,12 +69,14 @@
"debounce": "^1.2.0",
"decache": "^4.5.1",
"express": "^4.17.1",
"extract-zip": "^2.0.1",
"fs-extra": "^8.1.0",
"gunzip-maybe": "^1.4.1",
"helmet": "^3.21.2",
"http-proxy-middleware": "^1.0.6",
"minimist": "^1.2.5",
"morgan": "^1.9.1",
"node-fetch": "^2.6.1",
"node-graceful": "^2.0.1",
"prompts": "github:aral/prompts#custom-symbols-for-confirm",
"request-ip": "^2.1.3",
......
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