· 6 years ago · Jan 24, 2020, 08:30 PM
1import pkg_resources
2import platform
3import os
4from collections import defaultdict
5from inspect import cleandoc
6
7import asyncpg
8import discord
9from discord.ext import commands
10
11
12DISCORD_PUBLIC_VERSION = pkg_resources.get_distribution('discord.py').parsed_version.public
13PY_VERSION = platform.python_version()
14
15bot = commands.Bot(command_prefix=commands.when_mentioned_or('+/'))
16bot.chns = defaultdict(set)
17bot.msgs = set()
18
19
20class ChannelConv:
21 @classmethod
22 async def convert(cls, ctx, chn_id):
23 if chn_id != ctx.channel.id:
24 return bot.get_channel(int(chn_id))
25
26
27def getchn(chn_id: str) -> discord.TextChannel:
28 return bot.get_channel(int(chn_id))
29
30
31@bot.event
32async def on_ready():
33 #########################################
34 # THIS WORKS OUT-OF-THE-BOX ON HEROKU #
35 # IF NOT ON HEROKU REPLACE WITH YOUR #
36 # OWN INITIALIZATION PARAMETERS #
37 bot.pool = await asyncpg.create_pool(os.getenv('DATABASE_URL'))
38 # ALSO IF NOT ON HEROKU, MAKE SURE YOU #
39 # CREATE A PROPER ROLE/ACCT IN POSTGRES #
40 # FOR THE BOT (INSTEAD OF DOING IT IN #
41 # ONE SPOT LIKE BELOW) #
42 await bot.pool.execute('''CREATE TABLE IF NOT EXISTS chlinks (source BIGINT, dest BIGINT, PRIMARY KEY (source, dest))''')
43 #########################################
44 for i in await bot.pool.fetch('''SELECT source, dest FROM chlinks'''):
45 bot.chns[getchn(i['source'])].add(getchn(i['dest']))
46 print('oof')
47
48
49@bot.event
50async def on_message(msg):
51 st = 0
52 for i in bot.msgs.copy():
53 if i.content in msg.content or i.author.id != bot.user.id:
54 bot.msgs ^= {i}
55 st += i.content in msg.content
56 if st < 1:
57 if msg.channel in bot.chns:
58 for chn in bot.chns[msg.channel]:
59 try:
60 await chn.send(f'**<`{msg.guild.name}`/`#{msg.channel.name}`:{msg.author.nick or msg.author.name}>** {msg.content}')
61 bot.msgs.add(msg)
62 except Exception as e:
63 print(f'Error sending {msg.id} from {msg.channel.name} in {msg.guild.name} to {chn.name} in {chn.guild.name}. {e.__class__.__name__}: {e}')
64 await bot.process_commands(msg)
65
66
67@bot.event
68async def on_command_error(ctx, e):
69 await ctx.message.add_reaction('?')
70 if not isinstance(e, commands.errors.CommandNotFound):
71 await ctx.send(f'`{e.__class__.__name__}: {e}`')
72
73
74@bot.group()
75async def relay(ctx):
76 """
77 Relay commands between channels.
78 ``````apache
79 +/relay to [chnID chnID chnID ...]
80 # Send to this channel from the others #
81 ``````apache
82 +/relay from [chnID chnID chnID ...]
83 # Send from this channel to the others #
84 ``````apache
85 +/relay both [chnID chnID chnID ...]
86 # Send both ways between this channel and the others #
87 ``````
88 """
89 pass
90
91@relay.command('from')
92async def from_(ctx, *chns: ChannelConv):
93 """
94 Send to current channel from the given ones.
95 ``````apache
96 +/relay from [chnID chnID chnID ...]
97 """
98 async with bot.pool.acquire() as conn:
99 await conn.copy_records_to_table(
100 'chlinks',
101 records = list({(i.id, ctx.channel.id) for i in filter(None, chns)}),
102 columns = ['source', 'dest']
103 )
104 for chn in chns:
105 bot.chns[chn].add(ctx.channel)
106 await ctx.message.add_reaction('?')
107
108@relay.command()
109async def to(ctx, *chns: ChannelConv):
110 """
111 Send from current channel to the given ones.
112 ``````apache
113 +/relay to [chnID chnID chnID ...]
114 """
115 async with bot.pool.acquire() as conn:
116 await conn.copy_records_to_table(
117 'chlinks',
118 records = list({(ctx.channel.id, i.id) for i in filter(None, chns)}),
119 columns = ['source', 'dest']
120 )
121 bot.chns[ctx.channel].update(chns)
122 await ctx.message.add_reaction('?')
123
124@relay.command(aliases=['between', 'btwn'])
125async def both(ctx, *chns: ChannelConv):
126 """
127 Send between current channel and the given ones.
128 ``````apache
129 +/relay both [chnID chnID chnID ...]
130 """
131 recs = {(ctx.channel.id, i.id) for i in filter(None, chns)}
132 async with bot.pool.acquire() as conn:
133 await conn.copy_records_to_table(
134 'chlinks',
135 records = list(recs) + [i[::-1] for i in recs],
136 columns = ['source', 'dest']
137 )
138 bot.chns[ctx.channel].update(chns)
139 for chn in chns:
140 bot.chns[chn].add(ctx.channel)
141 await ctx.message.add_reaction('?')
142
143@bot.command()
144async def unlink(ctx, *chns: ChannelConv):
145 """
146 Unlink current channel from each given no matter their relation.
147 ``````apache
148 +/unlink [chnID chnID chnID ...]
149 """
150 bot.chns[ctx.channel] ^= set(chns) & bot.chns[ctx.channel]
151 for chn in chns:
152 if ctx.channel in bot.chns[chn]:
153 bot.chns[chn] ^= {ctx.channel}
154 await bot.pool.execute('''
155 DELETE FROM chlinks
156 WHERE (source = $1::bigint AND dest = $2::bigint)
157 OR (dest = $1::bigint AND source = $2::bigint)
158 ''',
159 ctx.channel.id,
160 chn.id
161 )
162 await ctx.message.add_reaction('?')
163
164@bot.command(aliases=['about'])
165async def info(ctx):
166 """About this bot."""
167 desc = f'''**```ini
168 {'[An inter-guild message-relaying demo bot]': ^45}```**
169 **Version numbers:**
170 python {PY_VERSION}
171 discord.py {DISCORD_PUBLIC_VERSION} (rewrite)
172
173 **Links:**
174 • [The original Reddit comment](https://reddit.com/comments/7yr4ur//dujbrym/)
175
176 **By Wright#9480**
177 ```FORTRAN
178 {f"'+/help' for command info": ^45}```
179 '''
180 await ctx.send(embed=discord.Embed(description=cleandoc(desc)))
181
182bot.run('TOKEN HERE')