Add Debian (.deb) installer (v1.1.0)

packaging/build-deb.sh builds an installable blitztext_<ver>_arm64.deb with a
desktop entry, app icon, and launcher. Bundles a relocatable venv (all Python
deps, no pip at install) and declares system deps (python3-gi, xdotool,
libnotify-bin, recorder). Built on /usr/bin/python3 so the tray works out of
the box. Installs via the Software app or `apt install ./…deb`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-06-04 09:25:32 +02:00
parent 689d948fa1
commit 6ef421c934
8 changed files with 203 additions and 8 deletions

1
linux/.gitignore vendored
View File

@ -1,3 +1,4 @@
.venv/
__pycache__/
*.pyc
dist/

View File

@ -9,6 +9,22 @@ The version is defined in [`blitztext/__init__.py`](blitztext/__init__.py).
## [Unreleased]
## [1.1.0] - 2026-06-04
### Added
- **Debian package** (`packaging/build-deb.sh`) producing an installable
`blitztext_<ver>_arm64.deb` with a desktop entry, app icon, and a `blitztext`
launcher. Installs via the Software app or `apt install ./…deb`. Bundles a
relocatable venv with all Python deps (no pip/network at install) and declares
system deps (python3-gi, xdotool, libnotify-bin, a recorder) so they pull in
automatically. The bundled venv is built on the system `/usr/bin/python3`, so
the tray works out of the box.
### Notes
- `python3-gi` is already present on a standard Ubuntu GNOME install; the tray
only seemed unavailable from source when the project venv was built from a
non-system Python (e.g. conda/miniforge). The `.deb` avoids this entirely.
## [1.0.1] - 2026-06-03
### Changed
@ -58,6 +74,7 @@ into that field.
AppIndicator typelibs and GNOME `ubuntu-appindicators` extension are already
present on the target host).
[Unreleased]: https://github.com/mARTin-B78/blitztext-app/compare/v1.0.1...HEAD
[Unreleased]: https://github.com/mARTin-B78/blitztext-app/compare/v1.1.0...HEAD
[1.1.0]: https://github.com/mARTin-B78/blitztext-app/compare/v1.0.1...v1.1.0
[1.0.1]: https://github.com/mARTin-B78/blitztext-app/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/mARTin-B78/blitztext-app/releases/tag/v1.0.0

View File

