Mastodon API gemを使って投稿する

[Mastodon API Ruby Gem](https://github.com/tootsuite/mastodon-api)を使ってMastodonのインスタンスに投稿するCLIのサンプルです。

## コード

```ruby:mastodon-cli-sample.rb
#!/usr/bin/env ruby

require 'bundler/setup'
Bundler.require(:default)

require 'mastodon'
require 'highline/import'
require 'oauth2'
require 'dotenv'
require 'pp'

DEFAULT_APP_NAME = "mastodon-cli-sample"
DEFAULT_MASTODON_URL = 'https://mstdn.jp'
FULL_ACCESS_SCOPES = "read write follow"

Dotenv.load

if !ENV["MASTODON_URL"]
  ENV["MASTODON_URL"] = ask("Instance URL: "){|q| q.default = DEFAULT_MASTODON_URL}
  File.open(".env", "a+") do |f|
    f.write "MASTODON_URL = '#{ENV["MASTODON_URL"]}'\n"
  end
end

scopes = ENV["MASTODON_SCOPES"] || FULL_ACCESS_SCOPES
app_name = ENV["MASTODON_APP_NAME"] || DEFAULT_APP_NAME

if !ENV["MASTODON_CLIENT_ID"] || !ENV["MASTODON_CLIENT_SECRET"]
  client = Mastodon::REST::Client.new(base_url: ENV["MASTODON_URL"])
  app = client.create_app(app_name, "urn:ietf:wg:oauth:2.0:oob", scopes)
  ENV["MASTODON_CLIENT_ID"] = app.client_id
  ENV["MASTODON_CLIENT_SECRET"] = app.client_secret
  File.open(".env", "a+") do |f|
    f.write "MASTODON_CLIENT_ID = '#{ENV["MASTODON_CLIENT_ID"]}'\n"
    f.write "MASTODON_CLIENT_SECRET = '#{ENV["MASTODON_CLIENT_SECRET"]}'\n"
  end
end

if !ENV["MASTODON_ACCESS_TOKEN"]
  client = OAuth2::Client.new(ENV["MASTODON_CLIENT_ID"],
                              ENV["MASTODON_CLIENT_SECRET"],
                              site: ENV["MASTODON_URL"])
  login_id = ask("Your Account: ")
  password = ask("Your Password: "){|q| q.echo = "*"}
  token = client.password.get_token(login_id, password, scope: scopes)
  ENV["MASTODON_ACCESS_TOKEN"] = token.token
  File.open(".env", "a+") do |f|
    f.write "MASTODON_ACCESS_TOKEN = '#{ENV["MASTODON_ACCESS_TOKEN"]}'\n"
  end
end

client = Mastodon::REST::Client.new(base_url: ENV["MASTODON_URL"],
                                    bearer_token: ENV["MASTODON_ACCESS_TOKEN"])

## 投稿する
message = ARGV[0] || ask("Your Message: ")
response = client.create_status(message)

## とりあえず結果を出力してみる
pp response
```

Gemfileは以下。

```ruby:Gemfile
source "https://rubygems.org"

gem "mastodon-api"
gem "highline"
gem "oauth2"
gem "dotenv"
```

## 使い方

Dotenvを使っていて、カレントディレクトリの`.env`ファイルに書かれている情報を環境変数として参照します。また、環境変数`MASTODON_URL`,`MASTODON_CLIENT_ID`,`MASTODON_CLIENT_SECRET`,`MASTODON_ACCESS_TOKEN`が設定されていない場合、`.env`ファイルに書き込みます。

.envファイルもなく、環境変数も設定されていない場合に実行すると、以下のようにMastodonインスタンスのURL、ID、パスワード、メッセージを聞いてきて、結果を出力します。

```shell-session
$ ./mastodon-cli-sample.rb 
Instance URL: |https://mstdn.jp| 
Your Account: your-email-address@example.jp
Your Password: *********************
Your Message: こんにちは
#<Mastodon::Status:0x007fef32678be8
 @attributes=
  {"id"=>11111111,
   "created_at"=>"2017-04-16T00:00:00.000Z",
   "in_reply_to_id"=>nil,
(略)
   "favourited"=>false,
   "reblogged"=>false}>
```

2回めに実行すると、上記の.envに保存された値を利用して、

```shell-session
$ ./mastodon-cli-sample.rb
Your Message: こんばんは
#<Mastodon::Status:0x007fd97abdcad0
 @attributes=
  {"id"=>2222222,
(略)
   "reblogged"=>false}>
```

書き込むメッセージは引数でも渡せます。

```shell-session
$ ./mastodon-cli-sample.rb　おはようございます
#<Mastodon::Status:0x007f907ab4b858
 @attributes=
  {"id"=>333333333,
   "created_at"=>"2017-04-16T14:58:17.152Z",
(略)
   "reblogged"=>false}>
```

.envの中身は以下のようになります（このトークンは削除済みです）。

```
MASTODON_URL = 'https://mstdn.jp'
MASTODON_CLIENT_ID = 'c966c6055fcf893a58826ac69bffe8532b4a38c3aa7103c776ef98364e96c3d3'
MASTODON_CLIENT_SECRET = '8b149559aa6f322749a703460927dbd91bc634973bc992822c6b6831bc3ff164'
MASTODON_ACCESS_TOKEN = '3de7aaba44c159b150e3db3b46d50a656924714967e2d7f054010d9de51b0aa6'
```

その他使用している環境変数は以下です。

|環境変数名|内容|
|--------------|----------------------|
| MASTODON_URL | MastodonインスタンスのURL|
| MASTODON_CLIENT_ID |クライアントID|
| MASTODON_CLIENT_SECRET |クライアントSECRET|
| MASTODON_ACCESS_TOKEN |アクセストークン|
| MASTODON_SCOPES | スコープ(read, write, followのうち必要なものをスペース区切りで) |
| MASTODON_APP_NAME |クライアントアプリ名(設定画面の「認証済みアプリ」で表示される)|

## 補足説明

Mastodon::REST::Client#create_appでclient_idとclient_secretを取得してからOAuth2::Clientのパスワード認証（？ RFC6749でいうところのResource Owner Password Credentials Grant）でアクセストークンを取得しています。最初それがよく分からなくて、Mastodon::REST::Clientでどうやってやればいいのか悩んでいましたが、そこはOAuth2を使うのが正解なのではという結論に達しました。

アクセストークンを取得したあとは改めてMastodon::REST::Client.newすると、今度は普通にAPIを叩けるようになります。それぞれのAPIの使い方は http://www.rubydoc.info/github/tootsuite/mastodon-api/master をどうぞ。

## 参考

* http://qiita.com/shindyu/items/6a1f0c567774516f07da
* https://github.com/tootsuite/documentation/tree/master/Using-the-API
* http://www.rubydoc.info/github/tootsuite/mastodon-api/master
* http://www.rubydoc.info/github/intridea/oauth2
* https://murashun.jp/blog/20150920-01.html