3 import java.io.BufferedReader;
5 import java.io.FileNotFoundException;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.InputStreamReader;
10 import java.io.OutputStream;
12 import java.net.HttpURLConnection;
13 import java.net.InetSocketAddress;
14 import java.net.Proxy;
15 import java.net.URLDecoder;
16 import java.net.URLEncoder;
17 import java.util.HashMap;
19 import java.util.logging.Level;
20 import java.util.logging.Logger;
21 import javax.net.ssl.HttpsURLConnection;
22 import nicobrowser.util.Util;
23 import saccubus.ConvertStopFlag;
24 import saccubus.net.VideoInfo.OfficialOption;
25 import saccubus.util.FileUtil;
33 * 説明: ニコニコ動画の動画をコメントつきで保存
37 * 著作権: Copyright (c) 2007 PSI
43 * @deprecated 2011/2 以降のコメントダウンロード仕様には対応していません.
48 public class NicoClientImpl implements NicoClient {
50 private static final Logger logger = Logger.getLogger(NicoClientImpl.class.getName());
51 private String Cookie = null;
52 private final String User;
53 private final String Pass;
54 private boolean Logged_in = false;
55 private final ConvertStopFlag StopFlag;
56 private final Proxy ConProxy;
58 public NicoClientImpl(final String user, final String pass,
59 final ConvertStopFlag flag, final String proxy, final int proxy_port) {
62 if (proxy != null && proxy.length() > 0 && proxy_port >= 0
63 && proxy_port <= 65535) {
64 ConProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy,
67 ConProxy = Proxy.NO_PROXY;
75 * @deprecated reduceComment は無視されます(常にtrueの動作をします).
78 public File getComment(VideoInfo vi, CommentInfo ci, final File file, final TextProgressListener status,
79 int back_comment, boolean reduceComment) {
80 return downloadComment(back_comment, file, vi, ci, status, false);
86 * @param file ダウンロード先ファイル.
87 * @param status 進捗通知リスナ.
88 * @return ダウンロードされたファイル. ダウンロードできなければnull.
91 public File getTcomment(VideoInfo vi, final File file, final TextProgressListener status) {
92 return downloadComment(1000, file, vi, status, true);
95 private File downloadComment(int back_comment, final File file, VideoInfo vi, final TextProgressListener status,
96 boolean isTcomm) throws NumberFormatException {
97 return downloadComment(back_comment, file, vi, null, status, isTcomm);
100 private File downloadComment(int back_comment, final File file, VideoInfo vi, CommentInfo ci,
101 final TextProgressListener status,
102 boolean isTcomm) throws NumberFormatException {
103 System.out.print("Downloading comment size:" + back_comment + "...");
105 if (file.canRead()) { // ファイルがすでに存在するなら削除する。
108 OutputStream fos = new FileOutputStream(file);
109 HttpURLConnection con = (HttpURLConnection) (new URL(vi.getMsgUrl())).openConnection(ConProxy);
110 con.setDoOutput(true);
111 con.setDoInput(true);
112 con.setRequestMethod("POST");
113 con.addRequestProperty("Cookie", Cookie);
114 con.addRequestProperty("Connection", "close");
116 OutputStream os = con.getOutputStream();
117 String tcommStr = (isTcomm) ? "fork=\"1\" " : "";
118 String official = "";
119 OfficialOption oo = vi.getOfficialOption();
121 official = "force_184=\"" + oo.getForce184() + "\" threadkey=\"" + oo.getThreadKey() + "\" ";
123 String req = "<thread user_id=\"" + vi.getUserId() + "\" when=\"" + ci.getWayBackTime() + "\" waybackkey=\""
124 + ci.getWayBackKey() + "\" res_from=\"-" + back_comment + "\" version=\"20061206\" thread=\"" + vi.
125 getThreadId() + "\" " + tcommStr + official + "/>";
126 os.write(req.getBytes());
129 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
130 System.out.println("ng.\nCan't download comment:" + vi.getMsgUrl());
133 InputStream is = con.getInputStream();
136 String content_length_str = con.getHeaderField("Content-length");
137 if (content_length_str != null && !content_length_str.equals("")) {
138 max_size = Integer.parseInt(content_length_str);
141 final byte[] buf = new byte[1024 * 1024];
142 while ((read = is.read(buf, 0, buf.length)) > 0) {
143 fos.write(buf, 0, read);
146 String per = Double.toString((((double) size) * 100) / max_size);
147 per = per.substring(0, Math.min(per.indexOf(".") + 3, per.length()));
148 status.setText("コメントダウンロード:" + per + "パーセント完了");
150 status.setText("コメントダウンロード中:" + Integer.toString(size >> 10) + "kbytesダウンロード");
152 if (StopFlag.needStop()) {
153 System.out.println("Stopped.");
162 System.out.println("ok.");
168 } catch (IOException ex) {
169 logger.log(Level.SEVERE, null, ex);
175 public File getVideo(VideoInfo vi, final File file, final TextProgressListener status) {
176 if (vi.getVideoUrl() == null) {
177 System.out.println("Video url is not detected.");
181 // if (file.canRead()) { // ファイルがすでに存在するなら削除する。
184 HttpURLConnection con = (HttpURLConnection) (new URL(vi.getVideoUrl())).openConnection(ConProxy);
186 con.setDoInput(true);
187 con.setRequestMethod("GET");
188 con.addRequestProperty("Cookie", Cookie);
190 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
191 System.out.println("Can't get video:" + vi.getVideoUrl());
194 final String extension = Util.getExtention(con.getContentType());
195 File outFile = appendExtension(file, extension);
196 InputStream is = con.getInputStream();
197 OutputStream os = new FileOutputStream(outFile);
198 String content_length_str = con.getHeaderField("Content-length");
200 if (content_length_str != null && !content_length_str.equals("")) {
201 max_size = Integer.parseInt(content_length_str);
204 System.out.print("Downloading video...");
206 final byte[] buf = new byte[1024 * 1024];
207 while ((read = is.read(buf, 0, buf.length)) > 0) {
209 os.write(buf, 0, read);
211 String per = Double.toString((((double) size) * 100)
213 per = per.substring(0, Math.min(per.indexOf(".") + 3, per.length()));
214 status.setText("動画ダウンロード:" + per + "パーセント完了");
216 status.setText("動画ダウンロード中:" + Integer.toString(size >> 10)
219 if (StopFlag.needStop()) {
220 System.out.println("Stopped.");
229 System.out.println("ok.");
235 } catch (FileNotFoundException ex) {
236 logger.log(Level.SEVERE, null, ex);
237 } catch (IOException ex) {
238 logger.log(Level.SEVERE, null, ex);
244 public String getVideoHistoryAndTitle(String tag) throws IOException {
245 String url = "http://www.nicovideo.jp/watch/" + tag;
246 System.out.print("Getting video history...");
247 String new_cookie = null;
248 String videoTitle = null;
250 HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
252 con.setRequestMethod("GET");
253 con.addRequestProperty("Cookie", Cookie);
254 con.addRequestProperty("Connection", "close");
256 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
257 throw new IOException("Can't getVideoHistory:" + url);
262 while ((key = con.getHeaderFieldKey(i)) != null) {
263 if (key.equalsIgnoreCase("Set-Cookie")) {
264 value = con.getHeaderField(i);
266 new_cookie = value.substring(0, value.indexOf(";"));
271 BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
274 while ((ret = br.readLine()) != null && index < 0) {
275 final String TITLE_PARSE_STR_START = "<title>";
276 if ((index = ret.indexOf(TITLE_PARSE_STR_START)) >= 0) {
277 videoTitle = ret.substring(index + TITLE_PARSE_STR_START.length(), ret.indexOf("‐", index));
278 videoTitle = FileUtil.safeFileName(videoTitle);
283 if (new_cookie == null) {
284 System.out.println("Can't getVideoHistory: cannot get cookie.");
287 System.out.println("ok.");
289 Cookie += new_cookie;
295 public VideoInfo getVideoInfo(String tag) throws IOException {
296 final String videoTitle = getVideoHistoryAndTitle(tag);
298 String url = "http://flapi.nicovideo.jp/api/getflv/" + tag;
299 if (tag.startsWith("nm")) {
302 System.out.print("Getting video informations...");
303 Map<String, String> res = new NicoApiRequest(url).get();
304 String threadId = res.get("thread_id");
305 String videoUrl = res.get("url");
306 String msgUrl = res.get("ms");
307 String userId = res.get("user_id");
308 int videoLength = -1;
309 String videoLengthStr = res.get("l");
311 videoLength = Integer.parseInt(videoLengthStr);
312 } catch (NumberFormatException ex) {
315 OfficialOption oo = null;
316 if ("1".equals(res.get("needs_key"))) {
317 oo = getOfficialOption(threadId);
320 VideoInfo vi = new VideoInfo(videoTitle, threadId, videoUrl, msgUrl, userId, videoLength, oo);
321 System.out.println("ok.");
325 private OfficialOption getOfficialOption(String threadId) throws IOException {
326 String url = "http://flapi.nicovideo.jp/api/getthreadkey?thread=" + threadId;
327 Map<String, String> map = new NicoApiRequest(url).get();
328 return new OfficialOption(map.get("threadkey"), map.get("force_184"));
332 public String getWayBackKey(VideoInfo vi) throws IOException {
334 System.out.print("Getting wayback key...");
335 String url = "http://flapi.nicovideo.jp/api/getwaybackkey?thread="
339 HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
341 con.setRequestMethod("GET");
342 con.addRequestProperty("Cookie", Cookie);
343 con.addRequestProperty("Connection", "close");
344 con.setDoInput(true);
346 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
347 System.out.println("Can't get WayBackKey:" + url);
348 throw new IOException("Can't get WayBackKey:" + url);
351 BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
355 } catch (IOException ex1) {
356 System.out.println("ng.");
357 logger.log(Level.SEVERE, null, ex1);
362 final String WAYBACKKEY_STR = "waybackkey=";
364 if ((idx = ret.indexOf(WAYBACKKEY_STR)) < 0) {
365 System.out.println("ng.");
366 System.out.println("Cannot find wayback key from response.");
367 throw new IOException("Cannot find wayback key from response.");
369 int end_idx = Math.max(ret.length(), ret.indexOf("&"));
370 String waybackkey = ret.substring(idx + WAYBACKKEY_STR.length(),
372 if (waybackkey == null || waybackkey.equals("")) {
373 System.out.println("ng.");
374 System.out.println("Cannot get wayback key.");
375 throw new IOException("Cannot get wayback key.");
377 System.out.println("ok. key:" + waybackkey);
382 public boolean isLoggedIn() {
386 private boolean login() {
388 HttpURLConnection con = (HttpsURLConnection) (new URL(
389 "https://secure.nicovideo.jp/secure/login?site=niconico")).openConnection(ConProxy);
391 con.setDoOutput(true);
392 HttpURLConnection.setFollowRedirects(false);
393 con.setInstanceFollowRedirects(false);
394 con.setRequestMethod("POST");
395 con.addRequestProperty("Connection", "close");
397 StringBuffer sb = new StringBuffer(4096);
398 sb.append("next_url=&");
400 sb.append(URLEncoder.encode(User, "Shift_JIS"));
401 sb.append("&password=");
402 sb.append(URLEncoder.encode(Pass, "Shift_JIS"));
403 sb.append("&submit.x=103&submit.y=16");
404 OutputStream os = con.getOutputStream();
405 os.write(sb.substring(0).getBytes());
408 int code = con.getResponseCode();
409 if (code < 200 || code >= 400) {
410 System.out.println("Can't login:" + con.getResponseMessage());
416 while ((key = con.getHeaderFieldKey(i)) != null) {
417 if (key.equalsIgnoreCase("Set-Cookie")) {
418 value = con.getHeaderField(i);
420 Cookie = value.substring(0, value.indexOf(";"));
426 if (Cookie == null) {
427 System.out.println("Can't login: cannot set cookie.");
430 System.out.println("Logged in.");
431 } catch (IOException ex) {
432 logger.log(Level.SEVERE, null, ex);
438 private File appendExtension(File file, String extension) {
439 final String e = "." + extension;
440 final String defExt = ".flv";
441 String path = file.getPath();
442 if (path.endsWith(e)) {
444 } else if (path.endsWith(defExt)) {
445 path = path.substring(0, path.length() - defExt.length());
447 return new File(path + e);
450 private class NicoApiRequest {
452 private final String url;
454 private NicoApiRequest(String url) {
458 private Map<String, String> get() throws IOException {
459 Map<String, String> map = new HashMap<String, String>();
460 System.out.print("Getting video informations...");
461 HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
463 con.setRequestMethod("GET");
464 con.addRequestProperty("Cookie", Cookie);
465 con.addRequestProperty("Connection", "close");
467 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
468 throw new IOException("Can't getVideoInfo:" + url);
471 BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
472 String ret = br.readLine();
475 ret = URLDecoder.decode(ret, "Shift_JIS");
476 String[] array = ret.split("&");
478 for (int i = 0; i < array.length; i++) {
479 int idx = array[i].indexOf("=");
483 String key = array[i].substring(0, idx);
484 String value = array[i].substring(idx + 1);