#!/usr/bin/env bash # Build a Debian/Ubuntu .deb for Timbre from the Flutter Linux release bundle. # # Works even on non-Debian hosts (e.g. Arch): a .deb is an `ar` archive of # `debian-binary` + `control.tar.gz` + `data.tar.gz`, so we assemble it with # `ar` + `tar` and never need `dpkg-deb`. # # Runtime deps are declared in the control file below. On Linux, media_kit # loads the *system* libmpv at runtime (it is NOT bundled), so libmpv is a hard # dependency. libsecret backs flutter_secure_storage; GTK backs the embedder. # # Usage: packaging/build_deb.sh [version] [arch] set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" VERSION="${1:-$(grep -m1 '^version:' pubspec.yaml | sed -E 's/version:\s*([0-9.]+).*/\1/')}" ARCH="${2:-amd64}" APPID="com.laforrestchurch.timbre" BUNDLE="build/linux/x64/release/bundle" OUT="build/deb" PKGDIR="$OUT/timbre_${VERSION}_${ARCH}" if [[ ! -x "$BUNDLE/timbre" ]]; then echo "Release bundle not found at $BUNDLE — run: flutter build linux --release" >&2 exit 1 fi echo "==> Staging package tree ($VERSION / $ARCH)" rm -rf "$PKGDIR" mkdir -p "$PKGDIR/opt/timbre" \ "$PKGDIR/usr/bin" \ "$PKGDIR/usr/share/applications" \ "$PKGDIR/usr/share/pixmaps" \ "$PKGDIR/usr/share/icons/hicolor/512x512/apps" \ "$PKGDIR/DEBIAN" # App payload → /opt/timbre; /usr/bin/timbre is a symlink (Flutter resolves # lib/ and data/ relative to the resolved executable path via /proc/self/exe). cp -r "$BUNDLE/." "$PKGDIR/opt/timbre/" ln -sf /opt/timbre/timbre "$PKGDIR/usr/bin/timbre" # Icon (into pixmaps for universal fallback + hicolor for modern launchers). cp assets/icon/icon.png "$PKGDIR/usr/share/pixmaps/timbre.png" cp assets/icon/icon.png "$PKGDIR/usr/share/icons/hicolor/512x512/apps/timbre.png" cat > "$PKGDIR/usr/share/applications/${APPID}.desktop" < "$PKGDIR/DEBIAN/control" < Installed-Size: ${INSTALLED_KB} Depends: libgtk-3-0 | libgtk-3-0t64, libmpv2 | libmpv1, libsecret-1-0 Recommends: avahi-daemon Description: Timbre — a Subsonic music client A Subsonic client for streaming your music library. Audio is played through libmpv, so it lands on the system mixer (PipeWire/PulseAudio) where a system equalizer such as EasyEffects can shape it. EOF # postinst/postrm: refresh desktop + icon caches when the tools exist (no-op # otherwise). Non-fatal so install never breaks on a minimal system. cat > "$PKGDIR/DEBIAN/postinst" <<'EOF' #!/bin/sh set -e if command -v update-desktop-database >/dev/null 2>&1; then update-desktop-database -q /usr/share/applications || true fi if command -v gtk-update-icon-cache >/dev/null 2>&1; then gtk-update-icon-cache -q /usr/share/icons/hicolor || true fi EOF cp "$PKGDIR/DEBIAN/postinst" "$PKGDIR/DEBIAN/postrm" chmod 0755 "$PKGDIR/DEBIAN/postinst" "$PKGDIR/DEBIAN/postrm" # md5sums for every payload file (relative paths, no ./ prefix — dpkg style). ( cd "$PKGDIR" && find opt usr -type f -print0 | xargs -0 md5sum > DEBIAN/md5sums ) echo "==> Assembling .deb" BUILD="$OUT/_assemble" rm -rf "$BUILD"; mkdir -p "$BUILD" echo "2.0" > "$BUILD/debian-binary" # control.tar.gz from DEBIAN/ contents; data.tar.gz from the filesystem tree. tar --owner=0 --group=0 --numeric-owner -czf "$BUILD/control.tar.gz" -C "$PKGDIR/DEBIAN" . tar --owner=0 --group=0 --numeric-owner -czf "$BUILD/data.tar.gz" \ -C "$PKGDIR" --exclude=./DEBIAN . DEB="$OUT/timbre_${VERSION}_${ARCH}.deb" rm -f "$DEB" # Member order is mandated by the .deb format: debian-binary, control, data. ( cd "$BUILD" && ar rc "$OLDPWD/$DEB" debian-binary control.tar.gz data.tar.gz ) rm -rf "$BUILD" echo "==> Built: $DEB" ls -lh "$DEB" echo "==> Contents (ar members):" && ar t "$DEB"