Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
38b2030
Android camera: a setup screen you can see, and hand-held robustness
claude Sep 12, 2026
846d6f9
Release 0.11.0: camera setup screen, hand-held robustness
claude Sep 12, 2026
5c49d5a
Android: the fifth detector hears the words (transcript, ADR 0012)
claude Sep 14, 2026
e555ad8
Release 0.12.0: transcript detector
claude Sep 14, 2026
f2fb1df
Android: error log, a crash that reports instead of vanishing, Materi…
claude Sep 14, 2026
e5bf772
Release 0.13.0: error log, crash reporting, Material interface
claude Sep 14, 2026
9473500
Android 0.14.0: no duck without a sighting, six selectable methods, c…
claude Sep 14, 2026
b2fc933
Android: import AdState instead of qualifying through the shadowed io…
claude Sep 14, 2026
d065675
Android 0.14.1: pages scroll clear of the bottom tab bar
claude Sep 14, 2026
880ce10
Android: Test TV through the running connection; a busy set is not a …
claude Sep 14, 2026
a51adb3
Android: local function for the test trace hook
claude Sep 14, 2026
02d6d29
Pi listener 0.15.0: the Python core learns what the phone learned
claude Sep 14, 2026
47978af
Print guide: the TV listener in a NESPi 4 case, for a 12-year-old
claude Sep 14, 2026
8878cab
Listener guide: optional SSD in the NESPi 4 cartridge (markdown and PDF)
claude Sep 15, 2026
9c699f5
Listener guide (markdown): the optional SSD section
claude Sep 15, 2026
6b63bc6
0.15.1: the listener by serial cable; rs232_sharp ducks like network_ip
claude Sep 15, 2026
390e636
Android 0.16.0: two AI judges (Claude API, local Qwen), the news tick…
claude Sep 15, 2026
5f7e2a8
Android: do not shadow the poll Runnable with the ticker flag
claude Sep 15, 2026
cfeb155
0.17.0: duck compensation from admuffs, three sizes of local AI, OneP…
claude Sep 15, 2026
0a94c21
0.18.0: break clock, timed manual ducks, and a remote with everything…
claude Sep 15, 2026
5a7da1a
Android: the Clock chip the Home page's status row refers to
claude Sep 15, 2026
758a232
0.19.0: learn the commercials from a stream; a memory that moves betw…
claude Sep 15, 2026
7b95e7f
0.20.0: a release for every platform
claude Sep 15, 2026
a980e84
tests: the frozen-bundle test must not find platforms/web in the work…
claude Sep 15, 2026
cf6fbbe
release: publish whatever built even if a binary runner fails
claude Sep 15, 2026
a11f926
0.21.0: break jingles, the ad badge, learned break lengths, an extend…
socrtwo Sep 15, 2026
3975ce4
0.22.0: aspect-ratio change on the HDMI path, crest factor in loudnes…
socrtwo Sep 16, 2026
e3e0ca6
0.23.0: the Android set-up wizard, a method-count audit, and an ideas…
socrtwo Sep 16, 2026
e9ea0f0
0.24.0: the backlog, built — six cues from comskip, MythTV and Auto-C…
socrtwo Sep 16, 2026
b58d369
Let the release publish: mypy must not need Pillow, and run the check…
socrtwo Sep 17, 2026
d925959
0.25.0: the wizard's Find my TV — Wi-Fi scan, serial cable and infrar…
socrtwo Sep 18, 2026
203dadf
0.26.0: any brand of TV from the phone — the wizard finds the set and…
socrtwo Sep 18, 2026
667ab5e
0.27.0: the other TV families — Android TV / Google TV, Hisense VIDAA…
socrtwo Sep 18, 2026
59b42db
Android packaging: exclude BouncyCastle's duplicate OSGi manifests
socrtwo Sep 18, 2026
a60adc8
README: rewritten for 0.27.0
socrtwo Sep 18, 2026
2917d2e
0.28.0: jingle families, segment stingers, the hour of day (ADR 0027)
socrtwo Sep 18, 2026
b10921e
0.28.1: close the first evening's learning loop; Forget, Save log, wi…
socrtwo Sep 19, 2026
c361be0
0.28.2: stream learning names a player that blocks capture within eig…
socrtwo Sep 19, 2026
fd19c71
0.28.3: every Android button answers the finger
socrtwo Sep 19, 2026
f61efc6
0.28.4: buttons show real outcomes only; model downloads verified and…
socrtwo Sep 19, 2026
52fc035
docs: Android README section on button states and downloads; version …
socrtwo Sep 19, 2026
4664a48
docs: platform READMEs no longer pin the 0.6.0 wheel name
socrtwo Sep 19, 2026
91be5f6
0.28.5: the remote as its own tab, drawn like one; no button wraps it…
socrtwo Sep 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
name: ci

