Compare commits
2 Commits
195e9015a8
...
8c2197a0d7
Author | SHA1 | Date |
---|---|---|
Ben Harris | 8c2197a0d7 | |
Ben Harris | 570dba09a6 |
|
@ -58,9 +58,5 @@ docs/_build/
|
|||
# PyBuilder
|
||||
target/
|
||||
|
||||
tildeclub.json
|
||||
tildeteam.json
|
||||
tildeverse.json
|
||||
config.json
|
||||
venv/
|
||||
account.json
|
||||
config.yaml
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"username": "bensbots",
|
||||
"password": "my super secret password"
|
||||
}
|
|
@ -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'
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"channels": [],
|
||||
"address": "127.0.0.1",
|
||||
"port": 6667,
|
||||
"tls": false,
|
||||
"botnick": "tooter"
|
||||
}
|
|
@ -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,
|
||||
)
|
|
@ -1,3 +1,4 @@
|
|||
Mastodon.py==1.5.1
|
||||
emoji==1.7.0
|
||||
ircrobots==0.6.1
|
||||
PyYAML==6.0
|
|
@ -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
117
tooter.py
|
@ -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))
|
||||
|
|
|
@ -13,4 +13,3 @@ StartLimitBurst=3
|
|||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
|
|
Loading…
Reference in New Issue