Twitterで有益な情報を発信する人のツイートを監視して、そのツイートの中でも特に自分が欲している情報だけを頂戴しようというゲスいツールをつくりました。

その名も「twatch(トゥウォッチ)」です。
Twitter+watchの造語となっております。

https://github.com/kokushin/node-twatch

概要

ざっくりいうと、フォローしているユーザーのツイートをリアルタイムで監視し、ツイートが投稿されたらSlackへ転送してくれるコマンドラインツールです。詳細はGitHubのREADME.mdをご確認くださいませ。

オプションとして、

  • 特定のユーザー名(スクリーンネーム)のツイートのみ監視(カンマ区切りで複数指定可能)
  • 特定のキーワードを含むツイートのみ監視(カンマ区切りで複数指定可能)
  • リンクを含むツイートのみ監視

の3種類のフィルターが用意されています。
これらは組み合わせて使用することができます。

↓ (動作デモ)「@lqxia」が「node.js」というキーワード含むツイートを行った際に、Slackへツイートが転送されている

demo.gif

Slackからプッシュ通知が飛ぶので気になればすぐにチラ見もスルーもできますし、ログも残るので後から読み返せます。
Twitterのようにずーーっと画面を開いて監視することも、ツイートの山に埋もれて探せない…なんてことも減るはずです。(たぶん)

開発時のメモ

実はNode.jsでCLIツールを作るのは初の試みでして、色々と試行錯誤しながらすすめました。
開発中に得られた知識をピックアップしてご紹介します。

Node.jsは6.11.2を使用

6x系からES6が安定して使えるため、2017年9月時点で最新の推奨版である6.11.2で開発しました。

ツイートの取得には Twitter Streaming API を利用

ツイートをリアルタイムで取得する必要があったので、「Twitter Streaming API」を利用しました。
npmで提供されているtwitterを使うことで、簡単に実装することができました。

Twitter Streaming API の ‘statuses/filter’ ではなく ‘user’ を使う

Twitter Streaming APIで取得するデータに対して、「ユーザー名、キーワード、言語」などフィルターを設定して取得することができる‘statuses/filter’というものが存在しており、これを使えば楽勝かなーと進めていたらユーザー名の指定のところでエラー。

1
2
3
4
5
6
7
8
client.stream('statuses/filter',
{
track: 'javascript',
language: 'ja',
follow: 'kokushing', // エラー!
...
}
...

いろいろ調べていたら、どうやらTwitterのユーザー名(スクリーンネーム)を指定するのはNGで、数字だけで構成された裏IDのようなものを指定しないといけないらしいです。このIDをいちいち調べてコマンド入力するのも面倒だな〜ってのとそんなに大量の情報も必要ないので、’statuses/filter’を使ったフィルタリングは断念し、‘user’というものとif分岐を組み合わせて処理することにしました。

‘user’を指定すると、「フォローしている全ユーザーのツイートのみを取得」することができるようです。

なので、フォローしているユーザーに限られてしまいますが、下記のようにif分岐と組み合わせることでとりあえず意図していた動作に持っていくことができました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
client.stream('user', {}, (stream) => {
stream.on('data', (obj) => {
// 取得したツイートのオブジェクト内に含まれるユーザー名、キーワードを
// 入力されたオプションの条件と一致するかどうか正規表現で判別し、
// 一致したらSlackに転送する
let tweet = {
'username': obj.user.screen_name, // Twitterのユーザー名
'text': obj.text, // 投稿されたツイート内容(URL含む)
'checkText': obj.text.replace(/(https:\/\/t.co\/([a-z|A-Z|0-9]+))/g, ''), // URLを含めないツイート内容(if分岐用)
'checkLink': obj.entities.urls.length > 0, // ツイート内容にリンクが1つ以上含まれているか(if分岐用)
}
// 1. ユーザー名、キーワードが入力されたオプションと一致しているかどうか
if (username.test(tweet.username) && keyword.test(tweet.checkText)) {
// 2. リンクを含むツイートのみ監視:ONのときにリンクが含まれていないものは転送させない
if (options.link === true && !tweet.checkLink) {
return
}
// 3. すべての条件を満たしたツイートのみをSlackへ転送
sendMessage(tweet.username, tweet.text)
}
...

入力されたコマンドの引数をNode.jsで受け取るには minimist を使う

コマンドの引数は process.argv に格納されるのですが、 minimistを利用すると引数の取得周りの処理がちょっとラクになります。

1
2
3
const options = {
user: minimist(process.argv).u || minimist(process.argv).user,
}

上記の場合だと、-u または -user という引数が存在する場合はその内容取得しを文字列で options.user に格納します。
引数が存在しない場合は undefined が返され、引数は存在するが中身がない場合は true を返します。

ターミナル上で表示される情報をデザインする

せっかくのCLIツールなので、出力テキストを着色することができるchalk、アスキーアートを生成できるfiglet、ローディングスピナーを生成できるoraなんかを使ってみました。
特にアスキーアートを生成できる「figlet」はギークな雰囲気を醸し出せるのでオススメです。

Screen Shot 2017-09-04 at 17.05.08.png

package.jsonに実行するコマンドを記述する

CLIツールなので、スクリプトを実行するためのコマンドとスクリプトをpackage.jsonへ登録します。
ローカルで実行される場合とグローバルで実行される場合の2パターンあります。

ローカル($ npm run twatch)で実行されることを想定したコマンドとスクリプトを“scripts”へ記述します。
※npm run scriptを利用することで自動的にパスが通ります

1
2
3
"scripts": {
"twatch": "node app.js"
}

グローバル($ twatch)で実行されることを想定したコマンドとスクリプトを“bin”へ記述します。

1
2
3
"bin": {
"twatch": "app.js"
}

npmへの登録はnpで!

ソースコードをGitHubで管理している必要がありますが、npmへ登録するときはnpというパッケージを利用するとラクです。
GitHubのタグの更新、リリース用ZIPファイルの作成と、npmへのアップロードを一括で実行してくれます。

実際に使ってみて

まだ試験運用中なんですが、結局のところTwitterフォローするユーザーの選定とキーワードの選定が難しいという感じです。
今は著名人、Web技術ネタをよく発信してくれる人、Qiita新着・人気、はてブホットエントリーなんかをフォローしてます。

キーワードは html,css,js,javascript,web,node,npm,yarn,gulp,php,react,vue,design,git,ux,ui,google,iphone,android,ios,mac こんな感じです。まだまだ改善の余地がありそうですね…

Screen Shot 2017-09-04 at 20.25.09.png

程よく拾えてるような気もします…
キーワードやフォロワーを定期的に変えてみて、ベストなパターンを研究中していこうと思います。

あと、現時点のバージョンでフォローしている人からしかツイートを取得できませんが(個人的には十分なのですが)、次のアップデートで全Twitterユーザーを対象にできるようなオプションを追加しようと思っています。
キーワードでフィルター掛けないととんでもない量の通知が飛びそう…

おまけ Raspberry Pi で常時起動させてみた

Node.js 6.11.2をインストール。
オートログインを設定して、/home/pi/.bash_profile の中にコマンド書くだけで出来ました。

asset.PNG

熱とか怖いですが、今のところ元気に動いてます。

参考にさせていただいたページ

※Qiitaに投稿したものの転載です
https://qiita.com/kokushin/items/95576cd2e3ebe9e906b6