OSDN Git Service

NicoClientをインタフェース化
authoryukihane <yukihane.feather@gmail.com>
Wed, 10 Aug 2011 06:00:25 +0000 (15:00 +0900)
committeryukihane <yukihane.feather@gmail.com>
Thu, 11 Aug 2011 07:06:14 +0000 (16:06 +0900)
(cherry picked from commit 39df6ade21fabaf6b3d074f24d497476f82681f6)

frontend/src/saccubus/converter/filegetter/WebFileInstanciator.java
frontend/src/saccubus/net/NicoClient.java
frontend/src/saccubus/net/NicoClientImpl.java [new file with mode: 0644]

index a2cd758..35083db 100644 (file)
@@ -6,6 +6,7 @@ import java.text.Normalizer;
 import saccubus.ConvertStopFlag;
 import saccubus.converter.profile.Proxy;
 import saccubus.net.NicoClient;
+import saccubus.net.NicoClientImpl;
 import saccubus.net.VideoInfo;
 
 /**
@@ -40,7 +41,8 @@ public class WebFileInstanciator extends FileInstanciator {
             host = null;
             port = -1;
         }
-        client = new NicoClient(li.getMail(), li.getPass(), stopFlag, host, port);
+        // TODO Implを直接newしている
+        client = new NicoClientImpl(li.getMail(), li.getPass(), stopFlag, host, port) {};
 
         if (!client.isLoggedIn()) {
             throw new IOException("ログインに失敗");
index 09f17d4..f411ac1 100644 (file)
 package saccubus.net;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.URL;
-import java.net.HttpURLConnection;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.URLEncoder;
-import java.net.URLDecoder;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
-import saccubus.ConvertStopFlag;
-import saccubus.util.FileUtil;
-import yukihane.Util;
-import static saccubus.net.VideoInfo.OfficialOption;
 
 /**
- * <p>
- * タイトル: さきゅばす
- * </p>
- * 
- * <p>
- * 説明: ニコニコ動画の動画をコメントつきで保存
- * </p>
- * 
- * <p>
- * 著作権: Copyright (c) 2007 PSI
- * </p>
- * 
- * <p>
- * 会社名:
- * </p>
- * 
- * @author 未入力
- * @version 1.0
+ *
+ * @author yuki
  */
-public class NicoClient {
-       private String Cookie = null;
+public interface NicoClient {
 
-       private static final String TITLE_PARSE_STR_START = "<title>";
-       private final static DateFormat DateFmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
-       private final static DateFormat DateFmt2 = new SimpleDateFormat("yyyy/MM/dd HH:mm");
+    String getBackCommentFromLength(VideoInfo videoInfo, String com);
 
-       private final String User;
-       private final String Pass;
-       private boolean Logged_in = false;
-       private final ConvertStopFlag StopFlag;
-       private final Proxy ConProxy;
+    File getComment(VideoInfo videoInfo, File file, TextProgressListener listener, String com);
 
-       private String WayBackKey = "0";
-       private String WayBackTime = "0";
-       private final static String WAYBACKKEY_STR = "waybackkey=";
+    File getTcomment(VideoInfo videoInfo, File file, TextProgressListener listener);
 
-       public NicoClient(final String user, final String pass,
-                       final ConvertStopFlag flag, final String proxy, final int proxy_port) {
-               User = user;
-               Pass = pass;
-               if (proxy != null && proxy.length() > 0 && proxy_port >= 0
-                               && proxy_port <= 65535) {
-                       ConProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy,
-                                       proxy_port));
-               } else {
-                       ConProxy = Proxy.NO_PROXY;
-               }
-               // ログイン
-               Logged_in = login();
-               StopFlag = flag;
-       }
+    File getVideo(VideoInfo videoInfo, File file, TextProgressListener listener);
 
-       public String getBackCommentFromLength(VideoInfo vi, String def) {
-        final int videoLength  = vi.getVideoLength();
-               if (videoLength < 0) {
-                       return def;
-               } else if (videoLength >= 0 && videoLength < 60) {
-                       return "100";
-               } else if (videoLength >= 60 && videoLength < 300) {
-                       return "250";
-               } else if (videoLength >= 300 && videoLength < 600) {
-                       return "500";
-               } else {
-                       return "1000";
-               }
-       }
+    boolean isLoggedIn();
 
-    public File getComment(VideoInfo vi, final File file, final TextProgressListener status, String back_comment) {
-        return downloadComment(back_comment, file, vi, status, false);
-    }
+    VideoInfo getVideoInfo(String tag, String time) throws IOException;
 
