184 lines
4.9 KiB
Crystal
184 lines
4.9 KiB
Crystal
require "discordcr"
|
|
require "json"
|
|
require "uuid"
|
|
require "./responses"
|
|
require "./reactions"
|
|
|
|
token = ENV["DISCORD_BOT_TOKEN"]? || raise "Missing DISCORD_BOT_TOKEN env variable"
|
|
|
|
puts("Bot #{token}")
|
|
|
|
client = Discord::Client.new(
|
|
token: "Bot #{token}",
|
|
client_id: 1475668463363293398_u64
|
|
)
|
|
|
|
DICT_FILE = "./dictionary.json"
|
|
USER_LIMIT = 100
|
|
|
|
def load_dict
|
|
if File.exists?(DICT_FILE)
|
|
JSON.parse(File.read(DICT_FILE)).as_h.transform_values do |defs|
|
|
defs.as_a.map do |d|
|
|
{
|
|
"id" => d["id"].as_s,
|
|
"definition" => d["definition"].as_s,
|
|
"author" => d["author"].as_s,
|
|
"upvotes" => d["upvotes"].as_i,
|
|
"downvotes" => d["downvotes"].as_i
|
|
}
|
|
end
|
|
end
|
|
else
|
|
{} of String => Array(Hash(String, String|Int32))
|
|
end
|
|
end
|
|
|
|
def save_dict(dict)
|
|
File.write(DICT_FILE, dict.to_json)
|
|
end
|
|
|
|
dictionary = load_dict
|
|
|
|
def user_def_count(dict, username)
|
|
dict.values.flatten.count { |d| d["author"] == username }
|
|
end
|
|
|
|
client.on_message_create do |payload|
|
|
content = payload.content
|
|
args = content.split(" ", 3)
|
|
command = args[0]?
|
|
user = payload.author.username
|
|
|
|
if payload.author.bot
|
|
next
|
|
end
|
|
|
|
case command
|
|
when "!add"
|
|
word = args[1]?
|
|
definition = args[2]?
|
|
|
|
if word.nil? || definition.nil?
|
|
client.create_message(payload.channel_id, "usage: !add <word> <definition>")
|
|
next
|
|
end
|
|
|
|
if user_def_count(dictionary, user) >= USER_LIMIT
|
|
client.create_message(payload.channel_id, "#{user}, you reached the limit of #{USER_LIMIT} definitions.")
|
|
next
|
|
end
|
|
|
|
dictionary[word] ||= [] of Hash(String, String | Int32)
|
|
dictionary[word] << {
|
|
"id" => UUID.random.to_s,
|
|
"definition" => definition,
|
|
"author" => user,
|
|
"upvotes" => 0,
|
|
"downvotes" => 0
|
|
}
|
|
|
|
save_dict(dictionary)
|
|
client.create_message(payload.channel_id, "added definition for **#{word}** by #{user}.")
|
|
|
|
when "!define"
|
|
word = args[1]?
|
|
if word.nil?
|
|
client.create_message(payload.channel_id, "usage: !define <word>")
|
|
next
|
|
end
|
|
|
|
defs = dictionary[word]?
|
|
if defs
|
|
text = defs.map_with_index do |d, i|
|
|
"#{i+1}. #{d["definition"]} (by #{d["author"]}) 👍#{d["upvotes"]} 👎#{d["downvotes"]}"
|
|
end.join("\n")
|
|
client.create_message(payload.channel_id, "**#{word}**:\n#{text}")
|
|
else
|
|
client.create_message(payload.channel_id, "no definition for **#{word}**.")
|
|
end
|
|
|
|
when "!list"
|
|
word = args[1]?
|
|
if word.nil?
|
|
client.create_message(payload.channel_id, "usage: !list <word>")
|
|
next
|
|
end
|
|
|
|
defs = dictionary[word]?
|
|
if defs
|
|
text = defs.map_with_index do |d, i|
|
|
"#{i+1}. #{d["definition"]} (by #{d["author"]}) 👍#{d["upvotes"]} 👎#{d["downvotes"]}"
|
|
end.join("\n")
|
|
client.create_message(payload.channel_id, "**#{word}** definitions:\n#{text}")
|
|
else
|
|
client.create_message(payload.channel_id, "no definitions found.")
|
|
end
|
|
|
|
when "!upvote", "!downvote"
|
|
word = args[1]?
|
|
index = args[2]? ? args[2].to_i : nil
|
|
|
|
if word.nil? || index.nil?
|
|
client.create_message(payload.channel_id, "usage: #{command} <word> <definition_number>")
|
|
next
|
|
end
|
|
|
|
defs = dictionary[word]?
|
|
if defs && index > 0 && index <= defs.size
|
|
target = defs[index - 1]
|
|
if command == "!upvote"
|
|
target["upvotes"] = target["upvotes"].to_i + 1
|
|
else
|
|
target["downvotes"] = target["downvotes"].to_i + 1
|
|
end
|
|
save_dict(dictionary)
|
|
client.create_message(payload.channel_id, "updated votes for definition #{index} of **#{word}**.")
|
|
else
|
|
client.create_message(payload.channel_id, "invalid word or definition number.")
|
|
end
|
|
|
|
when "!random"
|
|
if dictionary.empty?
|
|
client.create_message(payload.channel_id, "nichectionary is empty.")
|
|
next
|
|
end
|
|
|
|
word = dictionary.keys.sample
|
|
defs = dictionary[word]
|
|
def_choice = defs.sample
|
|
client.create_message(payload.channel_id,
|
|
"**#{word}**:\n#{def_choice["definition"]} (by #{def_choice["author"]}) 👍#{def_choice["upvotes"]} 👎#{def_choice["downvotes"]}"
|
|
)
|
|
|
|
when "!search"
|
|
term = args[1]?
|
|
if term.nil?
|
|
client.create_message(payload.channel_id, "usage: !search <term>")
|
|
next
|
|
end
|
|
|
|
matches = dictionary.select { |w, _| w.includes?(term) }
|
|
if matches.empty?
|
|
client.create_message(payload.channel_id, "no words matched `#{term}`.")
|
|
next
|
|
end
|
|
|
|
text = matches.keys.join(", ")
|
|
client.create_message(payload.channel_id, "words matching `#{term}`: #{text}")
|
|
end
|
|
|
|
Reactions.check_message(content).each do |emoji|
|
|
client.create_reaction(payload.channel_id, payload.id, emoji)
|
|
end
|
|
|
|
preset_reply = Responses.check_message(content)
|
|
if preset_reply
|
|
client.trigger_typing_indicator(payload.channel_id)
|
|
sleep 500.milliseconds
|
|
client.create_message(payload.channel_id, preset_reply, message_reference: payload.message_reference())
|
|
next
|
|
end
|
|
end
|
|
|
|
client.run
|