Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ body:
options:
- App UI
- PipeWire routing or default output following
- WirePlumber integration
- pipewire-gobject integration
- Analyzer or loudness monitoring
- Presets or AutoEq/Equalizer APO import
- GNOME Shell extension
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/install_or_packaging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ body:
id: extra
attributes:
label: Additional context
description: Mention whether GTK, Libadwaita, PipeWire, WirePlumber, and PipeWire JACK are installed when relevant.
description: Mention whether GTK, Libadwaita, PipeWire, WirePlumber, and pipewire-gobject are installed when relevant.
validations:
required: false
79 changes: 31 additions & 48 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
workflow_dispatch:
inputs:
flatpak_runtime_smoke:
description: Run the experimental Flatpak PipeWire/WirePlumber routing smoke test
description: Run the experimental Flatpak PipeWire routing smoke test
type: boolean
default: false
smoke_only:
Expand Down Expand Up @@ -52,7 +52,7 @@ jobs:
flatpak: ${{ steps.filter.outputs.flatpak }}
test: ${{ steps.filter.outputs.test }}
tooling: ${{ steps.filter.outputs.tooling }}
wp04: ${{ steps.filter.outputs.wp04 }}
pwg: ${{ steps.filter.outputs.pwg }}

steps:
- name: Detect changed files
Expand All @@ -71,7 +71,7 @@ jobs:
{
echo "test=true"
echo "tooling=true"
echo "wp04=true"
echo "pwg=true"
echo "flatpak=true"
} >> "$GITHUB_OUTPUT"
}
Expand All @@ -82,7 +82,7 @@ jobs:
{
echo "test=false"
echo "tooling=false"
echo "wp04=false"
echo "pwg=false"
echo "flatpak=false"
} >> "$GITHUB_OUTPUT"
exit 0
Expand All @@ -108,15 +108,15 @@ jobs:

test=false
tooling=false
wp04=false
pwg=false
flatpak=false