-    /**
-     * 投稿者コメントをダウンロードする.
-     * @param vi ビデオ情報.
-     * @param file ダウンロード先ファイル.
-     * @param status 進捗通知リスナ.
-     * @return ダウンロードされたファイル. ダウンロードできなければnull.
-     */
-    public File getTcomment(VideoInfo vi, final File file, final TextProgressListener status) {
-        return downloadComment("500", file, vi, status, true);
-    }
-
-    private File downloadComment(String back_comment, final File file, VideoInfo vi, final TextProgressListener status,
-            boolean isTcomm) throws NumberFormatException {
-        System.out.print("Downloading comment size:" + back_comment + "...");
-        try {
-                       if (file.canRead()) { // ファイルがすでに存在するなら削除する。
-                file.delete();
-            }
-            OutputStream fos = new FileOutputStream(file);
-            HttpURLConnection con = (HttpURLConnection) (new URL(vi.getMsgUrl()))
-                                       .openConnection(ConProxy);
-            con.setDoOutput(true);
-            con.setDoInput(true);
-            con.setRequestMethod("POST");
-            con.addRequestProperty("Cookie", Cookie);
-            con.addRequestProperty("Connection", "close");
-            con.connect();
-            OutputStream os = con.getOutputStream();
-            String tcommStr = (isTcomm) ? "fork=\"1\" " : "";
-            String official = "";
-            OfficialOption oo = vi.getOfficialOption();
-            if (oo != null) {
-                official = "force_184=\"" + oo.getForce184() + "\" threadkey=\"" + oo.getThreadKey() + "\" ";
-            }
-            String req = "<thread user_id=\"" + vi.getUserId() + "\" when=\"" + WayBackTime + "\" waybackkey=\""
-                    + WayBackKey + "\" res_from=\"-" + back_comment + "\" version=\"20061206\" thread=\"" + vi.
-                    getThreadId() + "\" " + tcommStr + official + "/>";
-            os.write(req.getBytes());
-            os.flush();
-            os.close();
-            if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
-                System.out.println("ng.\nCan't download comment:" + vi.getMsgUrl());
-                return null;
-            }
-            InputStream is = con.getInputStream();
-            int read = 0;
-            int max_size = 0;
-            String content_length_str = con.getHeaderField("Content-length");
-            if (content_length_str != null && !content_length_str.equals("")) {
-                max_size = Integer.parseInt(content_length_str);
-            }
-            int size = 0;
-            final byte[] buf = new byte[1024 * 1024];
-            while ((read = is.read(buf, 0, buf.length)) > 0) {
-                fos.write(buf, 0, read);
-                size += read;
-                if (max_size != 0) {
-                    String per = Double.toString((((double) size) * 100) / max_size);
-                    per = per.substring(0, Math.min(per.indexOf(".") + 3, per.length()));
-                    status.setText("コメントダウンロード:" + per + "パーセント完了");
-                } else {
-                    status.setText("コメントダウンロード中:" + Integer.toString(size >> 10) + "kbytesダウンロード");
-                }
-                if (StopFlag.needStop()) {
-                    System.out.println("Stopped.");
-                    is.close();
-                    os.flush();
-                    os.close();
-                    con.disconnect();
-                    file.delete();
-                    return null;
-                }
-            }
-            System.out.println("ok.");
-            is.close();
-            fos.flush();
-            fos.close();
-            con.disconnect();
-            return file;
-        } catch (IOException ex) {
-            ex.printStackTrace();
-        }
-        return null;
-    }
-
-       public File getVideo(VideoInfo vi, final File file, final TextProgressListener status) {
-               if (vi.getVideoUrl() == null) {
-                       System.out.println("Video url is not detected.");
-                       return null;
-               }
-               try {
-//                     if (file.canRead()) { // ファイルがすでに存在するなら削除する。
-//                             file.delete();
-//                     }
-                       HttpURLConnection con = (HttpURLConnection) (new URL(vi.getVideoUrl()))
-                                       .openConnection(ConProxy);
-                       /* 出力のみ */
-                       con.setDoInput(true);
-                       con.setRequestMethod("GET");
-                       con.addRequestProperty("Cookie", Cookie);
-                       con.connect();
-                       if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
-                               System.out.println("Can't get video:" + vi.getVideoUrl());
-                               return null;
-                       }
-            final String extension = Util.getExtention(con.getContentType());
-            File outFile = appendExtension(file, extension);
-                       InputStream is = con.getInputStream();
-                       OutputStream os = new FileOutputStream(outFile);
-                       String content_length_str = con.getHeaderField("Content-length");
-                       int max_size = 0;
-                       if (content_length_str != null && !content_length_str.equals("")) {
-                               max_size = Integer.parseInt(content_length_str);
-                       }
-                       int size = 0;
-                       System.out.print("Downloading video...");
-                       int read = 0;
-            final byte[] buf = new byte[1024 * 1024];
-                       while ((read = is.read(buf, 0, buf.length)) > 0) {
-                               size += read;
-                               os.write(buf, 0, read);
-                               if (max_size != 0) {
-                                       String per = Double.toString((((double) size) * 100)
-                                                       / max_size);
-                                       per = per.substring(0, Math.min(per.indexOf(".") + 3, per
-                                                       .length()));
-                                       status.setText("動画ダウンロード:" + per + "パーセント完了");
-                               } else {
-                                       status.setText("動画ダウンロード中:" + Integer.toString(size >> 10)
-                                                       + "kbytesダウンロード");
-                               }
-                               if (StopFlag.needStop()) {
-                                       System.out.println("Stopped.");
-                                       is.close();
-                                       os.flush();
-                                       os.close();
-                                       con.disconnect();
-                                       outFile.delete();
-                                       return null;
-                               }
-                       }
-                       System.out.println("ok.");
-                       is.close();
-                       os.flush();
-                       os.close();
-                       con.disconnect();
-                       return outFile;
-               } catch (FileNotFoundException ex) {
-                       ex.printStackTrace();
-               } catch (IOException ex) {
-                       ex.printStackTrace();
-               }
-               return null;
-       }
-
-    /** @return ビデオ名 */
-       public String getVideoHistoryAndTitle(String tag) throws IOException {
-               String url = "http://www.nicovideo.jp/watch/" + tag;
-               System.out.print("Getting video history...");
-               String new_cookie = null;
-        String videoTitle = null;
-
-        HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
-        /* リクエストの設定 */
-        con.setRequestMethod("GET");
-        con.addRequestProperty("Cookie", Cookie);
-        con.addRequestProperty("Connection", "close");
-        con.connect();
-        if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
-            throw new IOException("Can't getVideoHistory:" + url);
-        }
-        int i = 1;
-        String key;
-        String value;
-        while ((key = con.getHeaderFieldKey(i)) != null) {
-            if (key.equalsIgnoreCase("Set-Cookie")) {
-                value = con.getHeaderField(i);
-                if (value != null) {
-                    new_cookie = value.substring(0, value.indexOf(";"));
-                }
-            }
-            i++;
-        }
-        BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
-        String ret;
-        int index = -1;
-        while ((ret = br.readLine()) != null && index < 0) {
-            if ((index = ret.indexOf(TITLE_PARSE_STR_START)) >= 0) {
-                videoTitle = ret.substring(index + TITLE_PARSE_STR_START.length(), ret.indexOf("‐", index));
-                videoTitle = FileUtil.safeFileName(videoTitle);
-            }
-        }
-        br.close();
-        con.disconnect();
-        if (new_cookie == null) {
-            System.out.println("Can't getVideoHistory: cannot get cookie.");
-            return null;
-        }
-        System.out.println("ok.");
-        Cookie += "; ";
-        Cookie += new_cookie;
-
-        return videoTitle;
-       }
-
-    public VideoInfo getVideoInfo(String tag, String time) throws IOException {
-        final String videoTitle = getVideoHistoryAndTitle(tag);
-
-        String url = "http://flapi.nicovideo.jp/api/getflv/" + tag;
-        if (tag.startsWith("nm")) {
-            url += "?as3=1";
-        }
-        System.out.print("Getting video informations...");
-        Map<String,String> res = new NicoApiRequest(url).get();
-        String threadId = res.get("thread_id");
-        String videoUrl = res.get("url");
-        String msgUrl = res.get("ms");
-        String userId = res.get("user_id");
-        int videoLength = -1;
-        String videoLengthStr = res.get("l");
-        try{
-            videoLength = Integer.parseInt(videoLengthStr);
-        }catch(NumberFormatException ex){}
-
-        OfficialOption oo = null;
-        if ("1".equals(res.get("needs_key"))) {
-            oo = getOfficialOption(threadId);
-        }
-
-        VideoInfo vi = new VideoInfo(videoTitle, threadId, videoUrl, msgUrl, userId, videoLength, oo);
-        System.out.println("ok.");
-
-        if (!(time == null || time.equals("")) && !getWayBackKey(vi, time)) { // WayBackKey
-            throw new IOException();
-        }
-        return vi;
-    }
-
-    private OfficialOption getOfficialOption(String threadId) throws IOException {
-        String url = "http://flapi.nicovideo.jp/api/getthreadkey?thread="+threadId;
-        Map<String,String> map = new NicoApiRequest(url).get();
-        return new OfficialOption(map.get("threadkey"), map.get("force_184"));
-    }
-
-    private boolean getWayBackKey(VideoInfo vi, String time) {
-               System.out.print("Setting wayback time...");
-               Date date = null;
-               String waybacktime = "0";
-               try {
-                       date = DateFmt.parse(time);
-               } catch (ParseException ex2) {
-                       date = null;
-               }
-               if (date == null) {
-                       try {
-                               date = DateFmt2.parse(time);
-                       } catch (ParseException ex3) {
-                               date = null;
-                       }
-               }
-               if (date != null) {
-                       waybacktime = Long.toString(date.getTime() / 1000);
-                       System.out.println("ok.(" + date.toString() + "):" + waybacktime);
-               } else {
-                       try {
-                               long tmp_time = Long.parseLong(time);
-                               waybacktime = Long.toString(tmp_time);
-                               date = new Date(tmp_time * 1000);
-                               System.out.println("ok.(" + date.toString() + "):"
-                                               + waybacktime);
-                       } catch (NumberFormatException ex4) {
-                               System.out.println("ng.");
-                               System.out.println("Cannot parse wayback time.");
-                               return false;
-                       }
-               }
-               System.out.print("Getting wayback key...");
-               String url = "http://flapi.nicovideo.jp/api/getwaybackkey?thread="
-                               + vi.getThreadId();
-               String ret = "";
-               try {
-                       HttpURLConnection con = (HttpURLConnection) (new URL(url))
-                                       .openConnection(ConProxy);
-                       /* リクエストの設定 */
-                       con.setRequestMethod("GET");
-                       con.addRequestProperty("Cookie", Cookie);
-                       con.addRequestProperty("Connection", "close");
-                       con.setDoInput(true);
-                       con.connect();
-                       if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
-                               System.out.println("Can't get WayBackKey:" + url);
-                               return false;
-                       }
-                       /* 戻り値の取得 */
-                       BufferedReader br = new BufferedReader(new InputStreamReader(con
-                                       .getInputStream()));
-                       ret = br.readLine();
-                       br.close();
-                       con.disconnect();
-               } catch (IOException ex1) {
-                       System.out.println("ng.");
-                       ex1.printStackTrace();
-                       return false;
-               }
-               int idx = 0;
-               if ((idx = ret.indexOf(WAYBACKKEY_STR)) < 0) {
-                       System.out.println("ng.");
-                       System.out.println("Cannot find wayback key from response.");
-                       return false;
-               }
-               int end_idx = Math.max(ret.length(), ret.indexOf("&"));
-               String waybackkey = ret.substring(idx + WAYBACKKEY_STR.length(),
-                               end_idx);
-               if (waybackkey == null || waybackkey.equals("")) {
-                       System.out.println("ng.");
-                       System.out.println("Cannot get wayback key.");
-                       return false;
-               }
-               System.out.println("ok. key:" + waybackkey);
-               WayBackTime = waybacktime;
-               WayBackKey = waybackkey;
-               return true;
-       }
-
-       public boolean isLoggedIn() {
-               return Logged_in;
-       }
-
-       private boolean login() {
-               try {
-                       HttpURLConnection con = (HttpsURLConnection) (new URL(
-                                       "https://secure.nicovideo.jp/secure/login?site=niconico"))
-                                       .openConnection(ConProxy);
-                       /* 出力のみ */
-                       con.setDoOutput(true);
-                       HttpURLConnection.setFollowRedirects(false);
-                       con.setInstanceFollowRedirects(false);
-                       con.setRequestMethod("POST");
-                       con.addRequestProperty("Connection", "close");
-                       con.connect();
-                       StringBuffer sb = new StringBuffer(4096);
-                       sb.append("next_url=&");
-                       sb.append("mail=");
-                       sb.append(URLEncoder.encode(User, "Shift_JIS"));
-                       sb.append("&password=");
-                       sb.append(URLEncoder.encode(Pass, "Shift_JIS"));
-                       sb.append("&submit.x=103&submit.y=16");
-                       OutputStream os = con.getOutputStream();
-                       os.write(sb.substring(0).getBytes());
-                       os.flush();
-                       os.close();
-                       int code = con.getResponseCode();
-                       if (code < 200 || code >= 400) {
-                               System.out.println("Can't login:" + con.getResponseMessage());
-                               return false;
-                       }
-                       int i = 1;
-                       String key;
-                       String value;
-                       while ((key = con.getHeaderFieldKey(i)) != null) {
-                               if (key.equalsIgnoreCase("Set-Cookie")) {
-                                       value = con.getHeaderField(i);
-                                       if (value != null) {
-                                               Cookie = value.substring(0, value.indexOf(";"));
-                                       }
-                               }
-                               i++;
-                       }
-                       con.disconnect();
-                       if (Cookie == null) {
-                               System.out.println("Can't login: cannot set cookie.");
-                               return false;
-                       }
-                       System.out.println("Logged in.");
-               } catch (IOException ex) {
-                       ex.printStackTrace();
-                       return false;
-               }
-               return true;
-       }
-
-    private File appendExtension(File file, String extension) {
-        final String e = "." + extension;
-        final String defExt = ".flv";
-        String path = file.getPath();
-        if (path.endsWith(e)) {
-            return file;
-        } else if (path.endsWith(defExt)) {
-            path = path.substring(0, path.length() - defExt.length());
-        }
-        return new File(path + e);
-    }
-
-    private class NicoApiRequest {
-
-        private final String url;
-
-        private NicoApiRequest(String url) {
-            this.url = url;
-        }
-
-        private Map<String,String> get() throws IOException {
-            Map<String, String> map = new HashMap<String, String>();
-            System.out.print("Getting video informations...");
-            HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
-            /* リクエストの設定 */
-            con.setRequestMethod("GET");
-            con.addRequestProperty("Cookie", Cookie);
-            con.addRequestProperty("Connection", "close");
-            con.connect();
-            if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
-                throw new IOException("Can't getVideoInfo:" + url);
-            }
-            /* 戻り値の取得 */
-            BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
-            String ret = br.readLine();
-            br.close();
-            con.disconnect();
-            ret = URLDecoder.decode(ret, "Shift_JIS");
-            String[] array = ret.split("&");
-            int cnt = 0;
-            for (int i = 0; i < array.length; i++) {
-                int idx = array[i].indexOf("=");
-                if (idx < 0) {
-                    continue;
-                }
-                String key = array[i].substring(0, idx);
-                String value = array[i].substring(idx + 1);
-                map.put(key, value);
-            }
-            return map;
-        }
-    }
 }
