Linux
Node.js
Twitter
GoogleHome

google homeにつぶやきを読み上げてもらうfrom linuxホスト

google homeにつぶやきを読み上げてもらうfrom linuxホスト

google home mini 買っちゃったけど
IoTデバイス不足で静かなものです...
つぶやきでも喋ってもらいますか

雑なのでいろいろ抜けてますが取っ掛かりとしてはまぁありかなと思って書いておきます。

  • コードが少ない
  • 普通のlinuxで動いた
  • mdnsいけてるみたい

という事が言いたいだけです。

参考させて頂きました https://qiita.com/SatoTakumi/items/c9de7ff27e5b70508066

RaspberryPiでweb apiするのが流行りみたいですが

単なるlinuxホストで動かします。(Fedora 27)

作業してる裏でターミナルから実行させて流してます。

必要なもの

本当にコレで揃っているか無駄ないか覚えてない...X-(

  • dnf install nodejs
  • dnf install avahi-compat-libdns_sd-devel
  • npm install google-home-notifer
  • npm install mdns
  • npm install chalk (必須ではないですコンソール出力に色つけたかっただけ)

-gとかはそれぞれよしなに。

mdns(avahi)でぼんじゅぅるぅ〜出来なかったので以下参考に
https://qiita.com/udon11/items/fef44cec7b243f93151b
https://github.com/noelportugal/google-home-notifier (下の方に)

~/node_modules/mdns/lib/browser.js を編集したらmy環境では取れました。
動きますがlibから「Avahi native apiを使うように変更しなさいよ」って出ます

面倒ならip直書き方式でも良いかと。(他記事参照でお願いします

適当なディレクトリで以下ファイル並べて
mkfifo googleHome.pipe
しておいてください。
走行は
node ghpipe.js
してconsole1つ放置してください。Ctrl-cで終了想定。
喋るかの確認とかはmkfifoしてあるので実行中に他から並行で
echo "そだねー" > googleHome.pipe
とかで試せます。

ソース(同じディレクトリに並べてください

ghpipe.js
var fifoPath;
const fs = require('fs');
process.argv.forEach(function (val, index, array){
  if ( val === '-f' && array[index + 1] != undefined) {
    fifoPath = array[index + 1];
  }
});
console.log(fifoPath);
try {
  fs.statSync(fifoPath);
} catch(err) {
  fifoPath = './googleHome.pipe';
}
// console.log('ghpipe:' + fifoPath);
const googleHomePipe = require('./googleHomePipe');
googleHomePipe.connect(fifoPath);
const twline = require('./twline');
twline.connect(fifoPath, 'user');
googleHomePipe.js
module.exports = {
  connect: function(fifoPath){
    const fs = require('fs');
    const fd = fs.openSync(fifoPath, 'r+');
    const stream = fs.createReadStream(null, { fd });
    const googlehome = require('google-home-notifier');
    const language = 'ja';
    googlehome.device('Google-Home', language);

    stream.on('data', (data) => {
      var msg = data.toString().trim();
      // console.log('message:', msg);
      if (msg === 'EOF') {
        console.error('CLOSE END.');
        stream.close();
        return;
      }
      googlehome.notify(msg, function (res) {
        // console.error(res);
      });
    });

    stream.on('error', function(error) {
      console.error(error);
      throw error;
    });

  }
};
twline.js
module.exports = {
  connect: function(fifoPath, filter) {
    const chalk = require('chalk');
    const fs = require('fs');
    const twitter = require('twitter');
    const client = new twitter({
        consumer_key:        '取得方法 twitter apiとかで検索してください',
        consumer_secret:     '何か他のapi利用したクライアント動かすと',
        access_token_key:    '取得してくれて',
        access_token_secret: 'ファイルに残してくれたりするのでそれ流用とかでも。',
    });
    const fifo = fs.createWriteStream(fifoPath);

    client.stream(filter, function (stream) {
      stream.on('data', function(tweet) {
        // console.log('tw: %o', tweet);
        var msg = tweet.user.name + ' ' + tweet.text.toString().trim();
        console.log(chalk.white.bgBlue(tweet.user.screen_name) + ' ' + tweet.text);
        fifo.write(msg);
      });

      stream.on('end', function() {
        console.info('END');
      });

      stream.on('error', function(error) {
        console.error(error);
        throw error;
      });
    });
  },
};

空き時間にちょこちょこやったので基本コピペで異常系無視でconstとvarの使い分けとかstreamとかイイカゲン過ぎますのであしからず。
twline.jsのほうでtwitter.streamのfilterを検索とかにも出来ると思いますがリクエスト走ると前のはキャンセルされちゃいますのでカブらずに最後のだけ喋る感じです。