OSDN Git Service

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