1-bit-bridge

module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT

README ΒΆ

1-bit-bridge

Latest release Go version iOS app on App Store

Companion server for the 1-bit iOS music player β€” bit-exact playback of your own music library, including DSD, from anywhere. The bridge runs on a home server (Windows / Linux / macOS / NAS) and exposes your library over HTTPS + bearer-token auth with a pre-built manifest endpoint, so the iOS app syncs its whole library in a single request instead of walking a slow SMB tree.

πŸ‘‰ acoseac.github.io/1-bit-bridge for the landing page with install walk-through.

Why

1-bit's existing SMB transport is great on LAN but painful over Tailscale / similar overlays: SMB's chatty pread pattern multiplies every round-trip, and DERP-relayed connections can push latency past 3 seconds. 1-bit-bridge replaces SMB with an HTTP/2 protocol purpose-built for the app:

  • 5 primitives matching the iOS app's internal SMBConnectionPool API (list, stat, readRange, download, downloadStreaming), so the existing scanner + playback code paths are unchanged.
  • Pre-built library manifest β€” the bridge keeps a SQLite-backed index; iOS fetches the full library (or a ?since=<mtime> delta) in one call. Both scan phases (walk + enrich) are replaced by a single HTTP GET.
  • Bit-exact preserved β€” the bridge delivers bytes; iOS still pre-caches the full DSF file before playback, protecting the Hugo 2 DoP lock. The bridge never transcodes.

Status

v0.1.2 β€” wire protocol frozen at PROTOCOL.md v1. macOS binaries are Developer-ID-signed and Apple-notarized; Windows binaries are unsigned for now (Authenticode signing via SignPath Foundation pending). See the releases page for per-release notes.

Install

Grab a pre-built binary from the releases page β€” no Go toolchain required. Pick your OS + arch, then run bridge init.

macOS / Linux:

tar -xzf 1-bit-bridge_*_macos_arm64.tar.gz   # or linux_amd64 / linux_arm64 / macos_amd64
./bridge init

Writes config + TLS cert under ~/Library/Application Support/1-bit-bridge/ (macOS) or $XDG_CONFIG_HOME/1-bit-bridge/ (Linux), registers a launchd user agent / systemd user unit, opens the admin console.

Windows (PowerShell or File Explorer):

# Unzip 1-bit-bridge_*_windows_amd64.zip (or _arm64)
bridge.exe init

Two install paths on Windows:

  • Startup-folder launcher (default) β€” bridge init. Per-user, runs at logon, stops on logout. No admin required. Launcher lives at %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\com.acoseac.1-bit-bridge.cmd; config under %LOCALAPPDATA%\1-bit-bridge\.
  • Windows Service (survives logout) β€” bridge init --service, run from an elevated PowerShell. Installs an SCM service that starts at boot, runs as LocalSystem, logs to %PROGRAMDATA%\1-bit-bridge\bridge.log. Because the service runs as LocalSystem, point --library at a machine-wide path (e.g. C:\Music) rather than %USERPROFILE%\Music.

Uninstall: run bridge init again and answer "no" to overwrite (Startup launcher), or sc.exe delete 1-bit-bridge from an admin shell (Windows Service).

Preflight: bridge doctor

Before (or any time after) running bridge init, bridge doctor prints a punch list of what's wrong in your environment:

[ok]   platform            darwin/arm64
[ok]   config-dir          /Users/me/Library/Application Support/1-bit-bridge
[ok]   tls-cert            present
[FAIL] port-api            :7788 in use
  ↳ another process owns this port; stop it or pick a different address in bridge.yaml
[ok]   port-admin          free (:7789)
[ok]   library-roots       1 root(s) reachable
[ok]   service-manager     launchctl available
[ok]   browser-opener      open

bridge init runs doctor automatically and bails on fail (use --skip-doctor to override β€” not recommended).

Admin console β€” http://127.0.0.1:7789/. Add/remove library folders, pair iOS devices (QR + copy-buttons), revoke tokens, view scan state + stats. Loopback-only, no auth β€” anyone on the machine already has filesystem access to the token store.

