From d722842d200cd07680b6ff47f3dd967f7ce85a0f Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 5 Aug 2026 11:49:27 -0400 Subject: [PATCH] add auto trig for api and send via telegram --- DOC/AGENT_Context_Project.md | 35 +++- DOC/DEV.md | 11 +- DOC/POS.md | 33 ++- DOC/README.md | 2 +- DOC/SCRIPTS.md | 11 +- bin/pos | 2 + bin/pos-entertainment-config | 64 ++++++ bin/pos-entertainment-disable | 32 +++ bin/pos-entertainment-enable | 49 +++++ bin/pos-entertainment-send | 33 +-- bin/pos-entertainment-status | 55 +++++ completions/pos.bash | 19 ++ config/entertainment.env | 17 +- entertainment/gold.sh | 43 ++++ entertainment/joke.sh | 1 + entertainment/weather.sh | 1 + install.sh | 7 +- lib/entertainment-lib.sh | 380 ++++++++++++++++++++++++++++++++++ postinstall.sh | 5 +- 19 files changed, 739 insertions(+), 61 deletions(-) create mode 100755 bin/pos-entertainment-config create mode 100755 bin/pos-entertainment-disable create mode 100755 bin/pos-entertainment-enable create mode 100755 bin/pos-entertainment-status create mode 100755 entertainment/gold.sh create mode 100644 lib/entertainment-lib.sh diff --git a/DOC/AGENT_Context_Project.md b/DOC/AGENT_Context_Project.md index 10e64d4..4abb55c 100644 --- a/DOC/AGENT_Context_Project.md +++ b/DOC/AGENT_Context_Project.md @@ -30,7 +30,8 @@ Linux_post_install/ │ ├── lib/ │ ├── common.sh # Shared library (colors, logging, spinner, timer, run) -│ └── flags.sh # Feature flag store (flag_set/clear/is_set/value/list/status) +│ ├── flags.sh # Feature flag store (flag_set/clear/is_set/value/list/status) +│ └── entertainment-lib.sh # Entertainment module lib (ENABLED list, scheduler sync) │ ├── bin/ # CLI tools — installed to /usr/local/bin/ │ ├── pos # Main dispatcher — smart arg matching to pos-* scripts @@ -40,7 +41,11 @@ Linux_post_install/ │ ├── pos-docker-health # One-glance container health dashboard (exits 1 if unhealthy) │ ├── pos-docker-ps # Enhanced container overview (health, IPs, ports, uptime) │ ├── pos-docker-vbox # Disposable Docker-based VMs (create/enter/start/stop/rm/ls) +│ ├── pos-entertainment-config # Show or edit the entertainment config (ENABLED auto-trigger list, weather location) +│ ├── pos-entertainment-disable # Disable a plugin's auto-trigger (remove it from ENABLED) +│ ├── pos-entertainment-enable # Enable an auto-trigger for a plugin (systemd user timer) │ ├── pos-entertainment-send # Run a public-API plugin and send its output via Telegram (default sender) +│ ├── pos-entertainment-status # Show enabled plugins and their timer state │ ├── pos-media-mp3 # Download audio as MP3 (yt-dlp) │ ├── pos-media-mp4 # Download video as MP4 (interactive format select) │ ├── pos-network-checkport # Check TCP port connectivity @@ -62,9 +67,10 @@ Linux_post_install/ ├── features/ # User-customizable scripts (installed via --feature) │ └── autostart.sh # Boot-time script (via systemd, flag-gated) │ -├── entertainment/ # Public-API plugins for pos entertainment send (→ /usr/local/share/linux_post_install/entertainment) +├── entertainment/ # Public-API plugins for pos entertainment send (→ /usr/local/bin) │ ├── weather.sh # Current weather via Open-Meteo (no API key) -│ └── joke.sh # Random dad joke via icanhazdadjoke (no API key) +│ ├── joke.sh # Random dad joke via icanhazdadjoke (no API key) +│ └── gold.sh # Gold spot (XAU/USD) via goldprice.dev (no API key) │ ├── templates/ # Dev-only scaffolds — NOT installed by install.sh │ ├── pos-tool.sh # New `pos` CLI tool (→ bin/pos--) @@ -108,7 +114,7 @@ Linux_post_install/ │ ├── config/ │ ├── authorized_keys # SSH public keys (gitignored) -│ └── entertainment.env # Default weather location (auto-installed by postinstall) +│ └── entertainment.env # Weather location template (auto-installed by postinstall) │ ├── compose/ │ └── scale-tail/ # Git submodule → ScaleTail templates (119+ services) @@ -145,7 +151,7 @@ User runs: ./install.sh [--apps|--full|--feature|--dry-run|--skip |--step │ ├─ Phase 2: install.sh (requires root) │ └─ Copies bin/* → /usr/local/bin/ (chmod 755) -│ └─ Copies lib/common.sh + lib/flags.sh → /usr/local/bin/ (chmod 644) +│ └─ Copies lib/common.sh + lib/flags.sh + lib/entertainment-lib.sh → /usr/local/bin/ (chmod 644) │ └─ Copies x64_bin/* → /usr/local/bin/ on x86_64 (arm64_bin/ on aarch64) │ └─ [if --feature] Copies features/* → /usr/local/bin/ (asks before overwriting), │ then sets the matching feature flag @@ -211,7 +217,11 @@ All non-interactive `pos` commands log output to `~/.local/share/linux_post_inst | docker | health | `pos-docker-health` | One-glance container health dashboard (exits 1 if unhealthy) | | docker | ps | `pos-docker-ps` | Enhanced container overview (health, IPs, ports, uptime) | | docker | vbox | `pos-docker-vbox` | Disposable Docker-based VMs (create/enter/start/stop/rm/ls) | +| entertainment | config | `pos-entertainment-config` | Show or edit the entertainment config (ENABLED auto-trigger list, weather location) | +| entertainment | disable | `pos-entertainment-disable` | Disable a plugin's auto-trigger (remove it from ENABLED) | +| entertainment | enable | `pos-entertainment-enable` | Enable an auto-trigger for a plugin (systemd user timer) | | entertainment | send | `pos-entertainment-send` | Run a public-API plugin and send its output via Telegram (default sender) | +| entertainment | status | `pos-entertainment-status` | Show enabled plugins and their timer state | | media | mp3 | `pos-media-mp3` | Download audio as MP3 (yt-dlp) | | media | mp4 | `pos-media-mp4` | Download video as MP4 (interactive format select) | | network | checkport | `pos-network-checkport` | Check TCP port connectivity | @@ -365,7 +375,7 @@ All `.service` files in `systemd/` are automatically copied to `/etc/systemd/sys ### Runtime Config - `~/.config/linux_post_install/compose.env` — Docker Compose global defaults -- `~/.config/linux_post_install/entertainment.env` — entertainment plugin defaults (e.g. weather location); auto-installed from `config/entertainment.env` by `postinstall.sh` (no clobber) +- `~/.config/linux_post_install/entertainment.env` — entertainment plugin defaults: weather location + `ENABLED` auto-trigger list (`plugin, interval` pairs → systemd user timers via `pos entertainment enable/disable`); auto-installed from `config/entertainment.env` by `postinstall.sh` (no clobber, template printed) - `~/.bashrc` — Modified by postinstall (PATH, bash completion) ### Feature Flags @@ -470,21 +480,26 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:` |------|-------|---------| | `install.sh` | 192 | Main orchestrator — 4 phases with CLI flags, `--feature`, prebuilt arch bins | | `preinstall.sh` | 54 | System packages + hotspot deps + yt-dlp + fail2ban | -| `postinstall.sh` | 114 | fail2ban config, PATH, bash completion, systemd (flag-gated) | +| `postinstall.sh` | 115 | fail2ban config, PATH, bash completion, systemd (flag-gated) | | `lib/common.sh` | 121 | Shared library | | `lib/flags.sh` | 60 | Feature flag store (set/clear/is_set/value/list/status) | +| `lib/entertainment-lib.sh` | 380 | Entertainment module lib (ENABLED parsing, scheduler sync) | | `bin/flag-reader` | 58 | Inspect flags (list/status/`--raw`) | | `bin/flag-set` | 21 | Set a flag (optionally with a value) | | `bin/flag-clear` | 21 | Unset a flag | | `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) | -| `bin/pos` | 211 | CLI dispatcher with smart arg matching + logging + category help | +| `bin/pos` | 213 | CLI dispatcher with smart arg matching + logging + category help | | `bin/pos-communication-telegram` | 150 | Send Telegram messages via Bot API (--send, test, config set) | | `bin/pos-docker-compose` | 364 | Docker Compose service manager (ls/up/down/restart/logs/update/config) | | `bin/pos-docker-health` | 110 | One-glance container health dashboard (exits 1 if unhealthy) | | `bin/pos-docker-ps` | 128 | Enhanced container overview (health, IPs, ports, uptime) | | `bin/pos-docker-vbox` | 157 | Disposable Docker-based VMs (create/enter/start/stop/rm/ls) | -| `bin/pos-entertainment-send` | 124 | Run a public-API plugin and send its output via Telegram (default sender) | +| `bin/pos-entertainment-config` | 64 | Show or edit the entertainment config (ENABLED auto-trigger list, weather location) | +| `bin/pos-entertainment-disable` | 32 | Disable a plugin's auto-trigger (remove it from ENABLED) | +| `bin/pos-entertainment-enable` | 49 | Enable an auto-trigger for a plugin (systemd user timer) | +| `bin/pos-entertainment-send` | 93 | Run a public-API plugin and send its output via Telegram (default sender) | +| `bin/pos-entertainment-status` | 55 | Show enabled plugins and their timer state | | `bin/pos-media-mp3` | 35 | Download audio as MP3 (yt-dlp) | | `bin/pos-media-mp4` | 38 | Download video as MP4 (interactive format select) | | `bin/pos-network-checkport` | 45 | Check TCP port connectivity | @@ -495,7 +510,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:` | `bin/pos-system-backup` | 117 | Encrypted (AES-256) folder snapshots (tar + gpg) | | `bin/pos-system-firewall` | 285 | Interactive UFW management | | `bin/pos-usb-server` | 218 | USB Redirector server control (--ls, --share; prompts when args omitted) | -| `completions/pos.bash` | 150 | Dynamic bash completion | +| `completions/pos.bash` | 169 | Dynamic bash completion | | `apps/install.sh` | 171 | App install/uninstall picker/orchestrator | diff --git a/DOC/DEV.md b/DOC/DEV.md index 5eed107..37a02cf 100644 --- a/DOC/DEV.md +++ b/DOC/DEV.md @@ -20,7 +20,7 @@ How this repo works, how to add features, and what to keep in mind when editing. | Phase | Script | Responsibility | |-------|--------|----------------| | Pre | `preinstall.sh` | System packages, apt repos, global binaries (yt-dlp) | -| Install | `install.sh` | Copies `bin/*` → `/usr/local/bin/` (chmod 755), `lib/common.sh` → `/usr/local/bin/common.sh` | +| Install | `install.sh` | Copies `bin/*` → `/usr/local/bin/` (chmod 755), `lib/common.sh` + `lib/flags.sh` + `lib/entertainment-lib.sh` → `/usr/local/bin/` (chmod 644) | | Post | `postinstall.sh` | User config (SSH keys, PATH, bash completion), systemd services | Each phase is independent and runs only if the corresponding script exists. @@ -31,9 +31,9 @@ Each phase is independent and runs only if the corresponding script exists. |-----------|---------|-------------| | `bin/` | Daily-use CLI tools and wrappers | `/usr/local/bin/` | | `apps//` | Optional desktop app installers | run on demand | -| `lib/` | Shared library (`common.sh`) | sourced at build time | +| `lib/` | Shared libraries: `common.sh` (helpers), `flags.sh` (feature flags), `entertainment-lib.sh` (entertainment scheduling) | sourced at build time | | `config/` | Gitignored user config files | `~/.config//` (via postinstall) | -| `entertainment/` | Public-API plugins for the entertainment module | `/usr/local/share/linux_post_install/entertainment` (via install.sh Phase 2) | +| `entertainment/` | Public-API plugins for the entertainment module | `/usr/local/bin` (via install.sh Phase 2) | | `compose/` | ScaleTail templates (git submodule) | `/usr/local/share/linux_post_install/scale-tail` | | `systemd/` | Systemd unit files | `/etc/systemd/system/` (via postinstall) | @@ -179,15 +179,16 @@ make check # full self-consistency gate (syntax, exec bits, d ## Adding an Entertainment Plugin -The `entertainment` module routes public-API data to Telegram via the single runner `pos entertainment send ` (`bin/pos-entertainment-send`). +The `entertainment` module routes public-API data to Telegram via the single runner `pos entertainment send ` (`bin/pos-entertainment-send`). Auto-triggering is config-driven: `ENABLED` in `entertainment.env` holds `plugin, interval` pairs; the tools `pos entertainment config|enable|disable|status` (`bin/pos-entertainment-*`) reconcile the schedule. All shared logic (ENABLED parsing, interval→schedule mapping, scheduler sync) lives in `lib/entertainment-lib.sh` — sourced by the `pos-entertainment-*` tools (never by plugins). The scheduler is auto-detected: systemd user timers when a user systemd manager exists, otherwise a managed user crontab block. ### 1. Create the plugin -Drop an executable script in `entertainment/.sh`: +Drop an executable script in `entertainment/.sh` with a `# POS_PLUGIN: ` marker on line 3 (this is what makes it a plugin — the installed runner lists plugins by this marker, not by `.sh` files, since `/usr/local/bin` is shared with other tooling): ```bash #!/usr/bin/env bash set -euo pipefail +# POS_PLUGIN: myplugin err() { echo "ERROR: $*" >&2; exit 1; } command -v curl &>/dev/null || err "curl not found" diff --git a/DOC/POS.md b/DOC/POS.md index cc842d2..585a9a6 100644 --- a/DOC/POS.md +++ b/DOC/POS.md @@ -215,8 +215,13 @@ The bot token is a secret — it is stored only in `~/.config/linux_post_install | `pos entertainment send [--print] [--markdown] [args…]` | Run the plugin, send its output to Telegram (silent) | | `pos entertainment send --print` | Print the output locally; do not send | | `pos entertainment send --markdown` | Send with `--parse-mode markdown` (via `pos communication telegram`) | +| `pos entertainment config` | Show the config file (`~/.config/linux_post_install/entertainment.env`) | +| `pos entertainment config set KEY=VALUE…` | Set keys (e.g. `ENABLED`, `WEATHER_LAT`) and re-sync timers | +| `pos entertainment enable [interval]` | Add plugin to `ENABLED` + create/enable its systemd **user** timer | +| `pos entertainment disable ` | Remove plugin from `ENABLED` + disable/remove its timer | +| `pos entertainment status` | Enabled plugins + timer state + next fire time | -**Plugin lookup order:** `$ENTERTAINMENT_DIR` → repo `entertainment/` → `/usr/local/share/linux_post_install/entertainment/` (installed by `install.sh` Phase 2). A plugin name matches the file name with or without the `.sh` suffix. +**Plugin lookup order:** `$ENTERTAINMENT_DIR` → repo `entertainment/` → `/usr/local/bin/` (installed by `install.sh` Phase 2, beside the runner). A plugin name matches the file name with or without the `.sh` suffix. Plugins: @@ -224,12 +229,32 @@ Plugins: |--------|-----------|--------| | `weather` | Open-Meteo (no API key) | `~/.config/linux_post_install/entertainment.env`: `WEATHER_LAT`, `WEATHER_LON` (required), `WEATHER_CITY` (optional label) | | `joke` | icanhazdadjoke.com (no API key) | None | +| `gold` | goldprice.dev (no API key, anonymous free tier) | None | -**Config auto-install:** `postinstall.sh` copies the repo's `config/entertainment.env` (default: Al-Hasakah, Syria) to `~/.config/linux_post_install/entertainment.env` on install — but only if you haven't already created your own (no clobber). Override the default by creating/editing that file. +**Config auto-install:** `postinstall.sh` copies the repo's `config/entertainment.env` (a commented template showing each key's syntax) to `~/.config/linux_post_install/entertainment.env` on install — but only if you haven't already created your own (no clobber), and prints the template so you can fill in your location. Fill in `WEATHER_LAT`/`WEATHER_LON` (and optionally `WEATHER_CITY`) to enable the weather plugin. -**Adding a plugin:** drop an executable script in `entertainment/` (e.g. `myfeed.sh`). It must be non-interactive and print the message to stdout; errors go to stderr (exit nonzero). If it needs coordinates/tokens, read them from `~/.config/linux_post_install/entertainment.env` (chmod 600, env precedence). No registration needed. Dependencies beyond `curl`/`jq` (both in `preinstall.sh` PACKAGES) should be guarded with `command -v … || exit 1`. +**Adding a plugin:** drop an executable script in `entertainment/` (e.g. `myfeed.sh`) with a `# POS_PLUGIN: ` marker on line 3 — the runner lists and validates plugins by this marker, so non-plugin `.sh` files in the shared `/usr/local/bin` are ignored. The plugin must be non-interactive and print the message to stdout; errors go to stderr (exit nonzero). If it needs coordinates/tokens, read them from `~/.config/linux_post_install/entertainment.env` (chmod 600, env precedence). No registration needed. Dependencies beyond `curl`/`jq` (both in `preinstall.sh` PACKAGES) should be guarded with `command -v … || exit 1`. -**Automation:** the runner is headless/timer-friendly — no TTY prompts, exit 0 on success / 1 on failure. A systemd timer (e.g. hourly) can call `pos entertainment send weather` directly. Note the config files live under the user's `$HOME`, so the timer must run as that user (a systemd **user** unit, or a system unit with `Environment=HOME=/home/`). +**Automation (auto-trigger):** enable plugins on a schedule via the `ENABLED` key in the config — a comma-separated list of `plugin, interval` pairs: + +``` +ENABLED="weather, 5m gold, 1h joke, daily" +``` + +`pos entertainment enable [interval]` appends/updates one entry and re-syncs; `pos entertainment disable ` removes it; `pos entertainment config set ENABLED="…"` replaces the whole list. The scheduler backend is auto-detected on each sync: + +- **systemd** (when a user systemd manager is reachable): one **user timer** per enabled plugin (`~/.config/systemd/user/pos-entertainment-.{service,timer}`), running `pos entertainment send ` as your user on that schedule (`OnCalendar` + `Persistent=true`). `pos entertainment enable` also tries `sudo loginctl enable-linger $USER` once so timers fire without login. +- **cron** (fallback when no systemd user manager, e.g. this dev box): a managed block in your user crontab (`# POS-ENTERTAINMENT-BEGIN`…`END`), one line per plugin. Cron runs as your user and fires without login. + +Either way the job runs as you, so it reads your `$HOME` configs (weather location, Telegram token) natively — no `Environment=HOME=` hacks. + +Intervals: `5m 10m 15m 30m 45m hourly 2h 6h 12h daily weekly`, or a raw `OnCalendar=…` spec (systemd mode only; cron mode uses the named intervals). Default when omitted: `daily`. + +`pos entertainment status` shows the enabled plugins, the detected scheduler, and each plugin's interval + next/next-ish fire time (`systemctl --user list-timers` or the crontab block). + +Notes: +- The runner is headless/timer-friendly — no TTY prompts, exit 0 on success / 1 on failure. +- Scheduling is per-user for the user who runs `enable`; if you manage a different machine's user (e.g. via `runuser`/`sudo -u`), run the `enable`/`disable` commands as that user. ### flags diff --git a/DOC/README.md b/DOC/README.md index 6d1fda9..146938c 100644 --- a/DOC/README.md +++ b/DOC/README.md @@ -4,7 +4,7 @@ Everything in this folder is reference material for the `Linux_post_install` pro | Document | What it covers | |----------|----------------| -| [SCRIPTS.md](SCRIPTS.md) | Core installer scripts: `install.sh`, `preinstall.sh`, `postinstall.sh`, `lib/common.sh`, `lib/flags.sh`, `features/autostart.sh` — purpose, how each works, configuration | +| [SCRIPTS.md](SCRIPTS.md) | Core installer scripts: `install.sh`, `preinstall.sh`, `postinstall.sh`, `lib/common.sh`, `lib/flags.sh`, `lib/entertainment-lib.sh`, `features/autostart.sh` — purpose, how each works, configuration | | [POS.md](POS.md) | The `pos` CLI: dispatcher, every `pos-*` command, Docker Compose / ScaleTail config, legacy wrappers, flag CLIs | | [APPS.md](APPS.md) | Optional apps: `apps/install.sh` picker, installer conventions, full app catalog | | [SYSTEMD.md](SYSTEMD.md) | Systemd units (`autostart.service`, `ssh-agent.service`), feature-flag gating, bash completion | diff --git a/DOC/SCRIPTS.md b/DOC/SCRIPTS.md index dfe23f3..9764058 100644 --- a/DOC/SCRIPTS.md +++ b/DOC/SCRIPTS.md @@ -36,7 +36,7 @@ The phases: | # | Phase | Script/action | |---|-------|----------------| | 1 | preinstall | `preinstall.sh` — apt packages + yt-dlp | -| 2 | scripts | Copies `bin/*` → `/usr/local/bin/` (755), `lib/common.sh` + `lib/flags.sh` → `/usr/local/bin/` (644). Copies precompiled arch binaries from `x64_bin/` (or `arm64_bin/`) → `/usr/local/bin/`. With `--feature`: also installs `features/*` (see below) | +| 2 | scripts | Copies `bin/*` → `/usr/local/bin/` (755), `lib/common.sh` + `lib/flags.sh` + `lib/entertainment-lib.sh` → `/usr/local/bin/` (644). Copies precompiled arch binaries from `x64_bin/` (or `arm64_bin/`) → `/usr/local/bin/`. With `--feature`: also installs `features/*` (see below) | | 3 | postinstall | `postinstall.sh` — PATH, completion, SSH keys, systemd | | 4 | scalepoint | Shallow-clones ScaleTail templates to `/usr/local/share/linux_post_install/scale-tail` | | 5 (opt) | apps | `apps/install.sh` when `--apps` (interactive) or `--full` (all, non-interactive) | @@ -172,6 +172,15 @@ flag_clear autostart --- +## lib/entertainment-lib.sh — entertainment module + +**File:** `lib/entertainment-lib.sh` (installed to `/usr/local/bin/entertainment-lib.sh`) +**Purpose:** shared logic for the `pos entertainment` tools — config (`entertainment.env`), `ENABLED` auto-trigger list parsing (`plugin, interval` pairs), plugin lookup by `# POS_PLUGIN:` marker, interval→schedule mapping, and scheduler reconciliation (systemd **user** timers when a user manager is reachable, otherwise a managed user **crontab** block). + +Sourced by `bin/pos-entertainment-send|config|enable|disable|status` (after `lib/common.sh`). **Plugins must not source it** — their stdout is the sent message. + +--- + ## features/autostart.sh — boot-time feature **File:** `features/autostart.sh` (installed to `/usr/local/bin/autostart.sh` by `./install.sh --feature`) diff --git a/bin/pos b/bin/pos index 441bf6c..b7b91e2 100755 --- a/bin/pos +++ b/bin/pos @@ -116,6 +116,8 @@ EXAMPLES pos entertainment send weather Fetch Open-Meteo weather → Telegram pos entertainment send joke --print Preview a joke locally (no send) + pos entertainment enable weather 5m Auto-send weather to Telegram every 5 min + pos entertainment status Show enabled plugins + next run pos docker vbox create lab1 Create disposable Docker VM pos docker vbox create lab1 --dir . Create VM using current directory diff --git a/bin/pos-entertainment-config b/bin/pos-entertainment-config new file mode 100755 index 0000000..39bd720 --- /dev/null +++ b/bin/pos-entertainment-config @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -euo pipefail +# POS: entertainment config — Show or edit the entertainment config (ENABLED auto-trigger list, weather location) + +source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh" +source "$(dirname "$0")/../lib/entertainment-lib.sh" 2>/dev/null || source "$(dirname "$0")/entertainment-lib.sh" + +usage() { + cat < [interval]' or 'pos entertainment config set ...')" + fi + echo + echo "ENABLED: $(config_value ENABLED)" + echo "Intervals: 5m 10m 15m 30m 45m hourly 2h 6h 12h daily weekly, or OnCalendar=..." + ;; +esac diff --git a/bin/pos-entertainment-disable b/bin/pos-entertainment-disable new file mode 100755 index 0000000..72dd659 --- /dev/null +++ b/bin/pos-entertainment-disable @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# POS: entertainment disable — Disable a plugin's auto-trigger (remove it from ENABLED) + +source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh" +source "$(dirname "$0")/../lib/entertainment-lib.sh" 2>/dev/null || source "$(dirname "$0")/entertainment-lib.sh" + +usage() { + cat < + +Remove a plugin from the ENABLED list in +$CONFIG_FILE +and disable/remove its systemd user timer. + +Examples: + pos entertainment disable weather + pos entertainment disable gold +EOF + exit 0 +} + +case "${1:-}" in + -h|--help) usage ;; +esac + +[ $# -eq 1 ] || usage +plugin="$1" + +enabled_remove "$plugin" +sync_timers +ok "'$plugin' disabled — schedule synced" diff --git a/bin/pos-entertainment-enable b/bin/pos-entertainment-enable new file mode 100755 index 0000000..8d6c873 --- /dev/null +++ b/bin/pos-entertainment-enable @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail +# POS: entertainment enable — Enable an auto-trigger for a plugin (systemd user timer) + +source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh" +source "$(dirname "$0")/../lib/entertainment-lib.sh" 2>/dev/null || source "$(dirname "$0")/entertainment-lib.sh" + +usage() { + cat < [interval] + +Enable an auto-trigger: writes ', ' into the ENABLED list in +$CONFIG_FILE +and creates/enables a systemd user timer that runs 'pos entertainment send ' +on the schedule. Re-running without an interval keeps the plugin's current one. + +Available plugins: +$(list_plugins "$(plugin_dir)" | sed 's/^/ /') + +Intervals: 5m 10m 15m 30m 45m hourly 2h 6h 12h daily weekly, or OnCalendar=... +Default: $DEFAULT_INTERVAL + +Stop it with: pos entertainment disable + +Examples: + pos entertainment enable weather 5m + pos entertainment enable gold hourly + pos entertainment enable joke +EOF + exit 0 +} + +case "${1:-}" in + -h|--help) usage ;; +esac + +[ $# -ge 1 ] || usage +plugin="$1" +interval="${2:-}" + +resolve_plugin "$(plugin_dir)" "$plugin" >/dev/null +if [ -n "$interval" ]; then + interval_to_oncalendar "$interval" >/dev/null || \ + err "Invalid interval '$interval' (allowed: 5m 10m 15m 30m 45m hourly 2h 6h 12h daily weekly, or OnCalendar=...)" +fi + +enabled_upsert "$plugin" "$interval" +sync_timers +ok "'$plugin' enabled${interval:+ (every $interval)} — schedule synced" diff --git a/bin/pos-entertainment-send b/bin/pos-entertainment-send index 0c7447e..d8615b2 100755 --- a/bin/pos-entertainment-send +++ b/bin/pos-entertainment-send @@ -4,38 +4,7 @@ set -euo pipefail # POS_FLAGS: --print --markdown source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh" - -# ── Plugin directory lookup ───────────────────────────────────── -plugin_dir() { - if [ -n "${ENTERTAINMENT_DIR:-}" ]; then - echo "$ENTERTAINMENT_DIR" - elif [ -d "$(dirname "$0")/../entertainment" ]; then - echo "$(cd "$(dirname "$0")/../entertainment" && pwd)" - elif [ -d "/usr/local/share/linux_post_install/entertainment" ]; then - echo "/usr/local/share/linux_post_install/entertainment" - else - err "entertainment plugin dir not found (set ENTERTAINMENT_DIR)" - fi -} - -list_plugins() { - local dir="$1" f - for f in "$dir"/*; do - [ -f "$f" ] && [ -x "$f" ] && echo "$(basename "$f")" - done -} - -resolve_plugin() { - local dir="$1" name="$2" f - [ -n "$name" ] || err "No plugin given" - for f in "$dir/$name" "$dir/$name.sh"; do - if [ -f "$f" ] && [ -x "$f" ]; then - echo "$f" - return 0 - fi - done - err "Plugin '$name' not found in $dir — try one of: $(list_plugins "$dir" | tr '\n' ' ')" -} +source "$(dirname "$0")/../lib/entertainment-lib.sh" 2>/dev/null || source "$(dirname "$0")/entertainment-lib.sh" usage() { local dir plugins diff --git a/bin/pos-entertainment-status b/bin/pos-entertainment-status new file mode 100755 index 0000000..4b45dfe --- /dev/null +++ b/bin/pos-entertainment-status @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail +# POS: entertainment status — Show enabled plugins and their timer state + +source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh" +source "$(dirname "$0")/../lib/entertainment-lib.sh" 2>/dev/null || source "$(dirname "$0")/entertainment-lib.sh" + +usage() { + cat < [interval] +EOF + exit 0 +} + +case "${1:-}" in + -h|--help) usage ;; +esac + +raw="$(config_value ENABLED)" +echo "Config: $CONFIG_FILE" + +if [ -z "$raw" ]; then + echo "No plugins enabled." + echo "Enable one with: pos entertainment enable [interval]" + exit 0 +fi + +parse_enabled "$raw" +echo "Enabled plugins:" +for entry in "${ENABLED_ENTRIES[@]}"; do + plugin="${entry%%,*}"; interval="${entry##*,}" + [ "$interval" = "$plugin" ] && interval="$DEFAULT_INTERVAL" + printf ' %-12s %s\n' "$plugin" "$(interval_label "$interval")" +done + +echo +echo "Scheduler: $(if systemctl --user show-environment >/dev/null 2>&1; then echo 'systemd user timers'; elif command -v crontab >/dev/null 2>&1; then echo 'cron (user crontab)'; else echo 'none available'; fi)" +if systemctl --user show-environment >/dev/null 2>&1; then + echo "Timers (systemd --user):" + systemctl --user list-timers --no-pager 'pos-entertainment-*.timer' 2>/dev/null || \ + echo " (no timers)" +elif command -v crontab >/dev/null 2>&1; then + echo "Cron jobs (user crontab):" + block="$(cron_block)" + if [ -n "$block" ]; then + printf '%s\n' "$block" | sed 's/^/ /' + else + echo " (none)" + fi +fi diff --git a/completions/pos.bash b/completions/pos.bash index 81393f3..dd1309c 100644 --- a/completions/pos.bash +++ b/completions/pos.bash @@ -86,6 +86,19 @@ _pos() { COMPREPLY=($(compgen -W "${_pos_flags[$tool]:-} --help" -- "$cur")) } + _pos_entertainment_plugins() { + local d f name out=() + for d in /usr/local/bin "$pos_dir/../entertainment"; do + [ -d "$d" ] || continue + for f in "$d"/*.sh; do + [ -f "$f" ] || continue + name="$(grep -m1 '^# POS_PLUGIN:' "$f" 2>/dev/null | sed 's/^# POS_PLUGIN:[[:space:]]*//;s/[[:space:]]*$//')" + [ -n "$name" ] && out+=("$name") + done + done + COMPREPLY=($(compgen -W "${out[*]}" -- "$cur")) + } + # ── Dispatch ─────────────────────────────────────────────── case "${#words[@]}" in 2) @@ -118,6 +131,12 @@ _pos() { entertainment-send) _pos_complete_flags entertainment-send ;; + entertainment-enable|entertainment-disable) + _pos_entertainment_plugins + ;; + entertainment-config) + COMPREPLY=($(compgen -W "set --help" -- "$cur")) + ;; network-hotspot) _pos_complete_flags network-hotspot ;; diff --git a/config/entertainment.env b/config/entertainment.env index bb3d2a0..d19401c 100644 --- a/config/entertainment.env +++ b/config/entertainment.env @@ -1,3 +1,14 @@ -WEATHER_CITY=Al-Hasakah, Syria -WEATHER_LAT=36.51 -WEATHER_LON=40.75 +# Entertainment plugin defaults — used by 'pos entertainment send ' +# Copied to ~/.config/linux_post_install/entertainment.env on install (no clobber). +# Edit this file to set your location, then run: pos entertainment send weather --print +# +# Syntax: +# ENABLED="weather, 5m gold, 1h" # auto-trigger plugins; comma-separated +# # 'plugin, interval' pairs. Intervals: +# # 5m 10m 15m 30m 45m hourly 2h 6h 12h +# # daily weekly, or OnCalendar=... +# WEATHER_LAT= # required for the weather plugin, e.g. 52.52 +# WEATHER_LON= # required for the weather plugin, e.g. 13.41 +# WEATHER_CITY=