OSDN Git Service

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