Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/config.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"cmd_prefix": "!",
"output_msg": "<:username:> :message:",
"output_cmd": "CMD by :username:",
"log_events": true
"log_events": true,
"mentions": false
},
"formatting": {
"irc_to_discord": false,
Expand Down
2 changes: 1 addition & 1 deletion discord-irc-sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
config_file = sys.argv[1] if len(sys.argv) == 2 else None
settings = utils.read_config(config_file)

settings['irc']['master_bot'] = True
settings["irc"]["master_bot"] = True
discord_client = DiscordClient(settings)
irc_client = IRCClient(settings)

Expand Down
220 changes: 106 additions & 114 deletions src/discordclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,60 @@
import re

import discord
import discord.utils

from . import utils
from .formatting import D2IFormatter
from .notification import Notification

logger = utils.get_logger(__name__)


class DiscordClient(discord.Client):
def __init__(self, configuration):
self.h_token = configuration['discord']['token']
self.h_server_id = configuration['discord']['server']
self.h_channel_id = configuration['discord']['channel']
self.h_owner = configuration['discord']["owner"]
self.h_cmd_prefix = configuration['discord']["cmd_prefix"]
self.h_output_msg = configuration['discord']["output_msg"]
self.h_output_cmd = configuration['discord']["output_cmd"]
self.h_log_events = configuration['discord']["log_events"]
self.h_formatter = D2IFormatter(configuration)
self.h_channel = None
self.h_irc = None
self.users_bots = {}
self.callback = {
'notification' : {
'nick_in_use' :self.unimplemented,
'bot_created' :self.on_bot_created,
'bot_ch_nick' :self.on_bot_change_nick,
'bot_killed' :self.on_bot_killed},
'message' : {
'default' :self.h_send_message,
'command' :self.h_send_command,
'raw' :self.h_send_raw_message},
'quit' : {
'default' :self.on_irc_quit},
'kick' : {
'default' :self.on_irc_kick},
'part' : {
'default' :self.on_irc_part},
'join' : {
'default' :self.on_irc_join},

self.h_token = configuration["discord"]["token"]
self.h_server_id = configuration["discord"]["server"]
self.h_channel_id = configuration["discord"]["channel"]
self.h_owner = configuration["discord"]["owner"]
self.h_cmd_prefix = configuration["discord"]["cmd_prefix"]
self.h_output_msg = configuration["discord"]["output_msg"]
self.h_output_cmd = configuration["discord"]["output_cmd"]
self.h_log_events = configuration["discord"]["log_events"]
self.h_mentions = configuration["discord"]["mentions"]
self.h_formatter = D2IFormatter(configuration)
self.h_channel = None
self.h_irc = None
self.users_bots = {}
self.callback = {
"notification": {
"nick_in_use": self.unimplemented,
"bot_created": self.on_bot_created,
"bot_ch_nick": self.on_bot_change_nick,
"bot_killed": self.on_bot_killed,
},
"message": {
"default": self.h_send_message,
"command": self.h_send_command,
"raw": self.h_send_raw_message,
},
"quit": {"default": self.on_irc_quit},
"kick": {"default": self.on_irc_kick},
"part": {"default": self.on_irc_part},
"join": {"default": self.on_irc_join},
}
intents = discord.Intents.default()
intents.typing = False
intents.presences = False
intents.message_content = True
intents.members = self.h_mentions
super().__init__(intents=intents)

def unimplemented(self, notif):
print(notif)
print('This feature is not yet implemented')
logger.info(notif)
logger.info("This feature is not yet implemented")

def on_irc_alreadyinuse(self, notif):
del(self.users_bots[notif.src_user])
del self.users_bots[notif.src_user]

def on_irc_quit(self, notif):
pass
Expand All @@ -81,61 +84,61 @@ def set_irc(self, irc):
self.h_irc = irc

async def on_ready(self):
print("[Discord] Logged in as:")
print("[Discord] " + self.user.name)
logger.info("[Discord] Logged in as:")
logger.info("[Discord] " + self.user.name)

if len(self.guilds) == 0:
print("[Discord] Bot is not yet in any server.")
logger.info("[Discord] Bot is not yet in any server.")
await self.close()
return

if self.h_server_id == "":
print("[Discord] You have not configured a server to use in settings.json")
print("[Discord] Please put one of the server IDs listed below in settings.json")
logger.info("[Discord] You have not configured a server to use in settings.json")
logger.info("[Discord] Please put one of the server IDs listed below in settings.json")

for server in self.guilds:
print("[Discord] %s: %s" % (server.name, server.id))
logger.info("[Discord] %s: %s" % (server.name, server.id))

await self.close()
return

findServer = [x for x in self.guilds if x.id == self.h_server_id]
if not len(findServer):
print("[Discord] No server could be found with the specified id: " + self.h_server_id)
print("[Discord] Available servers:")
logger.info("[Discord] No server could be found with the specified id: " + self.h_server_id)
logger.info("[Discord] Available servers:")

for server in self.guilds:
print("[Discord] %s: %s" % (server.name, server.id))
logger.info("[Discord] %s: %s" % (server.name, server.id))

await self.close()
return

server = findServer[0]

if self.h_channel_id == "":
print("[Discord] You have not configured a channel to use in settings.json")
print("[Discord] Please put one of the channel IDs listed below in settings.json")
logger.info("[Discord] You have not configured a channel to use in settings.json")
logger.info("[Discord] Please put one of the channel IDs listed below in settings.json")

for channel in server.channels:
if channel.type == discord.ChannelType.text:
print("[Discord] %s: %s" % (channel.name, channel.id))
logger.info("[Discord] %s: %s" % (channel.name, channel.id))

await self.close()
return

find_channel = [x for x in server.text_channels if x.id == self.h_channel_id]
if not len(find_channel):
print("[Discord] No channel could be found with the specified id: " + self.h_server_id)
print("[Discord] Note that you can only use text channels.")
print("[Discord] Available channels:")
logger.info("[Discord] No channel could be found with the specified id: " + self.h_server_id)
logger.info("[Discord] Note that you can only use text channels.")
logger.info("[Discord] Available channels:")

for channel in server.channels:
if channel.type == discord.ChannelType.text:
print("[Discord] %s: %s" % (channel.name, channel.id))
logger.info("[Discord] %s: %s" % (channel.name, channel.id))

await self.close()
return

self.h_channel = find_channel[0]

async def on_message(self, message):
Expand All @@ -152,10 +155,8 @@ async def on_message(self, message):
return

username = self.get_nick(message.author)

content = message.clean_content


"""
Admin commands
"""
Expand All @@ -173,8 +174,8 @@ async def on_message(self, message):
"""
Send to IRC
"""
for c in content.split('\n'):
print("[Discord] <%s> %s" % (username, c))
for c in content.split("\n"):
logger.info("[Discord] <%s> %s" % (username, c))
self.h_send_to_irc(username, self.h_format_text(c.strip()))

async def on_member_join(self, member):
Expand All @@ -191,11 +192,8 @@ async def on_member_join(self, member):
return

username = self.get_nick(member)

message = self.h_format_text("*%s* has joined the server" % username)

self.h_send_notification('message', 'raw', message, username)

self.h_send_notification("message", "raw", message, username)

async def on_member_remove(self, member):
"""
Expand All @@ -211,10 +209,8 @@ async def on_member_remove(self, member):
return

username = self.get_nick(member)

message = self.h_format_text("*%s* has quit the server" % username)

self.h_send_notification('message', 'raw', message, username)
self.h_send_notification("message", "raw", message, username)

async def on_member_update(self, member_before, member_after):
"""
Expand All @@ -232,10 +228,9 @@ async def on_member_update(self, member_before, member_after):
if username_a != username_b:
if not self.h_log_events:
message = self.h_format_text("*%s* is now known as *%s*" % (username_b, username_a))
self.h_send_notification('message', 'raw', message, username_b)
self.h_send_notification('user', 'change_nick', None, username_b, username_a)
self.h_send_notification("message", "raw", message, username_b)
self.h_send_notification("user", "change_nick", None, username_b, username_a)


username = username_b

"""
Expand All @@ -244,19 +239,18 @@ async def on_member_update(self, member_before, member_after):
if member_before.status == discord.Status.offline and member_after.status != discord.Status.offline:
if not self.h_log_events:
message = self.h_format_text("*%s* has joined" % (username,))
self.h_send_notification('message', 'raw', message, None)
self.h_send_notification("message", "raw", message, None)

# spawn a new IRC user bot
self.h_send_notification('user', 'join', None, username)

self.h_send_notification("user", "join", None, username)

if member_before.status != discord.Status.offline and member_after.status == discord.Status.offline:
if not self.h_log_events:
message = self.h_format_text("*%s* has quit" % (username,))
self.h_send_notification('message', 'raw', message, None)
self.h_send_notification("message", "raw", message, None)

# kill the IRC user bot
self.h_send_notification('user', 'quit', None, username)
self.h_send_notification("user", "quit", None, username)

def get_nick(self, member):
if member.nick is not None:
Expand All @@ -265,52 +259,51 @@ def get_nick(self, member):

def hl_nicks(self, message):
for client in self.get_all_members():
nick = ''.join("[" + c.replace("\\","\\\\") + "]" for c in self.get_nick(client))
message = re.sub(r'\b(' + nick + r')\b', client.mention, message, flags=re.IGNORECASE)
nick = "".join("[" + c.replace("\\", "\\\\") + "]" for c in self.get_nick(client))
message = re.sub(r"\b(" + nick + r")\b", client.mention, message, flags=re.IGNORECASE)
return message

def de_hl_nick(self, nick):
special_chars = {
'a':'а',
'A':'А',
'B':'В',
'S':'Ѕ',
'M':'М',
'O':'О',
'o':'о',
'p':'р',
'P':'Р',
'c':'с',
'y':'у',
'x':'х',
's':'ѕ',
'i':'і',
'j':'ј',
'e':'е',
'0':'ѳ',
'h':'Һ'
"a": "а",
"A": "А",
"B": "В",
"S": "Ѕ",
"M": "М",
"O": "О",
"o": "о",
"p": "р",
"P": "Р",
"c": "с",
"y": "у",
"x": "х",
"s": "ѕ",
"i": "і",
"j": "ј",
"e": "е",
"0": "ѳ",
"h": "Һ",
}
output = [c for c in nick]
for key, letter in enumerate(nick):
if letter in special_chars:
output[key] = special_chars[letter]
return ''.join(output)
return "".join(output)
return nick[0] + "'" + nick[1:]


def h_raw_send_to_irc(self, message):
print("[Discord] %s" % message)
self.h_send_notification('message', 'raw', message, None)
logger.info("[Discord] %s" % message)
self.h_send_notification("message", "raw", message, None)

def h_send_to_irc(self, username, content):
if username not in self.users_bots.keys():
content = self.h_output_msg.replace(":username:", username).replace(":message:", content)

if content.startswith(self.h_cmd_prefix):
self.h_send_notification('message', 'raw', self.h_output_cmd.replace(":username:", username))
self.h_send_notification('message', 'raw', content, username)
self.h_send_notification("message", "raw", self.h_output_cmd.replace(":username:", username))
self.h_send_notification("message", "raw", content, username)
else:
self.h_send_notification('message', None, content, username)
self.h_send_notification("message", None, content, username)

# notification system

Expand All @@ -326,14 +319,13 @@ def h_send_notification(self, n_type, subtype=None, content=None, username=None,
def get_notification(self, notif):
self.callback[notif.n_type][notif.subtype](notif)


# discord sending

def h_send_message(self, notif):
user = '' if notif.src_user is None else '<'+notif.src_user+'> '
user = "" if notif.src_user is None else "<" + notif.src_user + "> "
if notif.src_user == self.user or notif.src_user in self.users_bots.keys():
return
asyncio.run_coroutine_threadsafe(self.h_send_message_async(user+notif.message), self.loop)
asyncio.run_coroutine_threadsafe(self.h_send_message_async(user + notif.message), self.loop)

def h_send_raw_message(self, notif):
asyncio.run_coroutine_threadsafe(self.h_send_message_async(notif.message), self.loop)
Expand Down
Loading