以前にニコニコ動画検索APIを作っていましたが、どうやら需要があるようです。
というわけで今回は検索のみではなくランキングも取得できるようにし作り直しました。
詳細はこちら。
現在はテスト運用ということで自分のテスト用ドメインで動作させています。
気が向いたらちゃんとしたドメインを取得します。
ランキングで動画データの宣伝のカウントが-1になっているのは仕様です。
今後改善策を見つけます。
IT系の記事を書いています。コメント、Twitterのフォロー、Skypeのコンタクトの追加は気軽にどうぞ。
以前にニコニコ動画検索APIを作っていましたが、どうやら需要があるようです。
というわけで今回は検索のみではなくランキングも取得できるようにし作り直しました。
詳細はこちら。
現在はテスト運用ということで自分のテスト用ドメインで動作させています。
気が向いたらちゃんとしたドメインを取得します。
ランキングで動画データの宣伝のカウントが-1になっているのは仕様です。
今後改善策を見つけます。
意外と使うことが多いのでメモ程度にライブラリを作った。
public final class ByteArray {
static byte[] fromObject(Object o) throws IOException{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(o);
byte[] bytes = bos.toByteArray();
out.close();
bos.close();
return bytes;
}
static Object toObject(byte[] bytes) throws OptionalDataException, StreamCorruptedException, ClassNotFoundException, IOException{
return new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
}
}
現在Androidの開発をやっているのですが、AIDLで通信するときにプリミティブ型(byte,int,String,and so on)のデータしか送れない。
本来ならParcelableを使わないといけないらしいのですが、そんなもの守る気はありません←
というわけで上のメソッドを使えば簡単にSerializableを実装しているObjectとByteを相互変換できます。
なんか、いろいろ難しい。
HttpsURLConnectionでKeep-Alive?
そんなことするならSSLSocket使って自分で処理します。
というわけで今回はAndroidでSSLSocketを使う方法。
javax.net.SocketFactory;
javax.net.ssl.SSLSocketFactory;
とりあえずこいつらを使います。
Socket s = SSLSocketFactory.getDefault().createSocket(host,port);//portは基本443で。
これでおk。はい、めでたしめでたし。
そしておまけ。
AndroidでBASE64エンコードするのは
android.util.Base64;
こいつをインポートして、
Base64.encodeToString("文字".getBytes(), Base64.DEFAULT);
これでおk。
どこのページに行ってもOAuthの事に関していろいろ書いてあるけど率直で使いやすいものがあまりみつからない。(俺の頭が悪いだけ)
というわけで今回はAndroidでTwitterのOAuth認証を簡単にできるActivityを作った。
このActivityに飛ばしてあげるだけでOK。
ここではTwitter4j 2.1.8を使っています。
getOAuthRequestTokenメソッドにコールバックを指定するとなぜかエラーで落ちてしまうので、それを回避するように作ってます。
onAuthorizedメソッドの引数にAccessTokenとAccessTokenSecretが飛んできますのでご自由にお使いください。
以下ソースコード
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.*;
import android.view.*;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.*;
import twitter4j.*;
import twitter4j.http.*;
public void onAuthorized(String accessToken,String accessTokenSecret){
//認証後後にやりたいことをここに書く。
finish();
}
public class TwitterOAuth extends Activity{
private Display display;
private Handler handler = new Handler();
private LinearLayout base,form;
private EditText verifier;
private WebView wb;
private Twitter twitter;
private AccessToken accToken;
private RequestToken reqToken;
private final String CONSUMER_KEY = "xxxxxxxxxxxxxxxxx"; // Consumer key をセット
private final String CONSUMER_SECRET = "yyyyyyyyyyyyyyyyyyy"; // Consumer secret をセット
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences pref = getPreferences(MODE_PRIVATE);
if(pref.getString("AccessToken","").equals("")||pref.getString("AccessTokenSecret","").equals("")){
display = ((WindowManager)getSystemService(this.WINDOW_SERVICE)).getDefaultDisplay();
base = new LinearLayout(this);
base.setOrientation(LinearLayout.VERTICAL);
form = new LinearLayout(this);
form.setOrientation(LinearLayout.HORIZONTAL);
verifier = new EditText(this);
verifier.setWidth(display.getWidth()-100);
verifier.setHeight(20);
Button button = new Button(this);
button.setText("OK");
button.setHint("PIN CODE");
button.setWidth(100);
button.setHeight(20);
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
handler.post(new Runnable(){
public void run(){
try {
accToken = twitter.getOAuthAccessToken(reqToken,verifier.getText().toString());
Editor e = getPreferences(MODE_PRIVATE).edit();
String accessToken = accToken.getToken();
String accessTokenSecret = accToken.getTokenSecret();
e.putString("AccessToken",accessToken);
e.putString("AccessTokenSecret",accessTokenSecret);
e.commit();
onAuthorized(accessToken,accessTokenSecret);
} catch (TwitterException e) {}
}
});
}
});
wb = new WebView(this);
wb.setWebViewClient(new WebViewClient());
form.addView(verifier);
form.addView(button);
base.addView(form);
base.addView(wb,new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
setContentView(base);
doAuthorize();
}else{
Toast.makeText(this,"You are already authorized.", Toast.LENGTH_LONG).show();
finish();
}
}
public void doAuthorize(){
twitter = new TwitterFactory().getOAuthAuthorizedInstance(CONSUMER_KEY,CONSUMER_SECRET);
try{
reqToken = twitter.getOAuthRequestToken();
wb.loadUrl(reqToken.getAuthorizationURL().toString());
wb.requestFocus(View.FOCUS_DOWN);
}catch(Exception e){Toast.makeText(this, "ERROR.",Toast.LENGTH_SHORT).show();}
}
}
この内容は自分のようなStreaming API?^q^やSSL?’q`な方に向けて書いていきます。
まず大まかな流れ。
1.SSLソケットを作る
2.BASIC認証用のキーを作成する
3.キーを使いリクエストヘッダを作成し送信する
4.データをもらう
これだけ。
Javaで書くとソースコードはこんな感じ。
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import sun.misc.BASE64Encoder;class test{
public static void main(String[] args) throws Exception {
//SSLSocketを作成
Socket s = HttpsURLConnection.getDefaultSSLSocketFactory().createSocket("stream.twitter.com",443);
//入出力用
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream());
//filterの場合、track=検索キーワードでキーワード検索の結果をリアルタイムで取得できる。
out.println("GET /1/statuses/filter.json?track=axe1lyze HTTP/1.1");//認証キーの作成 ユーザーID:パスワード をBASE64で暗号化
String key = new String((new BASE64Encoder()).encodeBuffer("UserID:Password".getBytes()));
out.println("Authorization:Basic "+key);
//フラッシュしてデータを送信
out.flush();
//これでデータを取得し続ける
String line;
while((line=in.readLine())!=null){System.out.println(line);}
}
}
取得形式はJSONだけなのかな?XMLもいけるとありがたいんだけども。
BASIC認証が使えるみたい。これはStreaming APIだけかな?
ツイートの投稿もこんな流れでできると幸せになれるんだけどなぁ。
自分が知らないだけでしたら申し訳ありません。
JavaScriptのオブジェクトの中身を表示するメソッド。
http://smokycat.info/category_javascript/106 この記事に張り合って書いてみた。
理系の人のコードはやたら短いし、変数名一文字だし、凄いですね。
dumpObject(obj)
で戻り値はJSON形式になっています。
※Javaでいうprivateで定義されている変数までは取得できません。
function dumpObject(obj,index,objKey){
index=index?index:0;index++;
var returnStr = "";
var tab = "";
for(i=1;i<index;i++)tab+="\t";
returnStr += "\n"+tab+(objKey?"\""+objKey+"\":":"")+"{";
for(key in obj)
returnStr += typeof obj[key]=="object"?
dumpObject(obj[key],index,key):
"\n"+tab+"\t"+"\""+key+"\":"+(typeof obj[key]=="string"?"\""+obj[key]+"\"":obj[key])+",";
return returnStr.substring(0,returnStr.length-1) + "\n"+tab+"}"+(!objKey?"":",");
}
以下のように使ってみてください。
window.open().document.write(dumpObject(eval("("+window.prompt()+")")).replace(/\n/g,"<br>").replace(/\t/g," "));
ほとんど必要ないと思いますが、以下のようにしてオブジェクトを復元できます。
eval("("+dumpObject(obj)+")");
Bookmarklet用
(function f(a,b,c){b=b?b:0;b++;var d="";var e="";for(i=1;i<b;i++)e+="\t";d+="\n"+e+(c?"\""+c+"\":":"")+"{";for(k in a)d+=typeof a[k]=="object"?f(a[k],b,k):"\n"+e+"\t"+"\""+k+"\":"+(typeof a[k]=="string"?"\""+a[k]+"\"":a[k])+",";return d.substring(0,d.length-1)+"\n"+e+"}"+(!c?"":",")})(obj)
この無名関数の引数(赤文字部分)にオブジェクトを渡してください。
以前にはデータ交換用と接続チェック用の2つのソケットをつないで、接続チェック用のソケットを使って相手が一定時間以内にデータを送ってきているかどうかで接続をチェックしていた。
あまりに無駄である。
もっと素直に簡単な方法があった。
Socket s = new ServerSocket(portNum).accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
try{
while(true)System.out.println(in.readLine());
}catch(IOException e){
System.out.println("Disconnected.");
}
これだけ。どうやら切断されたらIOExceptionに投げられるらしい。まぁ当たり前といえば当たり前なのかな?
というのを踏まえて、複数人が同時にアクセス出来るメッセージ交換システムを作ってみた。
以下ソースコード
SocketServer.java
import java.io.*;
import java.util.*;
import java.net.*;class SocketServer{
private static ArrayList<ServerSocketThread> socketThreads = new ArrayList<ServerSocketThread>();
public static void main(String[] args)throws IOException{
while(true){
ServerSocket sv = new ServerSocket(1024);
ServerSocketThread sst = new ServerSocketThread(sv.accept());
socketThreads.add(sst);
sst.start();
sv.close();
System.out.println("Connected!");
System.out.println("now : "+socketThreads.size()+"\n");
for(int i=0;i<socketThreads.size();i++){
try{socketThreads.get(i).send("Connected.");}catch(IOException ex){}
}
}
}
public static class ServerSocketThread extends Thread{
private Socket s;
private BufferedReader in;
private PrintWriter out;
ServerSocketThread(Socket s)throws IOException{
this.s = s;
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = new PrintWriter(s.getOutputStream());
}
public void run(){
try{
while(true){
String str = in.readLine();
for(int i=0;i<socketThreads.size();i++){
socketThreads.get(i).send(str);
}
}
}catch(IOException e){
socketThreads.remove(this);
System.out.println("Disconnected.");
System.out.println("now : "+socketThreads.size()+"\n");
for(int i=0;i<socketThreads.size();i++){
try{socketThreads.get(i).send("Disconnected.");}catch(IOException ex){}
}
}
}
public void send(String data)throws IOException{
out.println(data);
out.flush();
}
}
}
SocketClient.java
import java.io.*;
import java.util.*;
import java.net.*;class SocketClient{
private static Socket s;
public static void main(String[] args)throws IOException{
Scanner input = new Scanner(System.in);
s = new Socket("localhost",1024);
PrintWriter out = new PrintWriter(s.getOutputStream());
new ClientSocketThread().start();
while(true){
out.println(input.nextLine());
out.flush();
}
}
public static class ClientSocketThread extends Thread{
private BufferedReader in;
ClientSocketThread()throws IOException{
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
public void run(){
try{
while(true){
System.out.println(in.readLine());
}
}catch(IOException e){}
}
}
}
恐らくJavaプログラム間だけではなく、Java←→Flashでもいけると思います。
また時間があれば検証してみます。
これは面白いものが作れそうな予感。
もしこの記事を見た方で、「この人を我社に!」と思えた方がいらっしゃいましたら拾ってください!(切実)