chromecast-api ＋ Node.js（JavaScript）で Chromecast への動画のキャストを行う

以下の記事で扱った「Chromecast制御 ＋ JavaScript」の話に似た内容です。

●castjs を使って Chromecast への動画のキャストを JavaScript で行う（p5.js も併用） - Qiita
　https://qiita.com/youtoy/items/595147a78f4d2b2c8630

上記との違いは、自前で用意したプログラムをブラウザで動作させるのではなく、Node.js で動作させるという部分です。

## 今回利用するパッケージ
今回は、以下のパッケージを使って実装します。

●chromecast-api - npm
　https://www.npmjs.com/package/chromecast-api

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/6c3b7047-65ef-982a-3ebf-3189b31ac839.png)

## 実装内容
### JavaScript のコード
JavaScript のコードを以下に示します。

主要な部分は、[冒頭に掲載した記事](https://qiita.com/youtoy/items/595147a78f4d2b2c8630)で扱ったブラウザ向けに実装したものと似ていますが、いくつか違いがあります。それについては、コードの後の部分で書きます。

```javascript
const ChromecastAPI = require("chromecast-api");
const readline = require("readline");

const client = new ChromecastAPI();
let currentDevice = null;

const mediaURL =
  "http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4";

const friendlyName = "【ご自身の Chromecast の名前】";

client.on("device", function (device) {
  if (device.friendlyName !== friendlyName) {
    return;
  }

  currentDevice = device;
  device.play(mediaURL, function (err) {
    if (!err) {
      console.log(
        `デバイス名 ${currentDevice.friendlyName} の Chromecast で再生を開始しました`
      );
      console.log("'stop'と入力してEnterを押すと、キャストを停止します。");
    } else {
      console.error("再生開始時にエラーが発生しました:", err);
    }
  });
});

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on("line", (input) => {
  if (input.toLowerCase() === "stop") {
    if (currentDevice) {
      currentDevice.close(function (err) {
        if (!err) {
          console.log("キャストを停止しました。");
          rl.close();
          process.exit(0);
        } else {
          console.error("キャスト停止時にエラーが発生しました:", err);
        }
      });
    } else {
      console.log("接続されているデバイスがありません。");
    }
  } else {
    console.log("'stop'と入力してEnterを押すと、キャストを停止します。");
  }
});
```

### ブラウザ向けの実装と違う点
冒頭に掲載した記事で示していた、ブラウザ向けの実装と異なる点について少し触れます。

#### 接続するデバイスの指定
まず、以下の部分です。

```javascript
const friendlyName = "【ご自身の Chromecast の名前】";

client.on("device", function (device) {
  if (device.friendlyName !== friendlyName) {
    return;
  }

  。。。
}
```

「【ご自身の Chromecast の名前】」は、自分がつなぎたい Chromecast の名前を設定するところです。これを用いて、接続するデバイスを絞りこんでいます。

これを行った理由を少し補足します。

ブラウザ向けの実装だと、ブラウザ上で接続することが可能なデバイスのリストが表示され、それを手動で選ぶことで接続するデバイスが決まる流れでした。そのため、1回の処理でつながる先のデバイスは 1台となっていました。

一方、今回の記事の内容では、上記のデバイス指定の処理を入れておかないと、複数の接続可能なデバイスがある場合には、それらにいっせいにキャストを行ってしまいます。自分の自宅で試した時、このデバイス指定を行わずにキャストを行った際、画面付のスマートスピーカーも含め複数台のデバイスで同時に動画再生が行われてしまいました。

#### 接続解除の処理
次に、node コマンドを実行した後の状態で、文字列「stop」を入力して Enterキーを押すという入力・操作で、Chromecast との接続の解除が行われるようにしました。

これに関連する部分は、以下のとおりです。

```javascript
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on("line", (input) => {
  if (input.toLowerCase() === "stop") {
    if (currentDevice) {
      currentDevice.close(function (err) {
        if (!err) {
          console.log("キャストを停止しました。");
          rl.close();
          process.exit(0);
        } else {
          console.error("キャスト停止時にエラーが発生しました:", err);
        }
      });
    } else {
      console.log("接続されているデバイスがありません。");
    }
  } else {
    console.log("'stop'と入力してEnterを押すと、キャストを停止します。");
  }
});
```

もちろん、文字列の入力をトリガーにするのではなく、特定のキー単体での入力にしてしまっても問題ありません。

Readline を使ってそのような実装を行ったこともあるので、もし特定のキー単体での入力をトリガーにした実装にしたい場合は、よろしければ以下の記事をご覧ください。

●Node.js でキー入力を利用した効果音ポン出しをやってみる： Readline と play-sound を利用 - Qiita
　https://qiita.com/youtoy/items/64cbcd511869ed312c63

●Node.js で Readline をシンプルに使う（1桁の数字の入力を扱う） - Qiita
　https://qiita.com/youtoy/items/fcdab642baa7007f4645

### 実行してみる
それではプログラムを実行してみます。プログラムを実行する前準備として、npm コマンドでパッケージをインストールしておいてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/30b60989-2947-f150-1403-b0994ddd3aea.png)

あとは、node コマンドで処理を実行すると、Chromecast での動画再生が始まります。
また、node コマンドを実行した後の状態で、文字列「stop」を入力して Enterキーを押すと Chromecast との接続の解除が行われます。

これで、chromecast-api ＋ Node.js を使った Chromecast への動画のキャストを実現できました。