diff --git a/frontend/src/saccubus/net/NicoClientImpl.java b/frontend/src/saccubus/net/NicoClientImpl.java
new file mode 100644 (file)
index 0000000..5928376
--- /dev/null
@@ -0,0 +1,540 @@
+package saccubus.net;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URLEncoder;
+import java.net.URLDecoder;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import javax.net.ssl.HttpsURLConnection;
+import saccubus.ConvertStopFlag;
+import saccubus.util.FileUtil;
+import yukihane.Util;
+import static saccubus.net.VideoInfo.OfficialOption;
+
+/**
+ * <p>
+ * タイトル: さきゅばす
+ * </p>
+ *
+ * <p>
+ * 説明: ニコニコ動画の動画をコメントつきで保存
+ * </p>
+ *
+ * <p>
+ * 著作権: Copyright (c) 2007 PSI
+ * </p>
+ *
+ * <p>
+ * 会社名:
+ * </p>
+ *
+ * @author 未入力
+ * @version 1.0
+ */
+public class NicoClientImpl implements NicoClient {
+       private String Cookie = null;
+
+       private static final String TITLE_PARSE_STR_START = "<title>";
+       private final static DateFormat DateFmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+       private final static DateFormat DateFmt2 = new SimpleDateFormat("yyyy/MM/dd HH:mm");
+
+       private final String User;
+       private final String Pass;
+       private boolean Logged_in = false;
+       private final ConvertStopFlag StopFlag;
+       private final Proxy ConProxy;
+
+       private String WayBackKey = "0";
+       private String WayBackTime = "0";
+       private final static String WAYBACKKEY_STR = "waybackkey=";
+
+       public NicoClientImpl(final String user, final String pass,
+                       final ConvertStopFlag flag, final String proxy, final int proxy_port) {
+               User = user;
+               Pass = pass;
+               if (proxy != null && proxy.length() > 0 && proxy_port >= 0
+                               && proxy_port <= 65535) {
+                       ConProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy,
+                                       proxy_port));
+               } else {
+                       ConProxy = Proxy.NO_PROXY;
+               }
+               // ログイン
+               Logged_in = login();
+               StopFlag = flag;
+       }
+
+    @Override
+       public String getBackCommentFromLength(VideoInfo vi, String def) {
+        final int videoLength  = vi.getVideoLength();
+               if (videoLength < 0) {
+                       return def;
+               } else if (videoLength >= 0 && videoLength < 60) {
+                       return "100";
+               } else if (videoLength >= 60 && videoLength < 300) {
+                       return "250";
+               } else if (videoLength >= 300 && videoLength < 600) {
+                       return "500";
+               } else {
+                       return "1000";
+               }
+       }
+
+    @Override
+    public File getComment(VideoInfo vi, final File file, final TextProgressListener status, String back_comment) {
+        return downloadComment(back_comment, file, vi, status, false);
+    }
+
+    /**
+     * 投稿者コメントをダウンロードする.
+     * @param vi ビデオ情報.
+     * @param file ダウンロード先ファイル.
+     * @param status 進捗通知リスナ.
+     * @return ダウンロードされたファイル. ダウンロードできなければnull.
+     */
+    @Override
+    public File getTcomment(VideoInfo vi, final File file, final TextProgressListener status) {
+        return downloadComment("500", file, vi, status, true);
+    }
+
+    private File downloadComment(String back_comment, final File file, VideoInfo vi, final TextProgressListener status,
+            boolean isTcomm) throws NumberFormatException {
+        System.out.print("Downloading comment size:" + back_comment + "...");
+        try {
+                       if (file.canRead()) { // ファイルがすでに存在するなら削除する。
+                file.delete();
+            }
+            OutputStream fos = new FileOutputStream(file);
+            HttpURLConnection con = (HttpURLConnection) (new URL(vi.getMsgUrl()))
+                                       .openConnection(ConProxy);
+            con.setDoOutput(true);
+            con.setDoInput(true);
+            con.setRequestMethod("POST");
+            con.addRequestProperty("Cookie", Cookie);
+            con.addRequestProperty("Connection", "close");
+            con.connect();
+            OutputStream os = con.getOutputStream();
+            String tcommStr = (isTcomm) ? "fork=\"1\" " : "";
+            String official = "";
+            OfficialOption oo = vi.getOfficialOption();
+            if (oo != null) {
+                official = "force_184=\"" + oo.getForce184() + "\" threadkey=\"" + oo.getThreadKey() + "\" ";
+            }
+            String req = "<thread user_id=\"" + vi.getUserId() + "\" when=\"" + WayBackTime + "\" waybackkey=\""
+                    + WayBackKey + "\" res_from=\"-" + back_comment + "\" version=\"20061206\" thread=\"" + vi.
+                    getThreadId() + "\" " + tcommStr + official + "/>";
+            os.write(req.getBytes());
+            os.flush();
+            os.close();
+            if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                System.out.println("ng.\nCan't download comment:" + vi.getMsgUrl());
+                return null;
+            }
+            InputStream is = con.getInputStream();
+            int read = 0;
+            int max_size = 0;
+            String content_length_str = con.getHeaderField("Content-length");
+            if (content_length_str != null && !content_length_str.equals("")) {
+                max_size = Integer.parseInt(content_length_str);
+            }
+            int size = 0;
+            final byte[] buf = new byte[1024 * 1024];
+            while ((read = is.read(buf, 0, buf.length)) > 0) {
+                fos.write(buf, 0, read);
+                size += read;
+                if (max_size != 0) {
+                    String per = Double.toString((((double) size) * 100) / max_size);
+                    per = per.substring(0, Math.min(per.indexOf(".") + 3, per.length()));
+                    status.setText("コメントダウンロード:" + per + "パーセント完了");
+                } else {
+                    status.setText("コメントダウンロード中:" + Integer.toString(size >> 10) + "kbytesダウンロード");
+                }
+                if (StopFlag.needStop()) {
+                    System.out.println("Stopped.");
+                    is.close();
+                    os.flush();
+                    os.close();
+                    con.disconnect();
+                    file.delete();
+                    return null;
+                }
+            }
+            System.out.println("ok.");
+            is.close();
+            fos.flush();
+            fos.close();
+            con.disconnect();
+            return file;
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+       public File getVideo(VideoInfo vi, final File file, final TextProgressListener status) {
+               if (vi.getVideoUrl() == null) {
+                       System.out.println("Video url is not detected.");
+                       return null;
+               }
+               try {
+//                     if (file.canRead()) { // ファイルがすでに存在するなら削除する。
+//                             file.delete();
+//                     }
+                       HttpURLConnection con = (HttpURLConnection) (new URL(vi.getVideoUrl()))
+                                       .openConnection(ConProxy);
+                       /* 出力のみ */
+                       con.setDoInput(true);
+                       con.setRequestMethod("GET");
+                       con.addRequestProperty("Cookie", Cookie);
+                       con.connect();
+                       if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                               System.out.println("Can't get video:" + vi.getVideoUrl());
+                               return null;
+                       }
+            final String extension = Util.getExtention(con.getContentType());
+            File outFile = appendExtension(file, extension);
+                       InputStream is = con.getInputStream();
+                       OutputStream os = new FileOutputStream(outFile);
+                       String content_length_str = con.getHeaderField("Content-length");
+                       int max_size = 0;
+                       if (content_length_str != null && !content_length_str.equals("")) {
+                               max_size = Integer.parseInt(content_length_str);
+                       }
+                       int size = 0;
+                       System.out.print("Downloading video...");
+                       int read = 0;
+            final byte[] buf = new byte[1024 * 1024];
+                       while ((read = is.read(buf, 0, buf.length)) > 0) {
+                               size += read;
+                               os.write(buf, 0, read);
+                               if (max_size != 0) {
+                                       String per = Double.toString((((double) size) * 100)
+                                                       / max_size);
+                                       per = per.substring(0, Math.min(per.indexOf(".") + 3, per
+                                                       .length()));
+                                       status.setText("動画ダウンロード:" + per + "パーセント完了");
+                               } else {
+                                       status.setText("動画ダウンロード中:" + Integer.toString(size >> 10)
+                                                       + "kbytesダウンロード");
+                               }
+                               if (StopFlag.needStop()) {
+                                       System.out.println("Stopped.");
+                                       is.close();
+                                       os.flush();
+                                       os.close();
+                                       con.disconnect();
+                                       outFile.delete();
+                                       return null;
+                               }
+                       }
+                       System.out.println("ok.");
+                       is.close();
+                       os.flush();
+                       os.close();
+                       con.disconnect();
+                       return outFile;
+               } catch (FileNotFoundException ex) {
+                       ex.printStackTrace();
+               } catch (IOException ex) {
+                       ex.printStackTrace();
+               }
+               return null;
+       }
+
+    /** @return ビデオ名 */
+       public String getVideoHistoryAndTitle(String tag) throws IOException {
+               String url = "http://www.nicovideo.jp/watch/" + tag;
+               System.out.print("Getting video history...");
+               String new_cookie = null;
+        String videoTitle = null;
+
+        HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
+        /* リクエストの設定 */
+        con.setRequestMethod("GET");
+        con.addRequestProperty("Cookie", Cookie);
+        con.addRequestProperty("Connection", "close");
+        con.connect();
+        if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
+            throw new IOException("Can't getVideoHistory:" + url);
+        }
+        int i = 1;
+        String key;
+        String value;
+        while ((key = con.getHeaderFieldKey(i)) != null) {
+            if (key.equalsIgnoreCase("Set-Cookie")) {
+                value = con.getHeaderField(i);
+                if (value != null) {
+                    new_cookie = value.substring(0, value.indexOf(";"));
+                }
+            }
+            i++;
+        }
+        BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
+        String ret;
+        int index = -1;
+        while ((ret = br.readLine()) != null && index < 0) {
+            if ((index = ret.indexOf(TITLE_PARSE_STR_START)) >= 0) {
+                videoTitle = ret.substring(index + TITLE_PARSE_STR_START.length(), ret.indexOf("‐", index));
+                videoTitle = FileUtil.safeFileName(videoTitle);
+            }
+        }
+        br.close();
+        con.disconnect();
+        if (new_cookie == null) {
+            System.out.println("Can't getVideoHistory: cannot get cookie.");
+            return null;
+        }
+        System.out.println("ok.");
+        Cookie += "; ";
+        Cookie += new_cookie;
+
+        return videoTitle;
+       }
+
+    @Override
+    public VideoInfo getVideoInfo(String tag, String time) throws IOException {
+        final String videoTitle = getVideoHistoryAndTitle(tag);
+
+        String url = "http://flapi.nicovideo.jp/api/getflv/" + tag;
+        if (tag.startsWith("nm")) {
+            url += "?as3=1";
+        }
+        System.out.print("Getting video informations...");
+        Map<String,String> res = new NicoApiRequest(url).get();
+        String threadId = res.get("thread_id");
+        String videoUrl = res.get("url");
+        String msgUrl = res.get("ms");
+        String userId = res.get("user_id");
+        int videoLength = -1;
+        String videoLengthStr = res.get("l");
+        try{
+            videoLength = Integer.parseInt(videoLengthStr);
+        }catch(NumberFormatException ex){}
+
+        OfficialOption oo = null;
+        if ("1".equals(res.get("needs_key"))) {
+            oo = getOfficialOption(threadId);
+        }
+
+        VideoInfo vi = new VideoInfo(videoTitle, threadId, videoUrl, msgUrl, userId, videoLength, oo);
+        System.out.println("ok.");
+
+        if (!(time == null || time.equals("")) && !getWayBackKey(vi, time)) { // WayBackKey
+            throw new IOException();
+        }
+        return vi;
+    }
+
+    private OfficialOption getOfficialOption(String threadId) throws IOException {
+        String url = "http://flapi.nicovideo.jp/api/getthreadkey?thread="+threadId;
+        Map<String,String> map = new NicoApiRequest(url).get();
+        return new OfficialOption(map.get("threadkey"), map.get("force_184"));
+    }
+
+    private boolean getWayBackKey(VideoInfo vi, String time) {
+               System.out.print("Setting wayback time...");
+               Date date = null;
+               String waybacktime = "0";
+               try {
+                       date = DateFmt.parse(time);
+               } catch (ParseException ex2) {
+                       date = null;
+               }
+               if (date == null) {
+                       try {
+                               date = DateFmt2.parse(time);
+                       } catch (ParseException ex3) {
+                               date = null;
+                       }
+               }
+               if (date != null) {
+                       waybacktime = Long.toString(date.getTime() / 1000);
+                       System.out.println("ok.(" + date.toString() + "):" + waybacktime);
+               } else {
+                       try {
+                               long tmp_time = Long.parseLong(time);
+                               waybacktime = Long.toString(tmp_time);
+                               date = new Date(tmp_time * 1000);
+                               System.out.println("ok.(" + date.toString() + "):"
+                                               + waybacktime);
+                       } catch (NumberFormatException ex4) {
+                               System.out.println("ng.");
+                               System.out.println("Cannot parse wayback time.");
+                               return false;
+                       }
+               }
+               System.out.print("Getting wayback key...");
+               String url = "http://flapi.nicovideo.jp/api/getwaybackkey?thread="
+                               + vi.getThreadId();
+               String ret = "";
+               try {
+                       HttpURLConnection con = (HttpURLConnection) (new URL(url))
+                                       .openConnection(ConProxy);
+                       /* リクエストの設定 */
+                       con.setRequestMethod("GET");
+                       con.addRequestProperty("Cookie", Cookie);
+                       con.addRequestProperty("Connection", "close");
+                       con.setDoInput(true);
+                       con.connect();
+                       if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                               System.out.println("Can't get WayBackKey:" + url);
+                               return false;
+                       }
+                       /* 戻り値の取得 */
+                       BufferedReader br = new BufferedReader(new InputStreamReader(con
+                                       .getInputStream()));
+                       ret = br.readLine();
+                       br.close();
+                       con.disconnect();
+               } catch (IOException ex1) {
+                       System.out.println("ng.");
+                       ex1.printStackTrace();
+                       return false;
+               }
+               int idx = 0;
+               if ((idx = ret.indexOf(WAYBACKKEY_STR)) < 0) {
+                       System.out.println("ng.");
+                       System.out.println("Cannot find wayback key from response.");
+                       return false;
+               }
+               int end_idx = Math.max(ret.length(), ret.indexOf("&"));
+               String waybackkey = ret.substring(idx + WAYBACKKEY_STR.length(),
+                               end_idx);
+               if (waybackkey == null || waybackkey.equals("")) {
+                       System.out.println("ng.");
+                       System.out.println("Cannot get wayback key.");
+                       return false;
+               }
+               System.out.println("ok. key:" + waybackkey);
+               WayBackTime = waybacktime;
+               WayBackKey = waybackkey;
+               return true;
+       }
+
+    @Override
+       public boolean isLoggedIn() {
+               return Logged_in;
+       }
+
+       private boolean login() {
+               try {
+                       HttpURLConnection con = (HttpsURLConnection) (new URL(
+                                       "https://secure.nicovideo.jp/secure/login?site=niconico"))
+                                       .openConnection(ConProxy);
+                       /* 出力のみ */
+                       con.setDoOutput(true);
+                       HttpURLConnection.setFollowRedirects(false);
+                       con.setInstanceFollowRedirects(false);
+                       con.setRequestMethod("POST");
+                       con.addRequestProperty("Connection", "close");
+                       con.connect();
+                       StringBuffer sb = new StringBuffer(4096);
+                       sb.append("next_url=&");
+                       sb.append("mail=");
+                       sb.append(URLEncoder.encode(User, "Shift_JIS"));
+                       sb.append("&password=");
+                       sb.append(URLEncoder.encode(Pass, "Shift_JIS"));
+                       sb.append("&submit.x=103&submit.y=16");
+                       OutputStream os = con.getOutputStream();
+                       os.write(sb.substring(0).getBytes());
+                       os.flush();
+                       os.close();
+                       int code = con.getResponseCode();
+                       if (code < 200 || code >= 400) {
+                               System.out.println("Can't login:" + con.getResponseMessage());
+                               return false;
+                       }
+                       int i = 1;
+                       String key;
+                       String value;
+                       while ((key = con.getHeaderFieldKey(i)) != null) {
+                               if (key.equalsIgnoreCase("Set-Cookie")) {
+                                       value = con.getHeaderField(i);
+                                       if (value != null) {
+                                               Cookie = value.substring(0, value.indexOf(";"));
+                                       }
+                               }
+                               i++;
+                       }
+                       con.disconnect();
+                       if (Cookie == null) {
+                               System.out.println("Can't login: cannot set cookie.");
+                               return false;
+                       }
+                       System.out.println("Logged in.");
+               } catch (IOException ex) {
+                       ex.printStackTrace();
+                       return false;
+               }
+               return true;
+       }
+
+    private File appendExtension(File file, String extension) {
+        final String e = "." + extension;
+        final String defExt = ".flv";
+        String path = file.getPath();
+        if (path.endsWith(e)) {
+            return file;
+        } else if (path.endsWith(defExt)) {
+            path = path.substring(0, path.length() - defExt.length());
+        }
+        return new File(path + e);
+    }
+
+    private class NicoApiRequest {
+
+        private final String url;
+
+        private NicoApiRequest(String url) {
+            this.url = url;
+        }
+
+        private Map<String,String> get() throws IOException {
+            Map<String, String> map = new HashMap<String, String>();
+            System.out.print("Getting video informations...");
+            HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
+            /* リクエストの設定 */
+            con.setRequestMethod("GET");
+            con.addRequestProperty("Cookie", Cookie);
+            con.addRequestProperty("Connection", "close");
+            con.connect();
+            if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                throw new IOException("Can't getVideoInfo:" + url);
+            }
+            /* 戻り値の取得 */
+            BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
+            String ret = br.readLine();
+            br.close();
+            con.disconnect();
+            ret = URLDecoder.decode(ret, "Shift_JIS");
+            String[] array = ret.split("&");
+            int cnt = 0;
+            for (int i = 0; i < array.length; i++) {
+                int idx = array[i].indexOf("=");
+                if (idx < 0) {
+                    continue;
+                }
+                String key = array[i].substring(0, idx);
+                String value = array[i].substring(idx + 1);
+                map.put(key, value);
+            }
+            return map;
+        }
+    }
+}