update
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled

This commit is contained in:
2025-12-08 16:16:23 +01:00
commit c251f174ed
1349 changed files with 194301 additions and 0 deletions

154
release/goreleaser.yml Normal file
View File

@@ -0,0 +1,154 @@
# GoReleaser config
project_name: navidrome
version: 2
builds:
- id: navidrome
# Instead of compiling the binary with goreleaser, we just copy it from `binaries` folder
# This is because we need to compile the binaries with our Dockerfile, and to avoid having to
# compile it twice, we just copy the docker build output. The xxgo script handles this for us
tool: "./release/xxgo"
# All available targets compiled by the Dockerfile
targets:
- darwin_amd64
- darwin_arm64
- linux_386
- linux_amd64
- linux_arm_v5
- linux_arm_v6
- linux_arm_v7
- linux_arm64
- windows_386
- windows_amd64
archives:
- format_overrides:
- goos: windows
formats:
- zip
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
checksum:
name_template: "{{ .ProjectName }}_checksums.txt"
snapshot:
version_template: "{{ .Version }}-SNAPSHOT"
nfpms:
- id: navidrome
package_name: navidrome
file_name_template: '{{ .PackageName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
homepage: https://navidrome.org
description: |-
🎧☁ Your Personal Streaming Service
maintainer: Deluan Quintão <deluan at navidrome.org>
license: GPL-3.0
formats:
- deb
- rpm
dependencies:
- ffmpeg
suggests:
- mpv
overrides:
rpm:
dependencies:
- "(ffmpeg or ffmpeg-free)"
contents:
- src: release/linux/navidrome.toml
dst: /etc/navidrome/navidrome.toml
type: "config|noreplace"
file_info:
mode: 0644
owner: navidrome
group: navidrome
- dst: /var/lib/navidrome
type: dir
file_info:
owner: navidrome
group: navidrome
- dst: /opt/navidrome/music
type: dir
file_info:
owner: navidrome
group: navidrome
- src: release/linux/.package.rpm # contents: "rpm"
dst: /var/lib/navidrome/.package
type: "config|noreplace"
packager: rpm
- src: release/linux/.package.deb # contents: "deb"
dst: /var/lib/navidrome/.package
type: "config|noreplace"
packager: deb
scripts:
preinstall: "release/linux/preinstall.sh"
postinstall: "release/linux/postinstall.sh"
preremove: "release/linux/preremove.sh"
release:
draft: true
mode: append
footer: |
**Full Changelog**: https://github.com/navidrome/navidrome/compare/{{ .PreviousTag }}...{{ .Tag }}
## Helping out
This release is only possible thanks to the support of some **awesome people**!
Want to be one of them?
You can [sponsor](https://github.com/sponsors/deluan), pay me a [Ko-fi](https://ko-fi.com/deluan), or [contribute with code](https://www.navidrome.org/docs/developers/).
## Where to go next?
* Read installation instructions on our [website](https://www.navidrome.org/docs/installation/).
* Host Navidrome on [PikaPods](https://www.pikapods.com/pods/navidrome) for a simple cloud solution.
* Reach out on [Discord](https://discord.gg/xh7j7yF), [Reddit](https://www.reddit.com/r/navidrome/) and [Twitter](https://twitter.com/navidrome)!
# Add the MSI installers to the release
extra_files:
- glob: binaries/navidrome_386.msi
name_template: navidrome_{{.Version}}_windows_386_installer.msi
- glob: binaries/navidrome_amd64.msi
name_template: navidrome_{{.Version}}_windows_amd64_installer.msi
changelog:
sort: asc
use: github
filters:
exclude:
- "^test:"
- "^refactor:"
- Merge pull request
- Merge remote-tracking branch
- Merge branch
- go mod tidy
groups:
- title: "New Features"
regexp: '^.*?feat(\(.+\))??!?:.+$'
order: 100
- title: "Security updates"
regexp: '^.*?sec(\(.+\))??!?:.+$'
order: 150
- title: "Bug fixes"
regexp: '^.*?(fix|refactor)(\(.+\))??!?:.+$'
order: 200
- title: "Documentation updates"
regexp: ^.*?docs?(\(.+\))??!?:.+$
order: 400
- title: "Build process updates"
regexp: ^.*?(build|ci)(\(.+\))??!?:.+$
order: 400
- title: Other work
order: 9999

View File

@@ -0,0 +1 @@
deb

View File

@@ -0,0 +1 @@
rpm

View File

@@ -0,0 +1,2 @@
DataFolder = "/var/lib/navidrome"
MusicFolder = "/opt/navidrome/music"

View File

@@ -0,0 +1,28 @@
#!/bin/sh
# It is possible for a user to delete the configuration file in such a way that
# the package manager (in particular, deb) thinks that the file exists, while it is
# no longer on disk. Specifically, doing a `rm /etc/navidrome/navidrome.toml`
# without something like `apt purge navidrome` will result in the system believing that
# the file still exists. In this case, during install it will NOT extract the configuration
# file (as to not override it). Since `navidrome service install` depends on this file existing,
# we will create it with the defaults anyway.
if [ ! -f /etc/navidrome/navidrome.toml ]; then
printf "No navidrome.toml detected, creating in postinstall\n"
printf "DataFolder = \"/var/lib/navidrome\"\n" > /etc/navidrome/navidrome.toml
printf "MusicFolder = \"/opt/navidrome/music\"\n" >> /etc/navidrome/navidrome.toml
fi
postinstall_flag="/var/lib/navidrome/.installed"
if [ ! -f "$postinstall_flag" ]; then
# The primary reason why this would fail is if the service was already installed AND
# someone manually removed the .installed flag. In this case, ignore the error
navidrome service install --user navidrome --working-directory /var/lib/navidrome --configfile /etc/navidrome/navidrome.toml || :
# Any `navidrome` command will make a cache. Make sure that this is properly owned by the Navidrome user
# and not by root
chown navidrome:navidrome /var/lib/navidrome/cache
touch "$postinstall_flag"
fi

6
release/linux/preinstall.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
if ! getent passwd navidrome > /dev/null 2>&1; then
printf "Creating default Navidrome user\n"
useradd --home-dir /var/lib/navidrome --create-home --system --user-group navidrome
fi

View File

@@ -0,0 +1,30 @@
#!/bin/sh
action=$1
remove() {
postinstall_flag="/var/lib/navidrome/.installed"
if [ -f "$postinstall_flag" ]; then
# If this fails, ignore it
navidrome service uninstall || :
rm "$postinstall_flag"
printf "The following may still be present (especially if you have not done a purge):\n"
printf "1. /etc/navidrome/navidrome.toml (configuration file)\n"
printf "2. /var/lib/navidrome (database/cache)\n"
printf "3. /opt/navidrome (default location for music)\n"
printf "4. The Navidrome user (user name navidrome)\n"
fi
}
case "$action" in
"1" | "upgrade")
# For an upgrade, do nothing
# Leave the service file untouched
# This is relevant for RPM/DEB-based installs
;;
*)
remove
;;
esac

View File

@@ -0,0 +1,41 @@
<Fragment>
<UI Id="Navidrome_UI_Flow">
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
<Property Id="WixUI_Mode" Value="Minimal" />
<DialogRef Id="ErrorDlg" />
<DialogRef Id="FatalError" />
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<DialogRef Id="PrepareDlg" />
<DialogRef Id="ProgressDlg" />
<DialogRef Id="ResumeDlg" />
<DialogRef Id="UserExit" />
<DialogRef Id="WelcomeDlg" />
<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999" />
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MyCustomPropertiesDlg" />
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg" />
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg" />
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg" />
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg" />
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Condition="Installed AND PATCH" />
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2" Condition="Installed AND PATCH" />
<InstallUISequence>
<Show Dialog="WelcomeDlg" Before="ProgressDlg" Condition="Installed AND PATCH" />
</InstallUISequence>
<Property Id="ARPNOMODIFY" Value="1" />
</UI>
<UIRef Id="WixUI_Common" />
</Fragment>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<Fragment>
<UI>
<Dialog Id="MyCustomPropertiesDlg" Width="370" Height="270" Title="[ProductName] Setup" NoMinimize="yes">
<!--Header-->
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="WixUI_Bmp_Banner" />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes">
<Text>{\WixUI_Font_Title}Configuration</Text>
</Control>
<Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes">
<Text>Please enter configuration settings</Text>
</Control>
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
<!--Properties-->
<!-- Install directory -->
<Control Id="NameLabel1" Type="Text" X="30" Y="60" Width="220" Height="15" TabSkip="no" Text="&amp;Installation Folder (executable and configuration file):" />
<Control Id="NameEdit1" Type="Edit" X="30" Y="75" Width="220" Height="18" Property="INSTALLDIR" Text="[INSTALLDIR]" />
<!-- NAVIDROME_PORT -->
<Control Id="NameLabel2" Type="Text" X="30" Y="93" Width="100" Height="15" TabSkip="no" Text="&amp;Port:" />
<Control Id="NameEdit2" Type="Edit" X="30" Y="108" Width="220" Height="18" Property="ND_PORT" Text="[ND_PORT]" />
<!-- NAVIDROME_MUSICDIR -->
<Control Id="NameLabel3" Type="Text" X="30" Y="126" Width="100" Height="15" TabSkip="no" Text="&amp;Music Folder:" />
<Control Id="NameEdit3" Type="Edit" X="30" Y="141" Width="220" Height="18" Property="ND_MUSICFOLDER" Text="[ND_MUSICFOLDER]" />
<!-- NAVIDROME_DATADIR -->
<Control Id="NameLabel4" Type="Text" X="30" Y="159" Width="100" Height="15" TabSkip="no" Text="&amp;Data Folder:" />
<Control Id="NameEdit5" Type="Edit" X="30" Y="174" Width="220" Height="18" Property="ND_DATAFOLDER" Text="[ND_DATAFOLDER]" />
<!--Footer-->
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&amp;Next">
<Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">CostingComplete = 1</Publish>
<Publish Event="NewDialog" Value="VerifyReadyDlg"></Publish>
</Control>
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
</Dialog>
</UI>
</Fragment>

BIN
release/wix/bmp/banner.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

63
release/wix/build_msi.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/bin/sh
FFMPEG_VERSION="7.1"
FFMPEG_REPOSITORY=navidrome/ffmpeg-windows-builds
DOWNLOAD_FOLDER=/tmp
#Exit if GIT_TAG is not set
if [ -z "$GIT_TAG" ]; then
echo "GIT_TAG is not set, exiting..."
exit 1
fi
set -e
WORKSPACE=$1
ARCH=$2
NAVIDROME_BUILD_VERSION=$(echo "$GIT_TAG" | sed -e 's/^v//' -e 's/-SNAPSHOT/.1/')
echo "Building MSI package for $ARCH, version $NAVIDROME_BUILD_VERSION"
MSI_OUTPUT_DIR=$WORKSPACE/binaries/msi
mkdir -p "$MSI_OUTPUT_DIR"
BINARY_DIR=$WORKSPACE/binaries/windows_${ARCH}
if [ "$ARCH" = "386" ]; then
PLATFORM="x86"
WIN_ARCH="win32"
else
PLATFORM="x64"
WIN_ARCH="win64"
fi
BINARY=$BINARY_DIR/navidrome.exe
if [ ! -f "$BINARY" ]; then
echo
echo "$BINARY not found!"
echo "Build it with 'make single GOOS=windows GOARCH=${ARCH}'"
exit 1
fi
# Download static compiled ffmpeg for Windows
FFMPEG_FILE="ffmpeg-n${FFMPEG_VERSION}-latest-${WIN_ARCH}-gpl-${FFMPEG_VERSION}"
wget --quiet --output-document="${DOWNLOAD_FOLDER}/ffmpeg.zip" \
"https://github.com/${FFMPEG_REPOSITORY}/releases/download/latest/${FFMPEG_FILE}.zip"
rm -rf "${DOWNLOAD_FOLDER}/extracted_ffmpeg"
unzip -d "${DOWNLOAD_FOLDER}/extracted_ffmpeg" "${DOWNLOAD_FOLDER}/ffmpeg.zip" "*/ffmpeg.exe"
cp "${DOWNLOAD_FOLDER}"/extracted_ffmpeg/${FFMPEG_FILE}/bin/ffmpeg.exe "$MSI_OUTPUT_DIR"
cp "$WORKSPACE"/LICENSE "$WORKSPACE"/README.md "$MSI_OUTPUT_DIR"
cp "$BINARY" "$MSI_OUTPUT_DIR"
# package type indicator file
echo "msi" > "$MSI_OUTPUT_DIR/.package"
# workaround for wixl WixVariable not working to override bmp locations
cp "$WORKSPACE"/release/wix/bmp/banner.bmp /usr/share/wixl-*/ext/ui/bitmaps/bannrbmp.bmp
cp "$WORKSPACE"/release/wix/bmp/dialogue.bmp /usr/share/wixl-*/ext/ui/bitmaps/dlgbmp.bmp
cd "$MSI_OUTPUT_DIR"
rm -f "$MSI_OUTPUT_DIR"/navidrome_"${ARCH}".msi
wixl "$WORKSPACE"/release/wix/navidrome.wxs -D Version="$NAVIDROME_BUILD_VERSION" -D Platform=$PLATFORM --arch $PLATFORM \
--ext ui --output "$MSI_OUTPUT_DIR"/navidrome_"${ARCH}".msi

View File

@@ -0,0 +1,3 @@
FROM public.ecr.aws/docker/library/alpine
RUN apk update && apk add jq msitools
WORKDIR /workspace

93
release/wix/navidrome.wxs Normal file
View File

@@ -0,0 +1,93 @@
<?xml version='1.0' encoding='windows-1252'?>
<?if $(var.Platform) = x64 ?>
<?define ProductName = "Navidrome" ?>
<?define UpgradeCode = "2f154974-1443-41b6-b808-b8be530291b3" ?>
<?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?define Win64 = 'yes' ?>
<?else ?>
<?define ProductName = "Navidrome (x86)" ?>
<?define UpgradeCode = "2f0572e4-7e8c-42e7-a186-77f70ec0911a" ?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?define Win64 = "no" ?>
<?endif ?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<?include SettingsDlg.wxs?>
<?include Navidrome_UI_Flow.wxs?>
<Product Name="$(var.ProductName)" Id="*" UpgradeCode="$(var.UpgradeCode)" Language='1033' Codepage='1252' Version='$(var.Version)' Manufacturer='Deluan'>
<Package Id='*' Keywords='Installer' Description="$(var.ProductName)" Comments='' Manufacturer='Deluan' InstallerVersion='200' Languages='1033' Compressed='yes' SummaryCodepage='1252' InstallScope='perMachine' />
<MajorUpgrade AllowDowngrades="no" DowngradeErrorMessage="A newer version of $(var.ProductName) is already installed." />
<Media Id='1' Cabinet='main.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
<Property Id='DiskPrompt' Value="Navidrome Install [1]" />
<Property Id="REBOOT" Value="ReallySuppress" />
<Property Id="ND_PORT" Value="4533" />
<Property Id="ND_MUSICFOLDER" Value="C:\Music" />
<Property Id="ND_DATAFOLDER" Value="C:\ProgramData\Navidrome" />
<UIRef Id="Navidrome_UI_Flow"/>
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id="$(var.PlatformProgramFilesFolder)">
<Directory Id='INSTALLDIR' Name='Navidrome'>
<Component Id='LICENSEFile' Guid='eb5610a4-e3f3-4f36-ae2c-e96914e460c2' Win64="$(var.Win64)">
<File Id='LICENSE' Name='LICENSE' DiskId='1' Source='LICENSE' KeyPath='yes' />
</Component>
<Component Id='README.mdFile' Guid='d1ee412b-2ebc-4b0b-9fa7-0228ab707686' Win64="$(var.Win64)">
<File Id='README.md' Name='README.md' DiskId='1' Source='README.md' KeyPath='yes' />
</Component>
<Component Id="Configuration" Guid="9e17ed4b-ef13-44bf-a605-ed4132cff7f6" Win64="$(var.Win64)">
<IniFile Id="ConfigurationPort" Name="navidrome.ini" Action="createLine" Directory="INSTALLDIR" Key="Port" Section="default" Value="&apos;[ND_PORT]&apos;" />
<IniFile Id="ConfigurationMusicDir" Name="navidrome.ini" Action="createLine" Directory="INSTALLDIR" Key="MusicFolder" Section="default" Value="&apos;[ND_MUSICFOLDER]&apos;" />
<IniFile Id="ConfigurationDataDir" Name="navidrome.ini" Action="createLine" Directory="INSTALLDIR" Key="DataFolder" Section="default" Value="&apos;[ND_DATAFOLDER]&apos;" />
<IniFile Id="FFmpegPath" Name="navidrome.ini" Action="createLine" Directory="INSTALLDIR" Key="FFmpegPath" Section="default" Value="&apos;[INSTALLDIR]ffmpeg.exe&apos;" />
</Component>
<Component Id='MainExecutable' Guid='e645aa06-8bbc-40d6-8d3c-73b4f5b76fd7' Win64="$(var.Win64)">
<File Id='NavidromeExe' Name='Navidrome.exe' DiskId='1' Source='navidrome.exe' KeyPath='yes' />
<ServiceInstall
Description='Navidrome is a self-hosted music server and streamer'
ErrorControl='ignore'
Name = '$(var.ProductName)'
Id='NavidromeService'
Start='auto'
Type='ownProcess'
Vital='yes'
Arguments='service execute --configfile &quot;[INSTALLDIR]navidrome.ini&quot; --logfile &quot;[ND_DATAFOLDER]\navidrome.log&quot;'
/>
<ServiceControl Id='StartNavidromeService' Start='install' Stop='both' Remove='uninstall' Name='$(var.ProductName)' Wait='yes' />
</Component>
<Component Id='FFMpegExecutable' Guid='d17358f7-abdc-4080-acd3-6427903a7dd8' Win64="$(var.Win64)">
<File Id='ffmpeg.exe' Name='ffmpeg.exe' DiskId='1' Source='ffmpeg.exe' KeyPath='yes' />
</Component>
</Directory>
</Directory>
<Directory Id="ND_DATAFOLDER" name="[ND_DATAFOLDER]">
<Component Id='PackageFile' Guid='9eec0697-803c-4629-858f-20dc376c960b' Win64="$(var.Win64)">
<File Id='package' Name='.package' DiskId='1' Source='.package' KeyPath='no' />
</Component>
</Directory>
</Directory>
<InstallUISequence>
<Show Dialog="MyCustomPropertiesDlg" After="WelcomeDlg">Not Installed AND NOT WIX_UPGRADE_DETECTED</Show>
</InstallUISequence>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='LICENSEFile' />
<ComponentRef Id='README.mdFile' />
<ComponentRef Id='Configuration'/>
<ComponentRef Id='MainExecutable' />
<ComponentRef Id='FFMpegExecutable' />
<ComponentRef Id='PackageFile' />
</Feature>
</Product>
</Wix>

17
release/xxgo Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Use sed to extract the value of the -o parameter
output=$(echo "$@" | sed -n 's/.*-o \([^ ]*\).*/\1/p')
# Ensure the directory part of the output exists
mkdir -p "$(dirname "$output")"
# Build the source folder name based on GOOS, GOARCH and GOARM.
source="${GOOS}_${GOARCH}"
if [ "$GOARCH" = "arm" ]; then
source="${source}_${GOARM}"
fi
# Copy the output to the desired location
chmod +x binaries/"${source}"/navidrome*
cp binaries/"${source}"/navidrome* "$output"