Blogaomu

WEBアプリケーション開発とその周辺のメモをゆるふわに書いていきます。

Kanazawa.rb meetup #75 に参加しました #kzrb

今回はDMM.com 金沢事業所をお借りして開催!

kzrb.doorkeeper.jp

当初は自分含めて2人しか参加表明してなくて不安でしたが最終的には11人の参加になりました。わいわい。

Scala関西Summit 2018に行ってきた話

www.blogaomu.com

↑の話をベースに写真も追加したスライドを作って発表しました。コンセプトとしてはScala関西Summitに行った気になれる、だったんですが、いろいろ詰め込みすぎてだいぶ時間を取ってしまいました(すいません)。Scalaは可愛いを広めることができてよかったです。

Bufferを操作する

Kanazawa.rb告知用のSNS投稿をBufferで行っているとのことで、これをCLIでやれたらいろいろ捗るのでは?という考えから今回のもくもくタイムではBuffer APIを触ってみました。

APIを触る前にBuffer自体を使ったことが無かったのでアカウントを作っていろいろ試して概念を理解するところから始めました。

  • 1アカウントに対して複数のSNSアカウントをひもづけられる。ひもづいたSNSアカウントのことをProfileと呼んでいる
  • 投稿はQueueというものに格納され、特定の時刻になったらSNSアカウントを通して接続先のSNSに投稿される
    • 投稿時にQueueに入れる(Add to Queue)、即時にSNS投稿する(Share now)、任意の日時に投稿する(Schedule post)、の3つから選択できる
    • Queueに入った投稿は1件ずつ時刻(Posting times)が割り振られ、その時刻になると接続先のSNSに投稿される

投稿に関する概念はざっとこんな感じだと思います。詳しくはこの辺を見ると良さそう。 Managing your Queue - Buffer FAQ

概念を理解したところで、プログラムからBuffer APIを呼ぶ場合には公式のgemがあるのでこれを利用すると良さげです。

github.com

Buffer APIを利用する場合、先にアプリケーションの登録をサイト上で行う必要があります。画面に従って入力していけばOKです。ここで発行されたAccess tokenを使用します。

buffer.com

先ほど発行されたAccess tokenを環境変数 BUFFER_ACCESS_TOKEN に入れておいて、replでいろいろ操作してみます。

> require 'buffer'
> client = Buffer::Client.new(ENV['BUFFER_ACCESS_TOKEN'])
# Profileの取得
> profiles = client.profiles
=> [{"_id"=>"5bef956a4b1be7784607d225",
  "avatar"=>
   "http://pbs.twimg.com/profile_images/835761987728502784/QMKQ3UYI_normal.jpg",
  "avatar_https"=>
   "https://pbs.twimg.com/profile_images/835761987728502784/QMKQ3UYI_normal.jpg",
  "can_see_content_library"=>false,
  "counts"=>
   {"sent"=>4, "drafts"=>0, "daily_suggestions"=>25, "reminders"=>0, "pending"=>0},
  "cover_photo"=>
   "https://d3ijcis4e2ziok.cloudfront.net/default-cover-photos/blurry-blue-background-iii_facebook_timeline_cover.jpg",
  "created_at"=>1542428010,
  "default"=>true,
  "disabled"=>false,
  "disabled_features"=>[],
  "disconnected"=>false,
  "formatted_service"=>"Twitter",
  "formatted_username"=>"@TAKAyuki_atkwsk",
  "id"=>"5bef956a4b1be7784607d225",
  "is_analyze_enabled"=>false,
  "is_on_business_v2"=>false,
  "locked"=>false,
  "paused"=>false,
  "paused_schedules"=>[],
  "preferences"=>{},
  "reports_logo"=>nil,
  "schedules"=>
   [{"days"=>["sun"], "times"=>["09:55", "14:25", "16:44", "19:32"]},
    {"days"=>["mon"], "times"=>["09:55", "14:25", "16:44", "19:32"]},
    {"days"=>["tue"], "times"=>["09:55", "14:25", "16:44", "19:32"]},
    {"days"=>["wed"], "times"=>["09:55", "14:25", "16:44", "19:32"]},
    {"days"=>["thu"], "times"=>["09:55", "14:25", "16:44", "19:32"]},
    {"days"=>["fri"], "times"=>["09:55", "14:25", "16:44", "19:32"]},
    {"days"=>["sat"], "times"=>["09:55", "14:25", "16:44", "19:32"]}],
  "service"=>"twitter",
  "service_id"=>"77184067",
  "service_type"=>"profile",
  "service_username"=>"TAKAyuki_atkwsk",
  "shortener"=>{"domain"=>"buff.ly"},
  "statistics"=>{"followers"=>785},
  "timezone"=>"Asia/Tokyo",
  "timezone_city"=>"Tokyo - Asia",
  "user_id"=>"5bef953a4b1be777074c2b05",
  "utm_tracking"=>"disabled",
  "verb"=>"tweet"},
  ...]

