solstone-linux 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solstone_linux-0.1.0/.gitignore +10 -0
- solstone_linux-0.1.0/AGENTS.md +158 -0
- solstone_linux-0.1.0/CHANGELOG.md +27 -0
- solstone_linux-0.1.0/CLAUDE.md +1 -0
- solstone_linux-0.1.0/INSTALL.md +153 -0
- solstone_linux-0.1.0/LICENSE +661 -0
- solstone_linux-0.1.0/Makefile +165 -0
- solstone_linux-0.1.0/PKG-INFO +73 -0
- solstone_linux-0.1.0/README.md +58 -0
- solstone_linux-0.1.0/contrib/icons/hicolor/index.theme +12 -0
- solstone_linux-0.1.0/contrib/icons/hicolor/scalable/status/solstone-error.svg +17 -0
- solstone_linux-0.1.0/contrib/icons/hicolor/scalable/status/solstone-paused.svg +17 -0
- solstone_linux-0.1.0/contrib/icons/hicolor/scalable/status/solstone-recording.svg +7 -0
- solstone_linux-0.1.0/contrib/icons/hicolor/scalable/status/solstone-syncing.svg +16 -0
- solstone_linux-0.1.0/pyproject.toml +29 -0
- solstone_linux-0.1.0/scripts/extract_changelog.sh +37 -0
- solstone_linux-0.1.0/scripts/release.sh +117 -0
- solstone_linux-0.1.0/src/solstone_linux/__init__.py +6 -0
- solstone_linux-0.1.0/src/solstone_linux/activity.py +384 -0
- solstone_linux-0.1.0/src/solstone_linux/audio_detect.py +79 -0
- solstone_linux-0.1.0/src/solstone_linux/audio_mute.py +47 -0
- solstone_linux-0.1.0/src/solstone_linux/audio_recorder.py +186 -0
- solstone_linux-0.1.0/src/solstone_linux/chat_bridge.py +493 -0
- solstone_linux-0.1.0/src/solstone_linux/cli.py +489 -0
- solstone_linux-0.1.0/src/solstone_linux/config.py +130 -0
- solstone_linux-0.1.0/src/solstone_linux/dbus_service.py +149 -0
- solstone_linux-0.1.0/src/solstone_linux/dbusmenu.py +242 -0
- solstone_linux-0.1.0/src/solstone_linux/doctor.py +277 -0
- solstone_linux-0.1.0/src/solstone_linux/icons/hicolor/index.theme +12 -0
- solstone_linux-0.1.0/src/solstone_linux/icons/hicolor/scalable/status/solstone-error.svg +17 -0
- solstone_linux-0.1.0/src/solstone_linux/icons/hicolor/scalable/status/solstone-paused.svg +17 -0
- solstone_linux-0.1.0/src/solstone_linux/icons/hicolor/scalable/status/solstone-recording.svg +7 -0
- solstone_linux-0.1.0/src/solstone_linux/icons/hicolor/scalable/status/solstone-syncing.svg +16 -0
- solstone_linux-0.1.0/src/solstone_linux/install_guard.py +210 -0
- solstone_linux-0.1.0/src/solstone_linux/monitor_positions.py +110 -0
- solstone_linux-0.1.0/src/solstone_linux/observer.py +757 -0
- solstone_linux-0.1.0/src/solstone_linux/recovery.py +175 -0
- solstone_linux-0.1.0/src/solstone_linux/screencast.py +572 -0
- solstone_linux-0.1.0/src/solstone_linux/session_env.py +92 -0
- solstone_linux-0.1.0/src/solstone_linux/sni.py +250 -0
- solstone_linux-0.1.0/src/solstone_linux/solstone-linux.service.in +17 -0
- solstone_linux-0.1.0/src/solstone_linux/streams.py +87 -0
- solstone_linux-0.1.0/src/solstone_linux/sync.py +497 -0
- solstone_linux-0.1.0/src/solstone_linux/tray.py +577 -0
- solstone_linux-0.1.0/src/solstone_linux/upload.py +290 -0
- solstone_linux-0.1.0/tests/__init__.py +0 -0
- solstone_linux-0.1.0/tests/test_activity.py +644 -0
- solstone_linux-0.1.0/tests/test_chat_bridge.py +601 -0
- solstone_linux-0.1.0/tests/test_cli.py +208 -0
- solstone_linux-0.1.0/tests/test_config.py +86 -0
- solstone_linux-0.1.0/tests/test_dbus_service.py +281 -0
- solstone_linux-0.1.0/tests/test_dbusmenu.py +87 -0
- solstone_linux-0.1.0/tests/test_doctor.py +329 -0
- solstone_linux-0.1.0/tests/test_extract_changelog.py +64 -0
- solstone_linux-0.1.0/tests/test_install_guard.py +192 -0
- solstone_linux-0.1.0/tests/test_monitor_positions.py +58 -0
- solstone_linux-0.1.0/tests/test_observer.py +80 -0
- solstone_linux-0.1.0/tests/test_screencast.py +203 -0
- solstone_linux-0.1.0/tests/test_session_env.py +45 -0
- solstone_linux-0.1.0/tests/test_streams.py +46 -0
- solstone_linux-0.1.0/tests/test_sync.py +853 -0
- solstone_linux-0.1.0/tests/test_tray.py +351 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Development guidelines for solstone-linux, a standalone Linux desktop observer.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
solstone-linux is a companion app that runs alongside the main [solstone](https://solstone.app) journal. It is one of the owner's observers — it experiences screen and audio along with the owner on a Linux desktop using PipeWire and GStreamer, stores segments locally, and syncs them to your solstone journal. It runs as a systemd user service on GNOME Wayland sessions.
|
|
8
|
+
|
|
9
|
+
This is **not** part of the solstone monorepo. It is a standalone package with its own release lifecycle, installed via pipx alongside system-provided PyGObject/GStreamer bindings.
|
|
10
|
+
|
|
11
|
+
## Source Layout
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/solstone_linux/
|
|
15
|
+
__init__.py Package version
|
|
16
|
+
cli.py CLI entry point (run, setup, install-service, status)
|
|
17
|
+
solstone-linux.service.in Systemd unit template (rendered by install-service)
|
|
18
|
+
config.py Config loading/persistence (~/.local/share/solstone-linux/)
|
|
19
|
+
observer.py Main capture loop — state machine (idle/screencast), audio + video
|
|
20
|
+
screencast.py Portal-based multi-monitor recording (xdg-desktop-portal + GStreamer)
|
|
21
|
+
audio_recorder.py Stereo audio recording (mic + system via soundcard)
|
|
22
|
+
audio_detect.py Audio device detection via ultrasonic tone
|
|
23
|
+
audio_mute.py PulseAudio mute state detection
|
|
24
|
+
activity.py Cross-desktop activity detection (screen lock, power save) via DBus
|
|
25
|
+
monitor_positions.py Monitor position assignment from geometry
|
|
26
|
+
session_env.py Desktop session environment checks and recovery
|
|
27
|
+
streams.py Stream name derivation (hostname-based)
|
|
28
|
+
sync.py Background sync service — uploads completed segments to server
|
|
29
|
+
upload.py HTTP upload client for solstone ingest server
|
|
30
|
+
recovery.py Crash recovery for orphaned .incomplete segments
|
|
31
|
+
|
|
32
|
+
tests/ pytest test suite
|
|
33
|
+
contrib/ Reference icons for development fallback
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
The observer runs a single asyncio event loop with three concurrent concerns:
|
|
39
|
+
|
|
40
|
+
1. **Capture loop** (`observer.py`) — Checks activity status every 5 seconds, records audio continuously, manages screencast recording via GStreamer. Creates 5-minute segments in `~/.local/share/solstone-linux/captures/YYYYMMDD/stream/HHMMSS_DDD/`. Segment directories start as `.incomplete` and are renamed on finalization.
|
|
41
|
+
|
|
42
|
+
2. **Sync service** (`sync.py`) — Background asyncio task that walks the captures directory, queries the server for existing segments, and uploads missing ones. Circuit breaker pattern with error-type-aware thresholds.
|
|
43
|
+
|
|
44
|
+
3. **Chat bridge** (`chat_bridge.py`) — Background asyncio task that consumes server-sent callosum chat events, mirrors request/clear messages to an optional local FIFO, and fires click-capturing `notify-send` subprocesses when server opt-in allows Linux desktop notifications.
|
|
45
|
+
|
|
46
|
+
State machine has two modes: `screencast` (screen active, recording video) and `idle` (screen inactive). Mode transitions, mute state changes, and 5-minute intervals all trigger segment boundaries.
|
|
47
|
+
|
|
48
|
+
The capture loop never makes network calls. It writes locally; sync handles all uploads.
|
|
49
|
+
|
|
50
|
+
## Commands
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
make install # Create venv, install package + dev tools (pytest, ruff) via uv
|
|
54
|
+
make test # Run all tests
|
|
55
|
+
make test-only TEST=tests/test_config.py # Run specific test
|
|
56
|
+
make format # Auto-format with ruff
|
|
57
|
+
make ci # Lint + format check + tests
|
|
58
|
+
make install-service # Smart install-or-upgrade: guards against cross-repo contamination; runs CI in upgrade mode
|
|
59
|
+
make service-restart # systemctl restart wrapper
|
|
60
|
+
make service-status # systemctl status wrapper
|
|
61
|
+
make service-logs # systemctl log tail wrapper
|
|
62
|
+
make uninstall-service # Disable + remove unit + pipx uninstall
|
|
63
|
+
make clean # Remove build artifacts and caches
|
|
64
|
+
make versions # Show installed package versions
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Releasing
|
|
68
|
+
|
|
69
|
+
solstone-linux ships to PyPI via `scripts/release.sh`. The operator runs the
|
|
70
|
+
release from a clean checkout; there is no CI publish path.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
make release-test # upload to TestPyPI (requires TESTPYPI_TOKEN)
|
|
74
|
+
make release # upload to PyPI (requires PYPI_TOKEN)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The script refuses to run on a dirty tree, builds an sdist + a
|
|
78
|
+
`py3-none-any` wheel with `uv build`, runs `uvx twine check`, uploads,
|
|
79
|
+
tags the commit `vX.Y.Z`, pushes the tag, and creates a matching GitHub
|
|
80
|
+
Release with the artifacts attached and the CHANGELOG block as release
|
|
81
|
+
notes.
|
|
82
|
+
|
|
83
|
+
Before releasing, bump the version in BOTH `pyproject.toml` (`[project].version`)
|
|
84
|
+
and `src/solstone_linux/__init__.py` (`__version__`) — they must match — and add
|
|
85
|
+
a `## [X.Y.Z] - YYYY-MM-DD` block to `CHANGELOG.md`.
|
|
86
|
+
|
|
87
|
+
Set `RELEASE_DRY_RUN=1` to walk the full flow without uploading, tagging,
|
|
88
|
+
pushing, or publishing a GitHub Release; the build and `twine check` still
|
|
89
|
+
run for real.
|
|
90
|
+
|
|
91
|
+
## Development Principles
|
|
92
|
+
|
|
93
|
+
- **Simple code.** Prefer plain functions over classes. Use dataclasses for structured data. Only use classes when managing stateful lifecycle (Observer, Screencaster, SyncService, AudioRecorder).
|
|
94
|
+
- **Async by default.** The main loop is asyncio. DBus calls, subprocess management, and sync all use async. Audio recording uses a dedicated thread because soundcard is blocking.
|
|
95
|
+
- **No network in the capture loop.** The observer writes segments locally. The sync service uploads asynchronously. This keeps capture reliable even when the server is down.
|
|
96
|
+
- **Atomic directory operations.** Segments start as `HHMMSS.incomplete/`, are renamed to `HHMMSS_DDD/` on completion, or `HHMMSS.failed/` on recovery failure.
|
|
97
|
+
- **System site-packages required.** PyGObject and GStreamer bindings come from system packages. The venv (and pipx) must use `--system-site-packages`.
|
|
98
|
+
|
|
99
|
+
## File Headers
|
|
100
|
+
|
|
101
|
+
All `.py` source files must include this header as the first two lines:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# SPDX-License-Identifier: AGPL-3.0-only
|
|
105
|
+
# Copyright (c) 2026 sol pbc
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Add this header to new `.py` files in `src/solstone_linux/` and `tests/`. Do not add headers to markdown, TOML, or config files.
|
|
109
|
+
|
|
110
|
+
## Runtime Dependencies
|
|
111
|
+
|
|
112
|
+
System packages (not pip-installable):
|
|
113
|
+
- `python3-gobject` / `python3-gi` — PyGObject for GTK4 and GDK
|
|
114
|
+
- GStreamer with PipeWire plugin (`gst-launch-1.0 pipewiresrc`)
|
|
115
|
+
- PipeWire running
|
|
116
|
+
- `pactl` (PulseAudio utils) for mute detection
|
|
117
|
+
- xdg-desktop-portal with ScreenCast support
|
|
118
|
+
|
|
119
|
+
Python packages (in pyproject.toml):
|
|
120
|
+
- `requests` — HTTP upload client
|
|
121
|
+
- `numpy` — Audio buffer manipulation and RMS computation
|
|
122
|
+
- `soundfile` — FLAC encoding
|
|
123
|
+
- `soundcard` — Audio device enumeration and recording
|
|
124
|
+
- `dbus-next` — Async DBus client for portal and activity detection
|
|
125
|
+
- `PyGObject` — GDK monitor geometry (installed from system)
|
|
126
|
+
|
|
127
|
+
## Data Paths
|
|
128
|
+
|
|
129
|
+
- Config: `~/.local/share/solstone-linux/config/config.json`
|
|
130
|
+
- Captures: `~/.local/share/solstone-linux/captures/`
|
|
131
|
+
- State: `~/.local/share/solstone-linux/state/`
|
|
132
|
+
- Restore token: `~/.local/share/solstone-linux/config/restore_token`
|
|
133
|
+
- Install source marker: `~/.config/solstone-linux/.install-source` (tracks which repo clone owns the pipx install)
|
|
134
|
+
|
|
135
|
+
## Key Patterns
|
|
136
|
+
|
|
137
|
+
- **Activity detection is cross-desktop.** Uses ordered DBus fallback chains for screen lock (freedesktop.org ScreenSaver → GNOME ScreenSaver) and power save (Mutter DisplayConfig → KDE Solid PowerManagement). All backends degrade gracefully to safe defaults.
|
|
138
|
+
- **Audio is stereo-interleaved.** Left channel = microphone, right channel = system audio. When muted, channels are split into separate mono FLAC files.
|
|
139
|
+
- **Screencast uses xdg-desktop-portal.** Session persistence via restore tokens avoids re-prompting the user. GStreamer subprocess (`gst-launch-1.0`) handles the actual PipeWire recording.
|
|
140
|
+
- **Crash recovery runs on startup.** `recovery.py` scans for orphaned `.incomplete` directories older than 2 minutes and finalizes or marks them as failed.
|
|
141
|
+
|
|
142
|
+
## Testing
|
|
143
|
+
|
|
144
|
+
Tests use pytest with standard mocking. No system dependencies required for tests — audio devices, DBus, and GStreamer are mocked. Run `make test` to execute the full suite.
|
|
145
|
+
|
|
146
|
+
## Brand canon
|
|
147
|
+
|
|
148
|
+
- **solstone-linux is an observer.** Owner-facing canon describes solstone as observers + journal; sol is the keeper who lives in and tends your journal. In engineering architecture, `observers + sol agent + journal` is the running software this repo's code talks to. This repo implements one of those observers.
|
|
149
|
+
- **The canon lives elsewhere.** Owner-facing terminology comes from sol pbc's internal brand canon (system anatomy + voice terminology guides). This repo's branded prose follows it; the canon itself is not vendored here.
|
|
150
|
+
- **Use co-experience language in branded prose.** In README, INSTALL, onboarding text, settings copy, and error messages, describe solstone-linux as something that experiences screen and audio along with the owner. Never describe it as watching, recording, monitoring, or tracking the owner.
|
|
151
|
+
- **Keep code language in code-only contexts.** Internal architecture terms such as `Capture loop`, the capture pipeline, module names, and data-path names are canon-permitted here and must not be renamed just to match branded prose.
|
|
152
|
+
- **Edit with the surface in mind.** If the owner sees the string, follow the canon. If the text is naming code, pipelines, modules, or storage artifacts for engineers, the existing internal vocabulary stays.
|
|
153
|
+
|
|
154
|
+
Canon source of truth: sol pbc's internal brand canon (system-anatomy guide).
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
AGPL-3.0-only -- Copyright (c) 2026 sol pbc
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to solstone-linux are documented here.
|
|
4
|
+
The format is based on Keep a Changelog (https://keepachangelog.com/),
|
|
5
|
+
and this project adheres to Semantic Versioning.
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-05-19
|
|
8
|
+
|
|
9
|
+
First public release of solstone-linux — the Linux desktop observer
|
|
10
|
+
for your solstone journal.
|
|
11
|
+
|
|
12
|
+
solstone-linux runs as a systemd user service in your GNOME Wayland
|
|
13
|
+
session. It experiences screen and audio along with you, holds short
|
|
14
|
+
segments locally, and uploads them to your journal in the background.
|
|
15
|
+
|
|
16
|
+
### Install paths
|
|
17
|
+
|
|
18
|
+
- From PyPI: `pipx install --system-site-packages solstone-linux`,
|
|
19
|
+
then `solstone-linux install-service` to register the systemd unit.
|
|
20
|
+
- From a clone: `git clone` this repo and run `make install-service`
|
|
21
|
+
for development or unreleased changes.
|
|
22
|
+
|
|
23
|
+
Both paths rely on host packages for PyGObject, GStreamer with the
|
|
24
|
+
PipeWire plugin, PipeWire itself, `pactl`, and `xdg-desktop-portal`
|
|
25
|
+
with ScreenCast support. PyGObject and the GStreamer bindings ride
|
|
26
|
+
along from system site-packages — that is why `--system-site-packages`
|
|
27
|
+
matters.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AGENTS.md
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# installing solstone-linux
|
|
2
|
+
|
|
3
|
+
these instructions are for a coding agent and human working together. solstone-linux is a standalone observer that experiences your screen and audio along with you on linux desktops using PipeWire and GStreamer, and uploads to your solstone journal.
|
|
4
|
+
|
|
5
|
+
solstone must already be installed and running. if it isn't, start there: https://solstone.app/install
|
|
6
|
+
|
|
7
|
+
> **most users should run `sol observer install` from the solstone host instead of following this file by hand.** that one command handles the clone, the system-package preflight, the build, the registration, and the systemd unit — including a `--dry-run` mode to preview every step. the instructions below are for developers building from source or troubleshooting the install.
|
|
8
|
+
|
|
9
|
+
## before you begin
|
|
10
|
+
|
|
11
|
+
if `sol` is not in PATH, check `~/.local/bin/sol`.
|
|
12
|
+
|
|
13
|
+
check if solstone-linux is already installed and running:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
systemctl --user status solstone-linux
|
|
17
|
+
sol remote list
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
if it's already active and connected, you're done.
|
|
21
|
+
|
|
22
|
+
## what to sort out together
|
|
23
|
+
|
|
24
|
+
- **system dependencies.** the observer needs PyGObject, GStreamer, and PipeWire bindings from system packages. installing these requires sudo.
|
|
25
|
+
- **stream name.** this identifies this observer's stream. the machine's hostname is the typical choice.
|
|
26
|
+
|
|
27
|
+
### remote sol
|
|
28
|
+
|
|
29
|
+
The observer connects to your solstone journal over HTTPS — colocation is optional. For remote-sol setups:
|
|
30
|
+
|
|
31
|
+
- clone anywhere; the `$(sol root)/observers` path in step 2 only applies when sol is installed locally.
|
|
32
|
+
- `solstone-linux setup` will prompt for the journal URL (since local `sol remote list` isn't available) and auto-register the observer with your journal via HTTP, persisting the returned key. No manual key handoff is needed if the journal's observer-registration endpoint is reachable.
|
|
33
|
+
- otherwise, the install sequence below is the same.
|
|
34
|
+
|
|
35
|
+
## install sequence
|
|
36
|
+
|
|
37
|
+
1. install system dependencies for your distro, including `pipx`. if you need sudo, walk your human through it.
|
|
38
|
+
|
|
39
|
+
**fedora:**
|
|
40
|
+
```
|
|
41
|
+
sudo dnf install python3-gobject gtk4 gstreamer1-plugins-base gstreamer1-plugin-pipewire pipewire-gstreamer alsa-lib-devel pulseaudio-utils pipewire-pulseaudio xdg-desktop-portal pipx
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**debian / ubuntu:**
|
|
45
|
+
```
|
|
46
|
+
sudo apt install python3-gi gir1.2-gdk-4.0 gir1.2-gtk-4.0 gstreamer1.0-pipewire libasound2-dev pulseaudio-utils pipewire-pulse xdg-desktop-portal pipx
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**arch:**
|
|
50
|
+
```
|
|
51
|
+
sudo pacman -S python-gobject gtk4 gstreamer gst-plugin-pipewire libpulse alsa-lib xdg-desktop-portal pipx
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**opensuse:**
|
|
55
|
+
```
|
|
56
|
+
sudo zypper install python3-gobject python3-gobject-Gdk typelib-1_0-Gtk-4_0 \
|
|
57
|
+
gtk4-tools gstreamer-plugins-base gstreamer-plugin-pipewire \
|
|
58
|
+
pipewire-pulseaudio pulseaudio-utils alsa-devel \
|
|
59
|
+
xdg-desktop-portal python3-pipx
|
|
60
|
+
```
|
|
61
|
+
note: package names diverge from Fedora — `typelib-1_0-Gtk-4_0` (not `gtk4`), `gstreamer-plugin-pipewire` (singular), and `alsa-devel` (not `alsa-lib-devel`).
|
|
62
|
+
|
|
63
|
+
2. If you have local sol, cloning into `$(sol root)/observers` keeps observers colocated with your solstone journal. For remote-sol setups, clone anywhere — the observer runs independently of your journal at runtime:
|
|
64
|
+
```
|
|
65
|
+
cd "$(sol root)/observers"
|
|
66
|
+
git clone https://github.com/solpbc/solstone-linux.git
|
|
67
|
+
cd solstone-linux
|
|
68
|
+
make install-service
|
|
69
|
+
```
|
|
70
|
+
`make install-service` is a smart install-or-upgrade: detects fresh-install vs upgrade via a marker file, runs CI in upgrade mode, guards against cross-repo contamination.
|
|
71
|
+
|
|
72
|
+
3. run the interactive setup:
|
|
73
|
+
```
|
|
74
|
+
solstone-linux setup
|
|
75
|
+
```
|
|
76
|
+
this prompts for the journal URL and auto-registers via `sol` when available.
|
|
77
|
+
|
|
78
|
+
4. verify the service is running:
|
|
79
|
+
```
|
|
80
|
+
systemctl --user status solstone-linux
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## updating after a code change
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
git pull && make install-service
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## notes
|
|
90
|
+
|
|
91
|
+
- activity detection (idle timeout, screen lock, power save) works on both GNOME and KDE. on other desktops the observer still experiences your screen and audio fine, but activity-based segment boundaries won't trigger.
|
|
92
|
+
- the tray icon uses the StatusNotifierItem (SNI) D-Bus protocol. it works on KDE natively and GNOME with the AppIndicator extension. if no SNI host is available, the observer runs normally without a tray icon.
|
|
93
|
+
|
|
94
|
+
## appendix: GNOME tray support
|
|
95
|
+
|
|
96
|
+
the system tray icon appears automatically when the observer starts in a graphical session. on KDE Plasma this works out of the box. on GNOME, the AppIndicator extension is required.
|
|
97
|
+
|
|
98
|
+
GNOME removed native system tray support. the AppIndicator extension restores it via the same StatusNotifierItem protocol KDE uses. without it, the observer runs fine but has no tray icon.
|
|
99
|
+
|
|
100
|
+
**ubuntu:** already installed and enabled by default — skip this step.
|
|
101
|
+
|
|
102
|
+
**fedora:**
|
|
103
|
+
```
|
|
104
|
+
sudo dnf install gnome-shell-extension-appindicator
|
|
105
|
+
```
|
|
106
|
+
then log out and back in, or restart GNOME Shell (Alt+F2, type `r`, enter). enable the extension in GNOME Extensions app if not auto-enabled.
|
|
107
|
+
|
|
108
|
+
**arch:**
|
|
109
|
+
```
|
|
110
|
+
sudo pacman -S gnome-shell-extension-appindicator
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**other distros (openSUSE, etc.):**
|
|
114
|
+
|
|
115
|
+
if your distro doesn't ship an AppIndicator extension package, install it from extensions.gnome.org via the CLI:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
curl -LO https://extensions.gnome.org/extension-data/appindicatorsupportrgcjonas.gmail.com.v64.shell-extension.zip
|
|
119
|
+
gnome-extensions install appindicatorsupportrgcjonas.gmail.com.v64.shell-extension.zip
|
|
120
|
+
gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
then restart GNOME Shell — on Wayland, log out and back in; on X11, press Alt+F2 and type `r`. v64 supports GNOME Shell 45–50; check https://extensions.gnome.org/extension/615/appindicator-support/ for a newer build if you're on a later shell.
|
|
124
|
+
|
|
125
|
+
to check if it's working: `gnome-extensions list | grep appindicator` should show it. if the tray icon still doesn't appear, verify it's enabled: `gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com`
|
|
126
|
+
|
|
127
|
+
## Troubleshooting
|
|
128
|
+
|
|
129
|
+
Common install-time errors and their fixes:
|
|
130
|
+
|
|
131
|
+
- **`pkg-config: command not found` or `cairo` pkg-config failure**
|
|
132
|
+
- fedora: `sudo dnf install pkgconf-pkg-config cairo-devel`
|
|
133
|
+
- debian/ubuntu: `sudo apt install pkg-config libcairo2-dev`
|
|
134
|
+
- arch: `sudo pacman -S pkgconf cairo`
|
|
135
|
+
- opensuse: `sudo zypper install pkgconf-pkg-config cairo-devel`
|
|
136
|
+
|
|
137
|
+
- **`girepository-2.0` missing or `pygobject` build failure**
|
|
138
|
+
- fedora: `sudo dnf install gobject-introspection-devel`
|
|
139
|
+
- debian/ubuntu: `sudo apt install libgirepository1.0-dev`
|
|
140
|
+
- arch: `sudo pacman -S gobject-introspection`
|
|
141
|
+
- opensuse: `sudo zypper install gobject-introspection-devel`
|
|
142
|
+
|
|
143
|
+
- **`Python.h: No such file or directory`**
|
|
144
|
+
- fedora: `sudo dnf install python3-devel`
|
|
145
|
+
- debian/ubuntu: `sudo apt install python3-dev`
|
|
146
|
+
- arch: already bundled in `python` package
|
|
147
|
+
- opensuse: `sudo zypper install python3-devel`
|
|
148
|
+
|
|
149
|
+
- **`pipx: command not found`**
|
|
150
|
+
- fedora: `sudo dnf install pipx`
|
|
151
|
+
- debian/ubuntu: `sudo apt install pipx`
|
|
152
|
+
- arch: `sudo pacman -S python-pipx`
|
|
153
|
+
- opensuse: `sudo zypper install python3-pipx`
|