@ -37,6 +37,24 @@ transcribes, optionally rewrites, and types the result where your cursor is.
## Install
### Option A — Debian package (recommended on Ubuntu/Debian)
Build a `.deb` and install it with the Software app or apt:
```bash
cd linux
bash packaging/build-deb.sh # -> dist/blitztext_<ver>_arm64.deb
sudo apt install ./dist/blitztext_*.deb # or double-click the .deb in Files
```
This installs `blitztext` to `/opt/blitztext` (a self-contained bundle — no pip
step), adds a **Blitztext** entry to your app grid, and pulls in the system deps
(`python3-gi`, `xdotool`, `libnotify-bin`, a recorder). Launch it from the app
grid, or run `blitztext` / `blitztext gui` from a terminal. Remove with
`sudo apt remove blitztext`.
### Option B — run from source (venv)
```bash
cd linux
./install.sh
@ -45,6 +63,11 @@ cd linux
This creates `.venv`, installs `faster-whisper` + `pynput`, and writes the
default config to `~/.config/blitztext/config.toml`.
> For the **tray** from source, the venv must be built on a Python that can see
> the system `python3-gi``install.sh` uses `python3 -m venv
> --system-site-packages`, so use the system `/usr/bin/python3` (a conda/miniforge
> Python won't see the apt-installed `gi`). The `.deb` handles this for you.
## Run
Three front-ends, same engine (local Whisper + global hotkeys + xdotool typing):
@ -62,17 +85,18 @@ export OPENAI_API_KEY=sk-...
The tray is the closest match to the macOS menu-bar app: a status icon with a
menu listing every workflow (click to record), plus **Show panel**, **Settings…**,
and **Quit**. It needs PyGObject once (the GTK/AppIndicator typelibs and the
GNOME `ubuntu-appindicators` extension are already present here):
and **Quit**. It needs PyGObject (`python3-gi`) and the GTK/AppIndicator
typelibs — already present on a standard Ubuntu GNOME install (the `.deb`
declares them as dependencies):
```bash
sudo apt install python3-gi # one-time; no build, just the bindings
sudo apt install python3-gi # usually already installed
.venv/bin/python -m blitztext tray
```
If PyGObject is missing, `tray` prints this hint and falls back to the window.
(The venv is created with `--system-site-packages` so it can see the
apt-installed `gi`.)
If PyGObject isn't visible, `tray` prints this hint and falls back to the
window. The venv is created with `--system-site-packages` so it can see the
system `gi` — build it from `/usr/bin/python3`, not a conda/miniforge Python.
Either way, focus any text field and trigger a workflow — by tray menu, panel
button, or hotkey (defaults):

View File

@ -6,4 +6,4 @@ counterpart to the macOS Blitztext menu bar app: it runs natively on the host
(not in a container) so it can type into any application via xdotool.
"""
__version__ = "1.0.1"
__version__ = "1.1.0"

View File

@ -0,0 +1,11 @@
[Desktop Entry]
Type=Application
Name=Blitztext
GenericName=Voice Dictation
Comment=Speak and have the text typed into any field
Exec=blitztext tray
Icon=blitztext
Terminal=false
Categories=Utility;AudioVideo;Accessibility;
Keywords=dictation;speech;voice;transcription;whisper;stt;
StartupNotify=false

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#2b8cff"/>
<stop offset="1" stop-color="#0a5cf0"/>
</linearGradient>
</defs>
<rect x="8" y="8" width="112" height="112" rx="28" fill="url(#bg)"/>
<path d="M70 26 L42 70 H60 L56 102 L86 56 H66 Z"
fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 529 B

104
linux/packaging/build-deb.sh Executable file
View File

@ -0,0 +1,104 @@
#!/usr/bin/env bash
# Build a self-contained .deb for Blitztext (Ubuntu/Debian, arm64).
#
# Bundles a relocatable venv with the Python deps (faster-whisper, pynput,
# tomli-w) under /opt/blitztext so installation needs no pip/network. System
# integration (python3-gi, xdotool, libnotify-bin, a recorder) is declared via
# Depends so the Software app / apt pull them in.
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
LINUX_DIR="$(dirname "$HERE")" # .../linux
PKG="blitztext"
ARCH="$(dpkg --print-architecture)"
VER="$(sed -n 's/.*__version__ = "\(.*\)".*/\1/p' "$LINUX_DIR/blitztext/__init__.py")"
PYBIN="${PYBIN:-/usr/bin/python3}"
BUILD="$(mktemp -d)"
ROOT="$BUILD/${PKG}_${VER}_${ARCH}"
OUT_DIR="${OUT_DIR:-$LINUX_DIR/dist}"
trap 'rm -rf "$BUILD"' EXIT
echo "==> Building $PKG $VER ($ARCH) with $($PYBIN --version)"
# 1) Bundled, relocatable venv with all Python deps -------------------------
APPDIR="$ROOT/opt/$PKG"
VENV="$APPDIR/venv"
mkdir -p "$APPDIR"
"$PYBIN" -m venv --copies "$VENV"
"$VENV/bin/pip" install --upgrade pip -q
"$VENV/bin/pip" install -q -r "$LINUX_DIR/requirements.txt" tomli-w
# Drop the app package into the venv so `python -m blitztext` works.
cp -r "$LINUX_DIR/blitztext" "$VENV/lib/python"*/site-packages/
# Let the venv also see the system PyGObject (apt python3-gi) for tray mode,
# while still preferring its own bundled deps.
PYVENV="$VENV/pyvenv.cfg"
sed -i 's/^include-system-site-packages = false/include-system-site-packages = true/' "$PYVENV"
grep -q "^include-system-site-packages = true" "$PYVENV" || echo "include-system-site-packages = true" >> "$PYVENV"
# Trim build cruft to shrink the package.
find "$VENV" -type d -name "__pycache__" -prune -exec rm -rf {} + 2>/dev/null || true
rm -rf "$VENV/lib/python"*/site-packages/pip "$VENV/lib/python"*/site-packages/pip-* \
"$VENV"/bin/pip* "$VENV/lib/python"*/site-packages/setuptools* 2>/dev/null || true
cp "$LINUX_DIR/README.md" "$LINUX_DIR/CHANGELOG.md" "$APPDIR/"
# 2) Launcher, desktop entry, icon, docs ------------------------------------
install -Dm755 /dev/stdin "$ROOT/usr/bin/$PKG" <<'EOF'
#!/bin/sh
exec /opt/blitztext/venv/bin/python -m blitztext "$@"
EOF
install -Dm644 "$HERE/$PKG.desktop" "$ROOT/usr/share/applications/$PKG.desktop"
install -Dm644 "$HERE/$PKG.svg" "$ROOT/usr/share/icons/hicolor/scalable/apps/$PKG.svg"
install -Dm644 "$HERE/copyright" "$ROOT/usr/share/doc/$PKG/copyright"
# 3) DEBIAN control + maintainer scripts ------------------------------------
SIZE_KB="$(du -sk "$ROOT" | cut -f1)"
mkdir -p "$ROOT/DEBIAN"
cat > "$ROOT/DEBIAN/control" <<EOF
Package: $PKG
Version: $VER
Section: utils
Priority: optional
Architecture: $ARCH
Depends: python3 (>= 3.12), python3-gi, gir1.2-ayatanaappindicator3-0.1, xdotool, libnotify-bin, pipewire-bin | pulseaudio-utils | alsa-utils
Maintainer: Martin Bierschenk <mail@martin-bierschenk.de>
Installed-Size: $SIZE_KB
Description: Blitztext - local voice dictation for Linux
Focus any text field, press a hotkey, speak, and the transcribed text is
typed into that field. Optional LLM rewrite turns rough speech into a nicer
email, a calmer message, or adds emojis.
.
Transcription runs locally via faster-whisper; the optional rewrite uses any
OpenAI-compatible endpoint (OpenAI or a local server). Runs in the system
tray or as a small control-panel window. Requires an X11 session.
EOF
cat > "$ROOT/DEBIAN/postinst" <<'EOF'
#!/bin/sh
set -e
if [ "$1" = "configure" ]; then
gtk-update-icon-cache -qf /usr/share/icons/hicolor 2>/dev/null || true
update-desktop-database -q 2>/dev/null || true
fi
EOF
chmod 755 "$ROOT/DEBIAN/postinst"
cat > "$ROOT/DEBIAN/postrm" <<'EOF'
#!/bin/sh
set -e
# Remove runtime-generated files (e.g. *.pyc) left in the bundled venv.
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
rm -rf /opt/blitztext
fi
EOF
chmod 755 "$ROOT/DEBIAN/postrm"
# 4) Build -------------------------------------------------------------------
mkdir -p "$OUT_DIR"
DEB="$OUT_DIR/${PKG}_${VER}_${ARCH}.deb"
fakeroot dpkg-deb --build --root-owner-group "$ROOT" "$DEB" >/dev/null
echo "==> Built: $DEB ($(du -h "$DEB" | cut -f1))"

26
linux/packaging/copyright Normal file
View File

@ -0,0 +1,26 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: blitztext
Source: https://github.com/mARTin-B78/blitztext-app
Files: *
Copyright: 2026 Martin Bierschenk
License: MIT
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.