GWは9連休!…とか思っていたら、気づいたらもう半分過してしまい、若干凹んでいます。
働きたくないでござる
…さて、最近ネットやらTwitterで、やたら「Mastodon」という言葉を目にするようになりました。
ちなみに「Mastodon」の特徴を簡単に説明すると
てな感じです。
で、APIも公開されていて、いろんな人が各環境でのライブラリをすでに作っているわけで、あすかさんのブログにも、こんなものが紹介されていました。
kmycode.hatenablog.jp
「Mastonet」という、Guillaume Lacasa氏というフランス人の方が作成したC#用のMastodonライブラリです。
github.com
というわけで、どうせ寝てるだけだしMastodonの理解もかねて、僕も作ってみようと思いました。
Mastonetのインストール
Visual Studio使ってるなら、NuGet経由でインストールできます。
ただしGithubのREADME.md内にも「A preview version is available on Nuget : https://www.nuget.org/packages/Mastonet」
とある通り、「プレリリースを含める」チェックボックスにチェックを入れないと検索されないので、それだけは注意です。
とりあえずビューとソース本文
using System; using System.Threading.Tasks; using System.Windows.Forms; using Mastonet; using System.Diagnostics; namespace MastodonApp { public partial class Form1 : Form { private String timeLine = String.Empty; private TimelineStreaming stream = null; private enum StreamStetus { Not_Login = 0, Not_Start = 1, Now_Starting = 2, } private StreamStetus stream_status = StreamStetus.Not_Login; public Form1() { InitializeComponent(); } private async void button1_Click(object sender, EventArgs e) { var id = textBox1.Text; var pass = textBox2.Text; if (String.IsNullOrEmpty(id) || String.IsNullOrEmpty(pass)) { MessageBox.Show("IDまはたパスワードが未入力です。"); return; } try { var ret = await this.MastoNet_Run(id, pass); timer1.Interval = 5000; timer1.Enabled = true; timer1.Tick += new System.EventHandler(timer1_Tick); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } private Task<int> MastoNet_Run(String id, String pass) { return Task.Run(async () => { if (stream_status != StreamStetus.Now_Starting) { if (stream_status == StreamStetus.Not_Login) { var authClient = new AuthenticationClient("friends.nico"); var appRegistration = await authClient.CreateApp("MastodonApp", Scope.Read | Scope.Write | Scope.Follow); var auth = await authClient.ConnectWithPassword(id, pass); var client = new MastodonClient(appRegistration, auth); stream_status = StreamStetus.Not_Start; stream = client.GetPublicStreaming(); var dispString = String.Empty; stream.OnUpdate += (sender, e) => { var dispName = e.Status.Account.DisplayName; var content = e.Status.Content; dispString = dispName + "\r\n" + content + "\r\n" + "\r\n"; this.timeLine += dispString; }; } stream.Start(); this.stream_status = StreamStetus.Now_Starting; } return 0; }); } private void timer1_Tick(object sender, System.EventArgs e) { this.textBox3.Text = this.timeLine; } protected void button2_Click(object sender, EventArgs e) { if (stream != null && this.stream_status == StreamStetus.Now_Starting) { stream.Stop(); this.stream_status = StreamStetus.Not_Start; } } } }
と、ビューとソースを記載しましたが、重要なのはソースの「MastoNet_Run()」の内部です。
- アプリ登録
var authClient = new AuthenticationClient("friends.nico"); var appRegistration = await authClient.CreateApp("MastodonApp", Scope.Read | Scope.Write | Scope.Follow);
クライアント作成には「ClientID」「ClientSecret」という2つの値が必要で、これを取得するためにアプリ登録を行います。
アプリ登録は上記の通り、MastodonインスタンスのAuthenticationClientクラスを作成した上で、そのCreateApp()メソッドを実行すればOKです。
- 認証とクライアント作成
var auth = await authClient.ConnectWithPassword(id, pass);
var client = new MastodonClient(appRegistration, auth);
認証は、OAuthを使用する方法と、メアドとパスワードで行う方法があり、後者は上記の通りauthClient.ConnectWithPassword()メソッドを実行すればOK。
※ただし後者は作者曰く「非推奨」とのことなので、問題なければOAuthを使ったほうがよいみたいです。
前者の場合、作者のREADME.mdによれば
- AuthenticationClientクラスのOAuthUrl()メソッドを実行して、urlを取得
- 1で取得したurlにアクセスして、APICodeを取得
- 2で取得したAPICodeを引数にして、AuthenticationClientクラスのConnectWithCode()メソッドを実行
を実行すればOK…のはずなんですが、なぜか僕の環境ではうまくいかなかったので、今後の宿題にします。*1
で、クライアント作成ですが、ここまでで実行したCreateApp()メソッドの戻り値とConnectWith***()メソッドの戻り値を引数にして、MastodonClientクラスのインスタンスを作成するだけです。
- タイムラインのストリーミングと更新通知
stream = client.GetPublicStreaming(); var dispString = String.Empty; stream.OnUpdate += (sender, e) => { var dispName = e.Status.Account.DisplayName; var content = e.Status.Content; };
タイムラインのストリームは、先程作成したクライアントに各タイムラインストリーム取得用のメソッドが用意されているので、それを使用します。
(今回はGetPublicStreaming()メソッドで、連合タイムラインのストリームを取得しています。)
で、更新された場合、ストリームのOnUpdate()イベントハンドラーが呼ばれるので、その中に追加でやりたい処理を記載します。
なお、上記の通り、引数e(StreamUpdateEventArgs)の
- Status.Account.DisplayNameに「ユーザー名」
- Status.Contentに「本文」
が取得できます。
最後に、ストリームのstart()メソッドで、実際にストリーミングを開始します。(なおご想像の通り、stop()メソッドでストリーミングの停止ができます。)
※この時「この呼び出しを待たないため、現在のメソッドの実行は…」という警告が出るかもしれませんが、無視してOKです。
なお、上記ソースの実行結果はこちら。*2
まあ、いろんな方がブログなどで書いていたので知っていましたが、本文がHTMLタグ付きなんですよね…
本来はその対処も追加しないといけないですが、今回はまあいいでしょう。
というわけで、Masto.netを使用した、簡単なMastodonアプリの作成でした。
せっかくのGW、いろんな方がMastodonライブラリを作成されているので、機会があればMastodonアプリやライブラリの作成に挑戦するのもいいかもしれません。
さて明日からは、そろそろ本腰入れてXamarinプロジェクトを再開しないと。
…なんか普段より、むしろGWのほうがコーディング時間が長いような???
*1:これに限らず、インスタンス環境に依存する?事項がなんか多かった気がします。
初めに使用したインスタンスでは、url&API Codeの取得は問題なく出来たんですが…
あと、初めに使用したインスタンスではCreateApp()メソッド実行時に、強制的に接続が切断されていたのですが、friends.nicoインスタンスにしたら、ソースは1行も変えてないのに、全く問題なくなった…とか。これらは今後、要調査です。
*2:他の方がコンソールアプリでやっていたため、僕はフォームアプリで作成しましたが、手っ取り早く試すだけならコンソールアプリがおすすめです。
フォームアプリだどスレッドセーフとか非同期処理時のフォームコントロールプロパティ設定とかの関係で、コンソールアプリより少々厄介です。