OSDN Git Service

worker listenerのインタフェース名変更
[coroid/inqubus.git] / frontend / src / saccubus / worker / download / Download.java
1 package saccubus.worker.download;
2
3 import java.io.File;
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.Worker;
17 import saccubus.worker.WorkerListener;
18 import saccubus.worker.profile.CommentProfile;
19 import saccubus.worker.profile.GeneralProfile;
20 import saccubus.worker.profile.OutputProfile;
21 import saccubus.worker.profile.DownloadProfile;
22 import saccubus.worker.profile.ProxyProfile;
23
24 /**
25  * <p>タイトル: さきゅばす</p>
26  *
27  * <p>説明: ニコニコ動画の動画をコメントつきで保存</p>
28  *
29  * <p>著作権: Copyright (c) 2007 PSI</p>
30  *
31  * <p>会社名: </p>
32  *
33  * @author 未入力
34  * @version 1.0
35  */
36 public class Download extends Worker<DownloadResult, DownloadProgress> {
37
38     private static final Logger logger = Logger.getLogger(Download.class.getName());
39     private final DownloadProfile profile;
40     private final String videoId;
41
42     public Download(DownloadProfile profile, String videoId) {
43         this(profile, videoId, null);
44     }
45
46     /**
47      * コンバータを構築します.
48      * @param videoId 対象となる動画のID.
49      * @param time
50      * @param profile
51      * @param listener
52      * @param flag
53      */
54     public Download(DownloadProfile profile, String videoId, WorkerListener<DownloadProgress> listener) {
55         // TODO listener登録
56         super(listener);
57         this.videoId = videoId;
58         this.profile = profile;
59     }
60
61 //    @Override
62 //    public Boolean call() throws Exception {
63 //        try {
64 //            final DownloadResult result = doInBackground();
65 //            return Boolean.valueOf(result.getResultValue());
66 //        } finally {
67 //            // TODO 何か処理が必要?
68 ////            getStopFlag().finished();
69 //        }
70 //    }
71 //    // TODO Runnableを実装しなくなったので削除する
72 //    public void run() {
73 //        try {
74 //            call();
75 //        } catch (Exception ex) {
76 //            String text = (ex.getMessage() != null) ? ex.getMessage() : "予期しないエラー発生のため中断しました。";
77 //            sendText(text);
78 //            logger.log(Level.SEVERE, null, ex);
79 //        }
80 //    }
81     @Override
82     public DownloadResult call() throws Exception {
83
84         publish(new DownloadProgress("ログイン中"));
85
86         NicoHttpClient client = null;
87         nicobrowser.VideoInfo vi = null;
88         NamePattern videoNamePattern = null;
89         WayBackInfo wbi = null;
90         if (needsLogin()) {
91             client = createClientAndLogin();
92             vi = client.getVideoInfo(videoId);
93
94             final String name = profile.getVideoProfile().getFileName();
95             final String replaceFrom = profile.getGeneralProfile().getReplaceFrom();
96             final String replaceTo = profile.getGeneralProfile().getReplaceTo();
97             videoNamePattern = new NamePattern(name, replaceFrom, replaceTo, vi.getTitleInWatchPage());
98
99             if (needsBackLog()) {
100                 final String key = client.getWayBackKey(vi);
101                 wbi = new WayBackInfo(key, profile.getCommentProfile().getBackLogPoint());
102             }
103         }
104
105         checkStop();
106
107         File commentFile;
108         if (profile.getCommentProfile().isDownload()) {
109             final CommentProfile prof = profile.getCommentProfile();
110             final GeneralProfile gene = profile.getGeneralProfile();
111
112             final NamePattern pattern = new NamePattern(prof.getFileName(), gene.getReplaceFrom(), gene.getReplaceTo(),
113                     vi.getTitleInWatchPage());
114             // TODO コメントファイルに{low}は使えないことをどこかに書くべきか
115             final String name = pattern.createFileName(videoId, true);
116             final File file = new File(profile.getCommentProfile().getDir(), name);
117
118             commentFile = client.getCommentFile(vi, file.getPath(), wbi, profile.getCommentProfile().
119                     getLengthRelatedCommentSize(),
120                     profile.getCommentProfile().isDisablePerMinComment());
121         } else {
122             commentFile = profile.getCommentProfile().getLocalFile();
123         }
124
125         checkStop();
126
127         File videoFile;
128         GetFlvResult vf;
129         if (profile.getVideoProfile().isDownload()) {
130             vf = client.getFlvFile(vi, profile.getVideoProfile().getDir(), videoNamePattern,
131                     Status.GET_INFO, true, new ProgressListener() {
132
133                 @Override
134                 public void progress(long fileSize, long downloadSize) {
135                     final double vol = (double) downloadSize / (double) fileSize * 100.0;
136                     publish(new DownloadProgress(String.format("ダウンロード%.2f%%", vol)));
137                 }
138             });
139
140             videoFile = vf.getFile();
141         } else {
142             videoFile = profile.getVideoProfile().getLocalFile();
143         }
144         return new DownloadResult(true, videoFile, commentFile);
145
146
147         // TODO FFMPEG 実行開始は別タスクとして実装する.
148 //        if (!profile.getOutputFileSetting().isConvert()) {
149 //            publish(new DownloadProgress("動画・コメントを保存し、変換は行いませんでした。"));
150 //            return new DownloadResult(true);
151 //        }
152 //
153 //        if (!videoFile.isFile()) {
154 //            throw new IOException("入力動画ファイルが存在しません:" + videoFile.getPath());
155 //        }
156 //
157 //        if (profile.getOutputFileSetting().isAddComment()) {
158 //            if (!commentFile.isFile()) {
159 //                throw new IOException("入力コメントファイルが存在しません:" + commentFile.getPath());
160 //            }
161 //        } else {
162 //            commentFile = null;
163 //        }
164 //
165 //        /*ビデオ名の確定*/
166 //        final boolean isNotLow = (vf == null) ? true : (vf.getStatus() != Status.GET_LOW);
167 //        File convertedVideoFile = getOutputFileName(vi.getTitleInWatchPage(), isNotLow);
168 //
169
170 //        boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, videoFile,
171 //                convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
172 //        return res;
173     }
174
175     /** @return 何かダウンロードするものがあればtrue. */
176     private static boolean needsDownload(DownloadProfile profile) {
177         return (profile.getVideoProfile().isDownload() || profile.getCommentProfile().isDownload());
178     }
179
180     // TODO どこかに処理を移す必要がある.
181     /**
182      * (ネットワーク設定以外の)設定を検証する.
183      * @throws IllegalArgumentException 設定に不備がある場合.
184      */
185 //    private void validSetting() {
186 //        if (profile.getOutputFileSetting().isConvert()) {
187 //            File a = profile.getFfmpeg().getFfmpeg();
188 //            if (!a.canRead()) {
189 //                throw new IllegalArgumentException("FFmpegが見つかりません。");
190 //            }
191 //            if (profile.getFfmpeg().getVhook().getPath().indexOf(' ') >= 0) {
192 //                throw new IllegalArgumentException("すいません。現在vhookライブラリには半角空白は使えません。");
193 //            }
194 //            a = profile.getFfmpeg().getVhook();
195 //            if (!a.canRead()) {
196 //                throw new IllegalArgumentException("Vhookライブラリが見つかりません。");
197 //            }
198 //            a = profile.getFfmpeg().getFont();
199 //            if (!a.canRead()) {
200 //                throw new IllegalArgumentException("フォントが見つかりません。");
201 //            }
202 //        }
203 //    }
204     /**
205      * HttpClientを生成し, ニコニコ動画サーバへログインします.
206      * @return 生成したHttpClientインスタンス.
207      * @throws IOException ログイン失敗.
208      * @throws InterruptedException ログイン失敗.
209      */
210     // TODO HttpException を投げるのをやめたい. コンパイル時にHttpComponentが必要になるので.
211     private NicoHttpClient createClientAndLogin() throws IOException, InterruptedException, HttpException {
212         final NicoHttpClient client = createClient(profile.getProxyProfile());
213         final boolean hasLogin;
214         try {
215             hasLogin = client.login(profile.getLoginInfo().getMail(), profile.getLoginInfo().getPassword());
216             if (!hasLogin) {
217                 throw new IOException("login fail");
218             }
219         } catch (URISyntaxException ex) {
220             throw new IOException("login fail", ex);
221         }
222         return client;
223     }
224
225     private NicoHttpClient createClient(ProxyProfile proxy) {
226         if (proxy.use()) {
227             return new NicoHttpClient(proxy.getHost(), proxy.getPort());
228         } else {
229             return new NicoHttpClient();
230         }
231     }
232
233     /** @return ログインする必要があればtrue. */
234     private boolean needsLogin() {
235         return profile.getVideoProfile().isDownload() || profile.getCommentProfile().isDownload();
236     }
237
238     /** @return 過去ログ取得の必要があればtrue. */
239     private boolean needsBackLog() {
240         return profile.getCommentProfile().getBackLogPoint() >= 0L;
241     }
242
243     private void checkStop() throws InterruptedException {
244         if (Thread.interrupted()) {
245             throw new InterruptedException("中止要求を受け付けました");
246         }
247     }
248 }