Pairing an iOS device: on the Devices page, click Pair new device, give it a name, optionally edit the bridge URL (defaults to https://<hostname>.local:7788), then generate the token. The modal shows a QR encoding a bridge://pair?... URL β€” scan it in the 1-bit app, or copy the URL/token/fingerprint fields manually.

Build from source

Requires Go 1.25+.

make build          # builds ./bin/bridge for the host OS
make build-all      # cross-compiles darwin/linux/windows Γ— amd64/arm64 into dist/
make test           # unit tests

For a local release dry-run: goreleaser release --snapshot --clean.

Contributing

PRs welcome. See CONTRIBUTING.md for the branch / PR conventions, the pre-push checklist, and the mirror-PR rule that applies whenever a change touches the wire protocol shared with the 1-bit iOS app.

Security

Found a vulnerability? Please report privately via GitHub's Security Advisories β€” see SECURITY.md for scope, response SLA, and what to include in your report.

Tailscale modes

The bridge offers three Tailscale integration modes via the tailscale.mode key in bridge.yaml:

  • cli (default) β€” shells out to the host's installed tailscale binary for status detection and Let's Encrypt cert provisioning on *.ts.net connections. Requires Tailscale to be installed and running on the host.
  • tsnet β€” embeds a tailnet node directly in the bridge process via tailscale.com/tsnet. No Tailscale binary required; LE cert is renewed in-process. Authenticate with bridge tsnet auth on first run, or set tailscale.authKey for unattended deployments.
  • disabled β€” turns off both the CLI auto-pilot and the embedded tsnet node. Use this for LAN-only deployments. The admin tile renders a one-line explanation so operators who flipped to disabled accidentally can recover.

Mode changes require a bridge restart. The admin tile shows the current Tailscale state and any errors from the active path.

Manual run (without bridge init)

For anyone who wants to skip the service install or run the bridge out of an arbitrary directory:

./bridge init --no-service --yes --library /path/to/music --dir ./bridge-data
./bridge serve --config ./bridge-data/bridge.yaml

Protocol

See PROTOCOL.md. Every client endpoint is prefixed /v1/. The admin console (/, /api/*, /static/*) lives on a separate loopback listener and is not part of the wire protocol β€” iOS never talks to it.

License

MIT. See LICENSE.

Directories ΒΆ

Path Synopsis
cmd
bridge command
Command bridge is the 1-bit-bridge server CLI.
Command bridge is the 1-bit-bridge server CLI.
internal
admin
Package admin serves the local-only web console for operating a running bridge instance β€” adding/removing library roots, pairing/revoking client devices, and surfacing scan + uptime stats.
Package admin serves the local-only web console for operating a running bridge instance β€” adding/removing library roots, pairing/revoking client devices, and surfacing scan + uptime stats.
advertise
Package advertise enumerates every network endpoint a running bridge is reachable at β€” LAN IPv4 / IPv6, mDNS hostname, Tailscale interface β€” so /v1/health can self-report the full list to iOS clients, and the admin pairing QR can bake alternates into `bridge://pair?urls=...`.
Package advertise enumerates every network endpoint a running bridge is reachable at β€” LAN IPv4 / IPv6, mDNS hostname, Tailscale interface β€” so /v1/health can self-report the full list to iOS clients, and the admin pairing QR can bake alternates into `bridge://pair?urls=...`.
api
Package api implements the HTTP/2 handlers for the v1 wire protocol (see PROTOCOL.md at the repo root).
Package api implements the HTTP/2 handlers for the v1 wire protocol (see PROTOCOL.md at the repo root).
auth
Package auth manages bearer tokens: generation, hashed storage, and request-time validation.
Package auth manages bearer tokens: generation, hashed storage, and request-time validation.
backup
Package backup snapshots and restores the bridge's state directory.
Package backup snapshots and restores the bridge's state directory.
config
Package config loads and validates bridge.yaml (library roots, listen address, TLS paths, scan interval).
Package config loads and validates bridge.yaml (library roots, listen address, TLS paths, scan interval).
doctor
Package doctor runs environment preflight checks for `bridge init` and `bridge doctor`.
Package doctor runs environment preflight checks for `bridge init` and `bridge doctor`.
dsn
Package dsn builds SQLite URI DSN strings that safely encode filesystem paths containing URL-reserved characters (?, #, %) across POSIX and Windows.
Package dsn builds SQLite URI DSN strings that safely encode filesystem paths containing URL-reserved characters (?, #, %) across POSIX and Windows.
enrich
Package enrich looks up external metadata (MusicBrainz, Cover Art Archive) for tracks that are missing MBIDs or artwork, then updates the manifest store.
Package enrich looks up external metadata (MusicBrainz, Cover Art Archive) for tracks that are missing MBIDs or artwork, then updates the manifest store.
fs
Package fs resolves client-supplied relative paths against a configured library root and rejects traversal (`..`, absolute paths, symlink escapes).
Package fs resolves client-supplied relative paths against a configured library root and rejects traversal (`..`, absolute paths, symlink escapes).
logging
Package logging owns the bridge's structured-logging entry point.
Package logging owns the bridge's structured-logging entry point.
lrucache
Package lrucache implements a small bounded LRU cache safe for concurrent use.
Package lrucache implements a small bounded LRU cache safe for concurrent use.
manifest
Package manifest owns the library index: the SQLite-backed store, per- format tag extractors (FLAC / DSF / ALAC / WAV / MP3), and the filesystem scanner that drives them.
Package manifest owns the library index: the SQLite-backed store, per- format tag extractors (FLAC / DSF / ALAC / WAV / MP3), and the filesystem scanner that drives them.
mdns
Package mdns advertises the bridge on the local network as _onebit-bridge._tcp.local.
Package mdns advertises the bridge on the local network as _onebit-bridge._tcp.local.
packaging
Package packaging renders service-manager unit files (launchd plist on darwin, systemd user unit on linux) and installs them where the user's service manager expects to find them.
Package packaging renders service-manager unit files (launchd plist on darwin, systemd user unit on linux) and installs them where the user's service manager expects to find them.
pairing
Package pairing implements the in-memory state machine for the admin-approval pairing flow.
Package pairing implements the in-memory state machine for the admin-approval pairing flow.
supervision
Package supervision answers a single runtime question: "if this process calls os.Exit(0), will something relaunch us?"
Package supervision answers a single runtime question: "if this process calls os.Exit(0), will something relaunch us?"
tailscale
Package tailscale wraps the small surface area of the Tailscale CLI the bridge needs for HTTPS auto-pilot: detecting whether Tailscale is installed and what the local node's MagicDNS name is, and minting an HTTPS certificate via `tailscale cert`.
Package tailscale wraps the small surface area of the Tailscale CLI the bridge needs for HTTPS auto-pilot: detecting whether Tailscale is installed and what the local node's MagicDNS name is, and minting an HTTPS certificate via `tailscale cert`.
tls
Package tls mints a self-signed certificate on first run and loads existing cert/key material on subsequent runs.
Package tls mints a self-signed certificate on first run and loads existing cert/key material on subsequent runs.
transcode
Package transcode owns offline PCM-upscaling: building sox(1) invocations, choosing variant identifiers + sidecar paths, and the worker pool the CLI subcommand and (in Phase 2.5) the HTTP `POST /v1/upscale` handler share.
Package transcode owns offline PCM-upscaling: building sox(1) invocations, choosing variant identifiers + sidecar paths, and the worker pool the CLI subcommand and (in Phase 2.5) the HTTP `POST /v1/upscale` handler share.
tsnet
Package tsnet wraps the upstream tailscale.com/tsnet library so the bridge can run as its own embedded tailnet node β€” no external `tailscaled` daemon, no CLI shell-out, no on-disk Let's Encrypt cert files.
Package tsnet wraps the upstream tailscale.com/tsnet library so the bridge can run as its own embedded tailnet node β€” no external `tailscaled` daemon, no CLI shell-out, no on-disk Let's Encrypt cert files.
updater
Package updater polls the GitHub Releases API for newer 1-bit-bridge builds and drives the full self-update lifecycle: poll β†’ download β†’ SHA-256 verify (always) β†’ platform signature verify (macOS Apple codesign + Team-ID; Linux/Windows currently TLS-of-checksums.txt only, see verify_other.go for the seam where Sigstore / minisign / SignPath would land) β†’ swap (atomic rename on Unix; live rename + caller-driven restart on Windows, see swap_windows.go β€” note this is NOT the MoveFileEx/MOVEFILE_DELAY_UNTIL_REBOOT "pending rename" mechanism) β†’ arm rollback marker.
Package updater polls the GitHub Releases API for newer 1-bit-bridge builds and drives the full self-update lifecycle: poll β†’ download β†’ SHA-256 verify (always) β†’ platform signature verify (macOS Apple codesign + Team-ID; Linux/Windows currently TLS-of-checksums.txt only, see verify_other.go for the seam where Sigstore / minisign / SignPath would land) β†’ swap (atomic rename on Unix; live rename + caller-driven restart on Windows, see swap_windows.go β€” note this is NOT the MoveFileEx/MOVEFILE_DELAY_UNTIL_REBOOT "pending rename" mechanism) β†’ arm rollback marker.
version
Package version exports the server build version and the wire protocol version.
Package version exports the server build version and the wire protocol version.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL