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 ") 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 ") 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 ") 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} ") 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 ") 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