2008/11/06


UN*X版だとssh-agentの実行結果が SSH_AUTH_SOCK=/tmp/ssh-suhGif2116/agent.2116; export SSH_AUTH_SOCK;
SSH_AGENT_PID=5672; export SSH_AGENT_PID;
echo Agent pid 5672;
みたいになっててログイン時に eval `ssh-agent`
とするんですがWindowsだと、そう簡単には行かない。 @echo off
if not "%SSH_AGENT_PID%" == "" goto end
for /f "eol=; tokens=1,2 delims==;" %%1 in ('ssh-agent.exe') do (
 if "%%1" == "SSH_AUTH_SOCK" set SSH_AUTH_SOCK=%%2
 if "%%1" == "SSH_AGENT_PID" set SSH_AGENT_PID=%%2
)
ssh-add
:end
開発を始める前にコマンドプロンプトで1回これを動かすとパスフレーズを聞かれ、1回入力すれば以降は聞かれない様になる(sshはmsysGitに含まれる物を使ってる)。 さらにWindowsサポートツールに入ってる"setx.exe"を使えば、ユーザ環境変数への反映も出来る為、新しく起動したコマンドプロンプトでsshコマンドがSSH_AGENT_PID/SSH_AUTH_SOCKを見てくれるようになってもっとウマーとなるはず(↑のバッチでsetしている所でさらにsetxもする必要があるかな)。

とりあえずこれで楽になった。ウマー
Posted at by



2008/10/29


追記 最新版はgithubで作ってます。
mattn's nicodown at master — GitHub
http://github.com/mattn/nicodown/tree/master


適当だけど書いてみた。
タイトル取って来る所はlibxml使うの面倒臭かったのでXMLパーサ使わずベタで(実態参照文字あると変になるので気を付けて)。Windowsの場合だけWin32 APIでシフトJISにファイル名を変換しています。
荒いコードなので色々直し所がありますが、サンプルって事で。
//#define CURL_STATICLIB
#include <curl/curl.h>

#define HEX_DIGITS "0123456789ABCDEF"
#define IS_QUOTED(x) (*x == '%' && strchr(HEX_DIGITS, *(x+1)) && strchr(HEX_DIGITS, *(x+2)))

static char* response_data = NULL;  /* response data from server. */
static size_t response_size = 0;    /* response size of data */

static void
curl_handle_init() {
    response_data = NULL;
    response_size = 0;
}

static void
curl_handle_term() {
    if (response_data) free(response_data);
}

static size_t
curl_handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream) {
    if (!response_data)
        response_data = (char*)malloc(size*nmemb);
    else
        response_data = (char*)realloc(response_data, response_size+size*nmemb);
    if (response_data) {
        memcpy(response_data+response_size, ptr, size*nmemb);
        response_size += size*nmemb;
    }
    return size*nmemb;
}

int
main(int argc, char* argv[]) {
    CURLcode res;
    CURL* curl;
    char error[256];
    char name[256];
    char data[1024];
    char* buf = NULL;
    char* ptr = NULL;
    char* tmp = NULL;
    FILE* fp = NULL;
    int status = 0;

    // usage
    if (argc != 4) {
        fputs("usage: nicodown [usermail] [password] [video_id]", stderr);
        goto leave;
    }

    // default filename
    sprintf(name, "%s.flv", argv[3]);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_handle_returned_data);
    curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.jar");
    curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookies.txt");

    // login
    sprintf(data, "mail=%s&password=%s&next_url=/watch/%s", argv[1], argv[2], argv[3]);
    curl_handle_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://secure.nicovideo.jp/secure/login?site=niconico");
    curl_easy_setopt(curl, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, error);
        goto leave;
    }
    buf = malloc(response_size + 1);
    strcpy(buf, response_data);
    if (strstr(buf, "id=\"login_bar\"")) {
        printf("%s\n", buf);
        free(buf);
        fprintf(stderr, "failed to login\n");
        goto leave;
    }
    free(buf);
    curl_handle_term();

    // get video url, and get filename
    sprintf(data, "http://www.nicovideo.jp/api/getthumbinfo?v=%s", argv[3]);
    curl_handle_init();
    curl_easy_setopt(curl, CURLOPT_URL, data);
    curl_easy_setopt(curl, CURLOPT_POST, 0);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, error);
        goto leave;
    }
    buf = malloc(response_size + 1);
    strcpy(buf, response_data);
    ptr = strstr(buf, "<title>");
    if (ptr) {
        ptr += 7;
        tmp = strstr(ptr, "</title>");
        if (*tmp) {
            *tmp = 0;
            strcpy(name, ptr);
        }
#ifdef _WIN32
        {
            UINT codePage;
            size_t wcssize;
            wchar_t* wcsstr;
            size_t mbssize;
            char* mbsstr;

            codePage = CP_UTF8;
            wcssize = MultiByteToWideChar(codePage, 0, name, -1,  NULL, 0);
            wcsstr = (wchar_t*)malloc(sizeof(wchar_t) * (wcssize + 1));
            wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, wcsstr, wcssize + 1);
            wcsstr[wcssize] = 0;
            codePage = GetACP();
            mbssize = WideCharToMultiByte(codePage, 0, (LPCWSTR)wcsstr,-1,NULL,0,NULL,NULL);
            mbsstr = (char*)malloc(mbssize+1);
            mbssize = WideCharToMultiByte(codePage, 0, (LPCWSTR)wcsstr, -1, mbsstr, mbssize, NULL, NULL);
            mbsstr[mbssize] = 0;
            sprintf(name, "%s.flv", mbsstr);
            free(mbsstr);
            free(wcsstr);
        }
