2011/05/11

生成したプロセスの標準入出力を別のプロセスにリダイレクト

NILScriptでは、「Process.create()」やそのエイリアスである「run()」で外部プロセスを起動できます。
このメソッドでは、第2引数にオブジェクトとして様々なオプションを指定する事で、標準入出力の扱いなどを柔軟に設定出来ます。
例えば、「stdin」オプションにあらかじめProcess.create()で生成しておいた別のProcessオブジェクトを指定すると、そのプロセスの標準出力を次のプロセスの標準入力にリダイレクト出来ます。
コマンドプロンプトで「|」で複数のコマンドを繋いだときのように、出力と入力を直接繋ぐので、スクリプト側で読み出しと書き込みを行うよりも効率的に動作します。
他にも、ファイルやNULデバイスへのリダイレクトも可能です。これらの機能の詳細は、NILScriptに同梱のdoc\base_task.txtを参照して下さい。

以下は、この機能の利用例です。
//プログラムのパスと保存先を指定
var rtmpdump='D:\\bin\\rtmpdump-2.1d\\rtmpdump.exe';
var ffmpeg='D:\\bin\\ffmpeg.exe';
var dir='F:\\downloads';

var url=prompt('Enter MySpace URL(artist or song)','http://www.myspace.com/astralmess');
var swf='http://lads.myspacecdn.com/videos/MSMusicPlayer.swf';
var http=new (require('HTTP').HTTP)();

var downloadSong=function(sid){
    var xml=http.getText({
        url:'http://www.myspace.com/music/services/player?songId='+sid
          +'&ptype=4&action=getSong&el='+encodeURIComponent(url)+'&sample=0',
        referer:swf,
    });
    var title=xml.match(/<title>([^>]*)<\/title>/)[1].unescapeHTML();
    var rtmp=xml.match(/<rtmp>([^>]*)<\/rtmp>/)[1].unescapeHTML();
    println('Downloading: '+title);
    var p1=Process.create('"'+rtmpdump+'" -r '+rtmp+' -W '+swf+' -o -',{
        show:0
    });
    var p2=Process.create('"'+ffmpeg+'" -i - -acodec copy -metadata title="'
                    +title+'" "'+dir+'\\'+title.format('asfE')+'.mp3"',{
                        stdin:p1,
                        stdout:"",
                    });
    p2.wait('exit');
};

var m;
if(m=url.match(/^http:\/\/www\.myspace\.com\/[^\/]*\/music\/songs\/.*\-(\d+)$/i)){
    downloadSong(m[1]);
}else if(m=url.match(/^http:\/\/www\.myspace\.com\/[^\/]*\/?$/)){
    var html=http.getText(url);
    m=html.match(/<param[^>]*value="[^>"]*MSMusicPlayer\.swf"[^>]*>[\s\S]*?<param name="flashvars" value="([^">]*)"/)
    var param={};
    for(let pair in $G(m[1].split(/&/g))){
        var [,name,value]=pair.match(/^(.*?)=(.*)$/);
        param[name]=value;
    }
    http.getText({
        url:'http://www.myspace.com/music/services/player?artistUserId='
            +param.profid+'&playlistId='+param.plid
            +'&action=getArtistPlaylist&artistId='+param.artid,
        referer:swf,
    }).grep(/<song\s(?=[^>]*playType="FullSong")[^>]*songId="(\d+)"/g).map("1").execute(downloadSong);
}
音楽系SNS「MySpace」の指定したURLのページからプレイリストを抽出し、ストリーミングURLを「rtmpdump」でダウンロードし、「ffmpeg」でFLVからMP3を抽出して保存するというスクリプトですが、rtmpdumpの出力をffmpegにリダイレクトすることで、一時ファイルを作らずに処理を完了しています。
太字になっている部分が、ffmpegの標準入出力を指定している部分です。
「stdout:""」は、NULへのリダイレクトを示します。このようにして進捗などの出力を読み捨てないと、出力バッファが一杯になって処理が止まってしまう可能性があるので、注意が必要です。

0 件のコメント:

コメントを投稿