diff --git a/build/arch/PKGBUILD b/build/arch/PKGBUILD new file mode 100644 index 000000000..4751b44a4 --- /dev/null +++ b/build/arch/PKGBUILD @@ -0,0 +1,30 @@ +# Maintainer: advplyr +# Based on PKGBUILD From the aur + +pkgname=audiobookshelf-bin +pkgver=2.28.0 +pkgrel=1 +epoch=1 +pkgdesc="Self-hosted audiobook server for managing and playing audiobooks" +arch=() +url="https://github.com/advplyr/${pkgname}" +license=('GPL-3.0-only') +depends=("ffmpeg" "libnusqlite3") +backup=("etc/conf.d/${pkgname}") +options=("!debug") + +# The generator script will update the source and sha256sums dynamically. +# So we'll leave them empty for now and rely on the generator. + +source=() +sha256sums=() + + +package() { + install -Dm644 "${pkgname}.conf" "${pkgdir}/etc/conf.d/${pkgname}" + install -Dm644 "${pkgname}.hook" "${pkgdir}/etc/pacman.d/hooks/${pkgname}.hook" + install -Dm644 "${pkgname}.service" "${pkgdir}/usr/lib/systemd/system/${pkgname}.service" + install -Dm644 "${pkgname}.sysusers" "${pkgdir}/usr/lib/sysusers.d/${pkgname}.conf" + install -Dm644 "${pkgname}.tmpfiles" "${pkgdir}/usr/lib/tmpfiles.d/${pkgname}.conf" + install -Dm755 "audiobookshelf_${pkgver}" "${pkgdir}/usr/bin/audiobookshelf" +} diff --git a/build/arch/audiobookshelf.conf b/build/arch/audiobookshelf.conf new file mode 100644 index 000000000..2dd89027d --- /dev/null +++ b/build/arch/audiobookshelf.conf @@ -0,0 +1,12 @@ +NODE_ENV=production +METADATA_PATH=/var/lib/audiobookshelf/metadata +CONFIG_PATH=/var/lib/audiobookshelf/config +SOURCE=archlinux +FFMPEG_PATH=/usr/bin/ffmpeg +FFPROBE_PATH=/usr/bin/ffprobe +NUSQLITE3_PATH=/usr/lib/libnusqlite3.so +SKIP_BINARIES_CHECK=1 +PORT=13378 +HOST=0.0.0.0 +# ROUTER_BASE_PATH="/audiobookshelf" +# ALLOW_IFRAME=1 diff --git a/build/arch/audiobookshelf.hook b/build/arch/audiobookshelf.hook new file mode 100644 index 000000000..e7e8042be --- /dev/null +++ b/build/arch/audiobookshelf.hook @@ -0,0 +1,9 @@ +[Trigger] +Operation = Upgrade +Type = Package +Target = audiobookshelf + +[Action] +Description = Restarting audiobookshelf... +When = PostTransaction +Exec = /usr/bin/systemctl try-restart audiobookshelf.service diff --git a/build/arch/audiobookshelf.service b/build/arch/audiobookshelf.service new file mode 100644 index 000000000..1f44fe2da --- /dev/null +++ b/build/arch/audiobookshelf.service @@ -0,0 +1,16 @@ +[Unit] +Description=Self-hosted audiobook server for managing and playing audiobooks +Requires=network.target + +[Service] +Type=simple +EnvironmentFile=/etc/conf.d/audiobookshelf +WorkingDirectory=/var/lib/audiobookshelf +ExecStart=/usr/bin/audiobookshelf +ExecReload=/bin/kill -HUP $MAINPID +Restart=always +User=audiobookshelf +Group=audiobookshelf + +[Install] +WantedBy=multi-user.target diff --git a/build/arch/audiobookshelf.sysusers b/build/arch/audiobookshelf.sysusers new file mode 100644 index 000000000..c53d2ca60 --- /dev/null +++ b/build/arch/audiobookshelf.sysusers @@ -0,0 +1,2 @@ +u audiobookshelf - - /var/lib/audiobookshelf +g audiobookshelf - diff --git a/build/arch/audiobookshelf.tmpfiles b/build/arch/audiobookshelf.tmpfiles new file mode 100644 index 000000000..5720939fb --- /dev/null +++ b/build/arch/audiobookshelf.tmpfiles @@ -0,0 +1,2 @@ +d /var/lib/audiobookshelf 0755 audiobookshelf audiobookshelf +Z /var/lib/audiobookshelf - audiobookshelf audiobookshelf diff --git a/build/linuxpackager b/build/linuxpackager index 52a9beba9..8b8d2cad5 100755 --- a/build/linuxpackager +++ b/build/linuxpackager @@ -1,6 +1,80 @@ #!/bin/bash set -e set -o pipefail +set -u + +# Default values +BINARY_ONLY=false +BUILD_ARCH_LINUX=false +ARCH="" +PKG_NO_BYTECODE="" + +# Loop through arguments +for arg in "$@"; do + # Check for flags + if [ "$arg" == "--binary-only" ]; then + BINARY_ONLY=true + elif [ "$arg" == "--arch-linux" ]; then + BUILD_ARCH_LINUX=true + else + # If the argument is not a flag, assume it's the ARCH + ARCH="$arg" + fi +done + +# Autodetect host arch if not provided +if [ -z "$ARCH" ]; then + UNAME_ARCH=$(uname -m) + case "$UNAME_ARCH" in + x86_64) ARCH="amd64" ;; + aarch64|arm64) ARCH="arm64" ;; + *) + echo "Unsupported host architecture: $UNAME_ARCH" + exit 1 + ;; + esac + echo "No ARCH provided, using host architecture: $ARCH" +fi + +# Map ARCH to pkg target + npm arch +case "$ARCH" in + amd64) + PKG_TARGET="node20-linux-x64" + NPM_ARCH="x64" + ;; + arm64) + PKG_TARGET="node20-linux-arm64" + NPM_ARCH="arm64" + ;; + *) + echo "Unsupported architecture: $ARCH" + echo "Use amd64 or arm64" + exit 1 + ;; +esac + +# Ensure npm sees the right arch +export npm_config_arch=$NPM_ARCH +export npm_config_target_arch=$NPM_ARCH +# Check for QEMU ARM64 support +QEMU_ARM64_AVAILABLE=false + +if command -v qemu-aarch64-static >/dev/null 2>&1; then + # Check if binfmt_misc is registered + if [ -f /proc/sys/fs/binfmt_misc/qemu-aarch64 ]; then + QEMU_ARM64_AVAILABLE=true + fi +fi + +if [ "$(uname -m)" != "aarch64" ]; then + if [ "$ARCH" = "arm64" ]; then + if [ "$QEMU_ARM64_AVAILABLE" = false ]; then + echo "⚠ Warning: QEMU for ARM64 not found or not registered." + echo " ARM64 binary build may fail. Falling back to --no-bytecode." + PKG_NO_BYTECODE="--no-bytecode --public-packages '*' --public" + fi + fi +fi SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" @@ -9,14 +83,14 @@ cd "$SCRIPT_DIR/.." # Get package version without double quotes VERSION="$( eval echo $( jq '.version' package.json) )" DESCRIPTION="$( eval echo $( jq '.description' package.json) )" -OUTPUT_FILE="audiobookshelf_${VERSION}_amd64.deb" +OUTPUT_FILE="audiobookshelf_${VERSION}_${ARCH}.deb" echo ">>> Building Client" echo "--------------------" cd client rm -rf node_modules -npm ci --unsafe-perm=true --allow-root +npm ci --unsafe-perm=true --allow-root --arch=${NPM_ARCH} npm run generate cd .. @@ -24,34 +98,118 @@ echo ">>> Building Server" echo "--------------------" rm -rf node_modules -npm ci --unsafe-perm=true --allow-root +npm ci --unsafe-perm=true --allow-root --arch=${NPM_ARCH} echo ">>> Packaging" echo "--------------------" -# Create debian control file - mkdir -p dist -rm -rf dist/debian -cp -R build/debian dist/debian -chmod -R 775 dist/debian +# Package only binary if requested +if [ "$BINARY_ONLY" = true ]; then + echo "Building binary only for architecture: $ARCH" + npx @yao-pkg/pkg ${PKG_NO_BYTECODE} -t ${PKG_TARGET} -o dist/audiobookshelf_${VERSION}_${ARCH} . + echo "Finished! Binary: dist/audiobookshelf_${VERSION}_${ARCH}" + exit 0 +fi + +if [ "$BUILD_ARCH_LINUX" = true ]; then + echo ">>> Building for Arch Linux" + echo "----------------------------" + + # Create the directory to store the Arch Linux package + rm -rf dist/arch + cp -R build/arch dist/arch + + + # Build the binary with yao-pkg and place it in the specified directory + npx @yao-pkg/pkg ${PKG_NO_BYTECODE} -t ${PKG_TARGET} -o dist/arch/audiobookshelf_${VERSION} . + + # Update the PKGBUILD file with the new version + sed -i "s/pkgver=.*/pkgver=${VERSION}/" dist/arch/PKGBUILD + + # Calculate sha256sum for the built binary and strip the file name + for file in dist/arch/*; do + if [ -f "$file" ] && [[ "$file" != *PKGBUILD ]]; then + # Add the sha256sum for each file + sha256=$(sha256sum "$file" | awk '{print $1}') + sha256sums+=("$sha256") + + # Add file to source + source+=("$(basename "$file")") + fi + done + # Prepare sha256sums string for PKGBUILD + sha256_str="" + for s in "${sha256sums[@]}"; do + sha256_str+="'$s' " + done + sha256_str="${sha256_str% }" + + # Update sha256sums in the PKGBUILD file + sed -i "s|sha256sums=(.*)|sha256sums=($sha256_str)|" dist/arch/PKGBUILD + + # Update the source field in the PKGBUILD with the correct files, excluding PKGBUILD + source_str="" + for s in "${source[@]}"; do + source_str+="'$s' " + done + source_str="${source_str% }" + + # Update the PKGBUILD with the correct source field + sed -i "s|source=(.*)|source=($source_str)|" dist/arch/PKGBUILD + + # Modify the PKGBUILD to match the architecture being built + if [ "$ARCH" = "amd64" ]; then + # Set the arch to x86_64 for AMD64 build + sed -i "s/arch=(.*)/arch=('x86_64')/" dist/arch/PKGBUILD + elif [ "$ARCH" = "arm64" ]; then + # Set the arch to aarch64 for ARM64 build + sed -i "s/arch=(.*)/arch=('aarch64')/" dist/arch/PKGBUILD + else + echo "Unsupported architecture: $ARCH" + exit 1 + fi + + echo ">>> Building Arch Linux package" + # Ensure necessary tools are installed + if ! command -v makepkg >/dev/null 2>&1; then + echo "makepkg is required to build Arch Linux packages. Install it with: sudo pacman -S base-devel" + exit 1 + fi + + # Run makepkg to build the package + cd dist/arch + + PKGDEST=../ makepkg -sf --noconfirm --ignorearch + + echo "Finished! Arch Linux package built." + exit 0 +else + # Otherwise build .deb + rm -rf dist/debian + cp -R build/debian dist/debian + chmod -R 775 dist/debian + +# Create debian control file controlfile="Package: audiobookshelf Version: $VERSION Section: base Priority: optional -Architecture: amd64 +Architecture: ${ARCH} Depends: Maintainer: advplyr Description: $DESCRIPTION" - -echo "$controlfile" > dist/debian/DEBIAN/control; - -# Package debian -pkg -t node20-linux-x64 -o dist/debian/usr/share/audiobookshelf/audiobookshelf . - -fakeroot dpkg-deb -Zxz --build dist/debian - -mv dist/debian.deb "dist/$OUTPUT_FILE" - -echo "Finished! Filename: $OUTPUT_FILE" + + echo "$controlfile" > dist/debian/DEBIAN/control; + + # Package debian + mkdir -p dist/debian/usr/share/audiobookshelf + npx @yao-pkg/pkg ${PKG_NO_BYTECODE} -t ${PKG_TARGET} -o dist/debian/usr/share/audiobookshelf/audiobookshelf . + + fakeroot dpkg-deb -Zxz --build dist/debian + + mv dist/debian.deb "dist/$OUTPUT_FILE" + + echo "Finished! Filename: dist/${OUTPUT_FILE}.deb" +fi diff --git a/package.json b/package.json index 0d7ede593..330383a2a 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,14 @@ "prod": "npm run client && npm ci && node index.js", "build-win": "npm run client && pkg -t node20-win-x64 -o ./dist/win/audiobookshelf -C GZip .", "build-linux": "build/linuxpackager", + "build-linux-amd64": "build/linuxpackager amd64", + "build-linux-arm64": "build/linuxpackager arm64", + "build-linux-arch": "build/linuxpackager --arch-linux", + "build-linux-arch-amd64": "build/linuxpackager amd64 --arch-linux", + "build-linux-arch-arm64": "build/linuxpackager arm64 --arch-linux", + "build-linux-binary": "build/linuxpackager --binary-only", + "build-linux-amd64-binary": "build/linuxpackager amd64 --binary-only", + "build-linux-arm64-binary": "build/linuxpackager arm64 --binary-only", "docker": "docker buildx build --platform linux/amd64,linux/arm64 --push . -t advplyr/audiobookshelf", "docker-amd64-local": "docker buildx build --platform linux/amd64 --load . -t advplyr/audiobookshelf-amd64-local", "docker-arm64-local": "docker buildx build --platform linux/arm64 --load . -t advplyr/audiobookshelf-arm64-local",