# Every branch, not only main: work happens on long-lived feature branches
# here, and before 0.24.0 these checks first ran at release time — where a
# missing optional dependency failed the publish after every binary had built.
on:
push:
branches: [main]
branches: ["**"]
pull_request:

jobs:
Expand Down
132 changes: 128 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,78 @@ permissions:
contents: write

jobs:
# One-file binaries of the Python core (ADR 0019): the web front end,
# the device profiles and the example configs travel inside. ffmpeg is the
# only runtime dependency, on PATH. Each binary is smoke-tested on its own
# runner before it may be published.
binaries:
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-22.04, name: linux-x64 }
- { os: ubuntu-22.04-arm, name: linux-arm64 }
- { os: macos-latest, name: macos-arm64 }
- { os: windows-latest, name: windows-x64 }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Build
shell: bash
run: |
pip install ".[pi]" pyinstaller
pyinstaller --noconfirm --clean packaging/adhush.spec
- name: Smoke test the binary
shell: bash
run: |
set -e
bin="$PWD/dist/adhush"; [ "${{ runner.os }}" = Windows ] && bin="$PWD/dist/adhush.exe"
"$bin" --version
mkdir smoke && cd smoke
"$bin" init --config adhush.toml
test -f adhush.toml && test -d profiles
"$bin" doctor --config adhush.toml || true
python - <<'PY'
import sys; sys.path.insert(0, "..")
from adhush.capture.file_replay import write_fixture
from tests.synth import RATE, synthesize
frames, ts, audio, labels = synthesize([("program", 6.0), ("boundary", 1.0), ("ad", 12.0), ("program", 6.0)])
write_fixture("fixture.npz", frames=frames, frame_ts=ts, audio=audio, audio_rate=RATE)
print("fixture ok")
PY
"$bin" replay fixture.npz | tail -5
- name: Package (Linux / macOS)
if: runner.os != 'Windows'
shell: bash
run: |
version="${GITHUB_REF_NAME#v}"
mkdir -p out
if [ "${{ runner.os }}" = macOS ]; then
(cd dist && zip -q "../out/adhush-${version}-${{ matrix.name }}.zip" adhush)
else
tar -C dist -czf "out/adhush-${version}-${{ matrix.name }}.tar.gz" adhush
fi
- name: Package (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$version = "$env:GITHUB_REF_NAME".TrimStart("v")
New-Item -ItemType Directory -Force out | Out-Null
Compress-Archive -Path dist\adhush.exe, dist\adhushw.exe -DestinationPath "out\adhush-$version-${{ matrix.name }}.zip"
- uses: actions/upload-artifact@v4
with:
name: binary-${{ matrix.name }}
path: out/*
if-no-files-found: error

build-and-publish:
needs: binaries
# A binary runner failing must not hold the APK, the wheel and the web app
# hostage: publish what built, and the missing archive is simply absent.
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -29,24 +100,77 @@ jobs:
run: |
version="${GITHUB_REF_NAME#v}"
cp platforms/android/app/build/outputs/apk/debug/app-debug.apk "dist/adhush-${version}-android-debug.apk"
- name: Bundle the web front end
- name: "Bundle the web front end (also the iOS install, via Add to Home Screen)"
run: |
version="${GITHUB_REF_NAME#v}"
(cd platforms/web && zip -r "../../dist/adhush-web-${version}.zip" .)
- uses: actions/download-artifact@v4
continue-on-error: true
with:
pattern: binary-*
path: dist/bin
merge-multiple: true
- name: Raspberry Pi bundle (arm64 binary, listener config, guides)
run: |
version="${GITHUB_REF_NAME#v}"
mkdir -p dist/bin pi
if [ ! -f "dist/bin/adhush-${version}-linux-arm64.tar.gz" ]; then
echo "no arm64 binary this time: skipping the Pi bundle"; exit 0
fi
tar -C pi -xzf "dist/bin/adhush-${version}-linux-arm64.tar.gz"
cp config/adhush-listener.example.toml pi/
cp docs/print/AdHush-beginner-guide-listener-NESPi4.pdf docs/print/AdHush-beginner-guide-NESPi4.pdf pi/ 2>/dev/null || true
cat > pi/README.txt <<'TXT'
AdHush for Raspberry Pi 4 / 5 (64-bit Raspberry Pi OS, bookworm or newer)

sudo apt install -y ffmpeg
chmod +x adhush
./adhush init --listener # writes config/adhush.toml and the profiles
nano config/adhush.toml # the TV's serial port or address
./adhush doctor # what is missing, if anything
./adhush probe --active # the set should mute and unmute
./adhush service install # start at login, restart on failure

The illustrated build guides are in this folder as PDFs. Everything else:
https://github.com/socrtwo/adhush/blob/main/docs/build-guide-tv-listener.md
TXT
(cd pi && zip -q -r "../dist/adhush-${version}-raspberry-pi.zip" .)
- name: Gather the binaries that built
run: |
mkdir -p dist/bin
mv dist/bin/* dist/ 2>/dev/null || true
rmdir dist/bin 2>/dev/null || true
ls -la dist
- name: Release notes from the changelog
run: |
version="${GITHUB_REF_NAME#v}"
awk -v v="$version" '
$0 ~ "^## \\[" v "\\]" {on=1; next}
on && /^## \[/ {exit}
on {print}' CHANGELOG.md > dist/notes.md
echo >> dist/notes.md
echo "Platform matrix: docs/release.md" >> dist/notes.md
cat >> dist/notes.md <<'TXT'

## Downloads by platform

| Platform | File |
|---|---|
| Android (phone app) | `adhush-<ver>-android-debug.apk` — sideload |
| iOS / any phone (web app) | open `http://<core>:8675/` in Safari or Chrome → Add to Home Screen; the page is in `adhush-web-<ver>.zip` |
| Windows 10/11 x64 | `adhush-<ver>-windows-x64.zip` — `adhush.exe` (terminal) and `adhushw.exe` (silent, for the logon task) |
| macOS (Apple silicon) | `adhush-<ver>-macos-arm64.zip` — Intel Macs: the wheel |
| Linux x64 / ChromeOS (Intel) | `adhush-<ver>-linux-x64.tar.gz` |
| Linux arm64 / ChromeOS (ARM) | `adhush-<ver>-linux-arm64.tar.gz` |
| Raspberry Pi 4 / 5 | `adhush-<ver>-raspberry-pi.zip` — binary, listener config, the PDF guides |
| Any Python 3.11+ | `adhush-<ver>-py3-none-any.whl` |

Platform matrix and what each build can do: docs/release.md
TXT
- uses: softprops/action-gh-release@v2
with:
body_path: dist/notes.md
prerelease: ${{ contains(github.ref_name, '-') }}
files: |
dist/*.whl
dist/*.tar.gz
dist/adhush-web-*.zip
dist/*.zip
dist/adhush-*-android-debug.apk
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ captures/
config/adhush.toml
config/profiles/*.local.toml
.DS_Store
data/clock.tsv
data/jingles.tsv
Loading
Loading