こんにちは。
キャスレーコンサルティング システムインテグレーション部の田中(雅)です。
今まさに話題となっているMastodonと、まだまだ現役で動いているCGIを組み合わせてみました!
CGIでMastodon APIを実行、
そしてMastodonへトゥートし、タイムラインを見るWebアプリを実際に作っていきます。
Mastodon APIから情報を取得する部分は非常に簡単にできるので、
こちらを参考にどんどんMastodonを使っていただき、
コミュニケーションを活性化していただければ幸いです。
Mastodonとは
twitterによく似た短文投稿型のSNSです。
twitterと異なる部分の特徴として、
1つのインスタンスに趣味・嗜好が同じ人たちがあつまり、
その中でトゥート(twitterでいうツイート)を行うことで
検索せずともインスタンス内のすべてのトゥートを見ることができます。
また、サーバーを用意すればそれぞれでインスタンスを作ることも可能なため、
プライベートなコミュニケーションツールにもなります。
開発環境
CentOS7
Apache 2.4.6
Perl 5.16
主なPerl モジュールは
Template Toolkit
WWW::Curl::Easy
になります。
※今回はVirtualBoxを使用し開発を行いました。
事前準備
Mastodonのインスタンスにてアカウントを作成してください。
作成したプログラムファイル
cgi-bin
└mastodon
└conf
└mastodon.ini–アカウント情報などの設定ファイル
└tt
└home.html–テンプレートファイル
└toot.cgi–トゥート用CGI
└home.cgi–タイムライン表示用CGI
└Mastodon.pm–package
アカウント情報を取得
Mastodon API を実行するためAPI実行用のアカウントを取得する必要がありますので
APIを使用し、アカウント情報取得処理を実装しましょう。
home.cgi内アクセストークン取得処理
#!/usr/bin/perl -w use strict; use JSON; use utf8; use Data::Dumper; use Template; use Encode; use warnings; use Mastodon; # アカウント情報取得 初期時のみ my $account_info = Mastodon::get_account(); print "Content-type: text/html\n\n"; print $account_info; exit;
conf/mastodon.ini内
[account] host = [アカウントを取得しインスタンスのホスト] client_name = [トゥートの横の@部分] username = [ログイン時のメールアドレス] password = [ログイン時のパスワード] scope = read%20write%20follow</pre>
Mastodon.pm内
package Mastodon; use strict; use JSON; use utf8; use Data::Dumper; use Encode; use warnings; use URI; use Config::Tiny; use WWW::Curl::Easy; my $conf_file = 'conf/mastodon.ini'; my $conf = Config::Tiny->new->read($conf_file); our $mastodon_host = $conf->{account}->{host}; # 設定ファイルからアカウント情報取得 our $client_name = $conf->{account}->{client_name}; our $client_id = $conf->{account}->{client_id}; our $client_secret = $conf->{account}->{client_secret}; our $username = $conf->{account}->{username}; our $password = $conf->{account}->{password}; =comment POST リクエスト用関数 @param String $api_url @param Hash %request_param =cut sub post_request { my $api_url = shift; my %request_param = @_; my %response; my $uri = URI->new($api_url); $uri->query_form(\%request_param); my $curl = WWW::Curl::Easy->new(); $curl->setopt(CURLOPT_HEADER,1); $curl->setopt(CURLOPT_URL, $api_url); $curl->setopt(CURLOPT_POST, 1); $curl->setopt(CURLOPT_POSTFIELDS, $uri->query); my $response_body; $curl->setopt(CURLOPT_WRITEDATA,\$response_body); my $retcode = $curl->perform; if ($retcode == 0) { $response{'body'} = $response_body; $response{'header_size'} = $curl->getinfo(CURLINFO_HEADER_SIZE); return %response; } else { print "Error " . $curl->strerror($retcode) . "\n"; exit; } }
・
省略
・
=comment アカウント情報取得用関数 @param String $client_name =cut sub get_account { my $api_url = "https://".$mastodon_host."/api/v1/apps"; my %request_param = ( 'client_name' => $client_name, 'redirect_uris' => 'urn:ietf:wg:oauth:2.0:oob', 'scope' => 'read write follow', ); my %api_response = post_request($api_url, %request_param); # レスポンスからヘッダを削除 my $response_body = substr($api_response{'body'}, $api_response{'header_size'}); return $response_body; }
こちらで
http://localhost/cgi-bin/mastodon/home.cgi
をブラウザで見ると
{
“id”:******,
“redirect_uri”:”urn:ietf:wg:oauth:2.0:oob”,
“client_id”:”******”,
“client_secret”:”******”
}
といったJSONが表示されます。
ここで取得できた
client_idとclient_secretの値を
conf/mastodon.ini内に
client_id = [client_idの値]
client_secret = [client_secretの値]
として設定を追記ください。
では、本格的に実装を進めて参ります。
タイムラインをCGIで見よう
ローカルのタイムラインを見られるまでの機能を実装します。
同様にホームのタイムラインが見られるのが、今回作成したページになります。
タイムライン表示処理
home.cgi
アカウント情報取得に使った処理はコメントアウトし、
以下のような形にします。
・
省略
・
=account get # アカウント情報取得 初期時のみ my $account_info = Mastodon::get_account(); print "Content-type: text/html\n\n"; print $account_info; exit; =cut # access_token 取得 my $access_token = Mastodon::get_access_token(); # timeline取得 my $timeline_all = Mastodon::get_timeline_home($access_token); # 必要な情報のみをハッシュに格納 my %timeline; =comment # public用 foreach my $timeline_hash ( @$timeline_all ) { my $id = $timeline_hash->{"id"}; $timeline{$id}{"toot"} = $timeline_hash->{"account"}->{"note"}; $timeline{$id}{"tootter"} = $timeline_hash->{"account"}->{"display_name"}; } =cut # home用 foreach my $timeline_hash ( @$timeline_all ) { my $id = $timeline_hash->{"id"}; $timeline{$id}{"id"} = $timeline_hash->{"id"}; $timeline{$id}{"toot"} = $timeline_hash->{"content"}; $timeline{$id}{"tootter"} = $timeline_hash->{"account"}->{"username"}; } # ID降順でソート my %timeline_sort; my $i; foreach my $id (sort {$b <=> $a} keys %timeline) { $i++; $timeline_sort{$i} = $timeline{$id}; } my $template = Template->new( UNICODE => 1, ENCODING => 'utf-8', ); my $output; $template->process( 'tt/home.html', { timeline => \%timeline_sort }, \$output, 'binmode' => ':utf8' ); print "Content-type: text/html\n\n"; print encode('utf8', $output);
Mastodon.pm
=comment トークン認証付きGET リクエスト用関数 @param String $api_url @param String $access_token @param hash $request_param =cut sub get_request_auth { my $api_url = shift; my $access_token = shift; my %request_param = @_; my %response; my $curl = WWW::Curl::Easy->new(); $curl->setopt(CURLOPT_URL, $api_url); $curl->setopt(CURLOPT_HTTPHEADER, ['Authorization: Bearer '. $access_token]); my $response_body; $curl->setopt(CURLOPT_WRITEDATA,\$response_body); my $retcode = $curl->perform; if ($retcode == 0) { $response{'body'} = $response_body; $response{'header_size'} = $curl->getinfo(CURLINFO_HEADER_SIZE); return %response; } else { print "Error " . $curl->strerror($retcode) . "\n"; exit; } }
・
省略
・
=comment アクセストークン取得用関数 @param String $client_id @param String $client_secret @param String $username @param String $password =cut sub get_access_token { # API パラメータ設定 my $api_url = "https://".$mastodon_host."/oauth/token"; my %request_param = ( 'client_id' => $client_id, 'client_secret' => $client_secret, 'username' => $username, 'password' => $password, 'grant_type' => 'password',#パスワード認証はサービス向きでないので非推奨 'scope' => 'read write follow', ); my %api_response = post_request($api_url, %request_param); # APIのレスポンスからアクセストークン取得 my $response_body = substr($api_response{'body'}, $api_response{'header_size'}); my $api_result = JSON->new->utf8->decode($response_body); return $api_result->{access_token}; } =comment タイムライン取得用関数(home) @param String $access_token =cut sub get_timeline_home { my $access_token = shift; # タイムライン API URL my $api_url = "https://".$mastodon_host."/api/v1/timelines/home"; my %response = get_request_auth($api_url, $access_token); my $response_json = JSON->new->utf8->decode($response{'body'}); return $response_json; }
といった形で
まず、アクセストークンの取得を行い、それをヘッダに入れ、
タイムライン取得用(ホーム用)のAPIをCurlにて実行した後、
APIからのレスポンスを取得し、表示させています。
トゥートしてみよう!
といった形で
テキストエリアに「created shared value」と入力し、
「トゥート!!」ボタンを押すと
トゥートしてくれるという機能の実装になります。
「トゥート!!」ボタン押下後の遷移先は
toot.cgi にしており、toot.cgiに遷移するとトゥート用のAPIを実行し、
home.cgi に帰ってくる形の実装になります。
投稿後このような形で「created shared value」がトゥートされます。
では、トゥートについての実装部分になります。
toot.cgi
#!/usr/bin/perl -w use strict; use JSON; use utf8; use Data::Dumper; use Encode; use warnings; use CGI; use Mastodon; # access_token 取得 my $access_token = Mastodon::get_access_token(); # パラメータ名を指定し取得 my $input_param = new CGI; my $toot = $input_param->param('toot'); # トゥート投稿用 API実行 my $api_response = Mastodon::post_statuses($access_token, $toot); # home.cgiへリダイレクト print "Location: http://localhost/cgi-bin/mastodon/home.cgi\n\n";
Mastodon.pm
=comment トークン認証付きPOST リクエスト用関数 @param String $api_url @param String $access_token @param hash $request_param =cut sub post_request_auth { my $api_url = shift; my $access_token = shift; my %request_param = @_; my %response; my $uri = URI->new($api_url); $uri->query_form(\%request_param); my $curl = WWW::Curl::Easy->new(); $curl->setopt(CURLOPT_URL, $api_url); $curl->setopt(CURLOPT_HTTPHEADER, ['Authorization: Bearer '. $access_token]); $curl->setopt(CURLOPT_POST, 1); $curl->setopt(CURLOPT_POSTFIELDS, $uri->query); my $response_body; $curl->setopt(CURLOPT_WRITEDATA,\$response_body); my $retcode = $curl->perform; if ($retcode == 0) { $response{'body'} = $response_body; $response{'header_size'} = $curl->getinfo(CURLINFO_HEADER_SIZE); return %response; } else { print "Error " . $curl->strerror($retcode) . "\n"; exit; } }
・
省略
・
=comment トゥート投稿用関数 @param String $access_token @param String $status =cut sub post_statuses { my $access_token = shift; my $status = shift; # タイムライン API URL my $api_url = "https://".$mastodon_host."/api/v1/statuses"; my %request_param = ( 'status' => $status, ); my %response = post_request_auth($api_url, $access_token, %request_param); my $response_json = JSON->new->utf8->decode($response{'body'}); return $response_json; }
終わりに
今回使用したAPI以外にも
・パブリックなタイムラインを見るAPI
・フォロワー/フォローしている人を取得するAPI
・アカウントを検索するAPI
等もありますし、
websocket にてリアルタイムでタイムラインを見られるようにするのも、面白いかなと思っております。
また、この数日間でも様々な言語によって、Mastodonのライブラリが増えてきています。
ぜひ試してみてください。
最後までお読みいただきありがとうございました。