ustreamの録画flvデータのURLを得るスクリプト

Clouder::Blogger: ustreamの録画した動画のflvをダウンロードする方法

これは想像ですが、swf内でhttp://gw.ustream.tv/gateway.phpをPOSTしているのはわかっているので、そこで取得しているのか、もしくはJavaScriptでAjaxをつかってどこかから取得しているのか、といったところだと思いますが、いずれにしてももう少し解析が必要です。

とあるのをみて、gateway.php を調べてみました。

これはFlashのAMFのRPCサーバーで、録画されたものを再生するときには client.watch_video という関数を呼んでいるようです。

as3で書くと

package {
    import flash.display.*;
    import flash.net.*;

    public class gw extends Sprite {
        public function gw() {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;

            var cid:String = stage.loaderInfo.parameters["cid"];
            if (cid) {
                var nc:NetConnection = new NetConnection();
                nc.objectEncoding = ObjectEncoding.AMF0;
                nc.connect("http://gw.ustream.tv/gateway.php");
                nc.call("client.watch_video", new Responder(gatewayHandler), { cid: cid });
            }
        }

        private function gatewayHandler(res:Object):void {
            for (var i:String in res) {
                log(i+": "+res[i]);
            }
        }
    }
}

こんな感じになります。cid は再生URL http://ustream.tv/recorded/RLdKCmCouWOpkkEznZH4QA とかの RLdKCmCouWOpkkEznZH4QA 部分です。

これをperlで呼ぶにはどうしたらいいか! ということでがんばってみました。

CPANにこのAPIのサーバー側の実装 (AMF::Perl) があったのでそれを適当に読んだり、実際API呼んでるときのパケットと見比べたりしつつして以下のようにすればできました。

#!/usr/bin/env perl

use strict;
use warnings;

use AMF::Perl;
use LWP::UserAgent;

my $cid = shift || '5Fq8cQp9eHsEEknbQ22OOZniqS2xUiuz';

my $amf = AMF::Perl::Util::Object->new;
$amf->addBody('client.watch_video', '/1', { cid => $cid });

my $outputstream = AMF::Perl::IO::OutputStream->new;
my $serializer = AMF::Perl::IO::Serializer->new($outputstream, 'utf-8');
$serializer->serialize($amf);

my $amfdata = $outputstream->flush;

$amfdata =~ s/\xff\xff\xff\xff/\0\0\0\x31\x0a\0\0\0\x01/;

my $ua = LWP::UserAgent->new;

my $req = HTTP::Request->new( POST => 'http://gw.ustream.tv/gateway.php' );
$req->content( $output );
$req->content_type('application/x-amf');
$req->content_length( length $amfdata );

my $res = $ua->request($req);

my $deserializer = AMF::Perl::IO::Deserializer->new(AMF::Perl::IO::InputStream->new($res->content), 'utf-8');

use YAML;
print Dump $deserializer->getObject->getBodyAt(0)->{value};

これで

---
err_desc: ok
server_id: 9
success: 1
user_id: 32983
video_length: 366.207
video_name: broadcast/35957/1191239239348
video_type: broadcast

とかいう出力がでます。これから

http://flash{server_id}.ustream.tv:18881/{video_name}.flv

というflvのURLが作れます。

perlソースの途中の謎の置換 s/\xff\xff\xff\xff/\0\0\0\x31\x0a\0\0\0\x01/; してて、これはなにかよくわかってません。ただ実際のパケットと見比べて違う部分置換してみたらいけたという代物です。

あとこれで得られるflvデータの音声部分が謎のcodecで変換できない! だれかこれをmp3とかにする方法ご存知のかたいましたらぜひともお知らせください!

by typester / at 2007-10-03T19:18:00 / perl · ustream / Comments(0)