OSDN Git Service

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