/
/
/
1# syntax=docker/dockerfile:1
2
3# Python version is centralized in .python-version at repo root.
4# Workflows read that file and pass it here via --build-arg PYTHON_VERSION=...
5# The default below is a safety net for manual `docker build` without --build-arg.
6ARG PYTHON_VERSION=3.14
7
8# BASE docker image for music assistant container
9# This image forms the base for the final image and is not meant to be used directly
10# NOTE that the dev add-on is also based on this base image
11
12FROM python:${PYTHON_VERSION}-slim-trixie AS ffmpeg-builder
13
14# Enable non-free and contrib repositories for FDK-AAC and other codecs
15# (trixie uses the deb822 sources format)
16RUN sed -i 's/^Components: .*/Components: main contrib non-free non-free-firmware/' /etc/apt/sources.list.d/debian.sources
17
18# Install build dependencies for FFmpeg
19RUN apt-get update && apt-get install -y --no-install-recommends \
20 build-essential \
21 pkg-config \
22 yasm \
23 nasm \
24 git \
25 wget \
26 ca-certificates \
27 # Audio codec libraries
28 libfdk-aac-dev \
29 libmp3lame-dev \
30 libopus-dev \
31 libvorbis-dev \
32 libsoxr-dev \
33 libspeex-dev \
34 libtwolame-dev \
35 libvo-amrwbenc-dev \
36 libopencore-amrnb-dev \
37 libopencore-amrwb-dev \
38 libshine-dev \
39 # Audio processing and filters
40 librubberband-dev \
41 libbs2b-dev \
42 libsamplerate0-dev \
43 libmysofa-dev \
44 libjack-jackd2-dev \
45 libpulse-dev \
46 # Additional libraries
47 libbluray-dev \
48 libxml2-dev \
49 libssh-dev \
50 liblzma-dev \
51 # SSL/TLS support for HTTPS
52 libssl-dev \
53 && rm -rf /var/lib/apt/lists/*
54
55# Build FFmpeg 7.1.2 from source with comprehensive audio codec support
56ARG FFMPEG_VERSION=7.1.2
57RUN set -x \
58 && wget -q "https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.xz" -O /tmp/ffmpeg.tar.xz \
59 && tar -xJf /tmp/ffmpeg.tar.xz -C /tmp \
60 && cd /tmp/ffmpeg-${FFMPEG_VERSION} \
61 && ./configure \
62 --prefix=/usr/local \
63 --enable-gpl \
64 --enable-nonfree \
65 --enable-version3 \
66 # Audio codecs (comprehensive support)
67 --enable-libfdk-aac \
68 --enable-libmp3lame \
69 --enable-libopus \
70 --enable-libvorbis \
71 --enable-libspeex \
72 --enable-libtwolame \
73 --enable-libshine \
74 --enable-libopencore-amrnb \
75 --enable-libopencore-amrwb \
76 --enable-libvo-amrwbenc \
77 # Audio filters and resampling
78 --enable-libsoxr \
79 --enable-librubberband \
80 --enable-libbs2b \
81 --enable-libmysofa \
82 --enable-libjack \
83 --enable-libpulse \
84 # SSL/TLS support for HTTPS
85 --enable-openssl \
86 # Additional libraries for playlist and network support
87 --enable-libxml2 \
88 --enable-libssh \
89 --enable-lzma \
90 # Optimizations
91 --enable-runtime-cpudetect \
92 # Disable unnecessary features for smaller build
93 --disable-doc \
94 --disable-htmlpages \
95 --disable-manpages \
96 --disable-podpages \
97 --disable-txtpages \
98 --disable-debug \
99 --disable-static \
100 --enable-shared \
101 && make -j$(nproc) \
102 && make install \
103 && strip /usr/local/bin/ffmpeg /usr/local/bin/ffprobe \
104 && rm -rf /tmp/ffmpeg*
105
106##################################################################################################
107
108# PyAV wheel builder - builds PyAV against the custom FFmpeg
109FROM python:${PYTHON_VERSION}-slim-trixie AS pyav-builder
110
111RUN apt-get update && apt-get install -y --no-install-recommends \
112 gcc g++ python3-dev pkg-config && rm -rf /var/lib/apt/lists/*
113
114COPY --from=ffmpeg-builder /usr/local/lib/libav*.so* /usr/local/lib/
115COPY --from=ffmpeg-builder /usr/local/lib/libsw*.so* /usr/local/lib/
116COPY --from=ffmpeg-builder /usr/local/lib/libpostproc.so* /usr/local/lib/
117COPY --from=ffmpeg-builder /usr/local/include/ /usr/local/include/
118COPY --from=ffmpeg-builder /usr/local/lib/pkgconfig/ /usr/local/lib/pkgconfig/
119
120RUN ldconfig
121ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
122
123# Build PyAV wheel against the custom FFmpeg with the in the Sendspin provider manifest pinned version
124COPY music_assistant/providers/sendspin/manifest.json /tmp/sendspin_manifest.json
125RUN PYAV_VERSION=$(python -c "import json; reqs=json.load(open('/tmp/sendspin_manifest.json'))['requirements']; print(next(r.split('==')[1] for r in reqs if r.startswith('av==')))") && \
126 echo "Building PyAV version: ${PYAV_VERSION}" && \
127 pip wheel --no-binary av av==${PYAV_VERSION} -w /wheels/
128
129##################################################################################################
130
131# Build shairport-sync (airplay receiver provider) from source against this image's
132# libraries, using the same configuration as music_assistant/providers/airplay_receiver/bin/build_binaries.sh:
133# tinysvcmdns as embedded mDNS backend (no avahi), stdout/pipe outputs and metadata support.
134FROM python:${PYTHON_VERSION}-slim-trixie AS shairport-builder
135
136RUN apt-get update && apt-get install -y --no-install-recommends \
137 build-essential \
138 git \
139 autoconf \
140 automake \
141 libtool \
142 pkg-config \
143 libconfig-dev \
144 libpopt-dev \
145 libssl-dev \
146 libdbus-1-dev \
147 libglib2.0-dev \
148 ca-certificates \
149 && rm -rf /var/lib/apt/lists/*
150
151# Version and its commit SHA are the single source of truth (also read by
152# build_binaries.sh). Tags are mutable, so the fetched tag is verified against the
153# pinned SHA. Bump both when changing the version.
154ARG SHAIRPORT_VERSION=4.3.7
155ARG SHAIRPORT_SHA=0b1c4391ffd398e7b145eb4b98416261380adeea
156RUN set -x \
157 && git init /tmp/shairport-sync \
158 && cd /tmp/shairport-sync \
159 && git remote add origin https://github.com/mikebrady/shairport-sync.git \
160 && git fetch --depth 1 origin refs/tags/${SHAIRPORT_VERSION} \
161 && git checkout FETCH_HEAD \
162 && test "$(git rev-parse HEAD)" = "${SHAIRPORT_SHA}" \
163 && autoreconf -fi \
164 && ./configure \
165 --with-pipe \
166 --with-metadata \
167 --without-avahi \
168 --without-dns-sd \
169 --with-tinysvcmdns \
170 --with-ssl=openssl \
171 --with-stdout \
172 --sysconfdir=/etc \
173 && make -j$(nproc) \
174 && strip shairport-sync \
175 && cp shairport-sync /usr/local/bin/shairport-sync \
176 && rm -rf /tmp/shairport-sync
177
178##################################################################################################
179
180FROM python:${PYTHON_VERSION}-slim-trixie
181
182# Enable non-free and contrib repositories for codec libraries
183# (trixie uses the deb822 sources format)
184RUN sed -i 's/^Components: .*/Components: main contrib non-free non-free-firmware/' /etc/apt/sources.list.d/debian.sources
185
186# Install runtime dependencies
187RUN set -x \
188 && apt-get update \
189 && apt-get install -y --no-install-recommends \
190 ca-certificates \
191 libjemalloc2 \
192 tzdata \
193 wget \
194 # cifs utils and libnfs are needed for smb and nfs support (file provider)
195 cifs-utils \
196 libnfs14 \
197 nfs-common \
198 # airplay libraries
199 openssl \
200 libssl-dev \
201 libuuid1 \
202 libcurl4 \
203 libsodium23 \
204 libconfuse2 \
205 libevent-dev \
206 libjson-c5 \
207 libgcrypt20 \
208 # glib is needed by the shairport-sync binary (previously pulled in only
209 # indirectly via the pipewire/pulseaudio utils)
210 libglib2.0-0 \
211 # libsndfile needed for librosa audio file support (smartfades)
212 libsndfile1 \
213 # libchromaprint needed for AcoustID fingerprinting (acoustid_lookup)
214 libchromaprint1 \
215 # Audio codec runtime libraries (needed for FFmpeg)
216 libfdk-aac2 \
217 libmp3lame0 \
218 libopus0 \
219 libvorbis0a \
220 libvorbisenc2 \
221 libsoxr0 \
222 libspeex1 \
223 libtwolame0 \
224 libshine3 \
225 libopencore-amrnb0 \
226 libopencore-amrwb0 \
227 libvo-amrwbenc0 \
228 # Audio processing libraries
229 librubberband2 \
230 libbs2b0 \
231 libsamplerate0 \
232 libmysofa1 \
233 libjack-jackd2-0 \
234 libpulse0 \
235 # Additional libraries
236 libbluray2 \
237 libxml2 \
238 libssh-4 \
239 liblzma5 \
240 # Snapcast dependencies
241 libasound2 \
242 # PortAudio for local audio output (sounddevice)
243 libportaudio2 \
244 # Allows pipewire devices to be detected when running in docker container. (local audio)
245 pipewire-alsa \
246 # Allows pulse audio devices to be detected using pactl. (local audio)
247 pulseaudio-utils \
248 libvorbisidec1 \
249 libflac14 \
250 libavahi-client3 \
251 libavahi-common3 \
252 # AirPlay receiver dependencies (shairport-sync)
253 libconfig11 \
254 libpopt0 \
255 && apt-get clean \
256 && rm -rf /var/lib/apt/lists/* \
257 && rm -f \
258 /usr/bin/parecord \
259 /usr/bin/paplay \
260 /usr/bin/parec \
261 /usr/bin/pamon \
262 /usr/bin/pacat \
263 /usr/bin/pasuspender \
264 /usr/bin/pacmd
265
266# Install Snapcast 0.34.0 from GitHub releases (requires at least 0.27)
267ARG SNAPCAST_VERSION=0.34.0
268ARG TARGETARCH
269RUN set -x \
270 && if [ "$TARGETARCH" = "arm64" ]; then \
271 SNAPCAST_ARCH="arm64"; \
272 else \
273 SNAPCAST_ARCH="amd64"; \
274 fi \
275 && wget -q "https://github.com/badaix/snapcast/releases/download/v${SNAPCAST_VERSION}/snapserver_${SNAPCAST_VERSION}-1_${SNAPCAST_ARCH}_trixie.deb" -O /tmp/snapserver.deb \
276 && wget -q "https://github.com/badaix/snapcast/releases/download/v${SNAPCAST_VERSION}/snapclient_${SNAPCAST_VERSION}-1_${SNAPCAST_ARCH}_trixie.deb" -O /tmp/snapclient.deb \
277 # install via apt so any missing dependencies of the debs are resolved as well
278 && apt-get update \
279 && apt-get install -y --no-install-recommends /tmp/snapserver.deb /tmp/snapclient.deb \
280 && apt-get clean \
281 && rm -rf /var/lib/apt/lists/* \
282 && rm /tmp/snapserver.deb /tmp/snapclient.deb
283
284# Install go-librespot (used by the Spotify Connect provider) from GitHub releases.
285# The release binaries statically link libvorbis/libogg/libFLAC, so the only dynamic
286# dependency is libasound2 (already installed above for Snapcast).
287# The pinned SHA256 per arch is verified before extraction; bump both when changing the version.
288ARG GO_LIBRESPOT_VERSION=0.7.4
289RUN set -x \
290 && if [ "$TARGETARCH" = "arm64" ]; then \
291 GO_LIBRESPOT_ARCH="arm64"; \
292 GO_LIBRESPOT_SHA256="62b6c7ebee6abb1f59fa3cf20a9374dd5e8c5c1ca5dab329dd312f66b59faa8d"; \
293 else \
294 GO_LIBRESPOT_ARCH="x86_64"; \
295 GO_LIBRESPOT_SHA256="ee521eed02100ee4aa9919a147304aed5afc908c5a0c99f515c3da0aed89acf7"; \
296 fi \
297 && wget -q "https://github.com/devgianlu/go-librespot/releases/download/v${GO_LIBRESPOT_VERSION}/go-librespot_linux_${GO_LIBRESPOT_ARCH}.tar.gz" -O /tmp/go-librespot.tar.gz \
298 && echo "${GO_LIBRESPOT_SHA256} /tmp/go-librespot.tar.gz" | sha256sum -c - \
299 && tar -xzf /tmp/go-librespot.tar.gz -C /usr/local/bin go-librespot \
300 && chmod +x /usr/local/bin/go-librespot \
301 && rm /tmp/go-librespot.tar.gz
302
303# Copy FFmpeg binaries and libraries from builder stage
304COPY --from=ffmpeg-builder /usr/local/bin/ffmpeg /usr/local/bin/
305COPY --from=ffmpeg-builder /usr/local/bin/ffprobe /usr/local/bin/
306COPY --from=ffmpeg-builder /usr/local/lib/libav*.so* /usr/local/lib/
307COPY --from=ffmpeg-builder /usr/local/lib/libsw*.so* /usr/local/lib/
308COPY --from=ffmpeg-builder /usr/local/lib/libpostproc.so* /usr/local/lib/
309
310# Copy shairport-sync binary from builder stage (found by the airplay receiver
311# provider via its system PATH lookup)
312COPY --from=shairport-builder /usr/local/bin/shairport-sync /usr/local/bin/
313
314# Copy pre-built PyAV wheel for use by downstream images
315COPY --from=pyav-builder /wheels/ /usr/local/share/pyav-wheels/
316
317# Update shared library cache and verify FFmpeg
318RUN ldconfig && ffmpeg -version && ffprobe -version
319
320# Copy widevine client files to container
321RUN mkdir -p /usr/local/bin/widevine_cdm
322COPY widevine_cdm/* /usr/local/bin/widevine_cdm/
323
324# we need to set (very permissive) permissions to the workdir
325# and /tmp to allow running the container as non-root
326RUN chmod -R 777 /tmp
327
328LABEL \
329 org.opencontainers.image.title="Music Assistant Base Image" \
330 org.opencontainers.image.description="Base Image for Music Assistant server - not to be used directly" \
331 org.opencontainers.image.source="https://github.com/music-assistant/server" \
332 org.opencontainers.image.authors="The Music Assistant Team" \
333 org.opencontainers.image.licenses="Apache License 2.0"
334