Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8691

Qiitaの自分の投稿にLGTMが付いたら通知してもらう

$
0
0

自分が投稿した記事に、どなたかがLGTM(いいね)してくれると、やっぱりうれしくて、書いたかいがあったなあと、元気をもらえます。

そこで、30分ごとに、LGTM(いいね)数とフォロワー数をウォッチして、増えていたら、LINEに通知と、自宅にあるGoogleHomeスマートスピーカにしゃべってもらおうと思います。
コロナの影響でずっと在宅勤務なので、ちょっとしたアクセントにもなります。

ちなみに、GoogleHomeスマートスピーカは、これから立ち上げるcron実行PCと同じネットワークにある必要があります。

通知の準備

LINE通知には、LINE Notifyを使いました。
そのためには、パーソナルアクセストークンが必要です。

以下にアクセスして、アクセストークンの発行(開発者向け)をします。
 https://notify-bot.line.me/my/

グループに発行してもよいですし、1:1でLINE Notifyから通知を受け取る でもよいです。
そうすると、43文字程度のパーソナルアクセストークンが発行されます。あとで、使います。

image.png

Google Homeスマートスピーカからしゃべってもらうためには、スマートスピーカのIPアドレスが必要です。
スマートスピーカと連携済みのAndroidのGoogle Homeアプリから、デバイス設定を選ぶと、一番下の情報 というところに、IPアドレスがありますのでメモっておきます。

image.png

現在のLGTM(いいね)数とフォロワー数の取得

Qiita APIを見てみたのですが、記事ごとのLGTM(いいね)数は取得できますが、合計数をとれるようなAPIは見当たりませんでした。
そこで、QiitaのWebページからスクレーピングします。

スクレーピングには、npmのcheerioを使いました。
また、Webページの取得には、node-fetchを使いました。

npm install cheerio
npm install node-fetch

class=” UserCounterList__UserCounterItem-sc-******” のような感じのHTMLエレメントがあるので、その近辺を探しています。

image.png

ソースはこんな感じ。

