-
Notifications
You must be signed in to change notification settings - Fork 3
/
discord.py
142 lines (117 loc) · 5.53 KB
/
discord.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# Itabashi - quick and dirty discord bot
# itabashi_discord.py: discord bot
# Developed by Antonizoon for the Bibliotheca Anonoma
import asyncio
import sys
import aiohttp
import discord
import websockets
from italib import backoff
loop = asyncio.get_event_loop()
class DiscordManager:
def __init__(self, logger, config, event_manager):
self.logger = logger
self.config = config
self.events = event_manager
self.dispatch_channels = [config['links'][name]['channels']['discord'] for name in config['links'] if 'discord' in config['links'][name]['channels']]
# simplifies down to a simple list of IRC chans -> Discord chans
self.channels = {
'irc': {},
}
for name in config['links']:
link = config['links'][name]['channels']
if 'discord' in link and 'irc' in link:
if link['irc'] not in self.channels['irc']:
self.channels['irc'][link['irc']] = []
if link['discord'] not in self.channels['irc'][link['irc']]:
self.channels['irc'][link['irc']].append(link['discord'])
self.discord_channels = {}
self.events.register('irc message', self.handle_irc_message)
self.events.register('irc action', self.handle_irc_action)
# extract values we use from config
email = config['modules']['discord']['email']
password = config['modules']['discord']['password']
# create a client
self.client = discord.Client()
# attach events
self.client.event(self.on_ready)
self.client.event(self.on_message)
# start the discord.py client
@asyncio.coroutine
def main_task():
# guided by https://gist.github.com/Hornwitser/93aceb86533ed3538b6f
# thanks Hornwitser!
retry = backoff.ExponentialBackoff()
# login to Discord
while True:
try:
yield from self.client.login(email, password)
except (discord.HTTPException, aiohttp.ClientError):
logging.exception("discord.py failed to login, waiting and retrying")
yield from asyncio.sleep(retry.delay())
else:
break
# connect to Discord and reconnect when necessary
while self.client.is_logged_in:
if self.client.is_closed:
self.client._closed.clear()
self.client.http.recreate()
try:
yield from self.client.connect()
except (discord.HTTPException, aiohttp.ClientError,
discord.GatewayNotFound, discord.ConnectionClosed,
websockets.InvalidHandshake,
websockets.WebSocketProtocolError) as e:
if isinstance(e, discord.ConnectionClosed) and e.code == 4004:
raise # Do not reconnect on authentication failure
logging.exception("discord.py disconnected, waiting and reconnecting")
yield from asyncio.sleep(retry.delay())
# actually start running the client
asyncio.async(main_task())
# retrieve channel objects we use to send messages
@asyncio.coroutine
def on_ready(self):
print('Discord -- Logged in as')
print(self.client.user.name)
print(self.client.user.id)
print('------')
# show all available channels and fill out our internal lists
print('Available Discord Channels:')
for channel in self.client.get_all_channels():
print('#%s (%s)' % (channel.name, channel.id))
if channel.name in self.dispatch_channels:
self.discord_channels[channel.name] = channel
print('------')
self.events.dispatch('discord ready', {})
# dispatching messages
@asyncio.coroutine
def on_message(self, message):
# for our watched channels only
self.logger.debug('discord: raw 1')
if message.channel.name.lower() in self.dispatch_channels:
self.logger.debug('discord: raw 2')
# dispatch all but our own messages
if str(message.author) != str(self.client.user):
self.logger.debug('discord: raw 3 - dispatching')
full_message = [message.clean_content]
if not full_message[0]:
full_message.pop(0)
for attachment in message.attachments:
full_message.append(attachment.get('url', 'No URL for attachment'))
info = {
'type': 'message',
'service': 'discord',
'channel': message.channel,
'source': message.author,
'message': ' '.join(full_message),
}
self.events.dispatch('discord message', info)
# receiving messages
def handle_irc_message(self, event):
for chan in self.channels['irc'].get(event['channel'].name, []):
assembled_message = '**<{}>** {}'.format(event['source'].nick, event['message'])
asyncio.async(self.client.send_message(self.discord_channels[chan], assembled_message))
def handle_irc_action(self, event):
for chan in self.channels['irc'].get(event['channel'].name, []):
assembled_message = '**\\* {}** {}'.format(event['source'].nick, event['message'])
asyncio.async(self.client.send_message(self.discord_channels[chan], assembled_message))