Raspberry PiでNode.jsを使ってYoutubeストリーミング

Raspberry Piを手に入れてまず試しにやってみるのは音楽をストリーミング再生させてみることではないでしょうか。（私だけ？）

コマンドラインを利用すれば簡単にストリーミングさせることができます。

[コマンドラインからyoutubeを再生する - Qiita](http://qiita.com/tigberd/items/594c27426c5580450bf2)

こちらにあるように

```bash:ssh
$ youtube-dl 'https://www.youtube.com/watch?v=hoge' -o - | mplayer -
```

簡単にストリーミング再生出来ます。

## Node.jsでコマンドライン操作

Node.jsのマニュアル & ドキュメンテーションを見ると

```js:app.js
var spawn = require('child_process').spawn,
    ls    = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

ls.on('close', function (code) {
  console.log('child process exited with code ' + code);
});
```

こんな風に書いてあります。通常のコマンドはこれでいけるのですが、二つ以上のコマンドを組み合わせようとすると（パイプ）上手くいきません。

## node.jsでパイプを使ったコマンドを実行するには

[node.jsでパイプを使ったコマンドを実行するには - GitHubGist](https://gist.github.com/kjunichi/9439946)

こちらのGistを拝見したところ、`sh -c` コマンドを`child_process`で実行して、実際に行いたいコマンドは引数に格納して実行すれば良い様です。

分かった様な、分からない様な。（分ってない）試しに`app.js`をこんな風に書いてみました。

```js:app.js
var spawn = require('child_process').spawn;

var cmd = "youtube-dl 'https://www.youtube.com/watch?v=wArJc179HNk' -o - | mplayer - -novideo";

function shspawn(command) {
  return spawn('sh', ['-c', command]);
}

var child = shspawn(cmd);
var buf="";

child.stdout.on('data',function(data){
  buf=buf+data;
});
child.stderr.on('data',function (data){
  console.log('exec error: '+data);
});

child.on('close',function(code) {
  console.log("exit.");
});
```

1時間ほどのプレイリスト - [Indie/Indie-Pop Compilation - May 2015 (55-Minute Playlist)](https://www.youtube.com/watch?v=BChec-L3_Xo&ebc=ANyPxKpIBjIEemhBJDFnNed2SC7Oe0NsbGqykAvmOjL83vkx669Xl5KYSw_l9r87XsvVQ2Y3e4MxYL6Z_7SnIIeBrmFXZmZ6xQ) ですが上手くストリーミング再生出来ました。

## expressを使ってブラウザで操作する

`express`を利用して幾つかのプレイリストを操作できる様にしてみました。

![PonTube Pi 2016-03-02 23-29-46.png](https://qiita-image-store.s3.amazonaws.com/0/47128/5a0f315d-b2e1-b0cd-1ec1-bd3790d2d204.png)

```js:app.js
var express = require('express');
var ejs = require("ejs");
var spawn = require('child_process').spawn;

var app = express();
app.engine('ejs',ejs.renderFile);

app.get('/', function(req, res){
    res.render('pontube.ejs',
        {title: 'PonTube Pi'});
});

app.get('/control', function (req, res) {
  console.log(req.query);
  var id = req.query.id;
  var watch =  "https://www.youtube.com/watch?v=" + id;

  var clear_cmd = "killall mplayer";
  //console.log("cmd = "+cmd);

  function shspawn(command) {
    return spawn('sh', ['-c', command]);
  }

  var child = shspawn(clear_cmd);
  var buf="";

  child.stdout.on('data',function(data){
    buf=buf+data;
  });
  child.stderr.on('data',function (data){
    //console.log('exec error: '+data);
  });

  child.on('close',function(code) {
     console.log( 'CLEAR. PLAY.' );
  });

  var play_cmd = "youtube-dl " + watch + " -o - | mplayer - -novideo";

  function shspawn(command) {
    return spawn('sh', ['-c', command]);
  }

  var child = shspawn(play_cmd);
  var buf="";

  child.stdout.on('data',function(data){
    buf=buf+data;
  });
  child.stderr.on('data',function (data){
    //console.log('exec error: '+data);
  });

  child.on('close',function(code) {
    console.log( 'EXIT.' );
  });


});

  app.get('/stop', function (req, res) {
    console.log(req.query);
    var id = req.query.id;

    var stop_cmd = "killall mplayer";
    //console.log("cmd = "+cmd);

    function shspawn(command) {
      return spawn('sh', ['-c', command]);
    }

    var child = shspawn(stop_cmd);
    var buf="";

    child.stdout.on('data',function(data){
      buf=buf+data;
    });
    child.stderr.on('data',function (data){
      //console.log('exec error: '+data);
    });

    child.on('close',function(code) {
    console.log( 'STOP.' );
    });

    });

var server = app.listen(3000, function () {
  var host = server.address().address
  var port = server.address().port
  console.log('This app listening at http://192.168.0.12:'+ port)
});

```

```html:views/pontube.ejs
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta http-equiv="content-type"
        content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
    <title><%=title %></title>
     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" type="text/css" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
    <style>
    body{
      margin: 0 auto;
      max-width: 640px;
    }
     article{
       margin: 20px;
     }
    </style>
    </head>
<body>
    <header>
        <h1 class="text-center h2"><%=title %></h1>
    </header>
    <article>
    <div class="list-group">
      <button type="button" class="list-group-item" id="wArJc179HNk">Indie/Indie-Pop Compilation - May 2015 (55-Minute Playlist)</button>
      <button type="button" class="list-group-item" id="YYYJDalKI9E">Indie/Pop/Folk Compilation - January 2016 (1-Hour Playlist)</button>
      <button type="button" class="list-group-item" id="wiKgHFU8L9g">1.5 Hours of Rock n' Roll - Rock/Hard Rock Playlist</button>
      <button type="button" class="list-group-item" id="WVP3fUzQHcg">2 HOUR LONG Piano Music for Studying, Concentrating, and Focusing Playlist</button>
      <button type="button" class="list-group-item" id="ubZASS3uPrs">Relaxing Love Songs 80's & 90's Playlist</button>
    </div>
      <button class="btn btn-default" id="stop">stop</button>
    </article>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

    <script>
        $(".list-group-item").click(function() {
                var station = $(this).attr("id");　
                $.get("http://192.168.0.12:3000/control", { id: station } );
            });
        $(".btn").click(function() {
                var stop = $(this).attr("id");　
                $.get("http://192.168.0.12:3000/stop", { id: stop } );
            });

    </script>

</body>
</html>

```

コマンドライン操作も良いですが、手元のブラウザから操作出来ると愛着が湧いてきます。

![DSC_0001.jpg](https://qiita-image-store.s3.amazonaws.com/0/47128/e1e26ff9-3648-8aae-2356-5686ccaed700.jpeg)

音声コマンドと組み合わせても面白いかもしれません。では。