てきとう

てきとう

goo.glをいじってみる

日記書くネタもないし、なんか面白そうだったので、http:request/4の練習をかねて。
最初のうちは元ソースを読んでましたが、最終的にPython版の丸写し。*1
色々*2酷い事になっていますが、気にしてはいけません。


使い方:

1> c(googl).
{ok,googl}
2> inets:start().
ok
3> googl:get_short_url("http://d.hatena.ne.jp/zubenalt/").
"http://goo.gl/SsZe"
4> 

書いてる現在、ちゃんと動いてる・・・はず。

以下はソース。


JSONを読むのにmochijson2を使っているので、mochiwebを取ってくる必要があります。

%%% File    : googl.erl
%%% Author  : Zubenalt
%%% Description : depends on mochijson2
%%% Created : 16 Dec 2009 by Zubenalt

-module(googl).

-export([get_short_url/1, get_short_url/2]).
%-compile(export_all).

get_short_url(URI) ->
    get_short_url(URI,"toolbar@google.com").
get_short_url(URI, User) ->
    Token=make_auth_token(URI),
    Body="user="++User++"&url="++urlencode(URI)++"&auth_token="++Token,
    Ggl_URL="http://goo.gl/api/url",
    case http:request(post,
		      {Ggl_URL,[],"application/x-www-form-urlencoded",Body},
		      [{timeout, 6000}],[]) of
	{ok, {_,_,Res}}->
	    {struct,L}=R=mochijson2:decode(Res),
	    case lists:keyfind(<<"short_url">>,1,L) of
		{<<"short_url">>,Short_URL} ->
		    binary_to_list(Short_URL);
		false ->
		    {error, R}
	    end;
	Others -> Others
    end.

c(A)->
    c(0,A).
c(L,[])->
    L;
c(L,[H|T]) ->
    c(L+(H band 4294967295),T).

d(L) when L=<0 ->
    d(L+4294967296);
d(L) ->
    M=integer_to_list(L),
    O=d_(0,lists:reverse(M),false),
    M_=O rem 10,
    O_=o_1(M_,0,M),
    integer_to_list(O_)++M.

d_(O,[],_) ->
    O;
d_(O,[H|T],true) ->
    Q=list_to_integer([H])*2,
    d_(O+Q div 10+Q rem 10,T,false);
d_(O,[H|T],false) ->
    Q=list_to_integer([H]),
    d_(O+Q,T,true).

o_1(0,O,_) ->
    O;
o_1(M_,_O,M) ->
    o_2(M_,10-M_,M) div 2.
o_2(_M_,O,M) when length(M) rem 2 =/=1 ->
    O;
o_2(M_,O,M) ->
    o_3(M_,O,M).
o_3(_M_,O,_M) when O rem 2 =/=1 ->
    O;
o_3(_M_,O,_M) ->
    O+9.

e(URI) ->
    e_(5381,URI).
e_(M,[]) ->
    M;
e_(M,[H|T]) ->
    e_(c([M bsl 5, M, H]),T).

f(URI) ->
    f_(0,URI).
f_(M,[]) ->
    M;
f_(M,[H|T]) ->
    f_(c([H, M bsl 6, M bsl 16, -1*M]),T).

make_auth_token(URI) ->
    I_1 = e(URI),
    I_2 = (I_1 bsr 2) band 1073741823,
    I_3 = (I_2 bsr 4) band 67108800 bor (I_2 band 63),
    I_4 = (I_3 bsr 4) band 4193280 bor (I_3 band 1023),
    I = (I_4 bsr 4) band 245760 bor (I_4 band 16383),
    H = f(URI),
    K_1 = ((I bsr 2) band 15 bsl 4) bor H band 15,
    K_2 = K_1 bor ((((I bsr 6) band 15) bsl 12) bor ((H bsr 8) band 15 bsl 8)),
    K_3 = K_2 bor ((I bsr 10) band 15 bsl 20 bor ((H bsr 16) band 15 bsl 16)),
    K = K_3 bor (((I bsr 14) band 15) bsl 28 bor ((H bsr 24) band 15 bsl 24)),
    "7" ++ d(K).
    

-define(is_safe(C),
	$0=<C andalso C=<$9 orelse
	$A=<C andalso C=<$Z orelse
	$a=<C andalso C=<$z orelse
	C=:=$. orelse C=:=$- orelse C=:=$_ orelse C=:=$~).
urlencode(URI) ->
    urlencode(URI,[]).
urlencode([],Res) ->
    lists:flatten(lists:reverse(Res));
urlencode([H|T],SoFar) when ?is_safe(H) ->
    urlencode(T,[H|SoFar]);
urlencode([$\s|T],SoFar) ->
    urlencode(T,[$+|SoFar]);
urlencode([H|T],SoFar) ->
    urlencode(T,[[37|io_lib:format("~.16B",[H])]|SoFar]).

*1:id:LaclefYoshiさんありがとうございます、というか勝手に使ってすみませんm(__)m

*2:urlencode/2が勘だったり、http:request/4の引数が適当だったり