require 'yaml' require 'discordrb' require 'open-uri' require 'fileutils' require 'securerandom' require 'net/http' require 'json' require 'youtube-dl.rb' require 'sqlite3' db = SQLite3::Database.open 'tankbot.db' $settings = YAML.load(File.read "config.yaml")['settings'] bot = Discordrb::Commands::CommandBot.new token: $settings['token'], prefix: $settings['prefix'] def save_settings File.open("config.yaml", 'w') do |file| file.write(YAML.dump({'settings' => $settings})) end end bot.command(:reset) do |_event| _event.message.mentions.each do |user| user.on(_event.channel.server).nickname = nil end "Finished resetting" end bot.command(:reap, description: "Reaps images posted by the caller in the current channel.") do |_event, stop_id| next "No stop_id supplied" if stop_id == nil FileUtils::mkdir_p("/tmp/tankbot_images/") stop = false earliest_message_id = nil control_message = _event.send_message("Reaping images sent by #{_event.author.mention}. React to this message to stop.") until stop messages = _event.channel.history(100, earliest_message_id) messages.select{ |message| message.author === _event.author }.each do |message| puts "#{message.id}, #{stop_id}" if control_message.reactions? or message.id == stop_id stop = true break end message.attachments.select{ |attachment| attachment.image? }.each do |attachment| control_message.edit(control_message.content + "\nDownloading **#{attachment.filename}**... (#{message.timestamp.strftime("%F")})") open("/tmp/tankbot_images/#{attachment.id}-#{attachment.filename}", 'wb') do |file| file << open(attachment.url).read end end end stop = messages.length < 100 earliest_message_id = messages.last.id end filename = "#{SecureRandom.uuid}.tar.gz" `tar -czf /var/www/scr/#{filename} /tmp/tankbot_images` FileUtils::rm_rf("/tmp/tankbot_images") control_message.edit("https://scr.tankernn.eu/#{filename}") end bot.command(:neko, description: "Requests (sometimes lewd) nekos.") do |_event, keyword| url = "https://nekos.life/api/v2/img/" options = ["meow", "woof", "tickle", "feed", "poke", "slap", "avatar", "waifu", "lizard", "pat", "kiss", "neko", "cuddle", "fox_girl", "hug"] if options.include? keyword then response = JSON.parse(Net::HTTP.get(URI("#{url}#{keyword}"))) "Here's your lewds! °˖✧◝(⁰▿⁰)◜✧˖°\n#{response['url']}" else "No such tag. Please specify one of `#{options.join(", ")}`" end end bot.command(:lmgtfy, description: "Helps tech-illiterate people to enlightenment.") do |_event, *args| "http://lmgtfy.com/?s=d&q=#{args.join('+')}" end bot.command(:copypasta, description: "Cites the holy texts.") do |_event, keyword| pastafile = "copypastas.json" file = File.read pastafile pastas = JSON.parse file if pastas.include? keyword then pastas[keyword] else "No such pasta. Available pastas include `#{pastas.keys.join(", ")}`" end end class UserQueue def initialize(user) @user = user @songs = [] end attr_accessor :user attr_accessor :songs end class FairQueue def initialize(voice_bot) @voice_bot = voice_bot @queues = [] @now_playing = nil end def append(user, video) @queues.append UserQueue.new user unless @queues.any? { |queue| queue.user == user } @queues.select{ |queue| queue.user == user }.first.songs.append(video) end def queue queues = @queues.map{ |queue| queue.songs } target_length = queues.map{ |queue| queue.length }.max queues.map{ |queue| queue + (target_length - queue.length).times.collect{nil} }.transpose.flatten.compact end def play until @queues.empty? queue = @queues.shift @now_playing = queue.songs.shift # Rotate user to last place @queues.append queue unless queue.songs.empty? # Play song # song_log("Playing *#{video.title}*...") @voice_bot.play_file(@now_playing.filename) end @voice_bot.destroy end attr_accessor :now_playing end def format_title(video) total_seconds = video.information[:duration] seconds = total_seconds % 60 minutes = (total_seconds / 60) % 60 hours = total_seconds / (60 * 60) timestamp = format("%02d:%02d", minutes, seconds) timestamp = format("%02d:%s", hours, timestamp) if hours > 0 "**#{video.information[:fulltitle]}** `[#{timestamp}]`" end fairqueues = Hash.new youtube_dl_options = { default_search: 'ytsearch', format: 'bestaudio', output: 'cache/%(title)s-%(id)s.%(ext)s' } bot.command(:play, description: "Plays 'music' of your choosing in your voice channel.") do |_event, *query| voice_bot = _event.voice unless voice_bot then channel = _event.user.voice_channel next "You're not in any voice channel!" unless channel voice_bot = bot.voice_connect(channel) voice_bot.volume = $settings['volume'] fairqueues[_event.server] = FairQueue.new(voice_bot) end video = YoutubeDL.download query.join(' '), youtube_dl_options fairqueue = fairqueues[_event.server] fairqueue.append(_event.user, video) if voice_bot.playing? then "Added #{format_title(video)} to the queue." else Thread.new{fairqueue.play} "Started playing #{format_title(video)}" end end bot.command(:skip, description: "Expresses your dislike of the currently playing 'music'.") do |_event| _event.voice.stop_playing end bot.command(:np, description: "Shows what 'music' is currently playing.") do |_event| queue = fairqueues[_event.server] next "Nothing is playing." unless _event.voice format_title(queue.now_playing) end bot.command(:stop, description: "Puts an end to your misery.") do |_event| if _event.voice _event.voice.destroy "Stopped playing." else "Nothing is playing." end end bot.command(:queue, description: "Lists the impending torture.") do |_event| queue = fairqueues[_event.server] next "Nothing is playing." unless queue next "The queue is empty." if queue.queue.empty? queue.queue.each_with_index.map{|video, i| "#{i + 1}. #{format_title(video)}"}.join("\n") end bot.command(:volume, description: "Sets the severity of currently playing 'music'.") do |_event, volume| next "Nothing is playing." unless _event.voice $settings['volume'] = _event.voice.volume = [volume.to_f, 1.5].min save_settings "" end bot.command(:give, description: "Give a user some Good Boy Points (GBP).") do |_event| receiver = _event.message.mentions[0] sender = _event.author next 'You cannot give GBP to yourself.' if sender.id == receiver.id result = db.query "SELECT remaining FROM gbp WHERE user_id=?", sender.id first_result = result.next if first_result remaining = first_result[0] else remaining = $settings['gbp_per_week'] db.execute "INSERT INTO gbp VALUES (?, ?, ?)", sender.id, 0, $settings['gbp_per_week'] end next 'No GBP left to give this week.' unless remaining > 0 result = db.query "SELECT received FROM gbp WHERE user_id=?", receiver.id first_result = result.next if first_result received = first_result[0] else received = 0 db.execute "INSERT INTO gbp VALUES (?, ?, ?)", receiver.id, 0, $settings['gbp_per_week'] end db.execute "UPDATE gbp SET received = ? WHERE user_id = ?", received + 1, receiver.id db.execute "UPDATE gbp SET remaining = ? WHERE user_id = ?", remaining - 1, sender.id "#{sender.mention} gave 1 GBP to #{receiver.mention}." end bot.command(:leaderboard, description: "Show who's got the most Good Boy Points (GBP).") do |_event| results = db.query "SELECT user_id, received FROM gbp ORDER BY received DESC" "**Good Boy Points (GBP) Leaderboard**\n" + results.each_with_index.map{|row, i| "#{i + 1}. #{_event.server.member(row[0]).nick} - #{row[1]}"}.join("\n") end bot.voice_state_update() do |_event| user = _event.user channel = _event.channel if channel.id == $settings['naughty_corner'] # Deduct GBP result = db.query "SELECT received FROM gbp WHERE user_id=?", user.id first_result = result.next if first_result received = first_result[0] else received = 0 db.execute "INSERT INTO gbp VALUES (?, ?, ?)", receiver.id, 0, $settings['gbp_per_week'] end next unless received > 0 db.execute "UPDATE gbp SET received = ? WHERE user_id = ?", received - 1, user.id end end bot.run