index.js
constcheerio=require('cheerio');constfetch=require('node-fetch');const{URL,URLSearchParams}=require('url');asyncfunctionget_qiita_state(userid){returndo_get('https://qiita.com/'+userid,{}).then((text)=>{const$=cheerio.load(text);varstate={};varroot=$("[class^='UserCounterList__UserCounterItem-sc-']");root.each((i,elem)=>{varlabel=$(elem).children("[class^='UserCounterList__UserCounterItemLabel-sc-']").text();varnum=parseInt($(elem).children("[class^='UserCounterList__UserCounterItemCount-sc-']").text());state[label]=num;});// Posts, Contributions, Followersconsole.log(state);returnstate;});}functiondo_get(url,qs){varparams=newURLSearchParams(qs);varurl2=newURL(url);url2.search=params;returnfetch(url2.toString(),{method:'GET',}).then((response)=>{if(!response.ok)throw'status is not 200';returnresponse.text();});}

関数get_qiita_state()の呼び出しにより、

 { Posts : 投稿数, Contributions : LGTM数, Followers : フォロワー数 }

が返ってきます。

LINE通知する

関数line_notifyに、通知したいメッセージと、さきほどのパーソナルアクセストークンを指定します。

index.js
constfetch=require('node-fetch');const{URL,URLSearchParams}=require('url');constHeaders=fetch.Headers;functionline_notify(message,token){varparams={message:message};returndo_post_urlencoded_token('https://notify-api.line.me/api/notify',params,token);}functiondo_post_urlencoded_token(url,params,token){constheaders=newHeaders({'Content-Type':'application/x-www-form-urlencoded','Authorization':'Bearer '+token});varbody=newURLSearchParams(params);returnfetch(newURL(url).toString(),{method:'POST',body:body,headers:headers}).then((response)=>{if(!response.ok)throw'status is not 200';returnresponse.json();})}

GoogleHomeスマートスピーカにしゃべらせる

関数homeSpeechに、メッセージと、スマートスピーカのIPアドレスを指定すると、数秒後にスマートスピーカがしゃべります。

index.js
constClient=require('castv2-client').Client;constMediaReceiver=require('castv2-client').DefaultMediaReceiver;constgoogletts=require('google-tts-api');functionhomeSpeech(text,host){returngoogletts(text,'ja-JP',1).then(function(url){returnplayUrl(url,host);});}functionplayUrl(url,host){returnnewPromise((resolve,reject)=>{varclient=newClient();client.connect(host,()=>{client.launch(MediaReceiver,(err,player)=>{if(err){console.log('Error: %s',err.message);client.close();returnreject(err);}varmedia={contentId:url,contentType:'audio/mp3',streamType:'BUFFERED'};player.load(media,{autoplay:true},(err,status)=>{client.close();resolve('Device notified');});});});client.on('error',(err)=>{console.log('Error: %s',err.message);client.close();reject(err);});})}

本体

以上の関数を呼び出すメイン部です。
いくつか、ちょっと特殊処理を入れています。

LGTM数とフォロワー数は、以前のチェック時からの増加をみて、LINEとスマートスピーカから通知をしています。以前のチェック時の数は、ファイルに保存しています。
ファイル名として、QIITA_STATE_FILE を指定し、読み出しと更新用の関数をstate_read、state_updateを用意しました。

また、夜中に通知されても困るので、現在時刻を見て、NOTIFY_RANGE_HOURS の配列に示した時間の時だけ通知するようにしました。

index.js
constfs=require('fs');constQIITA_USERID=process.env.QIITA_USERID||'【チェックしたいQiitaユーザ名】';constGOOGLE_DEVICE_ADDRESS=process.env.DEVICE_ADDRESS||'【GoogleHomeスマートスピーカwのIPアドレス】';constQIITA_STATE_FILE=process.env.QIITA_STATE_FILE||'./data/qiita_state.json';constLINE_PERSONAL_ACCESS_TOKEN=process.env.LINE_PERSONAL_ACCESS_TOKEN||'【LINE Notifyのパーソナルアクセストークン】';constNOTIFY_RANGE_HOURS=process.env.NOTIFY_RANGE||[8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,0,1]get_qiita_state(QIITA_USERID).then(async(state)=>{varprev_state=state_read();vardate=newDate();varhour=date.getHours();if(NOTIFY_RANGE_HOURS.includes(hour)){state_update(state);varmessage="";if(state.Contributions>prev_state.Contributions)message+='いいねが'+(state.Contributions-prev_state.Contributions)+'件増えたよ。';if(state.Followers>prev_state.Followers){if(message!="")message+="\n";message+='フォロワーが'+(state.Followers-prev_state.Followers)+'人増えたよ。';}if(message!=""){awaithomeSpeech(message,GOOGLE_DEVICE_ADDRESS);awaitline_notify("\n"+message,LINE_PERSONAL_ACCESS_TOKEN);}else{console.log('no change');}}}).catch(error=>{console.log(error);});functionstate_read(){try{returnJSON.parse(fs.readFileSync(QIITA_STATE_FILE,'utf8'));}catch(error){return{};}}functionstate_update(state){fs.writeFileSync(QIITA_STATE_FILE,JSON.stringify(state),'utf8');}

ということで、以下を環境に合わせて変更してください。

・QIITA_USERID:チェックしたいQiitaユーザ名
・GOOGLE_DEVICE_ADDRESS:GoogleHomeスマートスピーカwのIPアドレス
・QIITA_STATE_FILE:現在のLGTM数の保存先ファイル名
・LINE_PERSONAL_ACCESS_TOKEN:LINE Notifyのパーソナルアクセストークン
・NOTIFY_RANGE_HOURS:通知されてもよい時間(時)の配列

cron化

シェルスクリプトを作成します。
以下例です。

vi index.sh
chmod +x index.sh

#!/bin/sh

cd /home/XXXXX/projects/node/cron_lgtm
/home/XXXXX/.nvm/versions/node/v8.12.0/bin/node index.js

あとはcronに登録するだけです。以下は30分ごとにチェックする場合です。

crontab -e

0,30 * * * * /home/XXXXX/projects/node/cron_lgtm/index.sh

以上


Viewing all articles
Browse latest Browse all 8691

Trending Articles