# 投稿をQueueに入れる
> client.create_update(
*   body: {
*     text: 'お腹吹田',
*     profile_ids: [profiles.find {|profile| profile.service == "twitter" }.id],
*   }
* )
=> {"updates"=>
  [{"_id"=>"5befaff6dd5072291b2a9b93",
    "client_id"=>"5befa27c4b1be72ec04037b3",
    "created_at"=>1542434806,
    "day"=>"Today",
    "due_at"=>1542450720,
    "due_time"=>"7:32 pm",
    "id"=>"5befaff6dd5072291b2a9b93",
    "is_video_processing"=>false,
    "library_update_id"=>"",
    "needs_approval"=>false,
    "organization_id"=>"5bef953a4b1be777074c2b07",
    "perm_approvable"=>false,
    "perm_editable"=>true,
    "pinned"=>false,
    "profile_id"=>"5bef956a4b1be7784607d225",
    "profile_service"=>"twitter",
    "shared_now"=>false,
    "status"=>"buffer",
    "text"=>"お腹吹田",
    "text_formatted"=>"お腹吹田",
    "text_md5"=>"e01909236cf97670e3f23a95e52c7072",
    "type"=>"text",
    "updated_at"=>1542434806,
    "user_id"=>"5bef953a4b1be777074c2b05",
    "via"=>"api"}],
 "buffer_percentage"=>20,
 "buffer_count"=>2,
 "success"=>true,
 "message"=>"One more tweet in your Buffer. Keep it topped up!",
 "code"=>false}

# 複数のProfileで投稿する
> client.create_update(body: {text: "こんにちは", profile_ids: profiles.map(&:id)})
=> (略)

# 特定の日時に投稿されるようにする
> client.create_update(body: {text: 'hogehoge', profile_ids: [profiles.find {|profile| profile.service == "twitter" }.send(:id)], scheduled_at: "20181117T19:00:00+09:00"})
=> (略)

ひとまず複数の投稿形式を試して思った通りに動作しました。 profile_ids を取ってくるところで少しハマりましたが、後はAPIパラメーターを調べつついけました。このあとはCLIとして操作できれば良いなと考えているのでthorと組み合わせて実装してみようと思っています。

懇親会

www.hotpepper.jp

www.hotpepper.jp

一次会は手羽先食べ放題コース!過去にいくつかの食べ放題に勝ってきたkzrb勢も手羽先には勝てなかった...。

二次会は安定の丸二。唐揚げがでかいぜ!

懇親会で、作業部屋のCO2濃度を計測して可視化およびアラートを出す仕組みを作りたいと相談したところ、まともな濃度センサーはお高いらしく中国から輸入するのが良さそう?とのことでした。また、Withingsの体重計でCO2濃度も測れるやつがあるらしく、可視化ならこれでもいいのではという話も。

次回のKanazawa.rbは年末恒例のLT大会です!