A collection of scripts that push notifications to ntfy (and optionally Telegram)
  • Python 96.4%
  • Just 2.2%
  • Shell 1.4%
Find a file
2026-03-19 21:55:35 +01:00
bin address code review feedback on jokes.py and memes.py 2026-03-18 13:20:14 +01:00
docs just: remove dedicated jokes/memes recipes, use consistent just run <name> 2026-03-18 13:22:19 +01:00
just just: remove dedicated jokes/memes recipes, use consistent just run <name> 2026-03-18 13:22:19 +01:00
lib Support comma-separated topics in send_ntfy() 2026-03-15 20:47:33 +01:00
scripts address code review feedback on jokes.py and memes.py 2026-03-18 13:20:14 +01:00
.env.example jokes.py: add daily Spanish joke script with internet/personal modes 2026-03-18 13:05:39 +01:00
.gitignore news.py: add staleness check and collapsed fallback digest 2026-03-18 12:51:00 +01:00
.python-version Initial bananify project 2026-03-15 16:58:44 +01:00
justfile just: remove dedicated jokes/memes recipes, use consistent just run <name> 2026-03-18 13:22:19 +01:00
pyproject.toml Initial bananify project 2026-03-15 16:58:44 +01:00
README.md just: remove dedicated jokes/memes recipes, use consistent just run <name> 2026-03-18 13:22:19 +01:00
uv.lock Initial bananify project 2026-03-15 16:58:44 +01:00

🍌 bananify

A collection of notification scripts that push useful info to ntfy (and optionally Telegram). Named after ntfy's banana mascot.

Scripts

Script Topic Schedule Source
weather.py weather 7am daily Open-Meteo (free, no key)
apod.py apod 7am daily NASA APOD (free)
news.py news 7am daily Configurable RSS feeds
quote.py quote 7am daily zenquotes.io (free)
jokes.py jokes 7am daily JokeAPI v2 / personal file
memes.py memes 12pm daily Reddit JSON API
system_health.py system-health 8am daily Local /proc / psutil
adguard_stats.py adguard 8am daily AdGuard Home API
ssl_expiry.py ssl-expiry Mon 9am TLS cert check (stdlib)
ssh_login.py ssh-login SSH login (PAM) PAM environment

Setup

git clone <repo-url> bananify && cd bananify
cp .env.example .env   # fill in your values
uv sync                # install deps

Configuration

All configuration lives in .env. See .env.example for all available options.

Required:

  • NTFY_URL — your ntfy server URL (e.g. https://ntfy.sh)
  • NTFY_TOKEN — ntfy access token

Optional:

  • WEATHER_LANG — geocoding/description language (en or es, default en)
  • HEALTH_MOUNT_LABELS — display names for mounts, e.g. /=Root,/mnt/media=Media
  • NTFY_TOPIC_<NAME> — override default topic per script; comma-separate to publish to multiple topics (e.g. bananify,news)
  • Telegram, AdGuard credentials, city list, RSS feeds, SSL domains, thresholds

News feeds (NEWS_FEEDS)

Each feed entry is comma-separated and supports three formats:

Format Example
url https://hnrss.org/frontpage
name|url HN|https://hnrss.org/frontpage
name|url|max HN|https://hnrss.org/frontpage|3
  • name — overrides the RSS feed title in the notification
  • max — per-feed headline limit; falls back to NEWS_MAX_HEADLINES if omitted
  • Each feed sends as a separate notification to avoid ntfy's 4096-byte attachment threshold

Jokes (JOKES_SOURCE, JOKES_FILE)

  • JOKES_SOURCE=internet (default) — fetches a Spanish joke from JokeAPI v2 (free, no key)
  • JOKES_SOURCE=personal — picks a random joke from a local markdown file at JOKES_FILE
  • Personal file format: jokes separated by --- delimiters, or as a bullet list (- joke text)

Memes (MEMES_SOURCES)

Each entry is comma-separated and supports two formats:

Format Example
subreddit me_irl
subreddit|count me_irl|3
  • count — number of image posts to send (default: 3)
  • NSFW posts are filtered by default; set MEMES_ALLOW_NSFW=true to include them
  • Each image post sends as a separate notification with inline image and click-through link

Running

just run weather        # run a single script
just run jokes
just run memes
just run-all            # run all scripts once

Or call the wrapper directly:

bin/bananify weather

Scheduling (cron)

0 7 * * *   /path/to/bananify/bin/bananify weather
0 7 * * *   /path/to/bananify/bin/bananify apod
0 7 * * *   /path/to/bananify/bin/bananify news
0 7 * * *   /path/to/bananify/bin/bananify quote
0 7 * * *   /path/to/bananify/bin/bananify jokes
0 8 * * *   /path/to/bananify/bin/bananify system_health
0 8 * * *   /path/to/bananify/bin/bananify adguard_stats
0 9 * * 1   /path/to/bananify/bin/bananify ssl_expiry
0 12 * * *  /path/to/bananify/bin/bananify memes

For SSH login alerts, see docs/cron.md.

Adding a new script

  1. Create scripts/my_thing.py — import from lib.notify:
    import sys, os
    sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
    from lib.notify import load_config, send_ntfy
    
    def main():
        cfg = load_config()
        # Optional: markdown=True, attach="https://...", click="https://..."
        send_ntfy(cfg, "my-topic", "Title", "Body")
    
    if __name__ == "__main__":
        main()
    
  2. Test: just run my_thing
  3. Add a cron entry using bin/bananify my_thing