This article is the 17th day article of Hamee Advent Calendar 2020.
As a hobby, I play a certain dangerous ☆ game, and at the end of every month, I mainly enjoy the event where 30 players form a team and compete for ranking. The top ranking teams play on Discord while keeping in touch with each other, but since they only interact by chat, if there are as many as 30 players, the information cannot be gathered and the event cannot proceed smoothly. there is. To solve that, I created a bot that writes to Google Spreadsheets from Discord chat content. However, since it is no longer used from this month, it will be a memorial service in this article.
Bot token is required for DiscordBot development. I wrote an article before, so please refer to this (this time it will work with Ruby).
-Try running discord bot with python
You also need the Spreadsheets API credentials to write to Spreadsheet. Please refer to ** [Google Sheets API Settings] ** in this article.
-Manipulate Sheets Using Google Sheets API
It runs on the Docker container, but I will omit Docker.
Since I made it in about 2 days, there are many parts that are not cool.
The prepared file and structure looks like this.
tree
.
├── Dockerfile
├── Gemfile
├── Gemfile.lock
└── source
├── .env
├── bot.rb
└── credentials.json
Prepare the following sheet as a bot that writes in column C of the row of the person who spoke
A | B | C | |
---|---|---|---|
1 | 252398827 | Mr. A | |
2 | 261223322 | Mr. B | |
3 | 348710907 | Mr. C |
Dockerfile
Dockerfile
FROM ruby:2.6.5
ENV APP_HOME /home/source
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile Gemfile
ADD Gemfile.lock Gemfile.lock
ADD ./source ./
RUN bundle install
CMD ["bundle", "exec", "ruby", "bot.rb"]
Build and run this Dockerfile
Gemfile
Gemfile
source 'https://rubygems.org'
gem 'dotenv'
gem 'discordrb'
gem 'google_drive'
credentials.json
Place the one prepared in the above preparation as it is.
bot.rb
I'm not thinking about errors throughout.
bot.rb
require "google/apis/sheets_v4"
require "googleauth/stores/file_token_store"
require "fileutils"
Dotenv.load
class Spreadsheet
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'.freeze
APPLICATION_NAME = 'MyBot'.freeze
CREDENTIALS_PATH = 'credentials.json'.freeze
TOKEN_PATH = 'token.yaml'.freeze
SCOPE = Google::Apis::SheetsV4::AUTH_SPREADSHEETS
ID = ENV['SHEAT_ID']
attr_accessor :service
def initialize
@service = Google::Apis::SheetsV4::SheetsService.new
@service.client_options.application_name = APPLICATION_NAME
@service.authorization = authorize
end
def authorize
client_id = Google::Auth::ClientId.from_file CREDENTIALS_PATH
token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
authorizer = Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
user_id = "default"
credentials = authorizer.get_credentials user_id
if credentials.nil?
url = authorizer.get_authorization_url base_url: OOB_URI
puts "Open the following URL in the browser and enter the " \
"resulting code after authorization:\n" + url
code = gets
credentials = authorizer.get_and_store_credentials_from_code(
user_id: user_id, code: code, base_url: OOB_URI
)
end
credentials
end
def read(range)
response = service.get_spreadsheet_values ID, range
response.values
end
def write(range, value)
data = Google::Apis::SheetsV4::ValueRange.new
data.major_dimension = 'ROWS'
data.range = range
data.values = [[value]]
options = {
value_input_option: 'RAW'
}
response_write = service.update_spreadsheet_value ID, range, data, options
response_write.updated_cells
end
end
bot.rb
require 'discordrb'
require 'dotenv'
Dotenv.load
class MyBot
attr_accessor :bot, :spreadsheet
def initialize
@bot = Discordrb::Commands::CommandBot.new client_id: ENV['CLIENT_ID'], token: ENV['BOT_TOKEN']
@spreadsheet = Spreadsheet.new
end
def start
settings
@bot.run
end
def get_user_row(user_id)
a = @spreadsheet.read('A:A')
(a.find_index [user_id.to_s]) + 1
end
def settings
@bot.message contains: /^[1-3]$/ do |event|
num = event.content
user_row = get_user_row event.user.id
@spreadsheet.write "C#{user_row}", num
end
end
end
bot = MyBot.new
bot.start
initialize
Use a class called CommandBot
I will not use it this time, but if you set prefix as the third argument, you can react only to messages that start with a specific character.
start
Run bot.run to start the bot
setting
In the above code, it responds to the remarks of only 1 to 3 letters regardless of which channel it is.
Writing is done by comparing the ID of the person who said the message with the ID on the spreadsheet.
Actually, there is a defect in the Dockerfile mentioned earlier, and when I start it, the following error is displayed.
/usr/local/bundle/gems/ffi-1.13.1/lib/ffi/library.rb:145:in `block in ffi_lib': Could not open library 'sodium': sodium: cannot open shared object file: No such file or directory. (LoadError)
Could not open library 'libsodium.so': libsodium.so: cannot open shared object file: No such file or directory
It seems that the library called libsodium is not enough, but even if I try to google it, I do not know who it is.
After all, it was properly written as a dependent file in discordrb README, and I just missed it. Since it wasn't explicitly stated in other blogs that explain discordrb, it was an example of getting stuck when trying to make only the basic part with copy and paste. Solved by adding the following description to the Dockerfile.
Dockerfile
RUN apt-get update -y && apt-get install -y libsodium-dev
At the end of November, the above bot was in operation. For various reasons this month, we plan to recreate the bot with node.js to expand its functionality and are currently under development. Personally, I'm happy to be able to develop a bot with Ruby, and it's good that my child is working hard to see the bot running.
Recommended Posts