Compare commits
10 Commits
a40e7cd288
...
529039dc87
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
529039dc87 | ||
|
|
63a51e7e0a | ||
|
|
c0fb6d9a32 | ||
|
|
3ad92e174d | ||
|
|
ed17a624fa | ||
|
|
252d5ccf98 | ||
|
|
8bc16e4d4e | ||
|
|
6cd78f1510 | ||
|
|
bc5b9bc799 | ||
|
|
0c12e69b81 |
209
README.md
209
README.md
@ -9,11 +9,19 @@ UltraBunt is the **ULTIMATE** Ubuntu setup script that transforms your fresh Ubu
|
||||
Think of it as a whole bunch of blu-tac'd together bash scripts that:
|
||||
- 🧙♂️ Install up to 560+ essential applications
|
||||
- 🎪 Organized into 25+ magnificent categories
|
||||
- 🚀 Handles APT, Snap, Flatpak, and custom installations
|
||||
- 🚀 Handles `apt`, `snap`, `flatpak`, and `.deb` installers
|
||||
- 🎨 Makes your terminal look absolutely gorgeous
|
||||
- 🔒 Set up a native LAMP wordpress site that works without all the ball-ache
|
||||
- ☕ Saves you pissfarting around in terminal for hours every frikkin time you install it
|
||||
|
||||
## ✅ Install Policy
|
||||
|
||||
UltraBunt installs apps only via `apt`, `snap`, `.deb`, or `flatpak` on Ubuntu-based systems.
|
||||
|
||||
- Python `pip` installations are disabled and have been removed.
|
||||
- Pip-only packages have been removed from the script and from this README.
|
||||
- Where possible, equivalents using `apt`, `snap`, `.deb`, or `flatpak` are provided.
|
||||
|
||||
## 🎪 THE MAGNIFICENT BUNTAGE CATEGORIES 🎪
|
||||
|
||||
### 🔧 Core Utilities - The Foundation of Greatness
|
||||
@ -50,7 +58,7 @@ Programming languages, frameworks, and development utilities:
|
||||
**Python3** - Python interpreter [APT]
|
||||
**Python3-pip** - Python package manager [APT]
|
||||
**Pipx** - Python app installer [APT]
|
||||
**Poetry** - Python dependency manager [SCRIPT]
|
||||
**Poetry** - Python dependency manager [APT]
|
||||
**Pyenv** - Python version manager [SCRIPT]
|
||||
**Go** - Go programming language [APT]
|
||||
**Rust** - Rust programming language [SCRIPT]
|
||||
@ -80,9 +88,9 @@ Programming languages, frameworks, and development utilities:
|
||||
**VirtualBox** - Virtualization [SCRIPT]
|
||||
**QEMU** - Machine emulator [APT]
|
||||
**Neovim** - Modern Vim editor [APT]
|
||||
**MkDocs** - Documentation generator [SCRIPT]
|
||||
**Insomnia** - API testing tool [SCRIPT]
|
||||
**Zed** - High-performance code editor [SCRIPT]
|
||||
**MkDocs** - Documentation generator [APT]
|
||||
**Insomnia** - API testing tool [DEB]
|
||||
**Zed** - High-performance code editor [DEB]
|
||||
**Postman** - API development platform [SCRIPT]
|
||||
**Bruno** - Open-source API client [SCRIPT]
|
||||
**Bruno (Snap)** - Bruno via Snap [SNAP]
|
||||
@ -560,9 +568,8 @@ Graphics editing and design applications:
|
||||
**GIMP (Flatpak)** - GIMP via Flatpak [FLATPAK]
|
||||
**Inkscape (Snap)** - Inkscape via Snap [SNAP]
|
||||
**Inkscape (Flatpak)** - Inkscape via Flatpak [FLATPAK]
|
||||
**Webcamize** - Webcam utility [SCRIPT]
|
||||
**Durdraw** - ASCII art editor [SCRIPT]
|
||||
**Pastel** - Color manipulation tool [SCRIPT]
|
||||
**Webcamize** - Webcam utility [APT]
|
||||
**Pastel** - Color manipulation tool [APT]
|
||||
|
||||
### 📄 Office & Productivity - Get Things Done
|
||||
Office suites and productivity applications:
|
||||
@ -585,22 +592,10 @@ Cutting-edge AI and machine learning tools:
|
||||
**Ollama** - Run LLMs locally [SCRIPT]
|
||||
**Gollama** - Ollama GUI client [SCRIPT]
|
||||
**LM Studio** - Local LLM interface [SCRIPT]
|
||||
**Text Generation WebUI** - Local text generation [SCRIPT]
|
||||
**Ollama** - Run LLMs locally [SCRIPT]
|
||||
**Gollama** - Ollama GUI client [SCRIPT]
|
||||
**LM Studio** - Local LLM interface [SCRIPT]
|
||||
**Whisper-cpp** - Speech recognition [SCRIPT]
|
||||
**ComfyUI** - Node-based AI interface [SCRIPT]
|
||||
**InvokeAI** - Professional AI art [SCRIPT]
|
||||
**LMDeploy** - LLM deployment toolkit [SCRIPT]
|
||||
**KoboldCpp** - AI storytelling backend [SCRIPT]
|
||||
**Automatic1111** - Popular SD interface [SCRIPT]
|
||||
**Fooocus** - Simplified Stable Diffusion [SCRIPT]
|
||||
**SD-Next** - Advanced Stable Diffusion [SCRIPT]
|
||||
**Kohya SS GUI** - LoRA training interface [SCRIPT]
|
||||
**Faster-Whisper** - Optimized speech recognition [SCRIPT]
|
||||
**WhisperX** - Enhanced Whisper with alignment [SCRIPT]
|
||||
**Coqui-STT** - Speech-to-text engine [SCRIPT]
|
||||
**Piper-TTS** - Text-to-speech synthesis [SCRIPT]
|
||||
**Mimic3** - Neural text-to-speech [SCRIPT]
|
||||
**Coqui-TTS** - Advanced text-to-speech [SCRIPT]
|
||||
**Yai** - AI powered terminal assistant [CUSTOM]
|
||||
|
||||
### 🕹️ Gaming Emulators - Retro Gaming
|
||||
@ -911,6 +906,168 @@ Want to make this even more ridiculously sublime?
|
||||
4. Update this README with the new application
|
||||
5. Test thoroughly on a clean system
|
||||
|
||||
# ♿ ACCESSIBILITY FEATURES ♿
|
||||
|
||||
UltraBunt is committed to being accessible to all users, including those with visual impairments. We've implemented comprehensive Text-to-Speech (TTS) support to make the installation process fully accessible.
|
||||
|
||||
## 🔊 Text-to-Speech Integration
|
||||
|
||||
The accessibility-enhanced version of UltraBunt provides full voice guidance throughout the installation process using the `spd-say` command from Speech Dispatcher.
|
||||
|
||||
### 🎯 Key Accessibility Features
|
||||
|
||||
- **🗣️ Voice Announcements**: All menu options, prompts, and system messages are spoken aloud
|
||||
- **👥 Female Voice**: Configured with a friendly female voice for better user experience
|
||||
- **⚡ Moderate Speed**: Speech rate optimized for clarity and comprehension
|
||||
- **🎵 Punctuation Support**: Important punctuation is vocalized for better context
|
||||
- **🔄 Real-time Feedback**: Installation progress and status updates are announced
|
||||
- **⚠️ Error Handling**: Graceful fallback when TTS is unavailable
|
||||
|
||||
### 🚀 Getting Started with Accessibility
|
||||
|
||||
#### Option 1: Use the Accessible Script (Recommended)
|
||||
```bash
|
||||
# Make the accessible script executable
|
||||
chmod +x ultrabunt-accessible.sh
|
||||
|
||||
# Run the accessibility-enhanced version
|
||||
./ultrabunt-accessible.sh
|
||||
```
|
||||
|
||||
#### Option 2: Enable TTS in Main Script
|
||||
```bash
|
||||
# Export TTS environment variables before running
|
||||
export ULTRABUNT_TTS_ENABLED=true
|
||||
export ULTRABUNT_TTS_VOICE=female1
|
||||
export ULTRABUNT_TTS_RATE=0
|
||||
|
||||
# Run the main script with TTS support
|
||||
./ultrabunt.sh
|
||||
```
|
||||
|
||||
### 📋 Prerequisites for TTS
|
||||
|
||||
The accessibility features require Speech Dispatcher to be installed:
|
||||
|
||||
```bash
|
||||
# Install Speech Dispatcher (usually pre-installed on Ubuntu)
|
||||
sudo apt update
|
||||
sudo apt install speech-dispatcher espeak-ng
|
||||
|
||||
# Test TTS functionality
|
||||
spd-say "Hello, UltraBunt accessibility is working!"
|
||||
```
|
||||
|
||||
### ⚙️ TTS Configuration Options
|
||||
|
||||
The accessible version supports several voice configuration options:
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| Voice Type | `female1` | Voice gender and variant |
|
||||
| Speech Rate | `0` (moderate) | Speaking speed (-100 to +100) |
|
||||
| Punctuation | `some` | Level of punctuation vocalization |
|
||||
| Language | `en` | Speech language |
|
||||
|
||||
### 🎛️ Voice Settings
|
||||
|
||||
You can customize the TTS experience by modifying these environment variables:
|
||||
|
||||
```bash
|
||||
# Voice selection (male1, male2, male3, female1, female2, female3, child_male, child_female)
|
||||
export ULTRABUNT_TTS_VOICE="female1"
|
||||
|
||||
# Speech rate (-100 = very slow, 0 = normal, +100 = very fast)
|
||||
export ULTRABUNT_TTS_RATE="0"
|
||||
|
||||
# Punctuation level (none, some, all)
|
||||
export ULTRABUNT_TTS_PUNCTUATION="some"
|
||||
|
||||
# Language code
|
||||
export ULTRABUNT_TTS_LANGUAGE="en"
|
||||
```
|
||||
|
||||
### 🔧 How It Works
|
||||
|
||||
The accessibility system integrates seamlessly with the existing UltraBunt interface:
|
||||
|
||||
1. **Menu Navigation**: All menu categories and options are announced
|
||||
2. **Installation Progress**: Package installations are narrated in real-time
|
||||
3. **User Prompts**: Input requests and confirmations are spoken
|
||||
4. **Status Updates**: System messages and warnings are vocalized
|
||||
5. **Error Handling**: Installation errors and issues are announced clearly
|
||||
|
||||
### 🎪 Accessible Menu Experience
|
||||
|
||||
When using the accessible version, you'll hear:
|
||||
- **Category Announcements**: "Development Tools menu with 15 options available"
|
||||
- **Option Reading**: Each package name and description is spoken
|
||||
- **Navigation Guidance**: Instructions for menu navigation
|
||||
- **Selection Confirmation**: Confirmation of your choices
|
||||
- **Installation Narration**: Real-time progress updates
|
||||
|
||||
### 🛠️ Technical Implementation
|
||||
|
||||
The accessibility features are implemented through:
|
||||
|
||||
- **`speak_if_enabled()` Function**: Core TTS functionality with ANSI color code filtering
|
||||
- **Enhanced UI Functions**: `ui_msg_accessible()`, `ui_input_accessible()`, `ui_menu_accessible()`
|
||||
- **Menu Integration**: TTS announcements in all menu functions
|
||||
- **Progress Narration**: Voice feedback during package installations
|
||||
- **Error Vocalization**: Spoken error messages and warnings
|
||||
|
||||
### 🔍 Troubleshooting TTS
|
||||
|
||||
If TTS isn't working:
|
||||
|
||||
1. **Check Speech Dispatcher**:
|
||||
```bash
|
||||
systemctl --user status speech-dispatcher
|
||||
```
|
||||
|
||||
2. **Test spd-say directly**:
|
||||
```bash
|
||||
spd-say "Testing speech synthesis"
|
||||
```
|
||||
|
||||
3. **Install missing components**:
|
||||
```bash
|
||||
sudo apt install speech-dispatcher espeak-ng pulseaudio
|
||||
```
|
||||
|
||||
4. **Restart audio services**:
|
||||
```bash
|
||||
pulseaudio --kill
|
||||
pulseaudio --start
|
||||
```
|
||||
|
||||
### 🌟 Accessibility Best Practices
|
||||
|
||||
The UltraBunt accessibility implementation follows these principles:
|
||||
|
||||
- **Non-intrusive**: TTS can be easily disabled without affecting functionality
|
||||
- **Informative**: All visual information has audio equivalents
|
||||
- **Efficient**: Speech is concise but comprehensive
|
||||
- **Customizable**: Users can adjust voice settings to their preferences
|
||||
- **Fallback-ready**: Graceful degradation when TTS is unavailable
|
||||
|
||||
### 🎯 Future Accessibility Enhancements
|
||||
|
||||
Planned improvements include:
|
||||
- **Keyboard Navigation**: Enhanced keyboard-only operation
|
||||
- **Screen Reader Support**: Better compatibility with screen readers
|
||||
- **Audio Cues**: Sound effects for different types of notifications
|
||||
- **Voice Commands**: Voice-controlled menu navigation
|
||||
- **Multi-language TTS**: Support for additional languages
|
||||
|
||||
### 💡 Tips for Visually Impaired Users
|
||||
|
||||
- Use the `ultrabunt-accessible.sh` script for the best experience
|
||||
- The script will automatically detect and configure TTS settings
|
||||
- All menu navigation can be done using standard keyboard controls
|
||||
- Press `Ctrl+C` at any time to safely interrupt TTS and exit
|
||||
- Installation progress is announced every few seconds during package installations
|
||||
|
||||
# 📜 LICENSE 📜
|
||||
|
||||
This project is licensed under the MIT License - because sharing is caring! seriously its just a bunch of bash stickytaped together go nuts.
|
||||
@ -925,7 +1082,7 @@ This project is licensed under the MIT License - because sharing is caring! seri
|
||||
## 🌟 Special Thanks
|
||||
- Ubuntu Community - For creating an OS for lazy ppl who hate windows
|
||||
- Open Source Developers - For the free shit
|
||||
- Beta Testers - For finding all our bugs
|
||||
- Tata Besters - For flinding all our blugs
|
||||
- Methylphenidate - For making this possible
|
||||
|
||||
# 🚀 FINAL WORDS 🚀
|
||||
@ -934,8 +1091,10 @@ The Ultimate Buntstaller isn't just a script - it's a statement. A statement tha
|
||||
|
||||
So go forth, brave user, and BUNTAGE ALL THE THINGS! 🎉
|
||||
|
||||
```
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ "In a world of packages, dare to be a BUNTAGE!" ║
|
||||
║ ║
|
||||
║ - The Ultimate Buntstaller Philosophy ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
```
|
||||
124
REVIEW.md
Normal file
124
REVIEW.md
Normal file
@ -0,0 +1,124 @@
|
||||
# Ultrabunt Code Review — 2026-07-17
|
||||
|
||||
Full review of `ultrabunt.sh` (17k lines) and `ultrabunt-accessible.sh`.
|
||||
Scope: real breakage and danger only — style ignored, silliness preserved.
|
||||
|
||||
Line numbers are approximate (the performance pass shifted things by a few
|
||||
dozen lines in places) — search for the quoted function name if a number is off.
|
||||
|
||||
---
|
||||
|
||||
## Fixed in this pass (performance + crashers)
|
||||
|
||||
These are already applied to `ultrabunt.sh`:
|
||||
|
||||
| What | Why it was slow/broken |
|
||||
|---|---|
|
||||
| Splash screen printed instantly | 78 lines × `sleep 0.05` + `sleep 1.5` = ~5.5s of dead air at every launch |
|
||||
| `apt-get update` skipped when lists < 6h old (`--refresh` to force) | Ran unconditionally at startup: 10–60s per launch on old hardware |
|
||||
| `log()` rewritten fork-free (`printf %(...)T` + direct append) | Old version forked ~3 processes per line (`$(date)`, pipe, `tee`) and was called per package per menu redraw; also sprayed stderr underneath whiptail. Set `ULTRABUNT_DEBUG=1` to mirror logs to stderr |
|
||||
| Removed per-check logging from `is_package_installed` | 3+ log lines (≈9 forks) per package, per menu redraw |
|
||||
| Category counts computed in ONE pass over `PACKAGES` | Old loop re-walked all ~600 packages once per category (~15,000 iterations) on every main-menu redraw |
|
||||
| `is_apt_installed` cache miss is now authoritative after startup scan | Old fallback forked `dpkg -l` for every NOT-installed package on every redraw — hundreds of forks per screen |
|
||||
| `build_package_cache` always does one full dump per package manager | "Selective mode" forked one `dpkg-query` per package — strictly slower than dumping everything (which is 1 fork) |
|
||||
| Deleted `refresh_cache_silent` + the 🔄 indicator | It forked ~600 background processes whose cache writes happened in a **child shell and were thrown away** — a subshell can't modify the parent's `INSTALLED_CACHE`. 100% wasted CPU on a machine that has none to spare |
|
||||
| Removed `log "Menu items array contents: ..."` | Wrote the entire ~5KB menu array to the log on every redraw |
|
||||
| dpkg checks filter on `Status-Status == installed` | `dpkg-query -W` also lists removed-but-not-purged (`rc`) packages, so uninstalled packages showed ✓ Installed |
|
||||
| Flatpak checks use exact match (`grep -Fxq` on the app-id column) | Bare `grep -q "$pkg"` matched substrings |
|
||||
| `((installed++))`-style counters → `x=$((x+1))` (6 sites in bulk ops) | `((x++))` returns exit 1 on the 0→1 increment; under `set -e` every bulk install/remove **killed the whole script after the first package** |
|
||||
| Bulk-select checklists sort names first, then build triples | Old code joined tag/desc/OFF triples into lines and sorted ALL lines, scrambling the checklist alignment |
|
||||
| `show_buntage_actions` menu guarded with `\|\| return`; install/reinstall success message now conditional on actual success | Cancel killed the script via `set -e`; failures reported "installed successfully!" |
|
||||
| `view_log_file` menu guarded with `\|\| return` | ESC/Cancel in the log viewer killed the whole script |
|
||||
| Swappiness regexes fixed (`vm\\.swappiness` → `vm\.swappiness`) + no-match grep guarded | The `\\.` inside single quotes is a literal backslash: "show entry" **crashed the script** and a duplicate `vm.swappiness` line was appended to sysctl.conf on every persist |
|
||||
| `wordpress_security_hardening`: domain validated, wp-config.php required | Entering `..` made `site_dir=/var/www/..` = `/var`, then "Fix File Permissions" ran `chown -R www-data:www-data /var` — **system-wrecking** |
|
||||
| Hardening checklist strips whiptail's literal quotes | No case arm ever matched `"file-permissions"` (with quotes), so every hardening option was silently skipped while reporting success |
|
||||
| `fun` category added to `CATEGORIES` | 15 packages were tagged `fun` but the category wasn't in the menu — permanently invisible |
|
||||
| `--no-media/--no-web/--no-network/-minimal/-core` use real category ids | They referenced ids that don't exist (`multimedia`, `music`, `web-browsers`, `network`, `education`…), so the exclusions silently did nothing |
|
||||
| Package-list sort uses `mapfile` instead of unquoted `$(sort)` | Glob chars in descriptions (`(_*_)`) could expand against files in the cwd |
|
||||
|
||||
Expected result: startup goes from ~40–70s to a few seconds (splash + one dpkg/snap/flatpak dump), and menu redraws go from seconds of fork-storm to near-instant pure-bash.
|
||||
|
||||
---
|
||||
|
||||
## Outstanding — HIGH (dangerous or feature completely broken)
|
||||
|
||||
### WordPress / database
|
||||
- **`finalize_wordpress_setup`**: custom setup's user-entered `site_dir` is ignored by the actual installers (they all install to `/var/www/$domain`) but the *finalizer still runs* `chown -R $(whoami):www-data "$site_dir"` + recursive chmod on the unvalidated path. Enter `/home` and it re-owns it. Validate/derive `site_dir` the same way the installers do.
|
||||
- **SQL injection everywhere a password/name is interpolated into `mysql -e "... IDENTIFIED BY '$pass'"`** (`setup_wordpress_database*`, `create_database_user_interactive` ~L16381, DB repair `eval` ~L13870). A single `'` in a password breaks or injects as MariaDB root. The repair path pipes it through `eval` too. Fix: validate names as `[A-Za-z0-9_]+`, pass passwords via `--defaults-extra-file` or here-doc `SET PASSWORD` with proper quoting.
|
||||
- **`setup_wordpress_database_custom` runs under command substitution but its whiptail dialogs aren't redirected to `/dev/tty`** — dialogs are captured into the result variable instead of being shown; flow appears hung and wp-config gets garbage credentials.
|
||||
- **wp-config salts**: the awk insert anchors on `/** MySQL settings` which WordPress renamed in 5.8 — the sed first *deletes* all AUTH_KEY…NONCE_SALT lines, then the insert never fires → **modern WP sites end up with no security keys at all**, silently.
|
||||
- **`setup_nginx_ssl`** writes the 443 block to `sites-available/$domain` while `.localhost` sites were created under the stripped base name → new file is never enabled; reports success, HTTPS never serves. Also appends a duplicate 443 block on every rerun (`tee -a`).
|
||||
- **phpMyAdmin installer** writes the MariaDB root password to predictable `/tmp/mysql_defaults_phpmyadmin.cnf` (pre-creatable by any local user; 644 window before chmod), and the follow-up `mysql --defaults-file` runs as the wrong user so it silently no-ops. Root password also logged in plaintext to `/var/log/ultrabunt.log` (~L10883) and wp-config gets loosened to 0664 (group-writable by www-data, world-readable).
|
||||
- **`delete_wordpress_site`** reads `/root/.mysql_root_password` *without sudo* → DB/user never actually dropped while reporting "completely removed including database"; also deletes the nginx vhost matching the *first label* of the domain (deleting `shop.example.com` can nuke `shop.localhost`'s config), and will DROP a database shared by other sites without cross-checking.
|
||||
- **`grant_file_access_to_user`**: `chmod -R 2775 /var/www` makes every *file* group-writable+setgid and world-readable — www-data can rewrite all PHP (persistence vector) and wp-config passwords are world-readable. Use 664 files / 2775 dirs.
|
||||
- **`show_individual_site_management`** uses `$site_dir` (never set locally — dynamically inherits the caller's *last* loop value) instead of the `site_root` it computes → wp-config view/edit/DB-info act on the **wrong site** whenever >1 site exists.
|
||||
|
||||
### Cloudflare / firewall
|
||||
- **`cloudflare_create_rule` builds its JSON with raw printf and no escaping** — every filter expression contains quotes (some contain newlines) → malformed JSON → **every rule creation fails**, including "light". The whole feature can't work as written. Also uses the deprecated legacy `firewall/rules` endpoint, and the country code `UK` should be `GB` (would block UK visitors incl. you).
|
||||
|
||||
### Mirror management
|
||||
- **The entire "fastest mirror" feature is dead**: it invokes `mirrorselect` (a Gentoo tool) which is never installed (`install_mirrorselect` actually installs `netselect-apt`). The auto mode uses netselect-apt's **Debian** mirror list and seds those hosts over `archive.ubuntu.com` → apt breaks. The "restore" path recomputes `$(date +%s)`-style backup names so it restores from a filename that doesn't exist and dies under `set -e` with sources.list already clobbered. `use_local_mirror`/`setup_local_mirror` write to `/etc/apt/` **without sudo** → instant permission-denied crash. On 24.04+ the real sources live in `/etc/apt/sources.list.d/ubuntu.sources` anyway. Recommend: rip this section out or rewrite around `netselect-apt`-for-Ubuntu with sudo and proper backup naming.
|
||||
- `run_mirrorselect_custom` does `eval "sudo mirrorselect $custom_flags"` on free-typed input — arbitrary shell as root by design.
|
||||
|
||||
### Reverse-proxy add-ons
|
||||
- **Umami**: publishes `3000:3000` on 0.0.0.0 (Docker's iptables bypass UFW) with hardcoded `APP_SECRET: replace-me-with-a-random-string` and default admin/umami login → internet-reachable with forgeable sessions on any VPS.
|
||||
- **Mailcow**: mailcow's own nginx defaults to 80/443 (collides with host nginx) while the proxy snippet assumes `127.0.0.1:8080` which nothing configures — either compose fails or the proxy points at a dead port; completion message advertises `https://` URLs no config provides.
|
||||
- Both add-on flows have zero error handling: any failed step under `set -e` kills the whole script with containers half-started and nginx confs already symlinked.
|
||||
|
||||
### Installers (selection — full list in agent notes)
|
||||
- **`install_arduino-ide`**: `unzip --strip-components=1` — flag doesn't exist; wipes `/opt/arduino-ide` then always fails, and `set -e` kills the script.
|
||||
- **`install_mailhog`**: `curl -Lo` without `-f` → 404 page installed as a root systemd-managed binary; also downloads into whatever cwd the script happens to be in (deno/zed installers `cd` into temp dirs and delete them, leaving a dead cwd).
|
||||
- **Plex**: `curl | sudo apt-key add -` — `apt-key` is gone on newer Ubuntu, so it aborts *after* deleting the old sources; key would land in the global trusted keyring.
|
||||
- **Fixed predictable `/tmp` paths + `sudo mv`/`dpkg -i`** (lazydocker, glow, cheat, broot, dog, discord, ums, gollama, koboldcpp, LM Studio…): a local user can pre-plant/race the file and get a root-installed binary. Use `mktemp -d`.
|
||||
- **`dpkg -i || apt-get install -f -y`** pattern (6+ sites): non-dependency dpkg failures are masked and reported as success.
|
||||
- **whisper.cpp** builds unpinned master and copies `main`/`quantize` — upstream renamed the binaries; always fails now, `make 2>/dev/null` hides why.
|
||||
- Version-pinned URLs that 404 now or soon: ctop (latest/download + 0.7.7), kind v0.20.0, Insomnia 8.6.1, mergerfs jammy-only deb, LM Studio 0.3.5, UMS deb name, balena-etcher remove targets the old package name.
|
||||
- `curl | bash` as root (nodesource, ollama, starship, ddev — ddev also points at the moved `drud/ddev` repo) — accepted risk for a personal tool, but at least pin/checksum the big ones.
|
||||
- `gpg --dearmor` without `--yes` (caddy, ngrok, docker, warp): reruns abort mid-way after old keys were already deleted.
|
||||
|
||||
### Packages that can never install (verified against live registries)
|
||||
- **apt, wrong/absent name**: `sqlitestudio` (26.04+ only), `chromium` (→ `chromium-browser`), `asciiquarium`, `batcat` (→ `bat`, and duplicates the existing `bat` entry), `mysql-workbench-community` (needs MySQL repo), `pgadmin4` (needs pgadmin repo), `bottom`, `google-drive-ocamlfuse` (PPA-only), `jellyfin` (needs jellyfin repo), `citra`, `dosbox-staging`, `python3-esptool` (→ `esptool`), `webcamize`; version-dependent: `exa` (gone in 24.04+, keep `eza`), `pastel`, `fastfetch` (25.04+), `qalculate` (→ `qalculate-gtk`), `bsnes`, `git-delta` (23.10+).
|
||||
- **snap, 404**: `tableplus`, `mongodb-compass`, `nextcloud-server` (→ `nextcloud`), `heroic`, `dosbox`, `platformio`.
|
||||
- **cargo/npm**: `qmasa` (→ `qmassa`), `dust` (→ `du-dust`), `adminmongo` (not on npm).
|
||||
- **flatpak**: citra + yuzu delisted from Flathub (Nintendo takedown); `freetube`/`stremio` use bare names instead of app IDs.
|
||||
|
||||
---
|
||||
|
||||
## Outstanding — MEDIUM
|
||||
|
||||
- MariaDB/MySQL passwords passed as `-p"$pass"` on the command line **everywhere** (~20 sites) — visible in `/proc/*/cmdline` to any local user (matters most on the VPS). Standard fix: `--defaults-extra-file=<(...)` or `MYSQL_PWD` for a personal box.
|
||||
- DB dumps from `backup_database_interactive` written world-readable (default umask) into `$BACKUP_DIR`; `grep -q "^${database}$"` treats the name as a regex.
|
||||
- wp-config credential extraction via `grep | cut -d"'" -f4` matches commented lines, no `head -1`, breaks on `'` in passwords (DB test/repair flows).
|
||||
- `restart_web_services` probes only php 8.1/8.0/7.4-fpm — never restarts the script's own PHP 8.3 FPM, so "optimize uploads" silently doesn't land. Same class: SQL-import optimizer derives paths from CLI `php -v` (can be a different version than FPM); `client_max_body_size` sed lowers larger values across *all* vhosts; `<IfModule mod_php8.c>` never matches; `mysql.connect_timeout` should be `mysqli.connect_timeout`.
|
||||
- MySQL "import optimization" permanently sets `innodb_flush_log_at_trx_commit=2` and blind `buffer_pool=512M` with no revert or RAM check; PHP `memory_limit=8G` per worker can OOM a small machine.
|
||||
- `modify_php_setting` interpolates unvalidated input into sed (a `/`, `&` or `\` corrupts php.ini).
|
||||
- Bulk ops: `install_package ... | tee` runs in a pipeline subshell, so cache updates inside are discarded — status can go stale for the session (harmless-ish now that redraws are cheap; re-run `build_package_cache` after bulk ops to be exact).
|
||||
- `ui_menu` returns the literal string `"back"` on ESC — any future package named `back` breaks navigation; bulk category picker can pass `"back"` into the match loop.
|
||||
- Web-config-summary site pickers push 3 args per non-live site into a *menu* (that's checklist syntax) — misaligned rows; "No live sites" branch unreachable.
|
||||
- Log viewer: Ctrl+C on `tail -f` SIGINTs the whole script (no trap); pager temp file at predictable `/tmp/ultrabunt_log_view_$$` copies sudo-read logs world-readable.
|
||||
- `wordpress_cleanup_menu` find: `-name "*.localhost" -o -name "*.local" -print0` — `-print0` binds to one branch; `.localhost` sites never listed.
|
||||
- certbot always adds `-d www.$domain` — fails for domains without a www record.
|
||||
- Hotkeys: >24 categories get lowercase tags but the handler uppercases before lookup (opens the wrong category); >48 reuses letters and silently overwrites. The "cycling" code for shared hotkeys is dead (assignment overwrites, never appends). Currently 27 categories, so the first overflow row (`a`) is already live.
|
||||
- `ultrabunt-accessible.sh`: launches `./ultrabunt.sh` relative to caller's cwd; instructs running the whole thing via `sudo`, which breaks `$USER`-based ownership logic in the main script and makes TTS silent (root has no Pulse session); `timeout 10s echo | festival` applies the timeout to `echo` (festival can hang forever); `sudo -u user cat > file` redirection still runs as root.
|
||||
|
||||
## Outstanding — LOW (grab-bag)
|
||||
|
||||
- `show_system_info` hardcodes a 50×140 dialog — breaks on a stock 80×24 SSH window.
|
||||
- Export list writes to predictable `/tmp/ultrabunt-packages-<ts>.txt`.
|
||||
- `get_status()` is dead code (never called; no arms for custom/npm/cargo methods).
|
||||
- `silversearcher-ag` and `ag` are duplicate entries for the same package.
|
||||
- `remove_phpmyadmin` only restarts services that are `is-enabled` — a running-but-disabled DB/web server stays down. `--force-yes` no longer exists in modern apt.
|
||||
- `__site_is_live` needs `host` (not on minimal Ubuntu) → everything reports "not live".
|
||||
- Keyboard config writes to `$HOME`/gsettings — configures root's session if run under sudo.
|
||||
- bun installer greps live `$PATH` instead of rc files → duplicate export lines per rerun.
|
||||
- README drift: claims pip is removed but `install_pip_package`/npm/cargo helpers and CUSTOM npm tools are still in the script; claims 25+ categories/560+ apps — counts don't match the code.
|
||||
|
||||
---
|
||||
|
||||
## Suggested priorities
|
||||
|
||||
1. **WordPress DB quoting + the `finalize_wordpress_setup` chown** — it's the feature you actually use, on machines you keep.
|
||||
2. **Delete or rewrite mirror management** — it cannot work and it edits sources.list.
|
||||
3. **Umami/Mailcow port + secret fixes** if you ever run them on the VPS.
|
||||
4. **Purge the ~25 never-installable package entries** (list above) — they just waste menu space and end in failure dialogs.
|
||||
5. Sweep the installers for `curl -f`, `mktemp -d`, and `gpg --dearmor --yes` — three mechanical patterns fix most of the installer findings.
|
||||
636
ultrabunt-accessible.sh
Executable file
636
ultrabunt-accessible.sh
Executable file
@ -0,0 +1,636 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Ultrabunt Accessible Installer
|
||||
# Enhanced version with Text-to-Speech support for visually impaired users
|
||||
# Uses spd-say (Speech Dispatcher) for audio feedback
|
||||
|
||||
# Color codes for visual users who might have partial sight
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
PURPLE='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
WHITE='\033[1;37m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# TTS Configuration
|
||||
TTS_ENABLED=true
|
||||
TTS_VOICE="female1"
|
||||
TTS_RATE="-20" # Slightly slower for clarity
|
||||
TTS_PITCH="0" # Normal pitch
|
||||
TTS_VOLUME="10" # Slightly louder
|
||||
TTS_PUNCTUATION="some" # Read some punctuation for clarity
|
||||
|
||||
# Function to check and install TTS dependencies
|
||||
install_tts_dependencies() {
|
||||
echo -e "${CYAN}Checking Text-to-Speech Dependencies...${NC}"
|
||||
|
||||
# Check if running with sudo privileges
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script needs to be run with sudo to install dependencies.${NC}"
|
||||
echo -e "${YELLOW}Please run: sudo ./ultrabunt-accessible.sh${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local packages_to_install=()
|
||||
local missing_packages=()
|
||||
|
||||
# Check for required packages
|
||||
echo -e "${YELLOW}Checking required packages...${NC}"
|
||||
|
||||
# Speech Dispatcher
|
||||
if ! dpkg -l | grep -q "^ii.*speech-dispatcher "; then
|
||||
missing_packages+=("speech-dispatcher")
|
||||
echo -e " ${RED}✗${NC} speech-dispatcher (not installed)"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} speech-dispatcher (installed)"
|
||||
fi
|
||||
|
||||
# PulseAudio
|
||||
if ! dpkg -l | grep -q "^ii.*pulseaudio "; then
|
||||
missing_packages+=("pulseaudio")
|
||||
echo -e " ${RED}✗${NC} pulseaudio (not installed)"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} pulseaudio (installed)"
|
||||
fi
|
||||
|
||||
# ALSA utilities
|
||||
if ! dpkg -l | grep -q "^ii.*alsa-utils "; then
|
||||
missing_packages+=("alsa-utils")
|
||||
echo -e " ${RED}✗${NC} alsa-utils (not installed)"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} alsa-utils (installed)"
|
||||
fi
|
||||
|
||||
# PulseAudio utilities
|
||||
if ! dpkg -l | grep -q "^ii.*pulseaudio-utils "; then
|
||||
missing_packages+=("pulseaudio-utils")
|
||||
echo -e " ${RED}✗${NC} pulseaudio-utils (not installed)"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} pulseaudio-utils (installed)"
|
||||
fi
|
||||
|
||||
# Festival speech synthesis (fallback TTS engine)
|
||||
if ! dpkg -l | grep -q "^ii.*festival "; then
|
||||
missing_packages+=("festival")
|
||||
echo -e " ${RED}✗${NC} festival (not installed)"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} festival (installed)"
|
||||
fi
|
||||
|
||||
# eSpeak (another TTS engine)
|
||||
if ! dpkg -l | grep -q "^ii.*espeak "; then
|
||||
missing_packages+=("espeak")
|
||||
echo -e " ${RED}✗${NC} espeak (not installed)"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} espeak (installed)"
|
||||
fi
|
||||
|
||||
# If packages are missing, offer to install them
|
||||
if [[ ${#missing_packages[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Missing packages detected:${NC}"
|
||||
for package in "${missing_packages[@]}"; do
|
||||
echo -e " • $package"
|
||||
done
|
||||
echo ""
|
||||
echo -e "${CYAN}These packages are required for text-to-speech functionality.${NC}"
|
||||
echo -e "${WHITE}Would you like to install them now? (y/n)${NC}"
|
||||
read -p "Install missing packages? " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo -e "${GREEN}Installing missing packages...${NC}"
|
||||
|
||||
# Update package list
|
||||
echo -e "${YELLOW}Updating package list...${NC}"
|
||||
apt update
|
||||
|
||||
# Install missing packages
|
||||
for package in "${missing_packages[@]}"; do
|
||||
echo -e "${YELLOW}Installing $package...${NC}"
|
||||
if apt install -y "$package"; then
|
||||
echo -e "${GREEN}✓ $package installed successfully${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Failed to install $package${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Configure audio system
|
||||
echo -e "${YELLOW}Configuring audio system...${NC}"
|
||||
|
||||
# Start PulseAudio if not running
|
||||
if ! pgrep -x "pulseaudio" > /dev/null && ! pgrep -x "pipewire" > /dev/null; then
|
||||
echo -e "${YELLOW}Starting PulseAudio...${NC}"
|
||||
# Get the actual user (not root) if running with sudo
|
||||
local actual_user="${SUDO_USER:-$USER}"
|
||||
if [[ -n "$actual_user" && "$actual_user" != "root" ]]; then
|
||||
sudo -u "$actual_user" pulseaudio --start 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN}✓ Audio system is running (PulseAudio/PipeWire)${NC}"
|
||||
fi
|
||||
|
||||
# Configure Speech Dispatcher
|
||||
echo -e "${YELLOW}Configuring Speech Dispatcher...${NC}"
|
||||
|
||||
# Stop Speech Dispatcher service first
|
||||
systemctl stop speech-dispatcher 2>/dev/null || true
|
||||
|
||||
# Create basic Speech Dispatcher config if it doesn't exist
|
||||
local spd_config_dir="/etc/speech-dispatcher"
|
||||
if [[ -d "$spd_config_dir" ]]; then
|
||||
# Ensure Speech Dispatcher can use available TTS engines
|
||||
if [[ -f "$spd_config_dir/speechd.conf" ]]; then
|
||||
# Enable espeak as default if available
|
||||
if command -v espeak >/dev/null 2>&1; then
|
||||
sed -i 's/^#.*DefaultModule.*espeak/DefaultModule espeak/' "$spd_config_dir/speechd.conf" 2>/dev/null || true
|
||||
echo -e " ${GREEN}✓${NC} Set espeak as default TTS engine"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create user-specific Speech Dispatcher config
|
||||
local actual_user="${SUDO_USER:-$USER}"
|
||||
if [[ -n "$actual_user" && "$actual_user" != "root" ]]; then
|
||||
local user_spd_dir="/home/$actual_user/.config/speech-dispatcher"
|
||||
sudo -u "$actual_user" mkdir -p "$user_spd_dir" 2>/dev/null || true
|
||||
|
||||
# Create a simple user config that prefers espeak with female voice
|
||||
if [[ ! -f "$user_spd_dir/speechd.conf" ]]; then
|
||||
sudo -u "$actual_user" cat > "$user_spd_dir/speechd.conf" << 'EOF'
|
||||
# User Speech Dispatcher Configuration
|
||||
LogLevel 3
|
||||
DefaultModule espeak
|
||||
DefaultLanguage en
|
||||
DefaultRate -20
|
||||
DefaultPitch 0
|
||||
DefaultVolume 100
|
||||
DefaultVoiceType female1
|
||||
EOF
|
||||
echo -e " ${GREEN}✓${NC} Created user Speech Dispatcher config with female voice"
|
||||
fi
|
||||
|
||||
# Also create espeak-specific config for female voice
|
||||
if [[ ! -f "$user_spd_dir/modules/espeak.conf" ]]; then
|
||||
sudo -u "$actual_user" mkdir -p "$user_spd_dir/modules" 2>/dev/null || true
|
||||
sudo -u "$actual_user" cat > "$user_spd_dir/modules/espeak.conf" << 'EOF'
|
||||
# Espeak module configuration
|
||||
EspeakDefaultVoice "en+f3"
|
||||
EspeakRate -20
|
||||
EspeakPitch 0
|
||||
EspeakVolume 100
|
||||
EOF
|
||||
echo -e " ${GREEN}✓${NC} Created espeak module config with female voice"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restart Speech Dispatcher service
|
||||
echo -e "${YELLOW}Restarting Speech Dispatcher service...${NC}"
|
||||
systemctl start speech-dispatcher 2>/dev/null || true
|
||||
sleep 2 # Give it time to start
|
||||
|
||||
# Check if Speech Dispatcher is running
|
||||
if systemctl is-active --quiet speech-dispatcher 2>/dev/null; then
|
||||
echo -e " ${GREEN}✓${NC} Speech Dispatcher service is running"
|
||||
else
|
||||
echo -e " ${YELLOW}⚠${NC} Speech Dispatcher service may not be running properly"
|
||||
fi
|
||||
|
||||
# Test audio output
|
||||
echo -e "${YELLOW}Testing audio system...${NC}"
|
||||
if command -v speaker-test >/dev/null 2>&1; then
|
||||
echo -e "${CYAN}Running brief audio test (2 seconds)...${NC}"
|
||||
timeout 2s speaker-test -t sine -f 1000 -l 1 2>/dev/null || echo -e "${YELLOW}Audio test completed (or no audio device available)${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ Dependencies installation completed!${NC}"
|
||||
echo ""
|
||||
else
|
||||
echo -e "${YELLOW}Skipping package installation. TTS may not work properly.${NC}"
|
||||
echo -e "${CYAN}You can install them manually later with:${NC}"
|
||||
echo -e "${WHITE}sudo apt update && sudo apt install ${missing_packages[*]}${NC}"
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN}✓ All required packages are already installed!${NC}"
|
||||
fi
|
||||
|
||||
# Additional audio system checks
|
||||
echo -e "${YELLOW}Performing audio system checks...${NC}"
|
||||
|
||||
# Check if audio devices are available
|
||||
if command -v aplay >/dev/null 2>&1; then
|
||||
local audio_devices=$(aplay -l 2>/dev/null | grep -c "card" || echo "0")
|
||||
if [[ "$audio_devices" -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Audio devices found ($audio_devices)"
|
||||
else
|
||||
echo -e " ${YELLOW}⚠${NC} No audio devices detected"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check PulseAudio/PipeWire status
|
||||
if command -v pulseaudio >/dev/null 2>&1 || command -v pipewire >/dev/null 2>&1; then
|
||||
if pgrep -x "pulseaudio" > /dev/null || pgrep -x "pipewire" > /dev/null; then
|
||||
echo -e " ${GREEN}✓${NC} Audio system is running (PulseAudio/PipeWire)"
|
||||
else
|
||||
echo -e " ${YELLOW}⚠${NC} Audio system is not running"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if pactl (PulseAudio control) works
|
||||
if command -v pactl >/dev/null 2>&1; then
|
||||
if pactl info >/dev/null 2>&1; then
|
||||
echo -e " ${GREEN}✓${NC} PulseAudio control interface is working"
|
||||
else
|
||||
echo -e " ${YELLOW}⚠${NC} PulseAudio control interface not responding"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to speak text using spd-say or fallback TTS engines
|
||||
speak_text() {
|
||||
local text="$1"
|
||||
local priority="${2:-text}" # Default priority is 'text'
|
||||
|
||||
if [[ "$TTS_ENABLED" == true ]]; then
|
||||
# Clean the text of ANSI color codes for speech
|
||||
local clean_text=$(echo "$text" | sed 's/\x1b\[[0-9;]*m//g')
|
||||
|
||||
# Kill any existing TTS processes to prevent overlap
|
||||
pkill -f "spd-say" 2>/dev/null || true
|
||||
pkill -f "espeak" 2>/dev/null || true
|
||||
|
||||
# Try spd-say first if no fallback is set
|
||||
if [[ -z "$TTS_FALLBACK" ]] && command -v spd-say >/dev/null 2>&1; then
|
||||
# Use spd-say with wait flag to prevent overlapping
|
||||
timeout 10s spd-say \
|
||||
--voice-type "$TTS_VOICE" \
|
||||
--rate "$TTS_RATE" \
|
||||
--pitch "$TTS_PITCH" \
|
||||
--volume "$TTS_VOLUME" \
|
||||
--punctuation-mode "$TTS_PUNCTUATION" \
|
||||
--priority "$priority" \
|
||||
--wait \
|
||||
"$clean_text" 2>/dev/null
|
||||
|
||||
# Use fallback TTS engines
|
||||
elif [[ "$TTS_FALLBACK" == "espeak" ]] && command -v espeak >/dev/null 2>&1; then
|
||||
# Use espeak directly with similar settings
|
||||
local espeak_rate=$((TTS_RATE + 175)) # Convert spd-say rate to espeak rate (approx)
|
||||
# Ensure espeak_rate is within valid range (80-450)
|
||||
if [[ $espeak_rate -lt 80 ]]; then espeak_rate=80; fi
|
||||
if [[ $espeak_rate -gt 450 ]]; then espeak_rate=450; fi
|
||||
|
||||
timeout 10s espeak \
|
||||
-s "$espeak_rate" \
|
||||
-p "$((TTS_PITCH + 50))" \
|
||||
-a "$((TTS_VOLUME * 20))" \
|
||||
-v "en+f3" \
|
||||
"$clean_text" 2>/dev/null
|
||||
|
||||
elif [[ "$TTS_FALLBACK" == "festival" ]] && command -v festival >/dev/null 2>&1; then
|
||||
# Use festival for TTS
|
||||
timeout 10s echo "$clean_text" | festival --tts 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to display and speak messages
|
||||
announce() {
|
||||
local message="$1"
|
||||
local color="${2:-$WHITE}"
|
||||
local priority="${3:-text}"
|
||||
|
||||
echo -e "${color}${message}${NC}"
|
||||
speak_text "$message" "$priority"
|
||||
}
|
||||
|
||||
# Function to check if Speech Dispatcher is available
|
||||
check_tts_availability() {
|
||||
if ! command -v spd-say >/dev/null 2>&1; then
|
||||
echo -e "${RED}Warning: spd-say (Speech Dispatcher) not found!${NC}"
|
||||
echo -e "${YELLOW}Text-to-speech will be disabled.${NC}"
|
||||
echo -e "${CYAN}To install Speech Dispatcher on Ubuntu/Debian:${NC}"
|
||||
echo -e "${WHITE}sudo apt update && sudo apt install speech-dispatcher${NC}"
|
||||
echo ""
|
||||
TTS_ENABLED=false
|
||||
echo -e "${WHITE}Press Enter to continue without TTS, or Ctrl+C to exit and install Speech Dispatcher...${NC}"
|
||||
read
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Testing Speech Dispatcher functionality...${NC}"
|
||||
|
||||
# Test if Speech Dispatcher is actually working with multiple methods
|
||||
local spd_working=false
|
||||
|
||||
# Method 1: Test with spd-say directly
|
||||
echo -e "${CYAN}Testing spd-say directly...${NC}"
|
||||
if timeout 5s spd-say -w "Testing speech" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ spd-say direct test successful${NC}"
|
||||
spd_working=true
|
||||
else
|
||||
echo -e "${RED}✗ spd-say direct test failed${NC}"
|
||||
fi
|
||||
|
||||
# Method 2: Test with different TTS engines if spd-say failed
|
||||
if [[ "$spd_working" == false ]]; then
|
||||
echo -e "${CYAN}Testing alternative TTS engines...${NC}"
|
||||
|
||||
# Try espeak directly
|
||||
if command -v espeak >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Trying espeak directly...${NC}"
|
||||
if timeout 3s espeak "Testing espeak" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ espeak works directly${NC}"
|
||||
# Update speak_text function to use espeak as fallback
|
||||
TTS_FALLBACK="espeak"
|
||||
spd_working=true
|
||||
else
|
||||
echo -e "${RED}✗ espeak test failed${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try festival if espeak failed
|
||||
if [[ "$spd_working" == false ]] && command -v festival >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Trying festival...${NC}"
|
||||
if timeout 3s echo "Testing festival" | festival --tts 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ festival works${NC}"
|
||||
TTS_FALLBACK="festival"
|
||||
spd_working=true
|
||||
else
|
||||
echo -e "${RED}✗ festival test failed${NC}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Final result
|
||||
if [[ "$spd_working" == true ]]; then
|
||||
echo -e "${GREEN}✓ Text-to-speech is working!${NC}"
|
||||
TTS_ENABLED=true
|
||||
if [[ -n "$TTS_FALLBACK" ]]; then
|
||||
echo -e "${YELLOW}Note: Using $TTS_FALLBACK as fallback TTS engine${NC}"
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}Warning: Speech Dispatcher found but not working properly!${NC}"
|
||||
echo -e "${YELLOW}This might be due to audio system issues or configuration problems.${NC}"
|
||||
echo -e "${CYAN}Troubleshooting steps:${NC}"
|
||||
echo -e "${WHITE}1. Check if PulseAudio is running: pulseaudio --check${NC}"
|
||||
echo -e "${WHITE}2. Test audio: speaker-test -c2 -t wav${NC}"
|
||||
echo -e "${WHITE}3. Restart Speech Dispatcher: sudo systemctl restart speech-dispatcher${NC}"
|
||||
echo -e "${WHITE}4. Check Speech Dispatcher status: systemctl status speech-dispatcher${NC}"
|
||||
echo ""
|
||||
TTS_ENABLED=false
|
||||
echo -e "${WHITE}Press Enter to continue without TTS...${NC}"
|
||||
read
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to test TTS and let user adjust settings
|
||||
test_and_configure_tts() {
|
||||
if [[ "$TTS_ENABLED" == true ]]; then
|
||||
announce "Welcome to the Ultrabunt Accessible Installer!" "$GREEN" "important"
|
||||
announce "This installer includes text-to-speech support for visually impaired users." "$CYAN"
|
||||
|
||||
echo ""
|
||||
announce "Testing your text-to-speech settings..." "$YELLOW"
|
||||
speak_text "This is a test of the text to speech system. Can you hear this clearly?"
|
||||
|
||||
# Give time for speech to complete
|
||||
sleep 2
|
||||
|
||||
echo ""
|
||||
echo -e "${WHITE}TTS Settings Test Complete${NC}"
|
||||
echo -e "${CYAN}Current settings:${NC}"
|
||||
echo -e " Voice: ${WHITE}$TTS_VOICE${NC} (friendly female voice)"
|
||||
echo -e " Speed: ${WHITE}$TTS_RATE${NC} (slightly slower for clarity)"
|
||||
echo -e " Volume: ${WHITE}$TTS_VOLUME${NC} (slightly louder)"
|
||||
echo -e " Punctuation: ${WHITE}$TTS_PUNCTUATION${NC} (reads some punctuation)"
|
||||
echo ""
|
||||
|
||||
while true; do
|
||||
echo -e "${YELLOW}TTS Configuration Options:${NC}"
|
||||
echo -e " ${WHITE}1)${NC} Continue with current settings"
|
||||
echo -e " ${WHITE}2)${NC} Make voice slower"
|
||||
echo -e " ${WHITE}3)${NC} Make voice faster"
|
||||
echo -e " ${WHITE}4)${NC} Make voice louder"
|
||||
echo -e " ${WHITE}5)${NC} Make voice quieter"
|
||||
echo -e " ${WHITE}6)${NC} Test current settings again"
|
||||
echo -e " ${WHITE}7)${NC} Disable TTS and continue silently"
|
||||
echo ""
|
||||
|
||||
read -p "Choose an option (1-7): " choice
|
||||
speak_text "You selected option $choice"
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
announce "Continuing with current TTS settings." "$GREEN"
|
||||
break
|
||||
;;
|
||||
2)
|
||||
TTS_RATE="-40"
|
||||
announce "Voice speed set to slower. Testing..." "$CYAN"
|
||||
# Update Speech Dispatcher config if needed
|
||||
update_spd_config
|
||||
speak_text "This is the new slower speed setting."
|
||||
sleep 3
|
||||
;;
|
||||
3)
|
||||
TTS_RATE="0"
|
||||
announce "Voice speed set to normal. Testing..." "$CYAN"
|
||||
# Update Speech Dispatcher config if needed
|
||||
update_spd_config
|
||||
speak_text "This is the normal speed setting."
|
||||
sleep 3
|
||||
;;
|
||||
4)
|
||||
TTS_VOLUME="30"
|
||||
announce "Voice volume set to louder. Testing..." "$CYAN"
|
||||
# Update Speech Dispatcher config if needed
|
||||
update_spd_config
|
||||
speak_text "This is the louder volume setting."
|
||||
sleep 3
|
||||
;;
|
||||
5)
|
||||
TTS_VOLUME="0"
|
||||
announce "Voice volume set to normal. Testing..." "$CYAN"
|
||||
# Update Speech Dispatcher config if needed
|
||||
update_spd_config
|
||||
speak_text "This is the normal volume setting."
|
||||
sleep 3
|
||||
;;
|
||||
6)
|
||||
announce "Testing current settings..." "$YELLOW"
|
||||
speak_text "This is a test of your current text to speech settings. How does this sound?"
|
||||
sleep 2
|
||||
;;
|
||||
7)
|
||||
TTS_ENABLED=false
|
||||
announce "Text-to-speech disabled. Continuing in silent mode." "$YELLOW"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
announce "Invalid option. Please choose 1 through 7." "$RED"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to update Speech Dispatcher configuration with current settings
|
||||
update_spd_config() {
|
||||
# Only update if we have a user config directory
|
||||
local actual_user="${SUDO_USER:-$USER}"
|
||||
if [[ -n "$actual_user" && "$actual_user" != "root" ]]; then
|
||||
local user_spd_dir="/home/$actual_user/.config/speech-dispatcher"
|
||||
|
||||
# Update the main config file if it exists
|
||||
if [[ -f "$user_spd_dir/speechd.conf" ]]; then
|
||||
# Update rate setting
|
||||
sed -i "s/^DefaultRate.*/DefaultRate $TTS_RATE/" "$user_spd_dir/speechd.conf" 2>/dev/null || true
|
||||
# Update volume setting
|
||||
sed -i "s/^DefaultVolume.*/DefaultVolume $TTS_VOLUME/" "$user_spd_dir/speechd.conf" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Update espeak module config if it exists
|
||||
if [[ -f "$user_spd_dir/modules/espeak.conf" ]]; then
|
||||
sed -i "s/^EspeakRate.*/EspeakRate $TTS_RATE/" "$user_spd_dir/modules/espeak.conf" 2>/dev/null || true
|
||||
sed -i "s/^EspeakVolume.*/EspeakVolume $TTS_VOLUME/" "$user_spd_dir/modules/espeak.conf" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Restart Speech Dispatcher to apply changes
|
||||
systemctl restart speech-dispatcher 2>/dev/null || true
|
||||
sleep 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to provide audio navigation help
|
||||
provide_navigation_help() {
|
||||
announce "Navigation Help for Ultrabunt Installer" "$CYAN" "important"
|
||||
announce "This installer uses numbered menus for easy navigation." "$WHITE"
|
||||
announce "Simply type the number of your choice and press Enter." "$WHITE"
|
||||
announce "You can always type 'help' for assistance, or 'quit' to exit." "$WHITE"
|
||||
announce "The installer will read all options aloud before asking for your choice." "$WHITE"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to announce menu options with audio
|
||||
announce_menu_options() {
|
||||
local menu_title="$1"
|
||||
shift
|
||||
local options=("$@")
|
||||
|
||||
announce "$menu_title" "$GREEN" "important"
|
||||
announce "Available options:" "$CYAN"
|
||||
|
||||
for i in "${!options[@]}"; do
|
||||
local option_num=$((i + 1))
|
||||
announce "Option $option_num: ${options[$i]}" "$WHITE"
|
||||
# Small pause between options for clarity
|
||||
sleep 0.3
|
||||
done
|
||||
|
||||
echo ""
|
||||
announce "Please enter your choice:" "$YELLOW"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
clear
|
||||
|
||||
# Check if we're running on a Linux system
|
||||
if [[ "$(uname)" != "Linux" ]]; then
|
||||
announce "Error: This accessible installer is designed for Linux systems only." "$RED" "important"
|
||||
announce "The main ultrabunt.sh script may work on other systems." "$YELLOW"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install TTS dependencies if needed (requires sudo)
|
||||
if [[ "$EUID" -eq 0 ]]; then
|
||||
install_tts_dependencies
|
||||
else
|
||||
echo -e "${YELLOW}Note: Running without sudo. If TTS doesn't work, try: sudo ./ultrabunt-accessible.sh${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check TTS availability
|
||||
check_tts_availability
|
||||
|
||||
# Welcome and TTS configuration
|
||||
echo -e "${PURPLE}╔══════════════════════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${PURPLE}║ ULTRABUNT ACCESSIBLE INSTALLER ║${NC}"
|
||||
echo -e "${PURPLE}║ Enhanced for Visually Impaired Users ║${NC}"
|
||||
echo -e "${PURPLE}╚══════════════════════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
|
||||
if [[ "$TTS_ENABLED" == true ]]; then
|
||||
test_and_configure_tts
|
||||
provide_navigation_help
|
||||
|
||||
# Ask if user wants to continue
|
||||
announce "Are you ready to start the Ultrabunt installation?" "$GREEN"
|
||||
announce "Type 'yes' to continue, 'help' for more information, or 'no' to exit." "$CYAN"
|
||||
|
||||
while true; do
|
||||
read -p "Your choice: " user_response
|
||||
speak_text "You entered: $user_response"
|
||||
|
||||
case "${user_response,,}" in
|
||||
yes|y)
|
||||
announce "Starting Ultrabunt installer with accessibility features enabled." "$GREEN" "important"
|
||||
break
|
||||
;;
|
||||
help|h)
|
||||
provide_navigation_help
|
||||
announce "Type 'yes' to continue or 'no' to exit." "$CYAN"
|
||||
;;
|
||||
no|n|quit|exit)
|
||||
announce "Exiting Ultrabunt accessible installer. Goodbye!" "$YELLOW" "important"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
announce "Please type 'yes' to continue, 'help' for information, or 'no' to exit." "$RED"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
echo -e "${YELLOW}Running in silent mode (TTS disabled)${NC}"
|
||||
echo -e "${WHITE}Press Enter to continue with the standard installer...${NC}"
|
||||
read
|
||||
fi
|
||||
|
||||
# Export TTS settings for the main script to use
|
||||
export ULTRABUNT_TTS_ENABLED="$TTS_ENABLED"
|
||||
export ULTRABUNT_TTS_VOICE="$TTS_VOICE"
|
||||
export ULTRABUNT_TTS_RATE="$TTS_RATE"
|
||||
export ULTRABUNT_TTS_PITCH="$TTS_PITCH"
|
||||
export ULTRABUNT_TTS_VOLUME="$TTS_VOLUME"
|
||||
export ULTRABUNT_TTS_PUNCTUATION="$TTS_PUNCTUATION"
|
||||
|
||||
# Launch the main Ultrabunt script
|
||||
announce "Loading main Ultrabunt installer..." "$GREEN" "important"
|
||||
|
||||
# Check if main script exists
|
||||
if [[ -f "./ultrabunt.sh" ]]; then
|
||||
# Make sure it's executable
|
||||
chmod +x ./ultrabunt.sh
|
||||
|
||||
# Run the main script with accessibility enhancements
|
||||
./ultrabunt.sh "$@"
|
||||
else
|
||||
announce "Error: ultrabunt.sh not found in current directory!" "$RED" "important"
|
||||
announce "Please ensure both scripts are in the same directory." "$YELLOW"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle script interruption gracefully
|
||||
trap 'announce "Installation interrupted by user. Goodbye!" "$YELLOW" "important"; exit 130' INT
|
||||
|
||||
# Only run main when executed directly, not when sourced for tests
|
||||
[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"
|
||||
4591
ultrabunt.sh
4591
ultrabunt.sh
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user