nejomibot 0.99.37__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.
- nejomibot-0.99.37/LICENSE +21 -0
- nejomibot-0.99.37/LICENSES/fortune-mod.txt +37 -0
- nejomibot-0.99.37/PKG-INFO +504 -0
- nejomibot-0.99.37/README.md +473 -0
- nejomibot-0.99.37/nejomibot/__init__.py +1 -0
- nejomibot-0.99.37/nejomibot/__main__.py +4 -0
- nejomibot-0.99.37/nejomibot/access.py +471 -0
- nejomibot-0.99.37/nejomibot/account.py +429 -0
- nejomibot-0.99.37/nejomibot/account_cli.py +2130 -0
- nejomibot-0.99.37/nejomibot/admins.py +290 -0
- nejomibot-0.99.37/nejomibot/albums.py +282 -0
- nejomibot-0.99.37/nejomibot/allowed.py +282 -0
- nejomibot-0.99.37/nejomibot/birthdays.py +530 -0
- nejomibot-0.99.37/nejomibot/bot.py +388 -0
- nejomibot-0.99.37/nejomibot/chat_cli.py +635 -0
- nejomibot-0.99.37/nejomibot/client.py +32 -0
- nejomibot-0.99.37/nejomibot/commands.py +601 -0
- nejomibot-0.99.37/nejomibot/config.py +427 -0
- nejomibot-0.99.37/nejomibot/contacts.py +605 -0
- nejomibot-0.99.37/nejomibot/delete.py +238 -0
- nejomibot-0.99.37/nejomibot/delivery.py +301 -0
- nejomibot-0.99.37/nejomibot/files.py +205 -0
- nejomibot-0.99.37/nejomibot/fortune.py +138 -0
- nejomibot-0.99.37/nejomibot/fortunes/computers +5733 -0
- nejomibot-0.99.37/nejomibot/fortunes/cookie +5698 -0
- nejomibot-0.99.37/nejomibot/fortunes/debian +406 -0
- nejomibot-0.99.37/nejomibot/fortunes/definitions +5667 -0
- nejomibot-0.99.37/nejomibot/fortunes/disclaimer +580 -0
- nejomibot-0.99.37/nejomibot/fortunes/drugs +1147 -0
- nejomibot-0.99.37/nejomibot/fortunes/education +962 -0
- nejomibot-0.99.37/nejomibot/fortunes/ethnic +851 -0
- nejomibot-0.99.37/nejomibot/fortunes/food +874 -0
- nejomibot-0.99.37/nejomibot/fortunes/fortunes +916 -0
- nejomibot-0.99.37/nejomibot/fortunes/fortunes_svenska +3042 -0
- nejomibot-0.99.37/nejomibot/fortunes/goedel +200 -0
- nejomibot-0.99.37/nejomibot/fortunes/humorists +1049 -0
- nejomibot-0.99.37/nejomibot/fortunes/kids +715 -0
- nejomibot-0.99.37/nejomibot/fortunes/knghtbrd +2342 -0
- nejomibot-0.99.37/nejomibot/fortunes/law +1296 -0
- nejomibot-0.99.37/nejomibot/fortunes/linux +1928 -0
- nejomibot-0.99.37/nejomibot/fortunes/literature +1329 -0
- nejomibot-0.99.37/nejomibot/fortunes/love +574 -0
- nejomibot-0.99.37/nejomibot/fortunes/magic +194 -0
- nejomibot-0.99.37/nejomibot/fortunes/medicine +423 -0
- nejomibot-0.99.37/nejomibot/fortunes/men-women +2548 -0
- nejomibot-0.99.37/nejomibot/fortunes/miscellaneous +1750 -0
- nejomibot-0.99.37/nejomibot/fortunes/news +257 -0
- nejomibot-0.99.37/nejomibot/fortunes/paradoxum +193 -0
- nejomibot-0.99.37/nejomibot/fortunes/people +4329 -0
- nejomibot-0.99.37/nejomibot/fortunes/perl +1022 -0
- nejomibot-0.99.37/nejomibot/fortunes/pets +187 -0
- nejomibot-0.99.37/nejomibot/fortunes/platitudes +1366 -0
- nejomibot-0.99.37/nejomibot/fortunes/politics +2965 -0
- nejomibot-0.99.37/nejomibot/fortunes/pratchett +3429 -0
- nejomibot-0.99.37/nejomibot/fortunes/riddles +563 -0
- nejomibot-0.99.37/nejomibot/fortunes/rules-of-acquisition +651 -0
- nejomibot-0.99.37/nejomibot/fortunes/science +3035 -0
- nejomibot-0.99.37/nejomibot/fortunes/shlomif-fav +3592 -0
- nejomibot-0.99.37/nejomibot/fortunes/songs-poems +7120 -0
- nejomibot-0.99.37/nejomibot/fortunes/sports +799 -0
- nejomibot-0.99.37/nejomibot/fortunes/startrek +829 -0
- nejomibot-0.99.37/nejomibot/fortunes/tao +1241 -0
- nejomibot-0.99.37/nejomibot/fortunes/the-x-files-taglines +82 -0
- nejomibot-0.99.37/nejomibot/fortunes/translate-me +61 -0
- nejomibot-0.99.37/nejomibot/fortunes/wisdom +1672 -0
- nejomibot-0.99.37/nejomibot/fortunes/work +2711 -0
- nejomibot-0.99.37/nejomibot/fortunes/zippy +1285 -0
- nejomibot-0.99.37/nejomibot/greeting.py +99 -0
- nejomibot-0.99.37/nejomibot/guide.py +48 -0
- nejomibot-0.99.37/nejomibot/health.py +452 -0
- nejomibot-0.99.37/nejomibot/healthcheck.py +42 -0
- nejomibot-0.99.37/nejomibot/help.py +682 -0
- nejomibot-0.99.37/nejomibot/holidays.py +996 -0
- nejomibot-0.99.37/nejomibot/i18n.py +326 -0
- nejomibot-0.99.37/nejomibot/incoming.py +291 -0
- nejomibot-0.99.37/nejomibot/info.py +141 -0
- nejomibot-0.99.37/nejomibot/languages.py +187 -0
- nejomibot-0.99.37/nejomibot/limits.py +32 -0
- nejomibot-0.99.37/nejomibot/lists.py +169 -0
- nejomibot-0.99.37/nejomibot/locale/da.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/da.po +3781 -0
- nejomibot-0.99.37/nejomibot/locale/da.toml +85 -0
- nejomibot-0.99.37/nejomibot/locale/de.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/de.po +3846 -0
- nejomibot-0.99.37/nejomibot/locale/de.toml +84 -0
- nejomibot-0.99.37/nejomibot/locale/el.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/el.po +3855 -0
- nejomibot-0.99.37/nejomibot/locale/el.toml +86 -0
- nejomibot-0.99.37/nejomibot/locale/es.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/es.po +3810 -0
- nejomibot-0.99.37/nejomibot/locale/es.toml +85 -0
- nejomibot-0.99.37/nejomibot/locale/fi.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/fi.po +3816 -0
- nejomibot-0.99.37/nejomibot/locale/fi.toml +85 -0
- nejomibot-0.99.37/nejomibot/locale/fr.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/fr.po +3879 -0
- nejomibot-0.99.37/nejomibot/locale/fr.toml +83 -0
- nejomibot-0.99.37/nejomibot/locale/messages.pot +3462 -0
- nejomibot-0.99.37/nejomibot/locale/nb.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/nb.po +3790 -0
- nejomibot-0.99.37/nejomibot/locale/nb.toml +85 -0
- nejomibot-0.99.37/nejomibot/locale/sv.mo +0 -0
- nejomibot-0.99.37/nejomibot/locale/sv.po +3778 -0
- nejomibot-0.99.37/nejomibot/locale/sv.toml +85 -0
- nejomibot-0.99.37/nejomibot/locale/template.toml +104 -0
- nejomibot-0.99.37/nejomibot/logo.png +0 -0
- nejomibot-0.99.37/nejomibot/mentions.py +71 -0
- nejomibot-0.99.37/nejomibot/messages.py +799 -0
- nejomibot-0.99.37/nejomibot/notices.py +447 -0
- nejomibot-0.99.37/nejomibot/onthisday.py +124 -0
- nejomibot-0.99.37/nejomibot/photos.py +1064 -0
- nejomibot-0.99.37/nejomibot/ping.py +22 -0
- nejomibot-0.99.37/nejomibot/profile.py +641 -0
- nejomibot-0.99.37/nejomibot/publicip.py +143 -0
- nejomibot-0.99.37/nejomibot/receipts.py +107 -0
- nejomibot-0.99.37/nejomibot/relay.py +182 -0
- nejomibot-0.99.37/nejomibot/reminders.py +341 -0
- nejomibot-0.99.37/nejomibot/rest.py +227 -0
- nejomibot-0.99.37/nejomibot/selfpromote.py +49 -0
- nejomibot-0.99.37/nejomibot/specials.py +751 -0
- nejomibot-0.99.37/nejomibot/status.py +414 -0
- nejomibot-0.99.37/nejomibot/styles.py +285 -0
- nejomibot-0.99.37/nejomibot/system.py +237 -0
- nejomibot-0.99.37/nejomibot/terminal.py +470 -0
- nejomibot-0.99.37/nejomibot/timers.py +955 -0
- nejomibot-0.99.37/nejomibot/timers_cli.py +222 -0
- nejomibot-0.99.37/nejomibot/today.py +126 -0
- nejomibot-0.99.37/nejomibot/weather.py +558 -0
- nejomibot-0.99.37/pyproject.toml +116 -0
- nejomibot-0.99.37/pyproject.toml.orig +105 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jodab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
The fortune libraries in nejomibot/fortunes, all but fortunes_svenska, come
|
|
2
|
+
unchanged from fortune-mod (https://github.com/shlomif/fortune-mod), under
|
|
3
|
+
its license, as its COPYING.txt gives it:
|
|
4
|
+
|
|
5
|
+
Copyright (c) 1986, 1993
|
|
6
|
+
The Regents of the University of California. All rights reserved.
|
|
7
|
+
|
|
8
|
+
This code is derived from software contributed to Berkeley by
|
|
9
|
+
Ken Arnold.
|
|
10
|
+
|
|
11
|
+
Redistribution and use in source and binary forms, with or without
|
|
12
|
+
modification, are permitted provided that the following conditions
|
|
13
|
+
are met:
|
|
14
|
+
1. Redistributions of source code must retain the above copyright
|
|
15
|
+
notice, this list of conditions and the following disclaimer.
|
|
16
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
17
|
+
notice, this list of conditions and the following disclaimer in the
|
|
18
|
+
documentation and/or other materials provided with the distribution.
|
|
19
|
+
3. All advertising materials mentioning features or use of this software
|
|
20
|
+
must display the following acknowledgement:
|
|
21
|
+
This product includes software developed by the University of
|
|
22
|
+
California, Berkeley and its contributors.
|
|
23
|
+
4. Neither the name of the University nor the names of its contributors
|
|
24
|
+
may be used to endorse or promote products derived from this software
|
|
25
|
+
without specific prior written permission.
|
|
26
|
+
|
|
27
|
+
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
28
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
29
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
30
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
31
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
32
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
33
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
34
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
35
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
36
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
37
|
+
SUCH DAMAGE.
|
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nejomibot
|
|
3
|
+
Version: 0.99.37
|
|
4
|
+
Summary: A Signal bot for a family or a group of friends
|
|
5
|
+
Keywords: signal,bot,signal-cli,self-hosted
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
License-File: LICENSES/fortune-mod.txt
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: No Input/Output (Daemon)
|
|
11
|
+
Classifier: Intended Audience :: System Administrators
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
15
|
+
Classifier: Topic :: Communications :: Chat
|
|
16
|
+
Requires-Dist: signalbot==2.2.0
|
|
17
|
+
Requires-Dist: aiohttp>=3.11
|
|
18
|
+
Requires-Dist: pillow>=13.0
|
|
19
|
+
Requires-Dist: pillow-heif>=1.8
|
|
20
|
+
Requires-Dist: pydantic-settings>=2.11
|
|
21
|
+
Requires-Dist: python-dateutil>=2.9
|
|
22
|
+
Requires-Dist: tzdata
|
|
23
|
+
Requires-Dist: segno>=1.6.6
|
|
24
|
+
Requires-Python: >=3.15
|
|
25
|
+
Project-URL: Source, https://github.com/jodab/nejomibot
|
|
26
|
+
Project-URL: Documentation, https://github.com/jodab/nejomibot#readme
|
|
27
|
+
Project-URL: Changelog, https://github.com/jodab/nejomibot/blob/main/CHANGELOG.md
|
|
28
|
+
Project-URL: Issues, https://github.com/jodab/nejomibot/issues
|
|
29
|
+
Project-URL: Container image, https://hub.docker.com/r/jodab/nejomibot
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
# nejomibot
|
|
35
|
+
|
|
36
|
+
[](https://github.com/jodab/nejomibot/actions/workflows/ci.yml)
|
|
37
|
+
[](https://github.com/jodab/nejomibot/releases)
|
|
38
|
+
|
|
39
|
+
> **Disclaimer:** This project began as a playground for teaching myself to
|
|
40
|
+
> make better use of Claude Code. Everything here was written by AI, under my
|
|
41
|
+
> guidance.
|
|
42
|
+
|
|
43
|
+
A self-hosted Signal bot for a family or a group of friends: a daily post
|
|
44
|
+
with the day's holidays, birthdays and name days, the weather and a photo
|
|
45
|
+
from your library; commands for photos, the weather, reminders and shared
|
|
46
|
+
lists; and timers that run any command on a schedule. The admins manage it
|
|
47
|
+
from Signal.
|
|
48
|
+
|
|
49
|
+
- **Photos** at random, by album, date or moment, or from this day in an
|
|
50
|
+
earlier year, with when and where they were taken, and optionally an age.
|
|
51
|
+
- **The day:** holidays in 35 countries, each group's birthdays and name
|
|
52
|
+
days, and the weather and forecast for any place.
|
|
53
|
+
- **Your own commands:** timers, and specials that combine texts and
|
|
54
|
+
commands.
|
|
55
|
+
- **Nine languages**, chosen per chat.
|
|
56
|
+
- **Private:** it answers only those you allow, takes admin commands only
|
|
57
|
+
in a direct chat, and by default logs no phone numbers or message text.
|
|
58
|
+
- **Reliable and light:** health checks with external pings, an outbox that
|
|
59
|
+
retries and outlasts restarts, and about 80 MB of memory.
|
|
60
|
+
|
|
61
|
+
It talks to Signal through [signalbot](https://pypi.org/project/signalbot/)
|
|
62
|
+
and [signal-cli-rest-api](https://github.com/bbernhard/signal-cli-rest-api)
|
|
63
|
+
in json-rpc mode. **Image:** `docker.io/jodab/nejomibot` or
|
|
64
|
+
`ghcr.io/jodab/nejomibot`, tagged `latest` and with each version.
|
|
65
|
+
**Package:** `uv tool install nejomibot`, from
|
|
66
|
+
[PyPI](https://pypi.org/project/nejomibot/), for the bot and its tools
|
|
67
|
+
without a container. **Source:**
|
|
68
|
+
[github.com/jodab/nejomibot](https://github.com/jodab/nejomibot).
|
|
69
|
+
|
|
70
|
+
## Getting started
|
|
71
|
+
|
|
72
|
+
You need a Linux host with Docker Compose or Podman (both containers take
|
|
73
|
+
about 450 MB of memory), an
|
|
74
|
+
[OpenWeatherMap API key](https://home.openweathermap.org/api_keys) (a new key
|
|
75
|
+
works within two hours), your photos (JPEG, PNG, GIF, WebP, AVIF or HEIC),
|
|
76
|
+
and a number for the bot that can receive a text message or a call and
|
|
77
|
+
isn't in use with Signal, as registering it signs it out everywhere else.
|
|
78
|
+
The bot can instead be
|
|
79
|
+
[linked to a phone](https://github.com/jodab/nejomibot#linking-to-a-phone).
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
mkdir -p ~/nejomibot/{data,photos,signal} && cd ~/nejomibot
|
|
83
|
+
curl -fsSLO https://raw.githubusercontent.com/jodab/nejomibot/main/deploy/compose.yaml
|
|
84
|
+
docker run --rm docker.io/jodab/nejomibot cat /app/config.example.toml > data/config.toml
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
In `data/config.toml`, set `account` (the bot's number, as `+46700000000`),
|
|
88
|
+
`admins` (yours), `openweather_api_key`, `weather_city`, `timezone` and
|
|
89
|
+
`language` (`en`, `da`, `de`, `el`, `es`, `fi`, `fr`, `nb` or `sv`); in
|
|
90
|
+
`compose.yaml`, the photos volume and `TZ`. Then:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
sudo chown -R 1000:1000 data signal && sudo chmod 700 data
|
|
94
|
+
docker compose up -d
|
|
95
|
+
docker compose exec nejomibot nejomibot-account setup
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Both containers run as UID 1000 (rootless Podman: `podman unshare chown`;
|
|
99
|
+
another user: `user:`, owning `data`), and the photos must be readable by
|
|
100
|
+
everyone. With SELinux, add `:Z` to the `data` and `signal` volumes and
|
|
101
|
+
`,z` to the photos volume.
|
|
102
|
+
|
|
103
|
+
The bot waits for its account. `nejomibot-account setup` registers the
|
|
104
|
+
number, with a code by text message or call, or links the bot to a phone. If
|
|
105
|
+
Signal asks for a captcha, solve one at
|
|
106
|
+
[signalcaptchas.org](https://signalcaptchas.org/registration/generate.html)
|
|
107
|
+
and paste the `signalcaptcha://` link behind **Open Signal** within a
|
|
108
|
+
minute. Give the bot a name, and a PIN, which keeps others from registering
|
|
109
|
+
its number. Then, from an admin's phone:
|
|
110
|
+
|
|
111
|
+
1. Send the bot `/help`. Commands may start with `.`, `!` or `/`.
|
|
112
|
+
2. Once the bot has replied, add it to a group (before that, Signal may only
|
|
113
|
+
invite it, which it doesn't accept), and allow the group from your direct
|
|
114
|
+
chat: `/allow Family`. People: `/allow +46700000002`.
|
|
115
|
+
3. `/chats` numbers the chats; `/timer add 08:00 1 /today; /weather;
|
|
116
|
+
/uniquephoto` posts to chat 1 daily, and `/timer run 1` tries it.
|
|
117
|
+
|
|
118
|
+
With Podman and systemd, use the
|
|
119
|
+
[Quadlets](https://github.com/jodab/nejomibot#podman-quadlets): they also
|
|
120
|
+
restart a container whose health check fails.
|
|
121
|
+
|
|
122
|
+
**No reply?** `admins` must hold your number, or if your Signal hides it
|
|
123
|
+
from everyone, your Signal ID, which `nejomibot-account identities` lists.
|
|
124
|
+
**A group is missing from `/chats`?** Signal only invited the bot: revoke
|
|
125
|
+
the invitation, and add it again.
|
|
126
|
+
|
|
127
|
+
## Commands
|
|
128
|
+
|
|
129
|
+
This page writes commands with `/`; the bot shows them with
|
|
130
|
+
`command_prefix`, `.` by default. `/help <command>` explains one, with
|
|
131
|
+
examples. Every language's names work in every chat (`/väder` is
|
|
132
|
+
`/weather`), and so do `/test` (`/status`), `/time` (`/info`), `/safety`
|
|
133
|
+
(`/contacts`) and `/day` (`/today`).
|
|
134
|
+
|
|
135
|
+
For everyone allowed:
|
|
136
|
+
|
|
137
|
+
| Command | Does |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `/photo [<album>] [<date>]` | A random photo, taken in a period (`2017-05`, `2017-05-14 15`) or the nearest, or nearest a moment (`2024-06-01 15:00`) |
|
|
140
|
+
| `/sphoto [<album>] [<date>]` | The same, without a caption |
|
|
141
|
+
| `/uniquephoto [<album>]` | A photo not yet sent in the current round |
|
|
142
|
+
| `/onthisday [<album>]` | A photo from this day, or within three days of it, in an earlier year |
|
|
143
|
+
| `/albums` | The albums, with their photos, years, birth dates and shortcuts |
|
|
144
|
+
| `/cache [<album>]` | The number and size of the photos, by type |
|
|
145
|
+
| `/today` | The date and time, the holidays, and in a group, its birthdays and name days |
|
|
146
|
+
| `/weather [<city>]` | The weather in `weather_city`, or a place such as `Springfield,MO,US` |
|
|
147
|
+
| `/forecast [<city>]` | Today's and tomorrow's weather, temperatures and chance of rain or snow |
|
|
148
|
+
| `/info` | The time in the `clocks`, and the `exchange_rate` |
|
|
149
|
+
| `/ping` | `pong!`, and how long the message took |
|
|
150
|
+
| `/fortune [<library>]` | A fortune; `all`, or `list` for the libraries |
|
|
151
|
+
| `/remind <when> <text>` | A reminder in the chat (`18:00`, `30m`, `fri 17:00`, `2026-12-24 15:00`); alone, the list; `remove <n>` |
|
|
152
|
+
| `/list [add <items>]` | The chat's list: `add milk, eggs`, `remove 2,5`, `clear` |
|
|
153
|
+
| `/birthdays` | The coming birthdays: the group's, or all, for an admin in a direct chat |
|
|
154
|
+
| `/namedays` | The coming name days, likewise |
|
|
155
|
+
| `/language [<language>]` | The chat's language, set by an admin in a group; `default` resets it |
|
|
156
|
+
| `/help [<command>]` | The commands you may use, or one command's page |
|
|
157
|
+
|
|
158
|
+
For admins, in a direct chat:
|
|
159
|
+
|
|
160
|
+
| Command | Does |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `/status` | The health checks, and the bot, account, network, container and host |
|
|
163
|
+
| `/album <album> [<birth date>]` | An album; sets its birth date (`-` removes it), or `shortcuts <names>` |
|
|
164
|
+
| `/today preview [<date>]` | What `/today` will say, in each group and a direct chat |
|
|
165
|
+
| `/contacts [<who>]` | Everyone the account knows, numbered; one person, with their safety number |
|
|
166
|
+
| `/contacts add <who> <name>` | Saves or renames a contact, also by number or `u:username` |
|
|
167
|
+
| `/trust [<who>] [<safety number>]` | The safety numbers; given one, marks it verified |
|
|
168
|
+
| `/allowed` | The allowed list |
|
|
169
|
+
| `/allow <who>` | Allows a person, or a group by name or ID |
|
|
170
|
+
| `/disallow <n>` | Takes someone off the allowed list |
|
|
171
|
+
| `/admins` | The admins |
|
|
172
|
+
| `/admin add <who> [<language>]` | Makes someone an admin; `/admin remove <n>` |
|
|
173
|
+
| `/profile` | The bot's name, About text, username and avatar |
|
|
174
|
+
| `/name <name>` | Sets the bot's name |
|
|
175
|
+
| `/about <text>` | Sets the About text, or `remove` |
|
|
176
|
+
| `/avatar` | Makes the picture sent with it the avatar, or `remove` |
|
|
177
|
+
| `/username <name>` | Sets the username, with a link to a chat with the bot, or `remove` |
|
|
178
|
+
| `/chats` | The chats that timers, `/msg` and `/run` post to, numbered |
|
|
179
|
+
| `/timers` | The timers |
|
|
180
|
+
| `/timer add <when> [<chats>] <commands>` | Adds a timer; `remove <n>`, `run <n>` |
|
|
181
|
+
| `/specials` | The specials |
|
|
182
|
+
| `/special add <name> <parts>` | Adds or changes a special; `shortcuts`, `everyone`, `admins`, `remove` |
|
|
183
|
+
| `/language <chats> <language>` | Sets the chats' language |
|
|
184
|
+
| `/msg <chats> <text>` | Posts a text to chats |
|
|
185
|
+
| `/run <chats> <commands>` | Posts commands' answers to chats |
|
|
186
|
+
| `/incoming [<n>,<n>]` | The latest direct messages from non-admins; forwards those given |
|
|
187
|
+
| `/birthday add <date> [<chats>] <who>` | Adds a birthday; `remove <n>` |
|
|
188
|
+
| `/nameday add <date> [<chats>] <who>` | Adds a name day; `remove <n>` |
|
|
189
|
+
| `/delete list` | The bot's latest messages, anywhere; `/delete <n>,<n>` deletes those |
|
|
190
|
+
| `/delivery` | How many received and read each of the bot's latest messages |
|
|
191
|
+
| `/selfpromote` | The bot's name and links, under its picture, to forward |
|
|
192
|
+
|
|
193
|
+
For admins, in any chat:
|
|
194
|
+
|
|
195
|
+
| Command | Does |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `/delete` | Deletes the bot's latest message in the chat, then the one before |
|
|
198
|
+
| `/mention all [<text>]` | Mentions everyone in the group |
|
|
199
|
+
|
|
200
|
+
`/avatar` needs attachments, which the examples turn off
|
|
201
|
+
(`JSON_RPC_IGNORE_ATTACHMENTS=true`); `podman exec -i nejomibot
|
|
202
|
+
nejomibot-chat -a - /avatar < picture.png` sets one from the host. The
|
|
203
|
+
`bot_*` settings fill in what `data/bot.txt`, the profile the bot keeps,
|
|
204
|
+
lacks.
|
|
205
|
+
|
|
206
|
+
## Who may use what
|
|
207
|
+
|
|
208
|
+
- **Admins:** those in `admins`, and those they add with `/admin add` (in
|
|
209
|
+
`data/admins.txt`). Admin commands work only in a direct chat, except
|
|
210
|
+
`/delete` and `/mention all`. Only the configuration's admins add and
|
|
211
|
+
remove admins and get the notices, and timers run as the first of them.
|
|
212
|
+
- **Everyone else** gets answers only if allowed: a person in a direct chat,
|
|
213
|
+
or everyone in an allowed group, in that group. Allowed people who send
|
|
214
|
+
something other than a command in a direct chat get a greeting, at most
|
|
215
|
+
once a day.
|
|
216
|
+
- **A limit:** the bot answers each person at most `command_limit` commands
|
|
217
|
+
(20) in `command_limit_minutes` (10); the admins, timers, `/run` and
|
|
218
|
+
specials aren't limited.
|
|
219
|
+
- **Edits:** an edited command runs in place of the original, within a day,
|
|
220
|
+
undoing what the original added or removed; posts and deletions aren't
|
|
221
|
+
repeated.
|
|
222
|
+
|
|
223
|
+
## Timers
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
/timer add 08:00 1,2 /today; /weather; /uniquephoto daily, to chats 1 and 2 of /chats
|
|
227
|
+
/timer add mon-fri 07:30 1 /weather
|
|
228
|
+
/timer add tomorrow 18:00 1 /photo once
|
|
229
|
+
/timer add every 2h /status without chats: to you
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`<when>` is times (`08:00,18:30`), days and a time (`mon-fri`, `sat,sun`,
|
|
233
|
+
`weekdays`, `weekends`), a date and a time (`2026-12-24 15:00`, `tomorrow
|
|
234
|
+
08:00`), or an interval of 10 minutes or more (`every 2h`), in `timezone`.
|
|
235
|
+
The commands, separated by `;`, run as the first admin's in a direct chat,
|
|
236
|
+
and every chat gets the same photo. Timers can't run what changes timers,
|
|
237
|
+
specials, birthdays, albums or access, `/msg`, `/run`, a chat's own commands
|
|
238
|
+
(`/remind`, `/list`, `/birthdays`, `/namedays`), `/delete` or `/contacts
|
|
239
|
+
add`. A run missed while the bot was down is made at its start, up to an
|
|
240
|
+
hour late. `nejomibot-timers` edits `data/timers.txt` from a shell.
|
|
241
|
+
|
|
242
|
+
## Specials
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
/special add /morning Good morning! /today + /weather; /uniquephoto
|
|
246
|
+
/special shortcuts /morning /gm
|
|
247
|
+
/special everyone /morning
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`;` or a line break starts a new message, a `+` on its own joins the parts
|
|
251
|
+
around it into one, and text before a command heads its answer, formatted as
|
|
252
|
+
given in Signal. A special has up to five parts and five shortcuts, can hold
|
|
253
|
+
any command a timer can run, but no special, and runs as whoever sends it.
|
|
254
|
+
`/special everyone` lets everyone allowed use it; the bot names any admin
|
|
255
|
+
commands in it, whose answers they would see.
|
|
256
|
+
|
|
257
|
+
## Photos
|
|
258
|
+
|
|
259
|
+
- Each folder directly in `photos_dir` is an album. `/album Alice shortcuts
|
|
260
|
+
/alice` makes `/alice` mean `/photo Alice`.
|
|
261
|
+
- `/uniquephoto` sends every photo once before it starts a new round, and
|
|
262
|
+
each album has its own round. The rounds are in `data/sent-photos.txt` and
|
|
263
|
+
`data/album-rounds.txt`: delete the file, or the album's lines, to start
|
|
264
|
+
over.
|
|
265
|
+
- When each photo was taken is read in the background at start, from new
|
|
266
|
+
and changed files, into `data/photo-index.txt` and memory (about 400 bytes
|
|
267
|
+
a photo; 47 s for 7,671 photos on a Raspberry Pi 4).
|
|
268
|
+
- Captions show the time in `timezone`. DateTimeOriginal counts as UTC when
|
|
269
|
+
DateTimeDigitized is a whole time zone away from it; otherwise its offset
|
|
270
|
+
tag applies, or else `photos_timezone`.
|
|
271
|
+
- With a birth date (`/album Alice 2019-06-15`, or `photos_birth_date` for
|
|
272
|
+
the photos in no album), captions show the age.
|
|
273
|
+
- HEIC/HEIF is sent as JPEG, unless `photos_heif = false` leaves it out;
|
|
274
|
+
[tools/tidy-photos.sh](https://github.com/jodab/nejomibot/blob/main/tools/tidy-photos.sh)
|
|
275
|
+
converts, renames and deduplicates a library.
|
|
276
|
+
- A GPS position adds a map link (`photos_map`).
|
|
277
|
+
|
|
278
|
+
## Birthdays, name days and holidays
|
|
279
|
+
|
|
280
|
+
`holidays = ["SE", "GR"]` adds those countries' public holidays and common
|
|
281
|
+
observances to `/today`, from AT, AU, BE, BG, CA, CH, CY, CZ, DE, DK, EE, ES,
|
|
282
|
+
FI, FR, GB, GR, HR, HU, IE, IS, IT, LT, LU, LV, MT, NL, NO, NZ, PL, PT, RO,
|
|
283
|
+
SE, SI, SK and US; only Sweden's and Greece's, and the days others share
|
|
284
|
+
with them, are translated. Birthdays and name days show in groups only: a
|
|
285
|
+
contact's (`/birthday add 1990-03-14 Alice`) in the groups they're in, and
|
|
286
|
+
others' (`/birthday add 1940-05-01 1 Grandma`) in the chats given, or in
|
|
287
|
+
every group.
|
|
288
|
+
|
|
289
|
+
## Languages
|
|
290
|
+
|
|
291
|
+
`language` sets the bot's language, and `/language sv` a chat's own. Each is
|
|
292
|
+
two files in
|
|
293
|
+
[nejomibot/locale](https://github.com/jodab/nejomibot/tree/main/nejomibot/locale):
|
|
294
|
+
`<code>.po`, the messages, and `<code>.toml`, its words for commands, times
|
|
295
|
+
and subcommands. `tools/translations.sh <code>` starts one, and after the
|
|
296
|
+
messages change, updates every `.po` (it needs GNU gettext).
|
|
297
|
+
|
|
298
|
+
## The bot from a terminal
|
|
299
|
+
|
|
300
|
+
The image's tools run with `podman exec` or `docker compose exec`; each has
|
|
301
|
+
`--help`, and a shell in the container starts with a guide to them (`help`):
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
podman exec -it nejomibot nejomibot-chat # as the first admin's direct chat
|
|
305
|
+
podman exec nejomibot nejomibot-chat /weather Helsinki # one message and its answers
|
|
306
|
+
podman exec -it nejomibot nejomibot-chat --to 1 # chat 1 of /chats, as the bot
|
|
307
|
+
podman exec -i nejomibot nejomibot-chat -a - "/msg 1 Look!" < photo.jpg
|
|
308
|
+
podman exec nejomibot nejomibot-chat --recent 20 --follow # messages received, in every chat
|
|
309
|
+
podman exec nejomibot nejomibot-timers # the timers
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
`--json` prints a JSON object a line, for scripts. `nejomibot-chat` reaches
|
|
313
|
+
the bot over an abstract Unix socket, which only its user and root may use.
|
|
314
|
+
|
|
315
|
+
## The Signal account
|
|
316
|
+
|
|
317
|
+
`nejomibot-account` registers or links the account, and manages its
|
|
318
|
+
profile, username, PIN, privacy, linked devices, safety numbers and rate
|
|
319
|
+
limits; `--dry-run` sends nothing.
|
|
320
|
+
|
|
321
|
+
```sh
|
|
322
|
+
podman exec -it nejomibot nejomibot-account # the status
|
|
323
|
+
podman exec -i nejomibot nejomibot-account profile --avatar - < logo.png
|
|
324
|
+
podman run --rm -it --no-healthcheck --network container:signal \
|
|
325
|
+
docker.io/jodab/nejomibot nejomibot-account setup # without the bot
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
When Signal rate-limits the bot, `nejomibot-account rate-limit --to <your
|
|
329
|
+
number>` leads you through the captcha that lifts the limit. Without the
|
|
330
|
+
image, `uvx --from nejomibot nejomibot-account --url HOST:PORT` runs it on
|
|
331
|
+
any machine that reaches signal-cli-rest-api.
|
|
332
|
+
|
|
333
|
+
### Linking to a phone
|
|
334
|
+
|
|
335
|
+
`nejomibot-account link` shows a QR code to scan in Signal on the phone
|
|
336
|
+
(**Settings > Linked devices**). The bot then needs no number, but what is
|
|
337
|
+
typed on the phone in a direct chat reaches it as if the other person had
|
|
338
|
+
sent it, as signalbot can't tell them apart, so it runs their commands, with
|
|
339
|
+
an admin's rights in a chat with an admin. The phone must come online every
|
|
340
|
+
30 days, or Signal unlinks the bot, and only the phone can set the PIN.
|
|
341
|
+
|
|
342
|
+
### An account without a phone number
|
|
343
|
+
|
|
344
|
+
Signal Android's beta registers accounts without a number, with a Signal
|
|
345
|
+
Login: an Account ID, which the bot calls the Signal ID, and a Recovery key.
|
|
346
|
+
Set `account` to the Signal ID, and give the bot a username, by which alone
|
|
347
|
+
people can find it. signal-cli-rest-api can link to such an account but not
|
|
348
|
+
restore it; signal-cli's `register --recovery-key` can, on
|
|
349
|
+
signal-cli-rest-api's data while it's stopped. People without a number go
|
|
350
|
+
by their Signal ID in `admins`, `/allow` and `/admin add`.
|
|
351
|
+
|
|
352
|
+
## Health checks
|
|
353
|
+
|
|
354
|
+
Every `healthcheck_minutes` (5), the bot checks signal-cli-rest-api (it
|
|
355
|
+
answers, in json-rpc mode, newer than 0.101), itself (no message has waited
|
|
356
|
+
15 minutes, and since the last round none was given up or failed with an
|
|
357
|
+
unknown outcome), Signal's servers (they list the linked devices), and
|
|
358
|
+
delivery (it hears receipts, and no three messages in a row have gone
|
|
359
|
+
unconfirmed for `unconfirmed_hours`, 12, with none confirmed since).
|
|
360
|
+
Failures are logged and lead `/status`; each round pings `healthcheck_url`,
|
|
361
|
+
such as a [healthchecks.io](https://healthchecks.io) URL, or its `/fail`,
|
|
362
|
+
with the results. The configuration's admins hear from the bot at each start
|
|
363
|
+
(`startup_notice`), at a rate limit, and when a safety number changes.
|
|
364
|
+
|
|
365
|
+
The image's health check is for liveness only: it never fails for Signal
|
|
366
|
+
or signal-cli-rest-api, which a restart wouldn't mend, nor while the bot
|
|
367
|
+
waits for its account. The Quadlets restart a container that fails it three
|
|
368
|
+
times running; Docker doesn't.
|
|
369
|
+
|
|
370
|
+
## Sending and Signal's rate limits
|
|
371
|
+
|
|
372
|
+
Each chat gets its messages in order. A send that surely failed is tried
|
|
373
|
+
again for `send_retry_hours` (3), marked late; a timeout isn't, as the
|
|
374
|
+
message may have arrived. Messages that have waited 30 seconds, and all
|
|
375
|
+
waiting at shutdown, are kept in `data/outbox` until sent. When Signal
|
|
376
|
+
rate-limits the bot (429), solving a captcha lifts the limit; meanwhile the
|
|
377
|
+
bot sends no receipts or typing, and tries only the oldest message, after 2
|
|
378
|
+
minutes, then twice as long each time, up to `rate_limit_retry_minutes`
|
|
379
|
+
(30), or soon after an admin's command.
|
|
380
|
+
|
|
381
|
+
## Which signal-cli-rest-api
|
|
382
|
+
|
|
383
|
+
The bot needs one newer than 0.101, the latest release, which crashes on
|
|
384
|
+
overlapping requests
|
|
385
|
+
([#885](https://github.com/bbernhard/signal-cli-rest-api/issues/885)) and
|
|
386
|
+
logs every message it receives
|
|
387
|
+
([#892](https://github.com/bbernhard/signal-cli-rest-api/issues/892)). Until
|
|
388
|
+
the next release, the examples in
|
|
389
|
+
[deploy/](https://github.com/jodab/nejomibot/tree/main/deploy) pin the CI
|
|
390
|
+
build `1792710189-ci` by digest; it reports its version as `unset`. Run it
|
|
391
|
+
in `json-rpc` mode: `json-rpc-native` has had bugs `json-rpc` hasn't, and
|
|
392
|
+
has no 32-bit ARM build. It has no authentication, so whoever reaches it
|
|
393
|
+
controls the account: the examples publish no port.
|
|
394
|
+
|
|
395
|
+
## Configuration
|
|
396
|
+
|
|
397
|
+
[config.example.toml](https://github.com/jodab/nejomibot/blob/main/config.example.toml)
|
|
398
|
+
(`/app/config.example.toml` in the image) describes every setting, aliases
|
|
399
|
+
included. The bot reads `NEJOMIBOT_CONFIG` (`/data/config.toml` in the
|
|
400
|
+
image), and `NEJOMIBOT_<SETTING>` variables override it (lists and tables as JSON).
|
|
401
|
+
An unknown or invalid setting stops the bot with its name.
|
|
402
|
+
|
|
403
|
+
`data_dir` (`/data`) must exist and belong to the bot's user. The bot
|
|
404
|
+
writes its files there atomically, readable by that user alone:
|
|
405
|
+
|
|
406
|
+
| File | Holds |
|
|
407
|
+
|---|---|
|
|
408
|
+
| `allowed.txt`, `admins.txt` | The allowed list, and the admins added |
|
|
409
|
+
| `timers.txt`, `specials.txt` | The timers and specials |
|
|
410
|
+
| `reminders.txt`, `lists.txt`, `languages.txt` | Each chat's reminders, list and language |
|
|
411
|
+
| `birthdays.txt`, `albums.txt` | Birthdays and name days; albums' birth dates and shortcuts |
|
|
412
|
+
| `sent-photos.txt`, `album-rounds.txt` | `/uniquephoto`'s rounds |
|
|
413
|
+
| `photo-index.txt` | When each photo was taken |
|
|
414
|
+
| `bot.txt` | The profile, with the avatar beside it |
|
|
415
|
+
| `outbox/`, `run.json` | Messages waiting; the last run's version and stop |
|
|
416
|
+
|
|
417
|
+
You may edit the allowed list, admins, timers, specials, reminders, lists,
|
|
418
|
+
birthdays, albums and languages by hand while the bot runs: the bot reads
|
|
419
|
+
them again when they change, and leaves comments and lines it can't read as
|
|
420
|
+
they are. `bot.txt` takes effect at the next start.
|
|
421
|
+
|
|
422
|
+
## Running it
|
|
423
|
+
|
|
424
|
+
The image runs as UID and GID 1000, or the user it's given, needs no
|
|
425
|
+
capabilities, and writes only to `/data`, which must belong to its user
|
|
426
|
+
(Podman's `:U`), and `/tmp`: the examples run it read-only, without new
|
|
427
|
+
privileges, with an init process. The photos go in `/photos`, read-only.
|
|
428
|
+
|
|
429
|
+
### Podman Quadlets
|
|
430
|
+
|
|
431
|
+
Copy [signal.container](https://github.com/jodab/nejomibot/blob/main/deploy/signal.container)
|
|
432
|
+
and [nejomibot.container](https://github.com/jodab/nejomibot/blob/main/deploy/nejomibot.container)
|
|
433
|
+
to `/etc/containers/systemd/` (rootless: `~/.config/containers/systemd/`,
|
|
434
|
+
`UserNS=keep-id:uid=1000,gid=1000` in place of `:U`, and `loginctl
|
|
435
|
+
enable-linger`), adjust the paths, and run `systemctl daemon-reload &&
|
|
436
|
+
systemctl start signal`, which starts the bot too. The bot shares
|
|
437
|
+
signal-cli-rest-api's network namespace, reaching it at `127.0.0.1:8080`
|
|
438
|
+
where nothing else can, and stops and starts with it. `signal.container`
|
|
439
|
+
checks signal-cli itself, where the image's own check only reaches the REST
|
|
440
|
+
layer.
|
|
441
|
+
|
|
442
|
+
### Updating
|
|
443
|
+
|
|
444
|
+
`docker compose pull && docker compose up -d`, or `podman pull
|
|
445
|
+
docker.io/jodab/nejomibot && systemctl restart nejomibot`. The
|
|
446
|
+
[changelog](https://github.com/jodab/nejomibot/blob/main/CHANGELOG.md) says
|
|
447
|
+
what to do, if anything, and a setting that must change stops the bot with
|
|
448
|
+
its name. A version tag in place of `latest` lets you choose when.
|
|
449
|
+
|
|
450
|
+
### Logs and verification
|
|
451
|
+
|
|
452
|
+
At `INFO`, the bot logs commands by name and the kind of chat, never phone
|
|
453
|
+
numbers, IDs or message text, which `log_level = "DEBUG"` adds; libraries
|
|
454
|
+
log at `WARNING`, where signalbot names whom a group message didn't reach.
|
|
455
|
+
Each release's images have signed build provenance;
|
|
456
|
+
[SECURITY.md](https://github.com/jodab/nejomibot/blob/main/SECURITY.md) has
|
|
457
|
+
more, and how to report a vulnerability:
|
|
458
|
+
|
|
459
|
+
```sh
|
|
460
|
+
gh attestation verify oci://docker.io/jodab/nejomibot:latest --repo jodab/nejomibot
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Development
|
|
464
|
+
|
|
465
|
+
```sh
|
|
466
|
+
uv sync # .venv: Python 3.15 and the locked dependencies
|
|
467
|
+
uv run pytest # the tests, against a stand-in signal-cli-rest-api
|
|
468
|
+
uv run ruff check && uv run ruff format --check && uv run pyright
|
|
469
|
+
tools/build-image.sh # the checks, then the amd64, arm64 and arm/v7 images
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
CI runs these, ShellCheck and an amd64 build on pushes to main and pull
|
|
473
|
+
requests; `tools/release.sh` releases what it passed.
|
|
474
|
+
[AGENTS.md](https://github.com/jodab/nejomibot/blob/main/AGENTS.md)
|
|
475
|
+
describes the design and the project's rules.
|
|
476
|
+
|
|
477
|
+
### Running from a checkout
|
|
478
|
+
|
|
479
|
+
The bot and its tools run on Python alone, without a container, and the
|
|
480
|
+
tests need nothing more. The bot needs a signal-cli-rest-api at
|
|
481
|
+
`signal_service`, such as the server's, published on its loopback
|
|
482
|
+
(`PublishPort=127.0.0.1:8080:8080` in `signal.container`) and reached with
|
|
483
|
+
`ssh -L 8080:127.0.0.1:8080 server`. Stop the server's bot first: two bots
|
|
484
|
+
on one account compete for its messages.
|
|
485
|
+
|
|
486
|
+
```sh
|
|
487
|
+
cp config.example.toml config.toml # account, admins, debug_group, ...
|
|
488
|
+
NEJOMIBOT_DEBUG=1 NEJOMIBOT_PHOTOS_DIR=~/Pictures uv run nejomibot
|
|
489
|
+
uv run nejomibot-chat /help # in another terminal, as the first admin
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Debug mode talks only to `debug_group` and the admins, and keeps its files
|
|
493
|
+
in a new temporary folder; for lasting ones, `mkdir -m 700 data` and set
|
|
494
|
+
`NEJOMIBOT_DATA_DIR=data`. Without uv, a Python 3.15 virtual environment
|
|
495
|
+
with `pip install -e . --group dev` (pip 25.1 or later) works too.
|
|
496
|
+
|
|
497
|
+
## License
|
|
498
|
+
|
|
499
|
+
MIT ([LICENSE](https://github.com/jodab/nejomibot/blob/main/LICENSE));
|
|
500
|
+
releases up to 0.99.14 were GPL-3.0-or-later, and remain so. The fortune
|
|
501
|
+
libraries but `fortunes_svenska`, the bot's own, come from
|
|
502
|
+
[fortune-mod](https://github.com/shlomif/fortune-mod), as Debian ships them,
|
|
503
|
+
under its BSD license
|
|
504
|
+
([LICENSES/fortune-mod.txt](https://github.com/jodab/nejomibot/blob/main/LICENSES/fortune-mod.txt)).
|