Compare commits

...

2 Commits

Author SHA1 Message Date
Ben Harris 8c2197a0d7 fix new ircrobots stuff 2022-05-09 16:42:31 -04:00
Ben Harris 570dba09a6 move to using config.py parser stuff 2022-05-09 15:34:00 -04:00
9 changed files with 132 additions and 84 deletions

6
.gitignore vendored
View File

@ -58,9 +58,5 @@ docs/_build/
# PyBuilder
target/
tildeclub.json
tildeteam.json
tildeverse.json
config.json
venv/
account.json
config.yaml

View File

@ -1,4 +0,0 @@
{
"username": "bensbots",
"password": "my super secret password"
}

16
config.example.yaml Normal file
View File

@ -0,0 +1,16 @@
server: localhost:6667
nickname: tooter
channel: "#meta"
sasl:
username: cloaks
password: hunter3
mastodon:
- name: tildeverse
client_id: 1234566
client_secret: beeeep
access_token: you do not want to know
api_base_url: https://tilde.zone
channels:
- '#club'

View File

@ -1,7 +0,0 @@
{
"channels": [],
"address": "127.0.0.1",
"port": 6667,
"tls": false,
"botnick": "tooter"
}

57
config.py Normal file
View File

@ -0,0 +1,57 @@
from dataclasses import dataclass
from mastodon import Mastodon
from typing import Tuple, Dict
import yaml
@dataclass
class Config(object):
server: Tuple[str, int, bool]
nickname: str
username: str
realname: str
channel: str
sasl: Tuple[str, str]
mastodon_accounts: Dict[str, Mastodon]
assigned_channels: Dict[str, str]
def load(filepath: str):
with open(filepath) as file:
config_yaml = yaml.safe_load(file.read())
nickname = config_yaml["nickname"]
server = config_yaml["server"]
hostname, port_s = server.split(":", 1)
tls = False
if port_s.startswith("+"):
tls = True
port_s = port_s.lstrip("+")
port = int(port_s)
accounts = {}
channels = {}
for acct in config_yaml["mastodon"]:
accounts[acct["name"]] = Mastodon(
client_id=acct["client_id"],
client_secret=acct["client_secret"],
access_token=acct["access_token"],
api_base_url=acct["api_base_url"],
)
if "channel" in acct:
channels[acct["channel"]] = acct["name"]
return Config(
(hostname, port, tls),
nickname,
config_yaml.get("username", nickname),
config_yaml.get("realname", nickname),
config_yaml["channel"],
(config_yaml["sasl"]["username"], config_yaml["sasl"]["password"]),
mastodon_accounts=accounts,
assigned_channels=channels,
)

View File

@ -1,3 +1,4 @@
Mastodon.py==1.5.1
emoji==1.7.0
ircrobots==0.6.1
PyYAML==6.0

View File

@ -1,7 +0,0 @@
{
"client_id": "myclientid",
"client_secret": "myclientsecret",
"access_token": "myaccesstoken",
"base_url": "https://tilde.zone",
"channel": "remove this key if you don't want to limit the bot"
}

117
tooter.py
View File

@ -1,80 +1,61 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
from mastodon import Mastodon
from irctokens import build, Line
from config import Config, load as config_load
from ircrobots import Bot as BaseBot
from ircrobots import Server as BaseServer
from ircrobots import ConnectionParams, SASLUserPass
from ircrobots import Server as BaseServer
from irctokens import build, Line
import asyncio
import emoji
import glob
import json
import os
import sys
HELP_TEXT = "helo i can send toots from irc: @tildeverse@tilde.zone - from @tildeteam from the #team channel)"
masto = {}
assigned_channels = {}
# load masto creds
for cred in glob.glob("tilde*.json"):
shortname, _ = os.path.splitext(cred)
with open(cred, "r") as f:
conf = json.load(f)
if "channel" in conf:
assigned_channels[conf["channel"]] = shortname
masto[shortname] = Mastodon(
client_id=conf["client_id"],
client_secret=conf["client_secret"],
access_token=conf["access_token"],
api_base_url=conf["base_url"],
)
if "tildeverse" not in masto:
print("you must populate tildeverse.json with mastodon credentials")
exit(1)
# do setup
with open("config.json", "r") as f:
config = json.load(f)
with open("account.json", "r") as f:
account = json.load(f)
channels = config["channels"]
if len(sys.argv) > 1:
for c in sys.argv[1:]:
channels.append("#" + c)
HELP_TEXT = "helo i can send toots from irc"
SOURCE_URL = "https://tildegit.org/ben/tooter"
def think(line):
def think(self, line):
chan = line.params[0]
cmd, *words = line.params[1].split(" ")
cmd = cmd.lower()[1:]
if cmd == "source":
return "https://tildegit.org/ben/tooter"
return SOURCE_URL
elif cmd in ["botlist", "toothelp"]:
return HELP_TEXT
elif cmd == "toot":
if len(words) >= 2:
status = emoji.emojize(" ".join(words[1:]), use_aliases=True)
status = emoji.emojize(" ".join(words), use_aliases=True)
author = line.tags.get("account", line.hostmask.nickname)
res = masto[
assigned_channels[chan] if chan in assigned_channels else "tildeverse"
].toot(f"{status}\n~{author}")
return "tooted! {}".format(res["url"])
if chan in self._config.assigned_channels:
account = self._config.mastodon_accounts[self._config.assigned_channels[chan]]
else:
account = self._config.mastodon_accounts.get("tildeverse")
if account:
res = account.toot(f"{status}\n~{author}")
if res:
return "tooted! {}".format(res["url"])
else:
return HELP_TEXT
class Server(BaseServer):
def __init__(self,
bot: BaseBot,
name: str,
cfg: Config):
super().__init__(bot, name)
self._config = cfg
async def line_send(self, line: Line):
print(f"{self.name} > {line.format()}")
print(f"> {line.format()}")
async def line_read(self, line: Line):
print(f"{self.name} < {line.format()}")
print(f"< {line.format()}")
if line.command == "001":
await self.send(build("JOIN", [",".join(channels)]))
await self.send(build("JOIN", [",".join(self._config.channel)]))
await self.send(build("MODE", [self.nickname, "+B"]))
if line.command == "INVITE":
@ -90,28 +71,44 @@ class Server(BaseServer):
and not ("batch" in line.tags and line.tags["batch"] == "1")
and line.params[1].startswith("!")
):
response = think(line)
response = think(self, line)
if response is not None:
await self.send(build("PRIVMSG", [line.params[0], response]))
class Bot(BaseBot):
def __init__(self, cfg: Config):
super().__init__()
self._config = cfg
def create_server(self, name: str):
return Server(self, name)
return Server(self, name, self._config)
async def main():
async def main(cfg: Config):
bot = Bot(cfg)
host, port, tls = cfg.server
sasl_user, sasl_pass = cfg.sasl
params = ConnectionParams(
config["botnick"],
host=config["address"],
port=config["port"],
tls=config["tls"],
sasl=SASLUserPass(account["username"], account["password"]),
cfg.nickname,
host,
port,
tls,
username=cfg.username,
realname=cfg.realname,
sasl=SASLUserPass(sasl_user, sasl_pass),
autojoin=[cfg.channel]
)
bot = Bot()
await bot.add_server("tilde", params)
await bot.add_server(host, params)
await bot.run()
if __name__ == "__main__":
asyncio.run(main())
parser = ArgumentParser()
parser.add_argument("config")
args = parser.parse_args()
config = config_load(args.config)
asyncio.run(main(config))

View File

@ -13,4 +13,3 @@ StartLimitBurst=3
[Install]
WantedBy=default.target