#endif
    }
    free(buf);
    printf("downloading %s\n", name);
    curl_handle_term();

    // get video url
    sprintf(data, "http://www.nicovideo.jp/api/getflv?v=%s", argv[3]);
    curl_handle_init();
    curl_easy_setopt(curl, CURLOPT_URL, data);
    curl_easy_setopt(curl, CURLOPT_POST, 0);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, error);
        goto leave;
    }
    buf = malloc(response_size + 1);
    strcpy(buf, response_data);
    ptr = strstr(response_data, "url=");
    if (!ptr) {
        free(buf);
        fprintf(stderr, "failed to get video info\n");
        goto leave;
    }
    tmp = strstr(ptr, "&");
    if (tmp) *tmp = 0;
    tmp = ptr;
    while(*tmp) {
        if (IS_QUOTED(tmp)) {
            char num = 0;
            sscanf(tmp+1, "%02x", &num);
            *tmp = num;
            strcpy(tmp + 1, tmp + 3);
        }
        tmp++;
    }
    strcpy(data, ptr + 4);
    printf("URL: %s\n", data);
    free(buf);
    curl_handle_term();

    // download video
    fp = fopen(name, "wb");
    if (!fp) {
        fprintf(stderr, "failed to open file\n");
        goto leave;
    }
    curl_handle_init();
    curl_easy_setopt(curl, CURLOPT_URL, data);
    curl_easy_setopt(curl, CURLOPT_POST, 0);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
    res = curl_easy_perform(curl);
    fclose(fp);
    if (res != CURLE_OK) {
        fprintf(stderr, error);
        goto leave;
    }

leave:
    curl_handle_term();
    curl_easy_cleanup(curl);

    return 0;
}
確認はWindowsでしかしてませんが、きっとUN*Xでも動くはず。perlやpythonやruby使わない派の方は雛形として持ってって下さい。

Posted at by




皆さん既に知ってたら御免なさい。ずっと知らなかったのでgithubには手を付けてませんでした。
githubは、cloneするとき # git clone git://github.com/yappo/konnitiwa.git
の代わりに # git clone http://github.com/yappo/konnitiwa.git
とgitをhttpにするとclone出来るのは知っていたのですが、pushはsshを使うのでport 22が開いてないとpush出来ない物と信じ込んでいました。
が、今日解決しました。以下私がWindowsで行った手順
Windowsじゃない人は最初の部分はすっ飛ばして下さい。

Git for Windowsを入れる

まずmsys Gitというのを入れます。
msysgit - Google Code
http://code.google.com/p/msysgit/downloads/list
注意点としては、PATH環境変数の設定具合によってはmsys Gitに含まれるコマンドライン郡の方が先に認識され、思う動きにならない可能性があります。例えば私の場合svn/trunkなvimを使っていますがmsys Gitにもvimが含まれている為、commit時にエラーが出たりします。

SSHキーを生成する

msys Gitに含まれるssh-keygenで生成します。 # ssh-keygen -C "xxx@example.com" -t rsa
以下省略

SSHキーをgithubに登録する

アカウントページにid_rsa.pubの値を貼り付けます。
https://github.com/account

github-ssh-pubkey
Titleは適当に"my windows abazure"と名付けました。

github.comへのssh接続を変更する

github.comへのSSH接続にはホスト名"ssh.github.com"、ポート"443"に接続する様に設定します。
※このssh.github.comが味噌です。
~/.ssh/config
Host github.com
    User git
    Hostname ssh.github.com
    Port 443
    IdentityFile c:/docume~1/mattn/.ssh/id_rsa
秘密鍵のパスをお間違え無く。

後はpushしまくれ

本当にpushしまくるのは良くないでしょうが...
yappo's konnitiwa at master — GitHub
こんにちわ
http://github.com/yappo/konnitiwa/tree/master
をforkし # git clone git@github.com:mattn/konnitiwa.git
Enter passphrase for key 'c:/docume~1/mattn/.ssh/id_rsa':
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 9 (delta 0), reused 6 (delta 0)
Receiving objects: 100% (9/9), done.
とclone出来ますのでREADMEを編集後に # git commit -a -m "added oops"
Created commit 109bbff: added oops
 1 files changed, 1 insertions(+), 0 deletions(-)
# git push Enter passphrase for key 'c:/docume~1/mattn/.ssh/id_rsa':
Counting objects: 5, done.
Writing objects: 100% (3/3), 264 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:mattn/konnitiwa.git
   66a8481..109bbff  master -> master
でpush出来ます。port 443なので防火壁内の人でもpush出来るかと思います。既にみんな知ってる話だと恥ずかしいですが...

それと昨日書いたニコニコ動画ダウンロードプログラムをgithubで作っていく事にしました。
mattn's nicodown at master — GitHub
http://github.com/mattn/nicodown/tree/master
codereposでも良かったのですが、なんなくgithubを使ってみたくなったので...

よいgithubライフを。

Posted at by