From b6cedd2bce6c49fa24b76a59621353c0b91c52f1 Mon Sep 17 00:00:00 2001 From: Sophie Schiller Date: Wed, 16 Apr 2025 17:36:45 +0200 Subject: [PATCH] navidrome: initial bundle --- bundles/navidrome/files/navidrome.service | 44 +++++++++++++ bundles/navidrome/items.py | 45 +++++++++++++ bundles/navidrome/metadata.py | 77 +++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 bundles/navidrome/files/navidrome.service create mode 100644 bundles/navidrome/items.py create mode 100644 bundles/navidrome/metadata.py diff --git a/bundles/navidrome/files/navidrome.service b/bundles/navidrome/files/navidrome.service new file mode 100644 index 0000000..90a1816 --- /dev/null +++ b/bundles/navidrome/files/navidrome.service @@ -0,0 +1,44 @@ +[Unit] +Description=Navidrome Music Server and Streamer compatible with Subsonic/Airsonic +After=remote-fs.target network.target +AssertPathExists=/var/opt/navidrome + +[Install] +WantedBy=multi-user.target + +[Service] +User=navidrome +Group=navidrome +Type=simple +ExecStart=/opt/navidrome/navidrome --configfile "/opt/navidrome/config.toml" +WorkingDirectory=/var/opt/navidrome +TimeoutStopSec=20 +KillMode=process +Restart=on-failure + +# See https://www.freedesktop.org/software/systemd/man/systemd.exec.html +DevicePolicy=closed +NoNewPrivileges=yes +PrivateTmp=yes +PrivateUsers=yes +ProtectControlGroups=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +RestrictNamespaces=yes +RestrictRealtime=yes +SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap +ReadWritePaths=/var/opt/navidrome + +# You can uncomment the following line if you're not using the jukebox This +# will prevent navidrome from accessing any real (physical) devices +PrivateDevices=yes + +# You can change the following line to `strict` instead of `full` if you don't +# want navidrome to be able to write anything on your filesystem outside of +# /var/lib/navidrome. +ProtectSystem=full + +# You can uncomment the following line if you don't have any media in /home/*. +# This will prevent navidrome from ever reading/writing anything there. +ProtectHome=true diff --git a/bundles/navidrome/items.py b/bundles/navidrome/items.py new file mode 100644 index 0000000..84e4e29 --- /dev/null +++ b/bundles/navidrome/items.py @@ -0,0 +1,45 @@ +users = { + 'navidrome': { + 'home': '/opt/navidrome', + }, +} + +directories = { + '/opt/navidrome': {}, + '/var/opt/navidrome': { + 'owner': 'navidrome', + }, +} +svc_systemd = { + 'navidrome': { + 'needs': { + 'file:/etc/systemd/system/navidrome.service', + 'file:/opt/navidrome/config.toml', + 'file:/opt/navidrome/navidrome', + }, + }, +} + +files = { + '/opt/navidrome/config.toml': { + 'content': repo.libs.faults.dict_as_toml(node.metadata.get('navidrome/config')), + 'triggers': { + 'svc_systemd:navidrome:restart', + }, + }, + '/etc/systemd/system/navidrome.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:navidrome:restart', + }, + }, + '/opt/navidrome/navidrome': { + 'content_hash': node.metadata.get('navidrome/sha1', None), + 'content_type': 'download', + 'mode': '0755', + 'source': f'https://github.com/navidrome/navidrome/releases/download/v{node.metadata.get('navidrome/version')}/navidrome_{node.metadata.get('navidrome/version')}_linux_amd64.tar.gz', + 'triggers': { + 'svc_systemd:navidrome:restart', + }, + }, +} diff --git a/bundles/navidrome/metadata.py b/bundles/navidrome/metadata.py new file mode 100644 index 0000000..4eeebb5 --- /dev/null +++ b/bundles/navidrome/metadata.py @@ -0,0 +1,77 @@ +defaults = { + 'apt': { + 'packages': { + 'ffmpeg': {}, + 'mpv': {}, + + }, + }, + 'navidrome': { + 'config': { + 'DataFolder': '/var/opt/navidrome', + 'Address': '127.0.0.1', + 'MusicFolder': '/mnt/music', + 'EnableExternalServices': False, + 'LastFM.Enabled': False, + 'ListenBrainz.Enabled': False, + 'PasswordEncryptionKey': repo.vault.password_for('{} encryption navidrome'.format(node.name)), + 'Scanner.Schedule': '@every 72h', + 'Port': 4533, + }, + }, + 'zfs': { + 'datasets': { + 'tank/navidrome': {}, + 'tank/navidrome/install': { + 'mountpoint': '/opt/navidrome', + 'needed_by': { + 'directory:/opt/navidrome', + }, + }, + 'tank/navidrome/home': { + 'mountpoint': '/var/opt/navidrome', + 'needed_by': { + 'directory:/var/opt/navidrome', + }, + }, + }, + }, +} + + +@metadata_reactor.provides( + 'navidrome/config/baseurl', +) +def baseurl(metadata): + return { + 'navidrome': { + 'config': { + 'BaseUrl': f'https://{metadata.get('navidrome/domain')}', + }, + }, + } + + +@metadata_reactor.provides( + 'nginx/vhosts/navidrome', +) +def nginx(metadata): + if not node.has_bundle('nginx'): + raise DoNotRunAgain + + return { + 'nginx': { + 'vhosts': { + 'navidrome': { + 'domain': metadata.get('navidrome/domain'), + 'locations': { + '/': { + 'target': f'http://127.0.0.1:{metadata.get('navidrome/config/port')}', + }, + }, + 'website_check_path': '/user/login', + 'website_check_string': 'Sign in', + }, + }, + }, + }