forked from DigitalPulseSoftware/NotaBot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot_utility.lua
217 lines (174 loc) · 5 KB
/
bot_utility.lua
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
-- Copyright (C) 2018 Jérôme Leclercq
-- This file is part of the "Not a Bot" application
-- For conditions of distribution and use, see copyright notice in LICENSE
local fs = require("coro-fs")
local json = require("json")
local path = require("path")
local discordDomains = {
-- no subdomain
["discord.com"] = true,
["discordapp.com"] = true,
-- public test build
["ptb.discord.com"] = true,
["ptb.discordapp.com"] = true,
-- canary
["canary.discord.com"] = true,
["canary.discordapp.com"] = true,
}
function Bot:DecodeChannel(guild, message)
assert(guild)
assert(message)
local channelId = message:match("<#(%d+)>")
if (not channelId) then
return nil, "Invalid channel id"
end
local channel = guild:getChannel(channelId)
if (not channel) then
return nil, "This channel is not part of this guild"
end
return channel
end
function Bot:DecodeEmoji(guild, message)
assert(guild)
assert(message)
local emojiId = message:match("<a?:[%w_]+:(%d+)>")
if (emojiId) then
-- Custom emoji
local emoji = self:GetEmojiData(guild, emojiId)
if (not emoji) then
return nil, "Failed to get emoji, maybe this is a global emoji?"
end
return emoji
else
-- Discord emoji
local emoji = self:GetEmojiData(guild, message)
if (not emoji) then
return nil, "Invalid emoji"
end
return emoji
end
end
function Bot:DecodeMember(guild, message)
assert(guild)
assert(message)
local userId = message:match("<@!?(%d+)>")
if (not userId) then
return nil, "Invalid user id"
end
local member = guild:getMember(userId)
if (not member) then
return nil, "This user is not part of this guild"
end
return member
end
function Bot:DecodeMessage(message, ignoreEscaped)
assert(message)
local e1, domain, guildId, channelId, messageId, e2 = message:match("(<?)https?://([%w%.]+)/channels/(%d+)/(%d+)/(%d+)(>?)")
if (not e1 or not discordDomains[domain]) then
return nil, "Invalid link"
end
if (ignoreEscaped and e1 == "<" and e2 == ">") then
return nil, "Escaped link"
end
local guild = self.Client:getGuild(guildId)
if (not guild) then
return nil, "Unavailable guild"
end
local channel = guild:getChannel(channelId)
if (not channel) then
return nil, "Unavailable channel"
end
local message = channel:getMessage(messageId)
if (not message) then
return nil, "Message not found"
end
return message
end
function Bot:DecodeRole(guild, message)
assert(guild)
assert(message)
local roleId = message:match("<@&(%d+)>")
if (not roleId) then
roleId = message:match("(%d+)")
if (not roleId) then
return nil, "Invalid role"
end
end
local role = guild:getRole(roleId)
if (not role) then
return nil, "This role is not part of this guild"
end
return role
end
function Bot:DecodeUser(message)
assert(message)
local userId = message:match("<@!?(%d+)>")
if (not userId) then
return nil, "Invalid user id"
end
local user = self.Client:getUser(userId)
if (not user) then
return nil, "Invalid user (maybe this account was deleted?)"
end
return user
end
function Bot:GenerateMessageLink(message)
local guildId = message.guild and message.guild.id or "@me"
return string.format("https://discordapp.com/channels/%s/%s/%s", guildId, message.channel.id, message.id)
end
local ehandler = function(err)
return debug.traceback(tostring(err))
end
function Bot:ProtectedCall(context, func, ...)
local success, a, b, c, d, e, f = xpcall(func, ehandler, ...)
if (not success) then
local err = string.format("%s failed: %s", context, a)
self.Client:warning(err)
return false, err
end
return success, a, b, c, d, e, f
end
-- Serialization/unserialization
function Bot:SerializeToFile(filepath, data, pretty)
local dirname = path.dirname(filepath)
if (dirname ~= ".") then
local success, err = fs.mkdirp(dirname)
if (not success) then
return false, string.format("Failed to create directory %s: %s", filepath, err)
end
end
local outputFile, err = io.open(filepath, "w+")
if (not outputFile) then
return false, string.format("Failed to open %s: %s", filepath, err)
end
local encoderState = {}
if (pretty) then
encoderState.indent = true
end
local success, serializedDataOrErr = pcall(json.encode, data, encoderState)
if (not success) then
return false, string.format("Failed to serialize data: %s", serializedDataOrErr)
end
local success, err = outputFile:write(serializedDataOrErr)
if (not success) then
return false, string.format("Failed to write data to file %s: %s", filepath, err)
end
outputFile:close()
return true
end
function Bot:UnserializeFromFile(filepath)
local saveFile, err = io.open(filepath, "r")
if (not saveFile) then
return nil, string.format("Failed to open %s: %s", filepath, err)
end
local content, err = saveFile:read("*a")
if (not content) then
return nil, string.format("Failed to read %s content: %s", filepath, err)
end
saveFile:close()
local success, contentOrErr = pcall(json.decode, content)
if (not success) then
return nil, string.format("Failed to unserialize %s content: %s", filepath, contentOrErr)
end
return contentOrErr
end