GuGa 1.0.3__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.
- guga-1.0.3/GuGa.egg-info/PKG-INFO +123 -0
- guga-1.0.3/GuGa.egg-info/SOURCES.txt +20 -0
- guga-1.0.3/GuGa.egg-info/dependency_links.txt +1 -0
- guga-1.0.3/GuGa.egg-info/entry_points.txt +2 -0
- guga-1.0.3/GuGa.egg-info/requires.txt +8 -0
- guga-1.0.3/GuGa.egg-info/top_level.txt +1 -0
- guga-1.0.3/MANIFEST.in +2 -0
- guga-1.0.3/PKG-INFO +123 -0
- guga-1.0.3/README.md +108 -0
- guga-1.0.3/guga/__init__.py +0 -0
- guga-1.0.3/guga/__pycache__/__init__.cpython-314.pyc +0 -0
- guga-1.0.3/guga/__pycache__/cli.cpython-314.pyc +0 -0
- guga-1.0.3/guga/__pycache__/daemon.cpython-314.pyc +0 -0
- guga-1.0.3/guga/alerter.py +174 -0
- guga-1.0.3/guga/cli.py +295 -0
- guga-1.0.3/guga/daemon.py +1025 -0
- guga-1.0.3/guga/installer.py +458 -0
- guga-1.0.3/guga/man/guga.1 +122 -0
- guga-1.0.3/guga/man/guga.md +37 -0
- guga-1.0.3/pyproject.toml +23 -0
- guga-1.0.3/setup.cfg +4 -0
- guga-1.0.3/setup.py +7 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: GuGa
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Linux to Android notification bridge.
|
|
5
|
+
Requires-Python: >=3.7
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: flask
|
|
8
|
+
Requires-Dist: flask-socketio
|
|
9
|
+
Requires-Dist: eventlet
|
|
10
|
+
Requires-Dist: gunicorn
|
|
11
|
+
Requires-Dist: python-dotenv
|
|
12
|
+
Requires-Dist: qrcode
|
|
13
|
+
Requires-Dist: cryptography
|
|
14
|
+
Requires-Dist: aiohttp
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="https://raw.githubusercontent.com/PositiveMatician/GuGa-Nexus/main/app-stable/app/src/main/assets/logo.png" width="128" height="128" />
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<h1 align="center">GuGa Nexus</h1>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
Send your Linux terminal and OS notifications straight to your Android.<br/>
|
|
24
|
+
No cloud. No subscription. No port forwarding.
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<a href="https://pypi.org/project/GuGa/">
|
|
29
|
+
<img src="https://img.shields.io/pypi/v/GuGa.svg" alt="PyPI Version" />
|
|
30
|
+
</a>
|
|
31
|
+
<img src="https://img.shields.io/badge/platform-Linux-lightgrey" alt="Platform" />
|
|
32
|
+
<img src="https://img.shields.io/badge/encryption-AES--256--GCM-green" alt="Encryption" />
|
|
33
|
+
<img src="https://img.shields.io/badge/license-MIT-yellow" alt="License" />
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
🔗 [View the full Open Source Repository on GitHub](https://github.com/PositiveMatician/GuGa-Nexus)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
**GuGa Nexus** is a minimalist, privacy-focused ecosystem that bridges your Linux machine and your Android device. It uses end-to-end AES-256-GCM encryption and works strictly over your own local network or a direct Cloudflare Tunnel—never storing your data on a third-party server.
|
|
41
|
+
|
|
42
|
+
- **Waiting for a long script to finish?** Get notified the moment it's done.
|
|
43
|
+
- **Training a model overnight?** Wake up to the final accuracy line in your notification.
|
|
44
|
+
- **SSHed into a remote server?** GuGa reaches your phone over the internet seamlessly.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
GuGa is distributed strictly as a standard Python module via PyPI.
|
|
51
|
+
|
|
52
|
+
1. **Install the package:**
|
|
53
|
+
```bash
|
|
54
|
+
pip install GuGa
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. **Initialize the background daemon:**
|
|
58
|
+
```bash
|
|
59
|
+
guga --install-service
|
|
60
|
+
```
|
|
61
|
+
*(This interactive setup will cleanly provision your systemd daemon and configure your network routing. Afterwards, your QR code will be generated).*
|
|
62
|
+
|
|
63
|
+
3. **Install the Android App:**
|
|
64
|
+
Download the `stable` Android APK from the [GitHub Releases Page](https://github.com/PositiveMatician/GuGa-Nexus/releases) and scan the QR code printed in your terminal!
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 🚀 Examples & Usage
|
|
69
|
+
|
|
70
|
+
Once deployed, the `guga` command-line utility is globally available on your terminal. It's designed to automatically detect whether you want to send a plain text notification, or if you want it to execute and watch a long-running process on your behalf.
|
|
71
|
+
|
|
72
|
+
### 1. Plain Notifications (Message Mode)
|
|
73
|
+
Send simple text updates directly to your Android device.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Push a simple message
|
|
77
|
+
guga "Build finished successfully ✅"
|
|
78
|
+
|
|
79
|
+
# You can also stream output into it via stdin!
|
|
80
|
+
echo "Database migration complete" | guga
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. Process Watching (Run Mode)
|
|
84
|
+
Put `guga` in front of any command. It will execute the command natively while streaming the output to your terminal just as normal. Once the command finishes, it will instantly notify your phone with the **Elapsed Time**, **Exit Status**, and the **Last Console Line**.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Get notified when training finishes
|
|
88
|
+
guga python train_model.py --epochs 100
|
|
89
|
+
|
|
90
|
+
# Compile code and get notified if it succeeded or crashed
|
|
91
|
+
guga make build-project
|
|
92
|
+
|
|
93
|
+
# Add custom labels to your notifications for clarity
|
|
94
|
+
guga -r ./deploy.sh --title "Production Server"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Post-Install Utilities
|
|
100
|
+
|
|
101
|
+
If you need to view your pairing credentials or manage your background daemon after installation, GuGa provides several utility commands:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
guga --qr # Show the pairing QR code
|
|
105
|
+
guga --show-pin # Show the secure Zero-Trust PIN
|
|
106
|
+
guga --install-service --reconfigure # Re-run the interactive setup
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
To control the Linux backend server explicitly:
|
|
110
|
+
```bash
|
|
111
|
+
sudo systemctl start guga # Start the server daemon
|
|
112
|
+
sudo systemctl stop guga # Stop the server daemon
|
|
113
|
+
journalctl -u guga -f # View live server connection logs
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Core Features & Architecture
|
|
119
|
+
|
|
120
|
+
* **Terminal Tracking:** Push notifications to Android via the `guga` global CLI.
|
|
121
|
+
* **System OS Monitoring:** Automatically intercepts DBus to forward your native Linux desktop notifications straight to your phone.
|
|
122
|
+
* **Zero-Trust Coupling:** Cryptographically secure pairing logic relying strictly on visual QR transmission + 8-Digit PINs (No OAuth or cloud-accounts required).
|
|
123
|
+
* **Network Versatility:** Operates flawlessly in **LAN-only mode** strictly over local WiFi, or seamlessly hooks into Cloudflared to grant you **Internet-anywhere access** without needing to own a domain or configure port-forwarding.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
GuGa.egg-info/PKG-INFO
|
|
6
|
+
GuGa.egg-info/SOURCES.txt
|
|
7
|
+
GuGa.egg-info/dependency_links.txt
|
|
8
|
+
GuGa.egg-info/entry_points.txt
|
|
9
|
+
GuGa.egg-info/requires.txt
|
|
10
|
+
GuGa.egg-info/top_level.txt
|
|
11
|
+
guga/__init__.py
|
|
12
|
+
guga/alerter.py
|
|
13
|
+
guga/cli.py
|
|
14
|
+
guga/daemon.py
|
|
15
|
+
guga/installer.py
|
|
16
|
+
guga/__pycache__/__init__.cpython-314.pyc
|
|
17
|
+
guga/__pycache__/cli.cpython-314.pyc
|
|
18
|
+
guga/__pycache__/daemon.cpython-314.pyc
|
|
19
|
+
guga/man/guga.1
|
|
20
|
+
guga/man/guga.md
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
guga
|
guga-1.0.3/MANIFEST.in
ADDED
guga-1.0.3/PKG-INFO
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: GuGa
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Linux to Android notification bridge.
|
|
5
|
+
Requires-Python: >=3.7
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: flask
|
|
8
|
+
Requires-Dist: flask-socketio
|
|
9
|
+
Requires-Dist: eventlet
|
|
10
|
+
Requires-Dist: gunicorn
|
|
11
|
+
Requires-Dist: python-dotenv
|
|
12
|
+
Requires-Dist: qrcode
|
|
13
|
+
Requires-Dist: cryptography
|
|
14
|
+
Requires-Dist: aiohttp
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="https://raw.githubusercontent.com/PositiveMatician/GuGa-Nexus/main/app-stable/app/src/main/assets/logo.png" width="128" height="128" />
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<h1 align="center">GuGa Nexus</h1>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
Send your Linux terminal and OS notifications straight to your Android.<br/>
|
|
24
|
+
No cloud. No subscription. No port forwarding.
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<a href="https://pypi.org/project/GuGa/">
|
|
29
|
+
<img src="https://img.shields.io/pypi/v/GuGa.svg" alt="PyPI Version" />
|
|
30
|
+
</a>
|
|
31
|
+
<img src="https://img.shields.io/badge/platform-Linux-lightgrey" alt="Platform" />
|
|
32
|
+
<img src="https://img.shields.io/badge/encryption-AES--256--GCM-green" alt="Encryption" />
|
|
33
|
+
<img src="https://img.shields.io/badge/license-MIT-yellow" alt="License" />
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
🔗 [View the full Open Source Repository on GitHub](https://github.com/PositiveMatician/GuGa-Nexus)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
**GuGa Nexus** is a minimalist, privacy-focused ecosystem that bridges your Linux machine and your Android device. It uses end-to-end AES-256-GCM encryption and works strictly over your own local network or a direct Cloudflare Tunnel—never storing your data on a third-party server.
|
|
41
|
+
|
|
42
|
+
- **Waiting for a long script to finish?** Get notified the moment it's done.
|
|
43
|
+
- **Training a model overnight?** Wake up to the final accuracy line in your notification.
|
|
44
|
+
- **SSHed into a remote server?** GuGa reaches your phone over the internet seamlessly.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
GuGa is distributed strictly as a standard Python module via PyPI.
|
|
51
|
+
|
|
52
|
+
1. **Install the package:**
|
|
53
|
+
```bash
|
|
54
|
+
pip install GuGa
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. **Initialize the background daemon:**
|
|
58
|
+
```bash
|
|
59
|
+
guga --install-service
|
|
60
|
+
```
|
|
61
|
+
*(This interactive setup will cleanly provision your systemd daemon and configure your network routing. Afterwards, your QR code will be generated).*
|
|
62
|
+
|
|
63
|
+
3. **Install the Android App:**
|
|
64
|
+
Download the `stable` Android APK from the [GitHub Releases Page](https://github.com/PositiveMatician/GuGa-Nexus/releases) and scan the QR code printed in your terminal!
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 🚀 Examples & Usage
|
|
69
|
+
|
|
70
|
+
Once deployed, the `guga` command-line utility is globally available on your terminal. It's designed to automatically detect whether you want to send a plain text notification, or if you want it to execute and watch a long-running process on your behalf.
|
|
71
|
+
|
|
72
|
+
### 1. Plain Notifications (Message Mode)
|
|
73
|
+
Send simple text updates directly to your Android device.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Push a simple message
|
|
77
|
+
guga "Build finished successfully ✅"
|
|
78
|
+
|
|
79
|
+
# You can also stream output into it via stdin!
|
|
80
|
+
echo "Database migration complete" | guga
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. Process Watching (Run Mode)
|
|
84
|
+
Put `guga` in front of any command. It will execute the command natively while streaming the output to your terminal just as normal. Once the command finishes, it will instantly notify your phone with the **Elapsed Time**, **Exit Status**, and the **Last Console Line**.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Get notified when training finishes
|
|
88
|
+
guga python train_model.py --epochs 100
|
|
89
|
+
|
|
90
|
+
# Compile code and get notified if it succeeded or crashed
|
|
91
|
+
guga make build-project
|
|
92
|
+
|
|
93
|
+
# Add custom labels to your notifications for clarity
|
|
94
|
+
guga -r ./deploy.sh --title "Production Server"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Post-Install Utilities
|
|
100
|
+
|
|
101
|
+
If you need to view your pairing credentials or manage your background daemon after installation, GuGa provides several utility commands:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
guga --qr # Show the pairing QR code
|
|
105
|
+
guga --show-pin # Show the secure Zero-Trust PIN
|
|
106
|
+
guga --install-service --reconfigure # Re-run the interactive setup
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
To control the Linux backend server explicitly:
|
|
110
|
+
```bash
|
|
111
|
+
sudo systemctl start guga # Start the server daemon
|
|
112
|
+
sudo systemctl stop guga # Stop the server daemon
|
|
113
|
+
journalctl -u guga -f # View live server connection logs
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Core Features & Architecture
|
|
119
|
+
|
|
120
|
+
* **Terminal Tracking:** Push notifications to Android via the `guga` global CLI.
|
|
121
|
+
* **System OS Monitoring:** Automatically intercepts DBus to forward your native Linux desktop notifications straight to your phone.
|
|
122
|
+
* **Zero-Trust Coupling:** Cryptographically secure pairing logic relying strictly on visual QR transmission + 8-Digit PINs (No OAuth or cloud-accounts required).
|
|
123
|
+
* **Network Versatility:** Operates flawlessly in **LAN-only mode** strictly over local WiFi, or seamlessly hooks into Cloudflared to grant you **Internet-anywhere access** without needing to own a domain or configure port-forwarding.
|
guga-1.0.3/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/PositiveMatician/GuGa-Nexus/main/app-stable/app/src/main/assets/logo.png" width="128" height="128" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">GuGa Nexus</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Send your Linux terminal and OS notifications straight to your Android.<br/>
|
|
9
|
+
No cloud. No subscription. No port forwarding.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://pypi.org/project/GuGa/">
|
|
14
|
+
<img src="https://img.shields.io/pypi/v/GuGa.svg" alt="PyPI Version" />
|
|
15
|
+
</a>
|
|
16
|
+
<img src="https://img.shields.io/badge/platform-Linux-lightgrey" alt="Platform" />
|
|
17
|
+
<img src="https://img.shields.io/badge/encryption-AES--256--GCM-green" alt="Encryption" />
|
|
18
|
+
<img src="https://img.shields.io/badge/license-MIT-yellow" alt="License" />
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
🔗 [View the full Open Source Repository on GitHub](https://github.com/PositiveMatician/GuGa-Nexus)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
**GuGa Nexus** is a minimalist, privacy-focused ecosystem that bridges your Linux machine and your Android device. It uses end-to-end AES-256-GCM encryption and works strictly over your own local network or a direct Cloudflare Tunnel—never storing your data on a third-party server.
|
|
26
|
+
|
|
27
|
+
- **Waiting for a long script to finish?** Get notified the moment it's done.
|
|
28
|
+
- **Training a model overnight?** Wake up to the final accuracy line in your notification.
|
|
29
|
+
- **SSHed into a remote server?** GuGa reaches your phone over the internet seamlessly.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
GuGa is distributed strictly as a standard Python module via PyPI.
|
|
36
|
+
|
|
37
|
+
1. **Install the package:**
|
|
38
|
+
```bash
|
|
39
|
+
pip install GuGa
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2. **Initialize the background daemon:**
|
|
43
|
+
```bash
|
|
44
|
+
guga --install-service
|
|
45
|
+
```
|
|
46
|
+
*(This interactive setup will cleanly provision your systemd daemon and configure your network routing. Afterwards, your QR code will be generated).*
|
|
47
|
+
|
|
48
|
+
3. **Install the Android App:**
|
|
49
|
+
Download the `stable` Android APK from the [GitHub Releases Page](https://github.com/PositiveMatician/GuGa-Nexus/releases) and scan the QR code printed in your terminal!
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 🚀 Examples & Usage
|
|
54
|
+
|
|
55
|
+
Once deployed, the `guga` command-line utility is globally available on your terminal. It's designed to automatically detect whether you want to send a plain text notification, or if you want it to execute and watch a long-running process on your behalf.
|
|
56
|
+
|
|
57
|
+
### 1. Plain Notifications (Message Mode)
|
|
58
|
+
Send simple text updates directly to your Android device.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Push a simple message
|
|
62
|
+
guga "Build finished successfully ✅"
|
|
63
|
+
|
|
64
|
+
# You can also stream output into it via stdin!
|
|
65
|
+
echo "Database migration complete" | guga
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 2. Process Watching (Run Mode)
|
|
69
|
+
Put `guga` in front of any command. It will execute the command natively while streaming the output to your terminal just as normal. Once the command finishes, it will instantly notify your phone with the **Elapsed Time**, **Exit Status**, and the **Last Console Line**.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Get notified when training finishes
|
|
73
|
+
guga python train_model.py --epochs 100
|
|
74
|
+
|
|
75
|
+
# Compile code and get notified if it succeeded or crashed
|
|
76
|
+
guga make build-project
|
|
77
|
+
|
|
78
|
+
# Add custom labels to your notifications for clarity
|
|
79
|
+
guga -r ./deploy.sh --title "Production Server"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Post-Install Utilities
|
|
85
|
+
|
|
86
|
+
If you need to view your pairing credentials or manage your background daemon after installation, GuGa provides several utility commands:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
guga --qr # Show the pairing QR code
|
|
90
|
+
guga --show-pin # Show the secure Zero-Trust PIN
|
|
91
|
+
guga --install-service --reconfigure # Re-run the interactive setup
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
To control the Linux backend server explicitly:
|
|
95
|
+
```bash
|
|
96
|
+
sudo systemctl start guga # Start the server daemon
|
|
97
|
+
sudo systemctl stop guga # Stop the server daemon
|
|
98
|
+
journalctl -u guga -f # View live server connection logs
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Core Features & Architecture
|
|
104
|
+
|
|
105
|
+
* **Terminal Tracking:** Push notifications to Android via the `guga` global CLI.
|
|
106
|
+
* **System OS Monitoring:** Automatically intercepts DBus to forward your native Linux desktop notifications straight to your phone.
|
|
107
|
+
* **Zero-Trust Coupling:** Cryptographically secure pairing logic relying strictly on visual QR transmission + 8-Digit PINs (No OAuth or cloud-accounts required).
|
|
108
|
+
* **Network Versatility:** Operates flawlessly in **LAN-only mode** strictly over local WiFi, or seamlessly hooks into Cloudflared to grant you **Internet-anywhere access** without needing to own a domain or configure port-forwarding.
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import asyncio.subprocess
|
|
3
|
+
import re
|
|
4
|
+
import aiohttp
|
|
5
|
+
import os
|
|
6
|
+
import platform
|
|
7
|
+
import sys
|
|
8
|
+
from dotenv import load_dotenv
|
|
9
|
+
|
|
10
|
+
CONFIG_DIR = os.path.expanduser("~/.guga")
|
|
11
|
+
env_path = os.path.join(CONFIG_DIR, '.env')
|
|
12
|
+
load_dotenv(dotenv_path=env_path)
|
|
13
|
+
|
|
14
|
+
# Enforce Linux-only restriction
|
|
15
|
+
if platform.system() != "Linux":
|
|
16
|
+
print("❌ ERROR: OS Notification monitoring only works on Linux (D-Bus required).")
|
|
17
|
+
print(f"Current OS: {platform.system()}")
|
|
18
|
+
sys.exit(1)
|
|
19
|
+
|
|
20
|
+
# ------------------------------------------------------------
|
|
21
|
+
# Configuration
|
|
22
|
+
# ------------------------------------------------------------
|
|
23
|
+
SERVER_URL = os.getenv("ALERTER_SERVER_URL", "http://localhost:6769/send")
|
|
24
|
+
LOG_FILE = os.path.join(CONFIG_DIR, "alerter.log")
|
|
25
|
+
|
|
26
|
+
# ------------------------------------------------------------
|
|
27
|
+
# Text Cleaning (Stripping Formatting)
|
|
28
|
+
# ------------------------------------------------------------
|
|
29
|
+
def clean_text(text: str) -> str:
|
|
30
|
+
"""
|
|
31
|
+
Strips HTML-like tags and common markdown formatting from text.
|
|
32
|
+
"""
|
|
33
|
+
if not text:
|
|
34
|
+
return ""
|
|
35
|
+
|
|
36
|
+
# 1. Strip HTML tags (e.g., <b>, <i>, <a href="...">)
|
|
37
|
+
text = re.sub(r'<[^>]+>', '', text)
|
|
38
|
+
|
|
39
|
+
# 2. Strip Markdown bold/italic/strike (e.g., **, *, __, _, ~~)
|
|
40
|
+
text = re.sub(r'(\*\*|__|\*|_|~~)', '', text)
|
|
41
|
+
|
|
42
|
+
# 3. Strip Markdown links [text](url) -> text
|
|
43
|
+
text = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', text)
|
|
44
|
+
|
|
45
|
+
# 4. Strip excessive newlines and whitespace
|
|
46
|
+
text = re.sub(r'\n+', ' ', text)
|
|
47
|
+
text = text.strip()
|
|
48
|
+
|
|
49
|
+
return text
|
|
50
|
+
|
|
51
|
+
# ------------------------------------------------------------
|
|
52
|
+
# Forwarding Logic
|
|
53
|
+
# ------------------------------------------------------------
|
|
54
|
+
async def forward_to_server(app_name: str, title: str, body: str):
|
|
55
|
+
"""
|
|
56
|
+
Sends the cleaned notification to the local server's /send route.
|
|
57
|
+
"""
|
|
58
|
+
clean_title = clean_text(title)
|
|
59
|
+
clean_body = clean_text(body)
|
|
60
|
+
|
|
61
|
+
payload_msg = f"{clean_title}: {clean_body}"
|
|
62
|
+
if not clean_title and not clean_body:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
log_entry = f"Forwarding: {payload_msg}\n"
|
|
66
|
+
print(log_entry.strip())
|
|
67
|
+
with open(LOG_FILE, "a") as f:
|
|
68
|
+
f.write(log_entry)
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
async with aiohttp.ClientSession() as session:
|
|
72
|
+
async with session.post(SERVER_URL, json={"message": payload_msg , "title":app_name}) as resp:
|
|
73
|
+
status_msg = f"Server Response: {resp.status}\n"
|
|
74
|
+
print(status_msg.strip())
|
|
75
|
+
with open(LOG_FILE, "a") as f:
|
|
76
|
+
f.write(status_msg)
|
|
77
|
+
except Exception as e:
|
|
78
|
+
err_msg = f"Error forwarding: {e}\n"
|
|
79
|
+
print(err_msg.strip())
|
|
80
|
+
with open(LOG_FILE, "a") as f:
|
|
81
|
+
f.write(err_msg)
|
|
82
|
+
|
|
83
|
+
# ------------------------------------------------------------
|
|
84
|
+
# D-Bus Monitor via Subprocess
|
|
85
|
+
# ------------------------------------------------------------
|
|
86
|
+
async def monitor_notifications():
|
|
87
|
+
"""
|
|
88
|
+
Runs dbus-monitor and parses its output to detect notifications.
|
|
89
|
+
"""
|
|
90
|
+
# Explicitly filter for method_call to avoid duplicates from signals
|
|
91
|
+
cmd = ["dbus-monitor", "type='method_call',interface='org.freedesktop.Notifications',member='Notify'"]
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
proc = await asyncio.create_subprocess_exec(
|
|
95
|
+
*cmd,
|
|
96
|
+
stdout=asyncio.subprocess.PIPE,
|
|
97
|
+
stderr=asyncio.subprocess.STDOUT
|
|
98
|
+
)
|
|
99
|
+
except Exception as e:
|
|
100
|
+
print(f"Failed to start dbus-monitor: {e}")
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
if not proc.stdout:
|
|
104
|
+
print("Failed to capture dbus-monitor stdout.")
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
print("Monitoring D-Bus for notifications (method calls only)...")
|
|
108
|
+
|
|
109
|
+
# State tracking
|
|
110
|
+
state = "IDLE"
|
|
111
|
+
app_name = ""
|
|
112
|
+
summary = ""
|
|
113
|
+
body = ""
|
|
114
|
+
|
|
115
|
+
while True:
|
|
116
|
+
line_bytes = await proc.stdout.readline()
|
|
117
|
+
if not line_bytes:
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
line = line_bytes.decode(errors='replace').strip()
|
|
121
|
+
|
|
122
|
+
# Detect start of method call specifically
|
|
123
|
+
if "method call" in line and "interface=org.freedesktop.Notifications; member=Notify" in line:
|
|
124
|
+
state = "APP_NAME"
|
|
125
|
+
app_name = ""
|
|
126
|
+
summary = ""
|
|
127
|
+
body = ""
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
if state == "APP_NAME":
|
|
131
|
+
match = re.search(r'string\s+"(.*)"', line)
|
|
132
|
+
if match:
|
|
133
|
+
app_name = match.group(1)
|
|
134
|
+
state = "REPLACES_ID"
|
|
135
|
+
|
|
136
|
+
elif state == "REPLACES_ID":
|
|
137
|
+
if "uint32" in line:
|
|
138
|
+
state = "ICON"
|
|
139
|
+
|
|
140
|
+
elif state == "ICON":
|
|
141
|
+
match = re.search(r'string\s+"(.*)"', line)
|
|
142
|
+
if match:
|
|
143
|
+
state = "SUMMARY"
|
|
144
|
+
|
|
145
|
+
elif state == "SUMMARY":
|
|
146
|
+
match = re.search(r'string\s+"(.*)"', line)
|
|
147
|
+
if match:
|
|
148
|
+
summary = match.group(1)
|
|
149
|
+
state = "BODY"
|
|
150
|
+
|
|
151
|
+
elif state == "BODY":
|
|
152
|
+
# Body can be a string or we might see 'array [' if body is empty
|
|
153
|
+
match = re.search(r'string\s+"(.*)"', line)
|
|
154
|
+
if match:
|
|
155
|
+
body = match.group(1)
|
|
156
|
+
# Done capturing this notification
|
|
157
|
+
print(f"\n[Intercepted] App: {app_name}")
|
|
158
|
+
with open(LOG_FILE, "a") as f:
|
|
159
|
+
f.write(f"\n[Intercepted] App: {app_name}\nTitle: {summary}\nBody: {body}\n")
|
|
160
|
+
asyncio.create_task(forward_to_server(app_name, summary, body))
|
|
161
|
+
state = "IDLE"
|
|
162
|
+
elif "array [" in line:
|
|
163
|
+
# Body was empty, moving to actions
|
|
164
|
+
print(f"\n[Intercepted] App: {app_name} (No body)")
|
|
165
|
+
with open(LOG_FILE, "a") as f:
|
|
166
|
+
f.write(f"\n[Intercepted] App: {app_name}\nTitle: {summary}\nBody: (empty)\n")
|
|
167
|
+
asyncio.create_task(forward_to_server(app_name, summary, ""))
|
|
168
|
+
state = "IDLE"
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__":
|
|
171
|
+
try:
|
|
172
|
+
asyncio.run(monitor_notifications())
|
|
173
|
+
except KeyboardInterrupt:
|
|
174
|
+
print("\nStopping OS Notification Alerter...")
|