diff --git a/cross/navidrome/Makefile b/cross/navidrome/Makefile new file mode 100644 index 00000000000..ded480f8185 --- /dev/null +++ b/cross/navidrome/Makefile @@ -0,0 +1,47 @@ +PKG_NAME = navidrome +PKG_VERS = 0.53.3 +PKG_EXT = tar.gz +PKG_DIST_NAME = v$(PKG_VERS).$(PKG_EXT) +PKG_DIST_SITE = https://github.com/navidrome/navidrome/archive +PKG_DIST_FILE = $(PKG_NAME)-$(PKG_VERS).$(PKG_EXT) +PKG_DIR = $(PKG_NAME)-$(PKG_VERS) + +BUILD_DEPENDS = native/go native/nodejs +DEPENDS = cross/taglib + +# C++11 compiler required +UNSUPPORTED_ARCHS = $(ARMv5_ARCHS) +# go does not support ppc archs +UNSUPPORTED_ARCHS += $(PPC_ARCHS) + +HOMEPAGE = https://www.navidrome.org/ +COMMENT = ๐ŸŽงโ˜ Modern Music Server and Streamer compatible with Subsonic/Airsonic. +LICENSE = GPL-3.0 License + +COMPILE_TARGET = navidrome_compile + +CGO_ENABLED = 1 +GO_BIN_DIR = $(WORK_DIR)/$(PKG_DIR)/$(PKG_NAME) + +# with parallel make, sometimes the frontent build (make buildjs) fails with: +# # github.com/navidrome/navidrome/ui +# ui/embed.go:9:5: embed build/asset-manifest.json: open ui/build/asset-manifest.json: no such file or directory +# ui/embed.go:9:5: embed build/index.html: open ui/build/index.html: no such file or directory +.NOTPARALLEL: + +include ../../mk/spksrc.cross-go.mk + +ENV += NPM_CONFIG_USER=root +PATH := $(WORK_DIR)/../../../native/nodejs/work-native/node/bin:$(PATH) + +.PHONY: navidrome_compile +# without "make buildjs" make buildall has warning: +# WARNING: This command does not build the frontend, it uses the latest built with 'make buildjs' +# therefore split "make buildall" into "make buildjs" and "make build" +navidrome_compile: + @$(MSG) "### Navidrom build prepare (make setup)" + @$(RUN) $(MAKE) setup + @$(MSG) "### Navidrom build frontend (make buildjs)" + @$(RUN) $(MAKE) buildjs + @$(MSG) "### Navidrom build application (make build)" + @$(RUN) $(MAKE) build diff --git a/cross/navidrome/PLIST b/cross/navidrome/PLIST new file mode 100644 index 00000000000..4b03eed62d8 --- /dev/null +++ b/cross/navidrome/PLIST @@ -0,0 +1 @@ +bin:bin/navidrome diff --git a/cross/navidrome/digests b/cross/navidrome/digests new file mode 100644 index 00000000000..1f8e8fd32b4 --- /dev/null +++ b/cross/navidrome/digests @@ -0,0 +1,3 @@ +navidrome-0.53.3.tar.gz SHA1 62f402fab156aa03e09be382688899bad79c4910 +navidrome-0.53.3.tar.gz SHA256 e0d5b0280c302938177b2241a5f9868a4b40cd603ddf5acb2ff0f9c40e44c13a +navidrome-0.53.3.tar.gz MD5 cb7ead899f64dca6526441e8ccd72e47 diff --git a/cross/navidrome/patches/001-patch_taglib-wrapper-for-older-gcc.patch b/cross/navidrome/patches/001-patch_taglib-wrapper-for-older-gcc.patch new file mode 100644 index 00000000000..c7b8a3814b7 --- /dev/null +++ b/cross/navidrome/patches/001-patch_taglib-wrapper-for-older-gcc.patch @@ -0,0 +1,32 @@ +# fix for older gcc (like 4.9.x) +# - mp3 tags: use explicit type for mp3File->ID3v2Tag()->frameListMap() +# as older gcc cannot dereference std::initializer_list correctly +# - mp4 tags: use mp4File->tag()->item instead of mp4File->tag()->itemMap() to access covers +# as side effect this fixes the build with older gcc +# +--- scanner/metadata/taglib/taglib_wrapper.cpp.orig 2022-01-22 00:35:19.000000000 +0000 ++++ scanner/metadata/taglib/taglib_wrapper.cpp 2022-07-30 20:04:45.252885556 +0000 +@@ -95,7 +95,7 @@ + if (TagLib::MPEG::File * + mp3File{dynamic_cast(f.file())}) { + if (mp3File->ID3v2Tag()) { +- const auto &frameListMap{mp3File->ID3v2Tag()->frameListMap()}; ++ const TagLib::ID3v2::FrameListMap &frameListMap{mp3File->ID3v2Tag()->frameListMap()}; + hasCover = !frameListMap["APIC"].isEmpty(); + } + } +@@ -107,9 +107,11 @@ + // ----- MP4 + else if (TagLib::MP4::File * + mp4File{dynamic_cast(f.file())}) { +- auto &coverItem{mp4File->tag()->itemMap()["covr"]}; +- TagLib::MP4::CoverArtList coverArtList{coverItem.toCoverArtList()}; +- hasCover = !coverArtList.isEmpty(); ++ if (mp4File->tag()->itemMap().contains("covr")) { ++ auto const &coverItem = mp4File->tag()->item("covr"); ++ auto const coverArtList = coverItem.toCoverArtList(); ++ hasCover = !coverArtList.isEmpty(); ++ } + } + // ----- Ogg + else if (TagLib::Ogg::Vorbis::File * diff --git a/cross/taglib/Makefile b/cross/taglib/Makefile index 5534ed89eac..8efa31ef30e 100644 --- a/cross/taglib/Makefile +++ b/cross/taglib/Makefile @@ -1,5 +1,5 @@ PKG_NAME = taglib -PKG_VERS = 1.12 +PKG_VERS = 1.13.1 PKG_EXT = tar.gz PKG_DIST_NAME = $(PKG_NAME)-$(PKG_VERS).$(PKG_EXT) PKG_DIST_SITE = https://taglib.org/releases @@ -14,5 +14,6 @@ LICENSE = LGPLv2.1 GNU_CONFIGURE = 1 CMAKE_ARGS += -DBUILD_SHARED_LIBS=ON CMAKE_ARGS += -Wno-dev +ADDITIONAL_CXXFLAGS = -Wno-deprecated-declarations -Wno-sign-compare include ../../mk/spksrc.cross-cmake.mk diff --git a/cross/taglib/PLIST b/cross/taglib/PLIST index e7fb16499e1..126246e1e69 100644 --- a/cross/taglib/PLIST +++ b/cross/taglib/PLIST @@ -1,7 +1,6 @@ -rsc:bin/taglib-config lnk:lib/libtag.so lnk:lib/libtag.so.1 -lib:lib/libtag.so.1.18.0 +lib:lib/libtag.so.1.19.1 lnk:lib/libtag_c.so lnk:lib/libtag_c.so.0 lib:lib/libtag_c.so.0.0.0 diff --git a/cross/taglib/digests b/cross/taglib/digests index f809fee6bb0..0c45e7deb08 100644 --- a/cross/taglib/digests +++ b/cross/taglib/digests @@ -1,3 +1,3 @@ -taglib-1.12.tar.gz SHA1 c06c44223f64ef61d29372659059d6b9e27c2efd -taglib-1.12.tar.gz SHA256 7fccd07669a523b07a15bd24c8da1bbb92206cb19e9366c3692af3d79253b703 -taglib-1.12.tar.gz MD5 4313ed2671234e029b7af8f97c84e9af +taglib-1.13.1.tar.gz SHA1 33325da48456d13c45fed7f772020f655bd1acca +taglib-1.13.1.tar.gz SHA256 c8da2b10f1bfec2cd7dbfcd33f4a2338db0765d851a50583d410bacf055cfd0b +taglib-1.13.1.tar.gz MD5 2fe6089da73ad414aa1b982b83415362 diff --git a/spk/navidrome/Makefile b/spk/navidrome/Makefile new file mode 100644 index 00000000000..0bc09e09a04 --- /dev/null +++ b/spk/navidrome/Makefile @@ -0,0 +1,38 @@ +SPK_NAME = navidrome +SPK_VERS = 0.53.3 +SPK_REV = 1 +SPK_ICON = src/navidrome.png + +DEPENDS = cross/navidrome + +# C++11 compiler required +UNSUPPORTED_ARCHS = $(ARMv5_ARCHS) +# go does not support ppc archs +UNSUPPORTED_ARCHS += $(PPC_ARCHS) + +MAINTAINER = hgy59 +HOMEPAGE = https://www.navidrome.org/ +DESCRIPTION = ๐ŸŽงโ˜ Modern Music Server and Streamer compatible with Subsonic/Airsonic. It gives you freedom to listen to your music collection from any browser or mobile device. +LICENSE = GPLv3 +DISPLAY_NAME = Navidrome +CHANGELOG = "Initial package release" + +STARTABLE = yes +SERVICE_SETUP = src/service-setup.sh + +SERVICE_USER = auto +SERVICE_PORT = 4533 +SERVICE_PORT_TITLE = Navidrome (HTTP) +ADMIN_PORT = $(SERVICE_PORT) + +WIZARDS_DIR = src/wizard +SERVICE_WIZARD_SHARENAME = wizard_music_folder + +POST_STRIP_TARGET = navidrome_extra_install + +include ../../mk/spksrc.spk.mk + +.PHONY: navidrome_extra_install +navidrome_extra_install: + install -d -m 755 $(STAGING_DIR)/var + install -m 644 src/navidrome.toml $(STAGING_DIR)/var/ diff --git a/spk/navidrome/src/navidrome.png b/spk/navidrome/src/navidrome.png new file mode 100644 index 00000000000..dec48606bc5 Binary files /dev/null and b/spk/navidrome/src/navidrome.png differ diff --git a/spk/navidrome/src/navidrome.toml b/spk/navidrome/src/navidrome.toml new file mode 100644 index 00000000000..2fe6bde828d --- /dev/null +++ b/spk/navidrome/src/navidrome.toml @@ -0,0 +1,135 @@ +# For all available configuration options see: +# https://www.navidrome.org/docs/usage/configuration-options/#available-options +# For security considerations see: +# https://www.navidrome.org/docs/usage/security/ +# + +# Folder where your music library is stored. Can be read-only +MusicFolder = "@@wizard_music_folder@@" + +# Folder to store application data (DB, cache...) +DataFolder= "/var/packages/navidrome/var" + +# Configure periodic scans using "cron" syntax. To disable it altogether, set it to "0" +# ScanSchedule = "@every 1m" + +# Log level. Useful for troubleshooting. Possible values: error, warn, info, debug, trace +# LogLevel = "info" + +# Whether or not sensitive information (like tokens and passwords) should be redacted (hidden) in the logs +# EnableLogRedacting = true + +# IP address the server will bind to +# Address = 0.0.0.0 + +# Enables transcoding configuration in the UI +# EnableTranscodingConfig = false + +# Size of transcoding cache. Set to "0" to disable cache +# TranscodingCacheSize = "100MB" + +# Size of image (art work) cache. Set to "0" to disable cache +# ImageCacheSize = "100MB" + +# Enable/disable .m3u playlist auto-import +# AutoImportPlaylists = true + +# Where to search for and import playlists from. Can be a list of folders/globs (separated by : ). Paths are relative to MusicFolder +# PlaylistsPath = ".:**/**" # (meaning MusicFolder and all its subfolders)" + +# Base URL (only the path part) to configure Navidrome behind a proxy (ex: /music) +# BaseUrl = "" + +# Change background image used in the Login page +# UILoginBackgroundUrl = "random music image from Unsplash.com" + +# Add a welcome message to the login screen +# UIWelcomeMessage = "" + +# Send basic info to your own Google Analytics account. Must be in the format UA-XXXXXXXX +# GATrackingID = "" + +# Sets the default theme used by the UI when logging in from a new browser. This value must match one of the options in the UI +# DefaultTheme = Dark + +# Controls whether the player in the UI will animate the album cover (rotation) +# EnableCoverAnimation = true + +# List of ignored articles when sorting/indexing artists +# IgnoredArticles = "The El La Los Las Le Les Os As O A Der Die Das" + +# Match query strings anywhere in searchable fields, not only in word boundaries. Useful for languages where words are not space separated +# SearchFullString = false + +# Uses music files' modification time when sorting by "Recently Added". Otherwise use import time +# RecentlyAddedByModTime = false + +# Configure the order to look for cover art images. Use special embedded value to get embedded images from the audio files +# CoverArtPriority = "embedded, cover.*, folder.*, front.*" + +# Set JPEG quality percentage for resized cover art images +# CoverJpegQuality = 75 + +# Enable the option in the UI to download music/albums/artists/playlists from the server +# EnableDownloads = true + +# How long Navidrome will wait before closing web ui idle sessions +# SessionTimeout = "24h" + +# How many login requests can be processed from a single IP during the AuthWindowLength. Set to 0 to disable the limit rater +# AuthRequestLimit = 5 + +# Window Length for the authentication rate limit +# AuthWindowLength = "20s" + +# Select metadata extractor implementation. Options: taglib or ffmpeg +# Scanner.Extractor = "taglib" + +# List of separators to split genre tags +# Scanner.GenreSeparators = ";/," + +# Set this to false to completely disable Last.fm integration +# LastFM.Enabled = true + +# Last.fm ApiKey +# LastFM.ApiKey = "Navidrome project's shared ApiKey" + +# Last.fm Shared Secret +# LastFM.Secret = "Navidrome project's shared Secret" + +# Two letter-code for language to be used to retrieve biographies from Last.fm +# LastFM.Language = "en" + +# Spotify Client ID. Required if you want Artist images +# Spotify.ID = "" + +# Spotify Client Secret. Required if you want Artist images +# Spotify.Secret = "" + +# Set this to false to completely disable ListenBrainz integration +# ListenBrainz.Enabled = true + +# Use Gravatar images as the user profile image. Needs the user's email to be filled +# EnableGravatar = false + +# Set this to false to completely disable ALL external integrations +# EnableExternalServices = true + +# Enable toggling "Heart"/"Loved" for songs/albums/artists in the UI (maps to "Star"/"Starred" in Subsonic Clients) +# EnableFavourites = true + +# Enable 5-star ratings in the UI +# EnableStarRating = true + +# Enable regular users to edit their details and change their password +# EnableUserEditing = true + +# Passphrase used to encrypt passwords in the DB. +# For details see: https://www.navidrome.org/docs/usage/security/#encrypted-passwords) +# PasswordEncryptionKey = "-" + +# HTTP header containing user name from authenticated proxy +# ReverseProxyUserHeader = "Remote-User" + +# Comma separated list of IP CIDRs which are allowed to use reverse proxy authentication, empty means "deny all" +# ReverseProxyWhitelist = "" diff --git a/spk/navidrome/src/service-setup.sh b/spk/navidrome/src/service-setup.sh new file mode 100644 index 00000000000..ee32310db25 --- /dev/null +++ b/spk/navidrome/src/service-setup.sh @@ -0,0 +1,15 @@ + +CONFIG_FILE="${SYNOPKG_PKGVAR}/navidrome.toml" +SERVICE_COMMAND="${SYNOPKG_PKGDEST}/bin/navidrome --port ${SERVICE_PORT} --configfile=${CONFIG_FILE}" +SVC_WRITE_PID=y +SVC_BACKGROUND=y + +# navidrome executable does not contain rpath +export LD_LIBRARY_PATH="${SYNOPKG_PKGDEST}/lib" + +service_postinst () +{ + # update config with values from wizard variables + sed -e "s|@@wizard_music_folder@@|${SHARE_PATH}|g" \ + -i "${CONFIG_FILE}" +} diff --git a/spk/navidrome/src/wizard/install_uifile b/spk/navidrome/src/wizard/install_uifile new file mode 100644 index 00000000000..d1fa20df0f1 --- /dev/null +++ b/spk/navidrome/src/wizard/install_uifile @@ -0,0 +1,26 @@ +[{ + "step_title": "Basic configuration", + "items": [ + { + "type": "textfield", + "desc": "Shared music folder. This must be a name for the shared folder only, without any path. This share is created at installation when it does not already exist.", + "subitems": [{ + "key": "wizard_music_folder", + "desc": "Shared music folder", + "defaultValue": "music", + "validator": { + "allowBlank": false, + "regex": { + "expr": "/^[^<>: */?\"]*/", + "errorText": "Share name must be a folder name only. Path separators, spaces and other special chars are not allowed." + } + } + } + ] + }, { + "desc": "" + }, { + "desc": "Navidrome runs as internal service user 'sc-navidrome' in DSM. The shared music folder above is configured at installation time to be accessible by this user.

If you manually change the music folder, make sure 'sc-navidrome' has permissions to access it.

Please read Permission Management for details." + } + ] +}]