feat(build): cross-platform desktop packaging; bump to 0.1.0
Build & Release / Run Tests (push) Has been cancelled
Traceability Validation / Check Requirement Traces (push) Has been cancelled
Build & Release / Build Linux (push) Has been cancelled
Build & Release / Build Android (push) Has been cancelled
Publish Documentation / Build & publish docs to gitea-pages (push) Has been cancelled
🏗️ Build and Test JellyTau / Android Compile Check (push) Has been cancelled
Build & Release / Create Release (push) Has been cancelled
🏗️ Build and Test JellyTau / Run Tests (push) Has been cancelled
Build & Release / Run Tests (push) Has been cancelled
Traceability Validation / Check Requirement Traces (push) Has been cancelled
Build & Release / Build Linux (push) Has been cancelled
Build & Release / Build Android (push) Has been cancelled
Publish Documentation / Build & publish docs to gitea-pages (push) Has been cancelled
🏗️ Build and Test JellyTau / Android Compile Check (push) Has been cancelled
Build & Release / Create Release (push) Has been cancelled
🏗️ Build and Test JellyTau / Run Tests (push) Has been cancelled
Adds Docker-based packaging for Linux desktop (deb/rpm), Arch
(.pkg.tar.zst via makepkg), and Windows. Windows cross-compiles from
Linux via the official Tauri path — the x86_64-pc-windows-msvc target
driven by cargo-xwin — and produces an NSIS installer (nsis via
tauri.conf.json targets, since the CLI rejects --bundles nsis on a Linux
host). Verified end to end: builds jellytau.exe + jellytau_x64-setup.exe.
Unifies everything on one registry builder image (Dockerfile.builder):
Android SDK/NDK, rpm/file, clang(+clang-cl)/lld/llvm/nsis, cargo-xwin and
the msvc target. Packaging tools sit in a trailing layer so tool changes
rebuild in ~1min instead of ~15. Desktop stages are thin FROM
${BUILDER_IMAGE} layers; Arch uses a separate archlinux image.
CLAUDE.md: CI must install no system toolchains — everything lives in the
image. Bumps version 0.0.18 -> 0.1.0 (Windows support + webview audio +
equalizer).
TRACES: UR-003, UR-005 | DR-004
This commit is contained in:
@@ -35,6 +35,20 @@ CI runs on **Gitea Actions** (`.gitea/workflows/`), not GitHub. Use the `gh` CLI
|
||||
only against the mirror if one exists; the canonical remote is
|
||||
`gitea.tourolle.paris`.
|
||||
|
||||
> **🔴 CI installs no system tools.** Never add an `apt-get`, `rustup`,
|
||||
> `sdkmanager`, mingw/nsis, or any other *toolchain/system-package* install to a
|
||||
> CI workflow step. Every build, test, and packaging **tool** must already live
|
||||
> in the Docker image the job runs in — the unified builder (`Dockerfile.builder`
|
||||
> → `gitea.tourolle.paris/dtourolle/jellytau-builder`) for Android/Linux/Windows,
|
||||
> or `Dockerfile.arch` for Arch. If a job needs a tool the image lacks, **add it
|
||||
> to the image, rebuild + push it** (`scripts/build-builder-image.sh`), and use
|
||||
> it from CI — do not install it at job time. This keeps builds reproducible and
|
||||
> fast, and is why the packaging stages are thin `FROM ${BUILDER_IMAGE}` layers.
|
||||
>
|
||||
> `bun install` (fetching the project's own JS deps per the lockfile) is **not**
|
||||
> a violation — that's project dependencies, not a toolchain. The rule is about
|
||||
> system tools, not npm/bun/cargo *packages* declared by the project.
|
||||
|
||||
## Before Committing
|
||||
|
||||
- Frontend: `bun run check` and `bun run test` must pass.
|
||||
|
||||
+31
@@ -1,4 +1,11 @@
|
||||
# Multi-stage build for JellyTau - Tauri Jellyfin client
|
||||
#
|
||||
# The desktop packaging stages (desktop-linux-build, windows-cross) build FROM
|
||||
# the unified registry builder image, which carries every packaging tool. Declared
|
||||
# here (before the first FROM) so it's in scope for those stages' FROM lines.
|
||||
# Override for local iteration: --build-arg BUILDER_IMAGE=jellytau-builder:latest
|
||||
ARG BUILDER_IMAGE=gitea.tourolle.paris/dtourolle/jellytau-builder:latest
|
||||
|
||||
FROM ubuntu:24.04 AS builder
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
@@ -108,6 +115,30 @@ RUN cd src-tauri && cargo fetch && cd .. && \
|
||||
bun run tauri android build --apk true && \
|
||||
echo "APK build complete!"
|
||||
|
||||
# Desktop packaging stages build FROM the unified registry builder image (see the
|
||||
# BUILDER_IMAGE ARG at the top), which already carries every packaging tool
|
||||
# (rpm/file for Linux, mingw-w64 + nsis + the x86_64-pc-windows-gnu rust target
|
||||
# for Windows). ONE source of dependency truth, shared with CI — no per-stage
|
||||
# apt/rustup here.
|
||||
|
||||
# Linux desktop packaging environment (deb + rpm; Arch is Dockerfile.arch).
|
||||
# Thin layer over the builder — the actual build runs at container-run time on
|
||||
# the bind-mounted source (see docker-compose.yml / scripts/build-desktop-linux.sh),
|
||||
# matching the `dev` service model. Run standalone with:
|
||||
# docker run --rm -v "$PWD:/app" -v "$PWD/dist:/app/dist" <img> \
|
||||
# bash -c "OUTPUT_DIR=/app/dist scripts/build-desktop-linux.sh"
|
||||
FROM ${BUILDER_IMAGE} AS desktop-linux-build
|
||||
WORKDIR /app
|
||||
CMD ["bash", "-c", "OUTPUT_DIR=/app/dist scripts/build-desktop-linux.sh"]
|
||||
|
||||
# Windows cross-compile environment (MSVC target via cargo-xwin). Video works via
|
||||
# WebView2 and audio via the webview <audio> backend; NSIS installer is produced
|
||||
# from Linux by cargo-xwin. Default bundles NSIS; override WIN_BUNDLES=none for
|
||||
# exe-only. Build runs at container-run time like above.
|
||||
FROM ${BUILDER_IMAGE} AS windows-cross
|
||||
WORKDIR /app
|
||||
CMD ["bash", "-c", "OUTPUT_DIR=/app/dist WIN_BUNDLES=${WIN_BUNDLES:-nsis} scripts/build-windows-cross.sh"]
|
||||
|
||||
# Final output stage
|
||||
FROM ubuntu:24.04 AS final
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# JellyTau Arch Linux package builder.
|
||||
#
|
||||
# Tauri has no pacman bundle target, so we build a real .pkg.tar.zst with makepkg
|
||||
# from packaging/arch/PKGBUILD. makepkg refuses to run as root, so we create a
|
||||
# non-root `builder` user with passwordless sudo (for `makepkg -s` pacman calls).
|
||||
#
|
||||
# docker build -f Dockerfile.arch -t jellytau-arch .
|
||||
# docker run --rm -v "$PWD/dist:/out" jellytau-arch
|
||||
FROM archlinux:latest
|
||||
|
||||
RUN pacman -Syu --noconfirm \
|
||||
base-devel git sudo \
|
||||
rust cargo nodejs \
|
||||
webkit2gtk-4.1 mpv gtk3 libayatana-appindicator \
|
||||
libsoup3 pkgconf openssl \
|
||||
&& pacman -Scc --noconfirm
|
||||
|
||||
# Bun is not in the official repos; install the upstream binary.
|
||||
RUN curl -fsSL https://bun.sh/install | bash && \
|
||||
ln -s /root/.bun/bin/bun /usr/local/bin/bun
|
||||
|
||||
# Non-root build user with passwordless sudo for makepkg's dependency step.
|
||||
RUN useradd -m builder && \
|
||||
echo 'builder ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/builder && \
|
||||
ln -sf /root/.bun/bin/bun /usr/local/bin/bun
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN chown -R builder:builder /app
|
||||
|
||||
USER builder
|
||||
ENV OUTPUT_DIR=/out
|
||||
RUN mkdir -p /out
|
||||
VOLUME ["/out"]
|
||||
|
||||
# Default: build the package. Output lands in /out (mount it to collect the pkg).
|
||||
CMD ["bash", "-c", "OUTPUT_DIR=/out scripts/build-arch.sh"]
|
||||
+33
-1
@@ -1,5 +1,9 @@
|
||||
# JellyTau Builder Image
|
||||
# Pre-built image with all dependencies for building and testing
|
||||
# Pre-built image with all dependencies for building, testing, and packaging:
|
||||
# - Android APK (SDK/NDK), Linux desktop (deb/rpm),
|
||||
# - Windows cross via the official Tauri path: MSVC target + cargo-xwin + NSIS
|
||||
# Arch packages build in a separate archlinux image (Dockerfile.arch) since
|
||||
# makepkg is Arch-specific.
|
||||
# Push to your registry: docker build -f Dockerfile.builder -t gitea.tourolle.paris/dtourolle/jellytau-builder:latest .
|
||||
|
||||
FROM ubuntu:24.04
|
||||
@@ -83,6 +87,34 @@ RUN $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME \
|
||||
# Set NDK environment variable
|
||||
ENV NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Desktop packaging tools — kept in a trailing layer ON PURPOSE so that adding
|
||||
# or changing a packaging tool doesn't invalidate the expensive apt/rust/Android
|
||||
# layers above (a tool tweak becomes a ~1-2 min rebuild, not ~15). Covers Linux
|
||||
# (deb/rpm) and Windows cross (MSVC via cargo-xwin + NSIS).
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
# Linux desktop packaging: rpmbuild for the .rpm bundle (deb needs nothing extra)
|
||||
rpm \
|
||||
file \
|
||||
# Windows cross-compile (official Tauri path: MSVC target via cargo-xwin).
|
||||
# clang provides clang-cl, the MSVC-compatible C compiler cc-rs uses to build
|
||||
# C deps (bundled sqlite, ring, ...); lld = linker; llvm = llvm-lib/ar etc;
|
||||
# nsis = installer generator.
|
||||
clang \
|
||||
lld \
|
||||
llvm \
|
||||
nsis \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
# Ubuntu's clang package ships clang but NOT the clang-cl alias that cc-rs
|
||||
# invokes for MSVC targets. clang-cl is the same binary in MSVC-compat mode,
|
||||
# so provide it as a symlink.
|
||||
&& ln -sf /usr/bin/clang /usr/local/bin/clang-cl
|
||||
|
||||
# Windows rust target + cargo-xwin (downloads the MSVC CRT/SDK at build time).
|
||||
RUN . $HOME/.cargo/env && \
|
||||
rustup target add x86_64-pc-windows-msvc && \
|
||||
cargo install --locked cargo-xwin
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["/bin/bash"]
|
||||
|
||||
@@ -33,6 +33,58 @@ services:
|
||||
ports:
|
||||
- "5172:5172" # In case you want to run dev server
|
||||
|
||||
# Linux desktop packages - deb + rpm + pacman into ./dist
|
||||
desktop-linux-build:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: desktop-linux-build
|
||||
args:
|
||||
# Defaults to the registry builder (Dockerfile's ARG). Point at a locally
|
||||
# built builder with: BUILDER_IMAGE=jellytau-builder:latest docker compose ...
|
||||
BUILDER_IMAGE: ${BUILDER_IMAGE:-gitea.tourolle.paris/dtourolle/jellytau-builder:latest}
|
||||
container_name: jellytau-desktop-linux-build
|
||||
volumes:
|
||||
- .:/app
|
||||
- cargo-cache:/root/.cargo
|
||||
- bun-cache:/root/.bun
|
||||
environment:
|
||||
- RUST_BACKTRACE=1
|
||||
- OUTPUT_DIR=/app/dist
|
||||
command: bash -c "OUTPUT_DIR=/app/dist scripts/build-desktop-linux.sh"
|
||||
|
||||
# Arch Linux package (.pkg.tar.zst via makepkg) into ./dist
|
||||
arch-build:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.arch
|
||||
container_name: jellytau-arch-build
|
||||
volumes:
|
||||
- ./dist:/out
|
||||
environment:
|
||||
- RUST_BACKTRACE=1
|
||||
- OUTPUT_DIR=/out
|
||||
|
||||
# Windows cross-compile (MSVC via cargo-xwin). Emits NSIS installer + .exe to
|
||||
# ./dist. Override WIN_BUNDLES=none for exe-only.
|
||||
windows-cross:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: windows-cross
|
||||
args:
|
||||
BUILDER_IMAGE: ${BUILDER_IMAGE:-gitea.tourolle.paris/dtourolle/jellytau-builder:latest}
|
||||
container_name: jellytau-windows-cross
|
||||
volumes:
|
||||
- .:/app
|
||||
- cargo-cache:/root/.cargo
|
||||
- bun-cache:/root/.bun
|
||||
environment:
|
||||
- RUST_BACKTRACE=1
|
||||
- OUTPUT_DIR=/app/dist
|
||||
- WIN_BUNDLES=${WIN_BUNDLES:-nsis}
|
||||
command: bash -c "OUTPUT_DIR=/app/dist WIN_BUNDLES=${WIN_BUNDLES:-nsis} scripts/build-windows-cross.sh"
|
||||
|
||||
# Development container - for interactive development
|
||||
dev:
|
||||
build:
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# Desktop packaging (Linux, Arch, Windows)
|
||||
|
||||
How to produce distributable desktop packages for JellyTau. All three flows can
|
||||
run in Docker so no host toolchain setup is required. Outputs land in `./dist`.
|
||||
|
||||
## One builder image (shared with CI)
|
||||
|
||||
The deb/rpm and Windows-cross flows build on the **unified registry builder**
|
||||
([../Dockerfile.builder](../Dockerfile.builder) →
|
||||
`gitea.tourolle.paris/dtourolle/jellytau-builder`), the same image CI uses. It
|
||||
carries every packaging tool: Android SDK/NDK, `rpm`/`file` (Linux bundler),
|
||||
`cargo-xwin` + `lld` + `llvm` + `nsis` + the `x86_64-pc-windows-msvc` rust target
|
||||
(Windows). There is **one** dependency source of truth — no per-stage tool
|
||||
installs.
|
||||
|
||||
The desktop stages in [../Dockerfile](../Dockerfile) are thin `FROM
|
||||
${BUILDER_IMAGE}` environments; the actual build runs at container-run time on
|
||||
your bind-mounted source (like the `dev` service), so source edits need no image
|
||||
rebuild.
|
||||
|
||||
**If you changed `Dockerfile.builder`** (e.g. added a tool), rebuild and push it
|
||||
first, or the packaging flows use the stale registry image:
|
||||
|
||||
```bash
|
||||
scripts/build-builder-image.sh # build + push :latest to the registry
|
||||
# ...or iterate locally without pushing:
|
||||
docker build -f Dockerfile.builder -t jellytau-builder:latest .
|
||||
BUILDER_IMAGE=jellytau-builder:latest bun run docker:build:windows
|
||||
```
|
||||
|
||||
Arch uses a separate `archlinux` image ([../Dockerfile.arch](../Dockerfile.arch))
|
||||
because `makepkg` is Arch-specific — it is not part of the unified builder.
|
||||
|
||||
| Target | Format | Docker command | Functional? |
|
||||
|--------|--------|----------------|-------------|
|
||||
| Debian/Ubuntu, Fedora | `.deb`, `.rpm` | `bun run docker:build:linux` | ✅ yes |
|
||||
| Arch Linux | `.pkg.tar.zst` | `bun run docker:build:arch` | ✅ yes |
|
||||
| Windows | NSIS installer + `.exe` | `bun run docker:build:windows` | ✅ yes (unsigned) |
|
||||
|
||||
## Linux: deb + rpm
|
||||
|
||||
Tauri's bundler produces these natively. The build runs on the existing Ubuntu
|
||||
builder image ([../Dockerfile](../Dockerfile), `desktop-linux-build` stage):
|
||||
|
||||
```bash
|
||||
bun run docker:build:linux # deb + rpm -> ./dist
|
||||
# or, on a host with the Tauri Linux deps installed:
|
||||
BUNDLES="deb,rpm" scripts/build-desktop-linux.sh
|
||||
```
|
||||
|
||||
Runtime dependency: the app links libmpv (audio) and WebKitGTK (webview + HTML5
|
||||
transcoded video). The deb/rpm declare these.
|
||||
|
||||
> Note: `appimage` is also a valid Tauri target if you want a portable bundle —
|
||||
> add it to `BUNDLES`.
|
||||
|
||||
## Arch Linux: pacman package
|
||||
|
||||
**Tauri has no `pacman` bundle target** (as of tauri-cli 2.9.x — valid targets
|
||||
are deb/rpm/appimage/msi/nsis/app/dmg). So we ship a hand-written PKGBUILD in
|
||||
[../packaging/arch/PKGBUILD](../packaging/arch/PKGBUILD) and build it with
|
||||
`makepkg` on an Arch base image ([../Dockerfile.arch](../Dockerfile.arch)):
|
||||
|
||||
```bash
|
||||
bun run docker:build:arch # .pkg.tar.zst -> ./dist
|
||||
```
|
||||
|
||||
The PKGBUILD is AUR-ready: swap its `source=()` for a release tarball/VCS URL to
|
||||
publish. Runtime deps: `webkit2gtk-4.1`, `mpv`, `gtk3`, `libayatana-appindicator`.
|
||||
|
||||
`makepkg` refuses to run as root, so the Docker stage builds as a non-root
|
||||
`builder` user. Because the image `COPY`s the source at build time, the
|
||||
`arch-build` compose service does **not** bind-mount the repo — rebuild the image
|
||||
to pick up source changes.
|
||||
|
||||
## Windows: NSIS installer cross-compiled from Linux
|
||||
|
||||
Produces a working (unsigned) NSIS installer + `.exe` via the official Tauri
|
||||
cross-compile path — the `x86_64-pc-windows-msvc` target driven by `cargo-xwin`.
|
||||
Video plays via WebView2 and audio via the webview `<audio>` backend. See
|
||||
[build-windows.md](build-windows.md) for the full explanation.
|
||||
|
||||
```bash
|
||||
bun run docker:build:windows # NSIS installer + .exe -> ./dist
|
||||
WIN_BUNDLES=none bun run docker:build:windows # exe only, skip bundling
|
||||
```
|
||||
|
||||
The Docker `windows-cross` stage is a thin layer over the builder, which carries
|
||||
`cargo-xwin` + `lld` + `llvm` + `nsis` + the `x86_64-pc-windows-msvc` target.
|
||||
Cross-compilation is Tauri's "last resort" path (less tested than building on
|
||||
Windows); a `windows-latest` CI job is the fallback if it misbehaves.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Windows build
|
||||
|
||||
JellyTau targets Linux and Android primarily, but a working Windows build —
|
||||
including an **NSIS installer cross-compiled from Linux** — is produced by the
|
||||
Docker tooling. It is not yet a first-class release target (no code signing / CI
|
||||
job / SMTC lockscreen), but it runs and plays media.
|
||||
|
||||
## How playback works on Windows
|
||||
|
||||
- **Video** — renders through the webview HTML5 `<video>` element (hls.js) on
|
||||
*every* platform; on Windows that is WebView2 (Chromium/Edge), which plays HLS +
|
||||
h264 fine. No Windows-specific code.
|
||||
- **Audio-only (music)** — the native audio backends are libmpv (Linux) and
|
||||
ExoPlayer (Android); neither exists on Windows. Instead
|
||||
`create_player_backend()` in [../src-tauri/src/lib.rs](../src-tauri/src/lib.rs)
|
||||
uses `WebviewAudioBackend` on non-Linux/non-Android targets: it hands the stream
|
||||
URL to a webview `<audio>` element (see
|
||||
[../src/lib/services/webviewAudio.ts](../src/lib/services/webviewAudio.ts)),
|
||||
which reports state back through the same `player_report_*` round-trip the video
|
||||
path uses. Pure Rust + Tauri events.
|
||||
|
||||
## Cross-compiling from Linux (MSVC + cargo-xwin)
|
||||
|
||||
We use the [official Tauri cross-compile path](https://v2.tauri.app/distribute/windows-installer/):
|
||||
the **MSVC** target (`x86_64-pc-windows-msvc`) driven by
|
||||
[`cargo-xwin`](https://github.com/rust-cross/cargo-xwin), which downloads the MSVC
|
||||
CRT / Windows SDK headers and links with `lld`. MSVC is the target Tauri
|
||||
officially supports for Windows (mingw/GNU is not), and — unlike GNU — it lets the
|
||||
Tauri CLI bundle the **NSIS installer from a Linux host**.
|
||||
|
||||
> Why not mingw/GNU? The GNU target *does* link a valid `.exe`, but the Tauri CLI
|
||||
> gates `--bundles` by the host OS unless it recognizes a real Windows build.
|
||||
> `--runner cargo-xwin --target x86_64-pc-windows-msvc` is what flips it into
|
||||
> Windows mode and enables the `nsis`/`msi` bundlers on Linux.
|
||||
|
||||
The builder image ([../Dockerfile.builder](../Dockerfile.builder)) bakes in the
|
||||
whole toolchain: the `x86_64-pc-windows-msvc` rust target, `cargo-xwin`, `lld`,
|
||||
`llvm`, and `nsis`.
|
||||
|
||||
```bash
|
||||
bun run docker:build:windows # NSIS installer + .exe -> ./dist
|
||||
WIN_BUNDLES=none bun run docker:build:windows # exe only, skip bundling
|
||||
```
|
||||
|
||||
Or directly on a host that has the toolchain:
|
||||
|
||||
```bash
|
||||
scripts/build-windows-cross.sh # nsis installer + exe
|
||||
WIN_BUNDLES=none scripts/build-windows-cross.sh # exe only
|
||||
```
|
||||
|
||||
Under the hood the build runs:
|
||||
|
||||
```bash
|
||||
tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis
|
||||
```
|
||||
|
||||
Outputs:
|
||||
- `.exe` — `src-tauri/target/x86_64-pc-windows-msvc/release/jellytau.exe`
|
||||
- NSIS installer — `.../release/bundle/nsis/*-setup.exe`
|
||||
|
||||
(both copied to `./dist` when `OUTPUT_DIR` is set).
|
||||
|
||||
## Caveats
|
||||
|
||||
- **Cross-compilation is a last resort** per Tauri's own docs — it's less tested
|
||||
than building on Windows. If it misbehaves, a `windows-latest` CI job or a
|
||||
Windows VM building natively (`tauri build --bundles nsis`) is the fallback.
|
||||
- **Code signing is not wired up** — the installer is unsigned, so Windows
|
||||
SmartScreen will warn on first run.
|
||||
|
||||
## Outstanding for a first-class Windows release
|
||||
|
||||
1. Gapless/crossfade + SMTC (lockscreen) — currently no-ops in the webview audio
|
||||
path.
|
||||
2. Downloaded (`Local` source) file playback needs `convertFileSrc` on the
|
||||
frontend; streaming works today.
|
||||
3. Code signing + a Windows packaging CI job.
|
||||
+7
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jellytau",
|
||||
"version": "0.0.18",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"packageManager": "bun@1.3.5",
|
||||
@@ -25,6 +25,12 @@
|
||||
"android:dev": "./scripts/build-and-deploy.sh",
|
||||
"android:check": "./scripts/check-android.sh",
|
||||
"android:logs": "./scripts/logcat.sh",
|
||||
"desktop:build:linux": "./scripts/build-desktop-linux.sh",
|
||||
"desktop:build:arch": "./scripts/build-arch.sh",
|
||||
"desktop:build:windows": "./scripts/build-windows-cross.sh",
|
||||
"docker:build:linux": "docker compose run --rm desktop-linux-build",
|
||||
"docker:build:arch": "docker compose run --rm arch-build",
|
||||
"docker:build:windows": "docker compose run --rm windows-cross",
|
||||
"clean": "./scripts/clean.sh",
|
||||
"tauri": "tauri",
|
||||
"traces": "bun run scripts/extract-traces.ts",
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Maintainer: Duncan Tourolle <duncan@tourolle.paris>
|
||||
#
|
||||
# JellyTau — a cross-platform Jellyfin client (Tauri + SvelteKit).
|
||||
#
|
||||
# This PKGBUILD builds from the local source tree by default (see the `dev`
|
||||
# convenience below), which is what scripts/build-arch.sh uses inside the Arch
|
||||
# Docker stage. For AUR distribution, replace the `source=()` line with a release
|
||||
# tarball/VCS URL and drop the local-copy prepare() step.
|
||||
|
||||
pkgname=jellytau
|
||||
pkgver=0.0.18
|
||||
pkgrel=1
|
||||
pkgdesc="A cross-platform Jellyfin client"
|
||||
arch=('x86_64')
|
||||
url="https://gitea.tourolle.paris/dtourolle/jellytau"
|
||||
license=('MIT')
|
||||
# Runtime: libmpv for audio, webkit2gtk for the webview + HTML5 transcoded video.
|
||||
depends=('webkit2gtk-4.1' 'mpv' 'gtk3' 'libayatana-appindicator')
|
||||
makedepends=('rust' 'cargo' 'bun' 'nodejs' 'pkgconf' 'libsoup3')
|
||||
options=('!strip' '!lto')
|
||||
|
||||
# Populated from the working tree by scripts/build-arch.sh (SRC env var).
|
||||
_srcdir="${JELLYTAU_SRC:-$startdir/../..}"
|
||||
|
||||
build() {
|
||||
cd "$_srcdir"
|
||||
export CARGO_HOME="${CARGO_HOME:-$srcdir/cargo-home}"
|
||||
bun install --frozen-lockfile || bun install
|
||||
bun run build
|
||||
# Only the raw binary is needed; packaging is done in package() below so we
|
||||
# control the Arch filesystem layout ourselves rather than via tauri-bundler.
|
||||
(cd src-tauri && cargo build --release --locked)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$_srcdir"
|
||||
|
||||
install -Dm755 "src-tauri/target/release/jellytau" \
|
||||
"$pkgdir/usr/bin/jellytau"
|
||||
|
||||
# Desktop entry
|
||||
install -Dm644 "packaging/arch/jellytau.desktop" \
|
||||
"$pkgdir/usr/share/applications/jellytau.desktop"
|
||||
|
||||
# Icons (hicolor)
|
||||
install -Dm644 "src-tauri/icons/32x32.png" \
|
||||
"$pkgdir/usr/share/icons/hicolor/32x32/apps/jellytau.png"
|
||||
install -Dm644 "src-tauri/icons/128x128.png" \
|
||||
"$pkgdir/usr/share/icons/hicolor/128x128/apps/jellytau.png"
|
||||
install -Dm644 "src-tauri/icons/128x128@2x.png" \
|
||||
"$pkgdir/usr/share/icons/hicolor/256x256/apps/jellytau.png"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=JellyTau
|
||||
Comment=A cross-platform Jellyfin client
|
||||
Exec=jellytau
|
||||
Icon=jellytau
|
||||
Terminal=false
|
||||
Categories=AudioVideo;Player;Audio;Video;
|
||||
StartupWMClass=jellytau
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# Build an Arch Linux package (.pkg.tar.zst) for JellyTau via makepkg.
|
||||
#
|
||||
# Tauri's bundler has no pacman target (as of tauri-cli 2.9.x), so we ship a
|
||||
# hand-written PKGBUILD in packaging/arch/ and build it with makepkg. This must
|
||||
# run on an Arch host / the `arch-build` Docker stage — makepkg is Arch-specific
|
||||
# and refuses to run as root, so run it as a non-root user with sudo for deps.
|
||||
#
|
||||
# Usage (typically inside the arch-build Docker stage as a non-root user):
|
||||
# scripts/build-arch.sh
|
||||
# OUTPUT_DIR=/app/dist scripts/build-arch.sh
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$REPO_ROOT/packaging/arch"
|
||||
|
||||
echo "🏛️ Building JellyTau Arch package"
|
||||
echo "=================================="
|
||||
|
||||
# Point the PKGBUILD at the working tree and give cargo/bun a writable home.
|
||||
export JELLYTAU_SRC="$REPO_ROOT"
|
||||
export CARGO_HOME="${CARGO_HOME:-$REPO_ROOT/.cargo-arch}"
|
||||
|
||||
# -s installs missing deps (needs sudo/root privileges for pacman), -f overwrites.
|
||||
makepkg -sf --noconfirm
|
||||
|
||||
echo ""
|
||||
echo "✅ Built Arch package(s):"
|
||||
ls -1 ./*.pkg.tar.zst
|
||||
|
||||
if [[ -n "${OUTPUT_DIR:-}" ]]; then
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
cp -v ./*.pkg.tar.zst "$OUTPUT_DIR/"
|
||||
echo ""
|
||||
echo "📦 Copied Arch package(s) to $OUTPUT_DIR"
|
||||
fi
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
# Build Linux desktop packages (deb + rpm) for JellyTau.
|
||||
#
|
||||
# Produces bundles under src-tauri/target/release/bundle/{deb,rpm}.
|
||||
# Runs on the existing Ubuntu builder image. NOTE: Tauri has no pacman bundle
|
||||
# target — the Arch package is built separately with makepkg (scripts/build-arch.sh
|
||||
# / Dockerfile.arch). `appimage` is also available if you want a portable bundle.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/build-desktop-linux.sh # deb + rpm
|
||||
# BUNDLES="deb,appimage" scripts/build-desktop-linux.sh # subset / add appimage
|
||||
# OUTPUT_DIR=/app/dist scripts/build-desktop-linux.sh # copy bundles out
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
BUNDLES="${BUNDLES:-deb,rpm}"
|
||||
|
||||
echo "🐧 Building JellyTau Linux desktop packages"
|
||||
echo "==========================================="
|
||||
echo "Bundles: $BUNDLES"
|
||||
echo ""
|
||||
|
||||
bun install --frozen-lockfile 2>/dev/null || bun install
|
||||
bun run build
|
||||
|
||||
# --bundles overrides tauri.conf.json bundle.targets so this script controls
|
||||
# exactly which Linux formats are produced (never NSIS here).
|
||||
bun run tauri build --bundles "$BUNDLES"
|
||||
|
||||
BUNDLE_ROOT="src-tauri/target/release/bundle"
|
||||
echo ""
|
||||
echo "✅ Built packages:"
|
||||
find "$BUNDLE_ROOT" -maxdepth 2 -type f \
|
||||
\( -name '*.deb' -o -name '*.rpm' -o -name '*.AppImage' \) -print
|
||||
|
||||
if [[ -n "${OUTPUT_DIR:-}" ]]; then
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
find "$BUNDLE_ROOT" -maxdepth 2 -type f \
|
||||
\( -name '*.deb' -o -name '*.rpm' -o -name '*.AppImage' \) \
|
||||
-exec cp -v {} "$OUTPUT_DIR/" \;
|
||||
echo ""
|
||||
echo "📦 Copied bundles to $OUTPUT_DIR"
|
||||
fi
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
# Cross-compile JellyTau for Windows from Linux, producing an NSIS installer.
|
||||
#
|
||||
# Uses the OFFICIAL Tauri cross-compile path (https://v2.tauri.app/distribute/
|
||||
# windows-installer/): the MSVC target driven by cargo-xwin, which downloads the
|
||||
# MSVC CRT/Windows SDK headers and links with lld. This is the target Tauri
|
||||
# officially supports for Windows (the mingw/GNU target is not), and unlike GNU
|
||||
# it can bundle the NSIS installer from a Linux host.
|
||||
#
|
||||
# Playback on Windows: video renders via WebView2 and audio via the webview
|
||||
# <audio> backend (WebviewAudioBackend) — see docs/build-windows.md.
|
||||
#
|
||||
# Requirements (present in the Docker windows-cross target / unified builder):
|
||||
# - rustup target x86_64-pc-windows-msvc
|
||||
# - cargo-xwin (cargo install --locked cargo-xwin)
|
||||
# - lld, llvm (linker + llvm-lib used by cargo-xwin)
|
||||
# - nsis (makensis) (installer generator)
|
||||
#
|
||||
# Usage:
|
||||
# scripts/build-windows-cross.sh # exe + NSIS installer
|
||||
# WIN_BUNDLES=none scripts/build-windows-cross.sh # exe only, skip bundling
|
||||
# OUTPUT_DIR=/app/dist scripts/build-windows-cross.sh
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
TARGET="x86_64-pc-windows-msvc"
|
||||
WIN_BUNDLES="${WIN_BUNDLES:-nsis}"
|
||||
|
||||
echo "🪟 Cross-compiling JellyTau for Windows ($TARGET, via cargo-xwin)"
|
||||
echo "================================================================"
|
||||
echo "Video plays via WebView2; audio via the webview <audio> backend."
|
||||
echo "Bundles: $WIN_BUNDLES"
|
||||
echo ""
|
||||
|
||||
bun install --frozen-lockfile 2>/dev/null || bun install
|
||||
bun run build
|
||||
|
||||
# --runner cargo-xwin + the MSVC target is what makes the Tauri CLI treat this as
|
||||
# a real Windows build and enable the nsis/msi bundlers on a Linux host.
|
||||
#
|
||||
# IMPORTANT: do NOT pass `--bundles nsis` here. tauri-cli 2.9.x validates the
|
||||
# `--bundles` flag against a static clap enum gated by the HOST OS (Linux allows
|
||||
# only deb/rpm/appimage) *before* it considers --target/--runner, so `--bundles
|
||||
# nsis` is rejected at arg-parse time. Instead the Windows bundle targets come
|
||||
# from tauri.conf.json (bundle.targets includes "nsis"), which is not subject to
|
||||
# that CLI validation — the bundler then picks nsis once it knows the target is
|
||||
# Windows.
|
||||
if [[ "$WIN_BUNDLES" == "none" ]]; then
|
||||
bun run tauri build --runner cargo-xwin --target "$TARGET" --no-bundle
|
||||
else
|
||||
bun run tauri build --runner cargo-xwin --target "$TARGET"
|
||||
fi
|
||||
|
||||
BIN_DIR="src-tauri/target/$TARGET/release"
|
||||
echo ""
|
||||
echo "✅ Built Windows artifacts:"
|
||||
find "$BIN_DIR" -maxdepth 1 -name '*.exe' -print
|
||||
find "$BIN_DIR/bundle" -type f \( -name '*.exe' -o -name '*.msi' \) -print 2>/dev/null || true
|
||||
|
||||
if [[ -n "${OUTPUT_DIR:-}" ]]; then
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
find "$BIN_DIR" -maxdepth 1 -name 'jellytau.exe' -exec cp -v {} "$OUTPUT_DIR/" \;
|
||||
# NSIS setup installers land in bundle/nsis/*-setup.exe; MSI in bundle/msi/*.msi.
|
||||
find "$BIN_DIR/bundle" -type f \( -name '*-setup.exe' -o -name '*.msi' \) \
|
||||
-exec cp -v {} "$OUTPUT_DIR/" \; 2>/dev/null || true
|
||||
echo ""
|
||||
echo "📦 Copied Windows artifacts to $OUTPUT_DIR"
|
||||
fi
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "jellytau",
|
||||
"version": "0.0.18",
|
||||
"version": "0.1.0",
|
||||
"identifier": "com.dtourolle.jellytau",
|
||||
"build": {
|
||||
"beforeDevCommand": "bun run dev",
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": ["deb", "rpm"],
|
||||
"targets": ["deb", "rpm", "nsis"],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
|
||||
Reference in New Issue
Block a user