wget.js2008年06月11日 03時54分48秒

wget.js

まったくもってくだらんと思うが、コマンドライン引数でURL渡すとローカルに保存するコンソールスクリプト。なんで作ろうとしたのか忘れたけど、なんか作ってみたので載せてく。

ソース

※:同じローカルファイル名で上書きできないバグを修正しました(08.06.13)

※:この記事のコメント欄でhATrayfloodさんからContent-Disposition対応ソースのURLを教えていただきました。ソースはこちら(JSファイル直リン)。(11.08.25)

以下のソースをコピーして「wget.js」とでもつけてローカルに保存するか、これを名前をつけて保存。

依存ライブラリは一切なし。ライセンスはNYSLね。

var fso = new ActiveXObject("Scripting.FileSystemObject");
var shell = new ActiveXObject("WScript.Shell");

// コマンドライン引数の取得
var args = new function() {
  var args = WSH.Arguments, result = [];
  for(var col = new Enumerator( args ); ! col.atEnd(); col.moveNext()) {
    result[ result.length ] = String( col.item() );
  }
  var named = {};
  for(var col = new Enumerator( args.Named ); ! col.atEnd(); col.moveNext()) {
    named[ String( col.item() ) ] = String( args.Named.Item( col.item() ) );
  }
  var unnamed = [];
  for(var col = new Enumerator( args.Unnamed ); ! col.atEnd(); col.moveNext()) {
    unnamed[ unnamed.length ] = String( col.item() );
  }
  result.named = named;
  result.unnamed = unnamed;
  
  result.toArray = function() {
    var result = [];
    for(var i = 0, l = this.length; i < l; i++) {
      result[ i ] = /((^".*"$)|(^'.*'$))/.test( this[i] ) ?
        this[i] : [ '"', this[i], '"' ].join("");
    }
    return result;
  };
  result.toString = function() {
    return this.toArray().join(" ");
  };
  return result;
}();

// cscriptで強制起動
if( /wscript\.exe$/i.test( WSH.FullName ) ) {
  shell.Run( [
    "cscript",
    /((^".*"$)|(^'.*'$))/.test( WSH.ScriptFullName ) ? WSH.ScriptFullName : [ '"', WSH.ScriptFullName, '"' ].join(""),
    args
  ].join(" ") );
  WSH.Quit();
}

// ユーティリティ関数定義
var echo = function(s) {
  print( [ s, "\n" ].join("") );
}
var print = function(s) {
  WSH.StdOut.Write( s || "" );
}
var input = function() {
  if( arguments[0] ) print( arguments[0] );
  print( ">" );
  return WSH.StdIn.ReadLine();
}
var nameFromUrl = function(url) {
  var parts = url.split( /[\\\/]/g );
  var f = parts[parts.length - 1];
  f = f.replace( /[\\\/:,;\*\?"<>\|]/g, "_" );
  parts[parts.length - 1] = f;
  return f;
}

Error.prototype.toString = function() {
  return this.description || this.message || this.number || this;
}

if( ! args.length || /^\/(\?|(help))/i.test( args[0] ) ) {
  // 引数がないか、ヘルプスイッチが指定された場合は使い方を表示して終了
  echo( "使い方 : [cscript | wscript] wget.js [ ]" );
  echo( "オプション : " );
  echo( "        アクセスするインターネットリソースのURL" );
  echo( "  保存先ファイルパス。省略時はURLのファイル名と" );
  echo( "             同じ名前でカレントディレクトリに保存" );
  echo();
  input( "Enter キーで終了します" );
} else {
  // メイン処理
  var url = args.unnamed[0], fileName = args.unnamed[1] || nameFromUrl(url);

  var xhr = new ActiveXObject("Microsoft.XMLHTTP");
  xhr.open( "get", url, true );
  var completed = false;
  xhr.onreadystatechange = function() {
    print( "." );
    if( xhr.readyState < 4 ) return;
    echo();
    try {
      var headers = (function(headers) {
        var result = {}, lines = headers.split( /((\r\n)|\r|\n)/g );
        for(var i = 0, l = lines.length; i < l; i++) {
          var matches = /^([^:]+): (.*)$/.exec( lines[i] );
          if( matches ) result[ matches[1].toLowerCase() ] = matches[2];
        }
        return result;
      })( xhr.getAllResponseHeaders() );
      echo( [ "ファイルサイズ : ", headers[ "content-length" ] || "不明" ].join("") );
      
      var stream = new ActiveXObject("ADODB.Stream");
      stream.Open();
      stream.Position = 0;
      stream.Type = 1;
      stream.Write( xhr.responseBody );
      stream.SaveToFile( fileName, 2 );  // adSaveCreateOverWrite
      echo( "完了" );
      
    } catch(e) {
      echo( e );
    } finally {
      if( stream ) {
        try { stream.Close(); } catch(ie) {}
      }
    }
    completed = true;
  }
  print( [ "url '", url, "' に接続中..." ].join("") );
  xhr.send();
  while( ! completed ) {
    WSH.Sleep( 50 );
  }
}

使い方

コマンドラインからcscript経由で使う。別にwscriptでもいいけど。

んで、カレントにwget.jsがあるとして、「http://server.domain/path/to/file.zip」をダウンロードするには

C:\wget_js>cscript wget.js http://server.domain/path/to/file.zip
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

url 'http://server.domain/path/to/file.zip' に接続中...
ファイルサイズ:1024
完了

C:\wget_js>

なんて感じ。

保存時のファイル名を指定したい場合は第二引数を使う。

C:\wget_js>cscript wget.js http://server.domain/path/to/file.zip myfile.zip
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

url 'http://server.domain/path/to/file.zip' に接続中...
ファイルサイズ:1024
完了

C:\wget_js>

て具合。保存先は当然パス指定もOK。

あとは

@echo off
cscript //nologo C:\wget_js\wget.js %*

みたいなバッチファイルを%SystemRoot%にでも入れとけばそこはかとなくwget風。

仕組みとか注意点とか

Microsoft.XMLHTTPでURLにアクセスして、受信したresponseBodyをそのままADODB.Streamに喰わせて保存してるだけ。

こんな乱暴なアプローチなので、いきおいすべてのデータをメモリ上で取り扱う構造なので、大きいファイルをこれで落とそうなんてしないほうがよいかと。あと、ftpでコケたときあったなー。XHRがエラー吐きやがるの。

あ、あとURLにfile://~とかやるとコピーコマンド代わりになるとか。まったく意味ないけど。

作ったはいいけど、自分でも使わなそうだなー。

コメント

_ hATrayflood ― 2011年08月21日 01時31分05秒

Content-Dispositionに対応させたので貼っておきます。

_ dara-j ― 2011年08月25日 20時25分50秒

hATrayfloodさん、コメントありがとうございます。

ちょっとContent-Dispositionを返してくれるようなURLが手近に見当たらなかったのでまだ動作は確認してませんが、ソース参考にさせていただきます。

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※なお、送られたコメントはブログの管理者が確認するまで公開されません。

名前:
メールアドレス:
URL:
コメント:

トラックバック

このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2008/06/11/3572173/tb

※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。