1 package saccubus.worker;
4 import java.io.IOException;
5 import java.net.URISyntaxException;
6 import java.util.concurrent.Callable;
7 import java.util.logging.Logger;
8 import javax.swing.SwingWorker;
9 import nicobrowser.GetFlvResult;
10 import nicobrowser.NamePattern;
11 import nicobrowser.NicoHttpClient;
12 import nicobrowser.ProgressListener;
13 import nicobrowser.WayBackInfo;
14 import nicobrowser.entity.NicoContent.Status;
15 import org.apache.http.HttpException;
16 import saccubus.worker.profile.CommentProfile;
17 import saccubus.worker.profile.GeneralProfile;
18 import saccubus.worker.profile.OutputProfile;
19 import saccubus.worker.profile.DownloadProfile;
20 import saccubus.worker.profile.ProxyProfile;
25 * <p>説明: ニコニコ動画の動画をコメントつきで保存</p>
27 * <p>著作権: Copyright (c) 2007 PSI</p>
34 public class Download extends SwingWorker<DownloadResult, DownloadProgress> implements Callable<Boolean> {
36 private static final Logger logger = Logger.getLogger(Download.class.getName());
37 private final DownloadProfile profile;
38 private final String videoId;
42 * @param videoId 対象となる動画のID.
48 public Download(DownloadProfile profile, String videoId) {
49 this.videoId = videoId;
50 this.profile = profile;
54 public Boolean call() throws Exception {
56 final DownloadResult result = doInBackground();
57 return Boolean.valueOf(result.getResultValue());
60 // getStopFlag().finished();
64 // // TODO Runnableを実装しなくなったので削除する
65 // public void run() {
68 // } catch (Exception ex) {
69 // String text = (ex.getMessage() != null) ? ex.getMessage() : "予期しないエラー発生のため中断しました。";
71 // logger.log(Level.SEVERE, null, ex);
75 protected DownloadResult doInBackground() throws Exception {
77 publish(new DownloadProgress("ログイン中"));
79 NicoHttpClient client = null;
80 nicobrowser.VideoInfo vi = null;
81 NamePattern videoNamePattern = null;
82 WayBackInfo wbi = null;
84 client = createClientAndLogin();
85 vi = client.getVideoInfo(videoId);
87 final String name = profile.getVideoSetting().getFileName();
88 final String replaceFrom = profile.getGeneralSetting().getReplaceFrom();
89 final String replaceTo = profile.getGeneralSetting().getReplaceTo();
90 videoNamePattern = new NamePattern(name, replaceFrom, replaceTo, vi.getTitleInWatchPage());
93 final String key = client.getWayBackKey(vi);
94 wbi = new WayBackInfo(key, profile.getCommentSetting().getBackLogPoint());
101 if (profile.getCommentSetting().isDownload()) {
102 final CommentProfile prof = profile.getCommentSetting();
103 final GeneralProfile gene = profile.getGeneralSetting();
105 final NamePattern pattern = new NamePattern(prof.getFileName(), gene.getReplaceFrom(), gene.getReplaceTo(),
106 vi.getTitleInWatchPage());
107 // TODO コメントファイルに{low}は使えないことをどこかに書くべきか
108 final String name = pattern.createFileName(videoId, true);
109 final File file = new File(profile.getCommentSetting().getDir(), name);
111 commentFile = client.getCommentFile(vi, file.getPath(), wbi, profile.getCommentSetting().
112 getLengthRelatedCommentSize(),
113 profile.getCommentSetting().isDisablePerMinComment());
115 commentFile = profile.getCommentSetting().getLocalFile();
122 if (profile.getVideoSetting().isDownload()) {
123 vf = client.getFlvFile(vi, profile.getVideoSetting().getDir(), videoNamePattern,
124 Status.GET_INFO, true, new ProgressListener() {
127 public void progress(long fileSize, long downloadSize) {
128 final double vol = (double) downloadSize / (double) fileSize * 100.0;
129 publish(new DownloadProgress(String.format("ダウンロード%.2f%%", vol)));
133 videoFile = vf.getFile();
135 videoFile = profile.getVideoSetting().getLocalFile();
137 return new DownloadResult(true, videoFile, commentFile);
140 // TODO FFMPEG 実行開始は別タスクとして実装する.
141 // if (!profile.getOutputFileSetting().isConvert()) {
142 // publish(new DownloadProgress("動画・コメントを保存し、変換は行いませんでした。"));
143 // return new DownloadResult(true);
146 // if (!videoFile.isFile()) {
147 // throw new IOException("入力動画ファイルが存在しません:" + videoFile.getPath());
150 // if (profile.getOutputFileSetting().isAddComment()) {
151 // if (!commentFile.isFile()) {
152 // throw new IOException("入力コメントファイルが存在しません:" + commentFile.getPath());
155 // commentFile = null;
159 // final boolean isNotLow = (vf == null) ? true : (vf.getStatus() != Status.GET_LOW);
160 // File convertedVideoFile = getOutputFileName(vi.getTitleInWatchPage(), isNotLow);
163 // boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, videoFile,
164 // convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
168 /** @return 何かダウンロードするものがあればtrue. */
169 private static boolean needsDownload(DownloadProfile profile) {
170 return (profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload());
173 // TODO どこかに処理を移す必要がある.
175 * (ネットワーク設定以外の)設定を検証する.
176 * @throws IllegalArgumentException 設定に不備がある場合.
178 // private void validSetting() {
179 // if (profile.getOutputFileSetting().isConvert()) {
180 // File a = profile.getFfmpeg().getFfmpeg();
181 // if (!a.canRead()) {
182 // throw new IllegalArgumentException("FFmpegが見つかりません。");
184 // if (profile.getFfmpeg().getVhook().getPath().indexOf(' ') >= 0) {
185 // throw new IllegalArgumentException("すいません。現在vhookライブラリには半角空白は使えません。");
187 // a = profile.getFfmpeg().getVhook();
188 // if (!a.canRead()) {
189 // throw new IllegalArgumentException("Vhookライブラリが見つかりません。");
191 // a = profile.getFfmpeg().getFont();
192 // if (!a.canRead()) {
193 // throw new IllegalArgumentException("フォントが見つかりません。");
199 * HttpClientを生成し, ニコニコ動画サーバへログインします.
200 * @return 生成したHttpClientインスタンス.
201 * @throws IOException ログイン失敗.
202 * @throws InterruptedException ログイン失敗.
204 // TODO HttpException を投げるのをやめたい. コンパイル時にHttpComponentが必要になるので.
205 private NicoHttpClient createClientAndLogin() throws IOException, InterruptedException, HttpException {
206 final NicoHttpClient client = createClient(profile.getProxySetting());
207 final boolean hasLogin;
209 hasLogin = client.login(profile.getLoginInfo().getMail(), profile.getLoginInfo().getPassword());
211 throw new IOException("login fail");
213 } catch (URISyntaxException ex) {
214 throw new IOException("login fail", ex);
219 private NicoHttpClient createClient(ProxyProfile proxy) {
221 return new NicoHttpClient(proxy.getHost(), proxy.getPort());
223 return new NicoHttpClient();
227 /** @return ログインする必要があればtrue. */
228 private boolean needsLogin() {
229 return profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload();
232 /** @return 過去ログ取得の必要があればtrue. */
233 private boolean needsBackLog() {
234 return profile.getCommentSetting().getBackLogPoint() >= 0L;
237 private void checkStop() throws InterruptedException {
238 if (Thread.interrupted()) {
239 throw new InterruptedException("中止要求を受け付けました");