while IFS= read -r path; do
case "$path" in
.github/workflows/ci.yml)
test=true
tooling=true
wp04=true
pwg=true
flatpak=true
;;
README.md|pyproject.toml|MANIFEST.in|src/*|tests/*|data/*|extensions/*)
Expand All @@ -134,13 +134,13 @@ jobs:
esac

case "$path" in
.github/workflows/ci.yml|docker/ubuntu-24.04-wp04.Dockerfile|tools/check_wireplumber_gi.py|src/mini_eq/wireplumber_backend.py)
wp04=true
.github/workflows/ci.yml|tools/check_pipewire_gobject.py|src/mini_eq/pipewire_backend.py|src/mini_eq/analyzer.py)
pwg=true
;;
esac

case "$path" in
.github/workflows/ci.yml|io.github.bhack.mini-eq.yaml|python3-dependencies.yaml|flatpak/*|src/*|data/*|pyproject.toml|MANIFEST.in|tools/check_wireplumber_gi.py)
.github/workflows/ci.yml|io.github.bhack.mini-eq.yaml|python3-dependencies.yaml|flatpak/*|src/*|data/*|pyproject.toml|MANIFEST.in|tools/check_pipewire_gobject.py)
flatpak=true
;;
esac
Expand All @@ -149,7 +149,7 @@ jobs:
{
echo "test=$test"
echo "tooling=$tooling"
echo "wp04=$wp04"
echo "pwg=$pwg"
echo "flatpak=$flatpak"
} >> "$GITHUB_OUTPUT"

Expand All @@ -158,7 +158,7 @@ jobs:
echo
echo "- test: \`$test\`"
echo "- tooling: \`$tooling\`"
echo "- wireplumber-0-4-compat: \`$wp04\`"
echo "- pipewire-gobject: \`$pwg\`"
echo "- flatpak: \`$flatpak\`"
} >> "$GITHUB_STEP_SUMMARY"

Expand Down Expand Up @@ -220,24 +220,31 @@ jobs:
sudo apt-get install -y \
gir1.2-adw-1 \
gir1.2-gtk-4.0 \
gobject-introspection \
libgirepository1.0-dev \
libglib2.0-dev \
libpipewire-0.3-dev \
meson \
ninja-build \
pipewire \
pipewire-jack \
python3-cairo \
python3-dev \
python3-gi \
python3-pip \
python3-setuptools \
python3-venv \
wireplumber
if apt-cache show gir1.2-wp-0.5 >/dev/null 2>&1; then
sudo apt-get install -y gir1.2-wp-0.5
else
sudo apt-get install -y gir1.2-wp-0.4
fi

- name: Install Python dependencies
if: ${{ needs.changes.outputs.test == 'true' }}
run: |
python3 -m venv /tmp/mini-eq-pwg-build
/tmp/mini-eq-pwg-build/bin/python -m pip install --upgrade pip
/tmp/mini-eq-pwg-build/bin/python -m pip wheel 'pipewire-gobject>=0.3.4,<0.4' -w /tmp/mini-eq-wheelhouse

python3 -m venv --system-site-packages .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install --no-index --find-links /tmp/mini-eq-wheelhouse 'pipewire-gobject>=0.3.4,<0.4'
.venv/bin/python -m pip install -e '.[dev]'

- name: Lint
Expand All @@ -263,7 +270,9 @@ jobs:
- name: Smoke-test wheel CLI
if: ${{ needs.changes.outputs.test == 'true' }}
run: |
python3 -m venv /tmp/mini-eq-wheel-test
python3 -m venv --system-site-packages /tmp/mini-eq-wheel-test
/tmp/mini-eq-wheel-test/bin/python -m pip install --upgrade pip
/tmp/mini-eq-wheel-test/bin/python -m pip install --no-index --find-links /tmp/mini-eq-wheelhouse 'pipewire-gobject>=0.3.4,<0.4'
/tmp/mini-eq-wheel-test/bin/python -m pip install dist/mini_eq-*.whl
/tmp/mini-eq-wheel-test/bin/mini-eq --help

Expand All @@ -275,32 +284,6 @@ jobs:
path: dist/*
if-no-files-found: error

wireplumber-0-4-compat:
needs: changes
if: ${{ always() && !(github.event_name == 'workflow_dispatch' && inputs.smoke_only) }}
runs-on: ubuntu-24.04

steps:
- name: Require change detection
if: ${{ needs.changes.result != 'success' }}
run: exit 1

- name: Skip unchanged scope
if: ${{ needs.changes.outputs.wp04 != 'true' }}
run: echo "No WirePlumber 0.4 compatibility changes detected; skipping compatibility job work."

- name: Check out repository
if: ${{ needs.changes.outputs.wp04 == 'true' }}
uses: actions/checkout@v6

- name: Build WirePlumber 0.4 compatibility image
if: ${{ needs.changes.outputs.wp04 == 'true' }}
run: docker build -f docker/ubuntu-24.04-wp04.Dockerfile -t mini-eq:wp04 .

- name: Check WirePlumber 0.4 GI compatibility
if: ${{ needs.changes.outputs.wp04 == 'true' }}
run: docker run --rm mini-eq:wp04

flatpak:
needs: changes
if: ${{ always() && !(github.event_name == 'workflow_dispatch' && inputs.smoke_only) }}
Expand Down Expand Up @@ -345,11 +328,11 @@ jobs:
if: ${{ needs.changes.outputs.flatpak == 'true' }}
run: flatpak run io.github.bhack.mini-eq --help

- name: Check WirePlumber 0.5 GI compatibility
- name: Check pipewire-gobject GI compatibility
if: ${{ needs.changes.outputs.flatpak == 'true' }}
run: |
flatpak run --filesystem="$PWD":ro --command=python3 io.github.bhack.mini-eq \
"$PWD/tools/check_wireplumber_gi.py" --expect-version 0.5
"$PWD/tools/check_pipewire_gobject.py" --expect-version 0.3.4

- name: Smoke-test Flatpak runtime modules
if: ${{ needs.changes.outputs.flatpak == 'true' }}
Expand All @@ -375,7 +358,7 @@ jobs:
"/app/share/licenses/io.github.bhack.mini-eq/mini-eq/LICENSE",
"/app/share/licenses/io.github.bhack.mini-eq/pipewire-filter-chain-module/COPYING",
"/app/share/licenses/io.github.bhack.mini-eq/pipewire-filter-chain-module/LICENSE",
"/app/share/licenses/io.github.bhack.mini-eq/wireplumber/LICENSE",
"/app/share/licenses/io.github.bhack.mini-eq/pipewire-gobject/LICENSE",
]

missing = [path for path in required_license_files if not Path(path).exists()]
Expand All @@ -386,7 +369,7 @@ jobs:
flatpak run --command=python3 io.github.bhack.mini-eq - <<'PY'
import importlib

required_modules = ["numpy", "jack", "_jack"]
required_modules = ["numpy", "pipewire_gobject"]

missing = []
for name in required_modules:
Expand Down
93 changes: 52 additions & 41 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ These notes apply to the whole repository.
## Project Context

Mini EQ is a small system-wide parametric equalizer for PipeWire desktops. It
uses GTK/Libadwaita for the UI, WirePlumber for routing and default-output
monitoring, PipeWire filter-chain with builtin biquad filters for DSP, and the
PipeWire JACK compatibility layer plus NumPy for spectrum analysis.
uses GTK/Libadwaita for the UI, pipewire-gobject for app-facing PipeWire
routing, metadata, and monitor capture, PipeWire filter-chain with builtin
biquad filters for DSP, and NumPy for spectrum analysis.

This is a public-facing repository. Treat every committed file, screenshot,
artifact, and log snippet as public. Keep user-facing documentation focused on
Expand All @@ -19,11 +19,12 @@ paths in ignored repo-local skills under `.agents/skills/`.

- `src/mini_eq/core.py`: EQ data models, preset JSON, biquad math, APO import.
- `src/mini_eq/filter_chain.py`: PipeWire filter-chain config generation.
- `src/mini_eq/wireplumber_backend.py`: WirePlumber GI compatibility layer.
- `src/mini_eq/wireplumber_stream_router.py`: stream routing helpers.
- `src/mini_eq/pipewire_backend.py`: pipewire-gobject-backed PipeWire registry,
metadata, and node-control layer.
- `src/mini_eq/pipewire_stream_router.py`: stream routing helpers.
- `src/mini_eq/routing.py`: system-wide EQ lifecycle and routing controller.
- `src/mini_eq/app.py` and `src/mini_eq/window*.py`: GTK/Libadwaita app and UI.
- `src/mini_eq/analyzer.py`: JACK/NumPy analyzer runtime.
- `src/mini_eq/analyzer.py`: pipewire-gobject monitor stream and NumPy analyzer runtime.
- `src/mini_eq/screenshot.py` and `tools/render_demo_screenshot.py`: maintainer
screenshot tooling, not user-facing CLI.
- `data/`: desktop and AppStream metadata.
Expand Down Expand Up @@ -70,18 +71,40 @@ desktop-file-validate data/io.github.bhack.mini-eq.desktop
.venv/bin/python -m twine check dist/*
```

The app depends on system GI/audio packages that Python packaging cannot
install: GTK4, Libadwaita, WirePlumber introspection, PipeWire, and PipeWire
JACK compatibility. Some tests skip automatically when optional runtime tools
are unavailable.
The app depends on system GI/audio packages that Python packaging cannot fully
install: GTK4, Libadwaita, PipeWire, a WirePlumber-managed session, and the
native libraries used by pipewire-gobject. PyGObject is a distro/runtime
dependency, not a Mini EQ PyPI dependency. Some tests skip automatically when
optional runtime tools are unavailable.

For real GTK widget behavior, run the opt-in AT-SPI smoke test inside its
nested headless GNOME Shell session:

```bash
MINI_EQ_RUN_ATSPI=1 .venv/bin/python -m pytest tests/test_mini_eq_atspi_widgets.py -q
```

For a deeper live runtime smoke, run the real GTK app in a private
PipeWire/WirePlumber graph with synthetic playback and AT-SPI UI driving:

```bash
.venv/bin/python tools/check_live_ui_runtime.py --timeout 35 --cycles 1
MINI_EQ_RUN_LIVE_UI=1 .venv/bin/python -m pytest tests/test_mini_eq_live_ui_runtime.py -q
```

When creating a fresh venv for pip/package validation, build pipewire-gobject in
a plain wheel-build venv first, then install that wheel into a
`--system-site-packages` Mini EQ venv. This keeps distro GI bindings visible at
runtime without making Ubuntu/Debian `g-ir-scanner` import partial `distutils`
modules from a system-site build venv.

## Change Guidelines

- Prefer existing patterns and small, targeted patches.
- Do not move logic between the large modules just to tidy them; split modules
only when the user asked for that refactor or the change needs it.
- Keep WirePlumber 0.4 and 0.5 compatibility in mind. Do not use a newer GI API
without checking the compatibility layer and tests.
- Keep the pipewire-gobject API boundary small and app-facing. WirePlumber stays
the host session manager, not a bundled GI dependency.
- Treat the Mini EQ D-Bus control interface as a project-internal app/Shell
extension contract with version-skew tolerance. Keep `api_version = 1`
additive only: add state fields, methods, and capabilities when needed, but do
Expand All @@ -102,11 +125,15 @@ are unavailable.
## Flatpak And Flathub

- Keep the upstream Flatpak manifest as a local development and CI manifest
using the checked-out source tree. The sibling Flathub repository uses a
using the checked-out source tree. The Flathub packaging repository uses a
release archive URL and SHA-256 for publishing.
- Before opening a Flathub PR, compare the upstream and sibling Flathub
manifests. The only expected manifest difference is the Mini EQ source block:
local `type: dir` upstream, release archive URL and SHA-256 in Flathub.
- Before opening a Flathub PR, compare the upstream and Flathub manifests and
synced dependency files. The only expected manifest difference is the Mini EQ
source block: local `type: dir` upstream, release archive URL and SHA-256 in
Flathub.
- Treat Flathub publishing PRs as maintainer-owned. Agents may prepare local
diffs, validation output, and handoff notes, but should not open, submit, or
merge Flathub PRs.
- Put user-facing Flatpak install information in `README.md`; keep Flathub
release workflow and repository split notes in `docs/flathub.md`.
- Do not hand-edit bundled Mini EQ source files in the Flathub repository. Fix
Expand Down Expand Up @@ -169,35 +196,19 @@ During release preparation, verify that version-bearing files agree:
URL. The package `__version__` is derived from release metadata and should not
be hardcoded separately.

Before publishing artifacts, run `tools/release_preflight.py`; its focused leak
scan covers `HEAD`, tracked worktree changes, and untracked non-ignored text
files. If reproducing the scan manually, check all three surfaces instead of
only committed history:
Before publishing artifacts, run the release preflight. Prefer the
containerized wrapper when the host does not already have the `pipewire-gobject`
sdist build dependencies installed:

```bash
git rev-list --count HEAD
git ls-remote --heads origin
git ls-remote --tags origin
leak_pattern='(/home/|/Users/|secret|token|api[_-]?key|github_pat|gh[pousr]_[A-Za-z0-9_]{20,}|pypi-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16}|ASIA[0-9A-Z]{16}|BEGIN [A-Z0-9 ]*PRIVATE KEY)'
git grep -n -I -E "$leak_pattern" HEAD -- . \
':(exclude)*.png' \
':(exclude)AGENTS.md' \
':(exclude)docs/release.md' \
':(exclude)tools/release_preflight.py'
git grep -n -I -E "$leak_pattern" -- . \
':(exclude)*.png' \
':(exclude)AGENTS.md' \
':(exclude)docs/release.md' \
':(exclude)tools/release_preflight.py'
git ls-files --others --exclude-standard -z -- . \
| grep -z -v -E '(^|/)(AGENTS\.md|docs/release\.md|tools/release_preflight\.py)$|\.png$' \
| xargs -0 -r grep -n -I -E "$leak_pattern" --
tools/run_release_preflight_container.sh
```

This grep is a focused privacy and credential smoke check, not a full secret
scanner. Keep GitHub secret scanning and push protection enabled; use an
external scanner such as Gitleaks for deeper local investigation when release
history or generated artifacts look suspicious:
Set `MINI_EQ_FLATHUB_MANIFEST` to a Flathub publishing manifest path when the
containerized preflight should include the manifest drift check.
The preflight owns the focused leak scan for `HEAD`, tracked worktree changes,
and untracked non-ignored text files. Use Gitleaks as an extra check when
release history or generated artifacts look suspicious:

```bash
gitleaks git --no-banner --redact .
Expand Down
2 changes: 0 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ include docs/release.md
include docs/social-preview.png
include docs/screenshots/README.md
include docs/screenshots/*.png
include docker/*.Dockerfile
include extensions/gnome-shell/README.md
recursive-include extensions/gnome-shell/mini-eq@bhack.github.io *
include flatpak/patches/*.patch
include tools/*.py
include tools/*.sh
recursive-include tools/gnome-shell-extension *.py
Loading
Loading