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.URLEncoder;
16 import java.net.URLDecoder;
17 import java.text.DateFormat;
18 import java.text.ParseException;
19 import java.text.SimpleDateFormat;
20 import java.util.Date;
21 import java.util.HashMap;
23 import javax.net.ssl.HttpsURLConnection;
24 import saccubus.ConvertStopFlag;
25 import saccubus.util.FileUtil;
27 import static saccubus.net.VideoInfo.OfficialOption;
31 *
\83^
\83C
\83g
\83\8b:
\82³
\82«
\82ã
\82Î
\82·
35 *
\90à
\96¾:
\83j
\83R
\83j
\83R
\93®
\89æ
\82Ì
\93®
\89æ
\82ð
\83R
\83\81\83\93\83g
\82Â
\82«
\82Å
\95Û
\91¶
39 *
\92\98\8dì
\8c : Copyright (c) 2007 PSI
46 * @author
\96¢
\93ü
\97Í
49 public class NicoClient {
50 private String Cookie = null;
52 private static final String TITLE_PARSE_STR_START = "<title>";
53 private final static DateFormat DateFmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
54 private final static DateFormat DateFmt2 = new SimpleDateFormat("yyyy/MM/dd HH:mm");
56 private final String User;
57 private final String Pass;
58 private boolean Logged_in = false;
59 private final ConvertStopFlag StopFlag;
60 private final Proxy ConProxy;
62 private String WayBackKey = "0";
63 private String WayBackTime = "0";
64 private final static String WAYBACKKEY_STR = "waybackkey=";
66 public NicoClient(final String user, final String pass,
67 final ConvertStopFlag flag, final String proxy, final int proxy_port) {
70 if (proxy != null && proxy.length() > 0 && proxy_port >= 0
71 && proxy_port <= 65535) {
72 ConProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy,
75 ConProxy = Proxy.NO_PROXY;
77 //
\83\8d\83O
\83C
\83\93
82 public String getBackCommentFromLength(VideoInfo vi, String def) {
83 final int videoLength = vi.getVideoLength();
84 if (videoLength < 0) {
86 } else if (videoLength >= 0 && videoLength < 60) {
88 } else if (videoLength >= 60 && videoLength < 300) {
90 } else if (videoLength >= 300 && videoLength < 600) {
97 public File getComment(VideoInfo vi, final File file, final TextProgressListener status, String back_comment) {
98 return downloadComment(back_comment, file, vi, status, false);
102 *
\93\8a\8de
\8eÒ
\83R
\83\81\83\93\83g
\82ð
\83_
\83E
\83\93\83\8d\81[
\83h
\82·
\82é.
103 * @param vi
\83r
\83f
\83I
\8fî
\95ñ.
104 * @param file
\83_
\83E
\83\93\83\8d\81[
\83h
\90æ
\83t
\83@
\83C
\83\8b.
105 * @param status
\90i
\92»
\92Ê
\92m
\83\8a\83X
\83i.
106 * @return
\83_
\83E
\83\93\83\8d\81[
\83h
\82³
\82ê
\82½
\83t
\83@
\83C
\83\8b.
\83_
\83E
\83\93\83\8d\81[
\83h
\82Å
\82«
\82È
\82¯
\82ê
\82Înull.
108 public File getTcomment(VideoInfo vi, final File file, final TextProgressListener status) {
109 return downloadComment("500", file, vi, status, true);
112 private File downloadComment(String back_comment, final File file, VideoInfo vi, final TextProgressListener status,
113 boolean isTcomm) throws NumberFormatException {
114 System.out.print("Downloading comment size:" + back_comment + "...");
116 if (file.canRead()) { //
\83t
\83@
\83C
\83\8b\82ª
\82·
\82Å
\82É
\91¶
\8dÝ
\82·
\82é
\82È
\82ç
\8dí
\8f\9c\82·
\82é
\81B
119 OutputStream fos = new FileOutputStream(file);
120 HttpURLConnection con = (HttpURLConnection) (new URL(vi.getMsgUrl()))
121 .openConnection(ConProxy);
122 con.setDoOutput(true);
123 con.setDoInput(true);
124 con.setRequestMethod("POST");
125 con.addRequestProperty("Cookie", Cookie);
126 con.addRequestProperty("Connection", "close");
128 OutputStream os = con.getOutputStream();
129 String tcommStr = (isTcomm) ? "fork=\"1\" " : "";
130 String official = "";
131 OfficialOption oo = vi.getOfficialOption();
133 official = "force_184=\"" + oo.getForce184() + "\" threadkey=\"" + oo.getThreadKey() + "\" ";
135 String req = "<thread user_id=\"" + vi.getUserId() + "\" when=\"" + WayBackTime + "\" waybackkey=\""
136 + WayBackKey + "\" res_from=\"-" + back_comment + "\" version=\"20061206\" thread=\"" + vi.
137 getThreadId() + "\" " + tcommStr + official + "/>";
138 os.write(req.getBytes());
141 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
142 System.out.println("ng.\nCan't download comment:" + vi.getMsgUrl());
145 InputStream is = con.getInputStream();
148 String content_length_str = con.getHeaderField("Content-length");
149 if (content_length_str != null && !content_length_str.equals("")) {
150 max_size = Integer.parseInt(content_length_str);
153 final byte[] buf = new byte[1024 * 1024];
154 while ((read = is.read(buf, 0, buf.length)) > 0) {
155 fos.write(buf, 0, read);
158 String per = Double.toString((((double) size) * 100) / max_size);
159 per = per.substring(0, Math.min(per.indexOf(".") + 3, per.length()));
160 status.setText("
\83R
\83\81\83\93\83g
\83_
\83E
\83\93\83\8d\81[
\83h
\81F" + per + "
\83p
\81[
\83Z
\83\93\83g
\8a®
\97¹");
162 status.setText("
\83R
\83\81\83\93\83g
\83_
\83E
\83\93\83\8d\81[
\83h
\92\86\81F" + Integer.toString(size >> 10) + "kbytes
\83_
\83E
\83\93\83\8d\81[
\83h");
164 if (StopFlag.needStop()) {
165 System.out.println("Stopped.");
174 System.out.println("ok.");
180 } catch (IOException ex) {
181 ex.printStackTrace();
186 public File getVideo(VideoInfo vi, final File file, final TextProgressListener status) {
187 if (vi.getVideoUrl() == null) {
188 System.out.println("Video url is not detected.");
192 // if (file.canRead()) { //
\83t
\83@
\83C
\83\8b\82ª
\82·
\82Å
\82É
\91¶
\8dÝ
\82·
\82é
\82È
\82ç
\8dí
\8f\9c\82·
\82é
\81B
195 HttpURLConnection con = (HttpURLConnection) (new URL(vi.getVideoUrl()))
196 .openConnection(ConProxy);
197 /*
\8fo
\97Í
\82Ì
\82Ý */
198 con.setDoInput(true);
199 con.setRequestMethod("GET");
200 con.addRequestProperty("Cookie", Cookie);
202 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
203 System.out.println("Can't get video:" + vi.getVideoUrl());
206 final String extension = Util.getExtention(con.getContentType());
207 File outFile = appendExtension(file, extension);
208 InputStream is = con.getInputStream();
209 OutputStream os = new FileOutputStream(outFile);
210 String content_length_str = con.getHeaderField("Content-length");
212 if (content_length_str != null && !content_length_str.equals("")) {
213 max_size = Integer.parseInt(content_length_str);
216 System.out.print("Downloading video...");
218 final byte[] buf = new byte[1024 * 1024];
219 while ((read = is.read(buf, 0, buf.length)) > 0) {
221 os.write(buf, 0, read);
223 String per = Double.toString((((double) size) * 100)
225 per = per.substring(0, Math.min(per.indexOf(".") + 3, per
227 status.setText("
\93®
\89æ
\83_
\83E
\83\93\83\8d\81[
\83h
\81F" + per + "
\83p
\81[
\83Z
\83\93\83g
\8a®
\97¹");
229 status.setText("
\93®
\89æ
\83_
\83E
\83\93\83\8d\81[
\83h
\92\86\81F" + Integer.toString(size >> 10)
230 + "kbytes
\83_
\83E
\83\93\83\8d\81[
\83h");
232 if (StopFlag.needStop()) {
233 System.out.println("Stopped.");
242 System.out.println("ok.");
248 } catch (FileNotFoundException ex) {
249 ex.printStackTrace();
250 } catch (IOException ex) {
251 ex.printStackTrace();
256 /** @return
\83r
\83f
\83I
\96¼ */
257 public String getVideoHistoryAndTitle(String tag) throws IOException {
258 String url = "http://www.nicovideo.jp/watch/" + tag;
259 System.out.print("Getting video history...");
260 String new_cookie = null;
261 String videoTitle = null;
263 HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
264 /*
\83\8a\83N
\83G
\83X
\83g
\82Ì
\90Ý
\92è */
265 con.setRequestMethod("GET");
266 con.addRequestProperty("Cookie", Cookie);
267 con.addRequestProperty("Connection", "close");
269 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
270 throw new IOException("Can't getVideoHistory:" + url);
275 while ((key = con.getHeaderFieldKey(i)) != null) {
276 if (key.equalsIgnoreCase("Set-Cookie")) {
277 value = con.getHeaderField(i);
279 new_cookie = value.substring(0, value.indexOf(";"));
284 BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
287 while ((ret = br.readLine()) != null && index < 0) {
288 if ((index = ret.indexOf(TITLE_PARSE_STR_START)) >= 0) {
289 videoTitle = ret.substring(index + TITLE_PARSE_STR_START.length(), ret.indexOf("
\81]", index));
290 videoTitle = FileUtil.safeFileName(videoTitle);
295 if (new_cookie == null) {
296 System.out.println("Can't getVideoHistory: cannot get cookie.");
299 System.out.println("ok.");
301 Cookie += new_cookie;
306 public VideoInfo getVideoInfo(String tag, String time) throws IOException {
307 final String videoTitle = getVideoHistoryAndTitle(tag);
309 String url = "http://flapi.nicovideo.jp/api/getflv/" + tag;
310 if (tag.startsWith("nm")) {
313 System.out.print("Getting video informations...");
314 Map<String,String> res = new NicoApiRequest(url).get();
315 String threadId = res.get("thread_id");
316 String videoUrl = res.get("url");
317 String msgUrl = res.get("ms");
318 String userId = res.get("user_id");
319 int videoLength = -1;
320 String videoLengthStr = res.get("l");
322 videoLength = Integer.parseInt(videoLengthStr);
323 }catch(NumberFormatException ex){}
325 OfficialOption oo = null;
326 if ("1".equals(res.get("needs_key"))) {
327 oo = getOfficialOption(threadId);
330 VideoInfo vi = new VideoInfo(videoTitle, threadId, videoUrl, msgUrl, userId, videoLength, oo);
331 System.out.println("ok.");
333 if (!(time == null || time.equals("")) && !getWayBackKey(vi, time)) { // WayBackKey
334 throw new IOException();
339 private OfficialOption getOfficialOption(String threadId) throws IOException {
340 String url = "http://www.nicovideo.jp/api/getthreadkey?thread="+threadId;
341 Map<String,String> map = new NicoApiRequest(url).get();
342 return new OfficialOption(map.get("threadkey"), map.get("force_184"));
345 private boolean getWayBackKey(VideoInfo vi, String time) {
346 System.out.print("Setting wayback time...");
348 String waybacktime = "0";
350 date = DateFmt.parse(time);
351 } catch (ParseException ex2) {
356 date = DateFmt2.parse(time);
357 } catch (ParseException ex3) {
362 waybacktime = Long.toString(date.getTime() / 1000);
363 System.out.println("ok.(" + date.toString() + "):" + waybacktime);
366 long tmp_time = Long.parseLong(time);
367 waybacktime = Long.toString(tmp_time);
368 date = new Date(tmp_time * 1000);
369 System.out.println("ok.(" + date.toString() + "):"
371 } catch (NumberFormatException ex4) {
372 System.out.println("ng.");
373 System.out.println("Cannot parse wayback time.");
377 System.out.print("Getting wayback key...");
378 String url = "http://www.nicovideo.jp/api/getwaybackkey?thread="
382 HttpURLConnection con = (HttpURLConnection) (new URL(url))
383 .openConnection(ConProxy);
384 /*
\83\8a\83N
\83G
\83X
\83g
\82Ì
\90Ý
\92è */
385 con.setRequestMethod("GET");
386 con.addRequestProperty("Cookie", Cookie);
387 con.addRequestProperty("Connection", "close");
388 con.setDoInput(true);
390 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
391 System.out.println("Can't get WayBackKey:" + url);
394 /*
\96ß
\82è
\92l
\82Ì
\8eæ
\93¾ */
395 BufferedReader br = new BufferedReader(new InputStreamReader(con
400 } catch (IOException ex1) {
401 System.out.println("ng.");
402 ex1.printStackTrace();
406 if ((idx = ret.indexOf(WAYBACKKEY_STR)) < 0) {
407 System.out.println("ng.");
408 System.out.println("Cannot find wayback key from response.");
411 int end_idx = Math.max(ret.length(), ret.indexOf("&"));
412 String waybackkey = ret.substring(idx + WAYBACKKEY_STR.length(),
414 if (waybackkey == null || waybackkey.equals("")) {
415 System.out.println("ng.");
416 System.out.println("Cannot get wayback key.");
419 System.out.println("ok. key:" + waybackkey);
420 WayBackTime = waybacktime;
421 WayBackKey = waybackkey;
425 public boolean isLoggedIn() {
429 private boolean login() {
431 HttpURLConnection con = (HttpsURLConnection) (new URL(
432 "https://secure.nicovideo.jp/secure/login?site=niconico"))
433 .openConnection(ConProxy);
434 /*
\8fo
\97Í
\82Ì
\82Ý */
435 con.setDoOutput(true);
436 HttpURLConnection.setFollowRedirects(false);
437 con.setInstanceFollowRedirects(false);
438 con.setRequestMethod("POST");
439 con.addRequestProperty("Connection", "close");
441 StringBuffer sb = new StringBuffer(4096);
442 sb.append("next_url=&");
444 sb.append(URLEncoder.encode(User, "Shift_JIS"));
445 sb.append("&password=");
446 sb.append(URLEncoder.encode(Pass, "Shift_JIS"));
447 sb.append("&submit.x=103&submit.y=16");
448 OutputStream os = con.getOutputStream();
449 os.write(sb.substring(0).getBytes());
452 int code = con.getResponseCode();
453 if (code < 200 || code >= 400) {
454 System.out.println("Can't login:" + con.getResponseMessage());
460 while ((key = con.getHeaderFieldKey(i)) != null) {
461 if (key.equalsIgnoreCase("Set-Cookie")) {
462 value = con.getHeaderField(i);
464 Cookie = value.substring(0, value.indexOf(";"));
470 if (Cookie == null) {
471 System.out.println("Can't login: cannot set cookie.");
474 System.out.println("Logged in.");
475 } catch (IOException ex) {
476 ex.printStackTrace();
482 private File appendExtension(File file, String extension) {
483 final String e = "." + extension;
484 final String defExt = ".flv";
485 String path = file.getPath();
486 if (path.endsWith(e)) {
488 } else if (path.endsWith(defExt)) {
489 path = path.substring(0, path.length() - defExt.length());
491 return new File(path + e);
494 private class NicoApiRequest {
496 private final String url;
498 private NicoApiRequest(String url) {
502 private Map<String,String> get() throws IOException {
503 Map<String, String> map = new HashMap<String, String>();
504 System.out.print("Getting video informations...");
505 HttpURLConnection con = (HttpURLConnection) (new URL(url)).openConnection(ConProxy);
506 /*
\83\8a\83N
\83G
\83X
\83g
\82Ì
\90Ý
\92è */
507 con.setRequestMethod("GET");
508 con.addRequestProperty("Cookie", Cookie);
509 con.addRequestProperty("Connection", "close");
511 if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
512 throw new IOException("Can't getVideoInfo:" + url);
514 /*
\96ß
\82è
\92l
\82Ì
\8eæ
\93¾ */
515 BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
516 String ret = br.readLine();
519 ret = URLDecoder.decode(ret, "Shift_JIS");
520 String[] array = ret.split("&");
522 for (int i = 0; i < array.length; i++) {
523 int idx = array[i].indexOf("=");
527 String key = array[i].substring(0, idx);
528 String value = array[i].substring(idx + 1);