Skip to content

Commit a8d95be

Browse files
committed
feat: add dccbot console entry point, systemd user unit, install docs
dccbot/__main__.py exposes a main(argv) launcher so release wheels are directly runnable via the new "dccbot" console script; bot.py delegates to it while keeping its repo-relative config.json default. The shipped dccbot.service runs the bot as a systemd user unit. README gains an Installation section covering source checkout, release wheels, and the service setup.
1 parent ee7c887 commit a8d95be

5 files changed

Lines changed: 90 additions & 14 deletions

File tree

‎README.md‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,42 @@ Features
2727
* MD5 verification of completed transfers
2828
* incomplete file suffix support (auto-renamed on completion)
2929

30+
Installation
31+
------------
32+
33+
### From source
34+
35+
```bash
36+
git clone https://github.com/luni/dccbot.git
37+
cd dccbot
38+
uv sync
39+
cp config.json.sample config.json
40+
# edit config.json, then:
41+
uv run python bot.py
42+
```
43+
44+
### From a release
45+
46+
Each release ships a wheel and a source distribution on the
47+
[releases page](https://github.com/luni/dccbot/releases):
48+
49+
```bash
50+
uv tool install ./dccbot-0.4.0-py3-none-any.whl # or: pipx install / pip install
51+
dccbot --config /path/to/config.json
52+
```
53+
54+
### Running as a systemd user service
55+
56+
Copy `dccbot.service` to `~/.config/systemd/user/`, adjust the paths in
57+
`ExecStart` to your install, then:
58+
59+
```bash
60+
systemctl --user daemon-reload
61+
systemctl --user enable --now dccbot
62+
# optional: keep it running after logout
63+
loginctl enable-linger "$USER"
64+
```
65+
3066
Usage
3167
-----
3268

‎bot.py‎

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
#!env python3
22

3-
import logging
43
import os
54

6-
from aiohttp import web
7-
8-
from dccbot.app import create_app
9-
10-
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s]%(message)s")
5+
from dccbot.__main__ import main
116

127
if __name__ == "__main__":
13-
app = create_app(os.path.join(os.path.dirname(__file__), "config.json"))
14-
# bind_addr/bind_port have already been normalized to host/port by
15-
# IRCBotManager._normalize_http_config.
16-
http_config = app["bot_manager"].config.get("http", {})
17-
if http_config.get("socket"):
18-
web.run_app(app, path=http_config["socket"])
19-
else:
20-
web.run_app(app, host=http_config.get("host", "127.0.0.1"), port=http_config.get("port", 8080))
8+
main(["--config", os.path.join(os.path.dirname(__file__), "config.json")])

‎dccbot.service‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[Unit]
2+
Description=dccbot IRC XDCC download bot
3+
Documentation=https://github.com/luni/dccbot
4+
After=network-online.target
5+
Wants=network-online.target
6+
7+
[Service]
8+
Type=simple
9+
# Installed from a release wheel (pipx/uv tool install/pip):
10+
ExecStart=%h/.local/bin/dccbot --config %h/.config/dccbot/config.json
11+
# Running from a source checkout instead? Use its virtualenv:
12+
# ExecStart=%h/dccbot/.venv/bin/python %h/dccbot/bot.py
13+
Restart=on-failure
14+
RestartSec=10
15+
16+
[Install]
17+
WantedBy=default.target

‎dccbot/__main__.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Command line entry point for dccbot."""
2+
3+
import argparse
4+
import logging
5+
import os
6+
7+
from aiohttp import web
8+
9+
from dccbot.app import create_app
10+
11+
12+
def main(argv: list[str] | None = None) -> None:
13+
"""Start the dccbot aiohttp application."""
14+
parser = argparse.ArgumentParser(prog="dccbot", description="IRC XDCC download bot")
15+
parser.add_argument("--config", default="config.json", help="path to the configuration file (default: ./config.json)")
16+
args = parser.parse_args(argv)
17+
18+
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s]%(message)s")
19+
20+
app = create_app(os.path.abspath(args.config))
21+
# bind_addr/bind_port have already been normalized to host/port by
22+
# IRCBotManager._normalize_http_config.
23+
http_config = app["bot_manager"].config.get("http", {})
24+
if http_config.get("socket"):
25+
web.run_app(app, path=http_config["socket"])
26+
else:
27+
web.run_app(app, host=http_config.get("host", "127.0.0.1"), port=http_config.get("port", 8080))
28+
29+
30+
if __name__ == "__main__":
31+
main()

‎pyproject.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ description = "An IRC XDCC download bot written in python with aiohttp and ircpy
1212
readme = "README.md"
1313
license = {text = "MIT License"}
1414
requires-python = ">=3.10"
15+
1516
dependencies = [
1617
"aiohttp>=3.14.1",
1718
"irc>=20.5.0",
@@ -23,6 +24,9 @@ dependencies = [
2324
"cryptography>=43.0.0,<51.0.0",
2425
]
2526

27+
[project.scripts]
28+
dccbot = "dccbot.__main__:main"
29+
2630
[dependency-groups]
2731
dev = [
2832
"pytest-aiohttp>=1.1.0",

0 commit comments

Comments
 (0)