1 package saccubus.converter;
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.ConvertStopFlag;
17 import saccubus.net.TextProgressListener;
18 import saccubus.converter.profile.CommentProfile;
19 import saccubus.converter.profile.FfmpegProfile;
20 import saccubus.converter.profile.GeneralProfile;
21 import saccubus.converter.profile.OutputProfile;
22 import saccubus.converter.profile.Profile;
23 import saccubus.converter.profile.ProxyProfile;
28 * <p>説明: ニコニコ動画の動画をコメントつきで保存</p>
30 * <p>著作権: Copyright (c) 2007 PSI</p>
37 public abstract class Converter extends SwingWorker<ConvertResult, ConvertProgress> implements Callable<Boolean> {
39 private static final Logger logger = Logger.getLogger(Converter.class.getName());
40 private final Profile profile;
41 private final String movieId;
45 * @param id 対象となる動画のID.
51 public Converter(String id, Profile profile,
52 TextProgressListener listener, ConvertStopFlag flag) {
54 this.profile = profile;
58 public Boolean call() throws Exception {
60 final ConvertResult result = doInBackground();
61 return Boolean.valueOf(result.getResultValue());
64 // getStopFlag().finished();
68 // // TODO Runnableを実装しなくなったので削除する
69 // public void run() {
72 // } catch (Exception ex) {
73 // String text = (ex.getMessage() != null) ? ex.getMessage() : "予期しないエラー発生のため中断しました。";
75 // logger.log(Level.SEVERE, null, ex);
79 protected ConvertResult doInBackground() throws Exception {
80 if (!shouldRun(profile)) {
81 publish(new ConvertProgress("何もすることがありません"));
82 return new ConvertResult(true);
86 final FfmpegProfile ov = profile.getFfmpeg().getFfmpegOption();
88 // TODO ログインしないで良い場合もある.
89 publish(new ConvertProgress("ログイン中"));
93 NicoHttpClient client = null;
94 nicobrowser.VideoInfo vi = null;
95 NamePattern videoNamePattern = null;
96 WayBackInfo wbi = null;
98 client = createClientAndLogin();
99 vi = client.getVideoInfo(movieId);
101 final String name = profile.getVideoSetting().getFileName();
102 final String replaceFrom = profile.getGeneralSetting().getReplaceFrom();
103 final String replaceTo = profile.getGeneralSetting().getReplaceTo();
104 videoNamePattern = new NamePattern(name, replaceFrom, replaceTo, vi.getTitleInWatchPage());
106 if (needsBackLog()) {
107 final String key = client.getWayBackKey(vi);
108 wbi = new WayBackInfo(key, profile.getCommentSetting().getBackLogPoint());
115 if (profile.getCommentSetting().isDownload()) {
116 final CommentProfile prof = profile.getCommentSetting();
117 final GeneralProfile gene = profile.getGeneralSetting();
119 final NamePattern pattern = new NamePattern(prof.getFileName(), gene.getReplaceFrom(), gene.getReplaceTo(),
120 vi.getTitleInWatchPage());
121 // TODO コメントファイルに{low}は使えないことをどこかに書くべきか
122 final String name = pattern.createFileName(movieId, true);
123 final File file = new File(profile.getCommentSetting().getDir(), name);
125 commentFile = client.getCommentFile(vi, file.getPath(), wbi, profile.getCommentSetting().
126 getLengthRelatedCommentSize(),
127 profile.getCommentSetting().isDisablePerMinComment());
129 commentFile = profile.getCommentSetting().getLocalFile();
135 GetFlvResult vf = null;
136 if (profile.getVideoSetting().isDownload()) {
137 vf = client.getFlvFile(vi, profile.getVideoSetting().getDir(), videoNamePattern,
138 Status.GET_INFO, true, new ProgressListener() {
141 public void progress(long fileSize, long downloadSize) {
142 throw new UnsupportedOperationException("Not supported yet.");
146 public boolean getCancel() {
147 throw new UnsupportedOperationException("Not supported yet.");
151 videoFile = vf.getFile();
153 videoFile = profile.getVideoSetting().getLocalFile();
156 if (!profile.getOutputFileSetting().isConvert()) {
157 publish(new ConvertProgress("動画・コメントを保存し、変換は行いませんでした。"));
158 return new ConvertResult(true);
161 if (!videoFile.isFile()) {
162 throw new IOException("入力動画ファイルが存在しません:" + videoFile.getPath());
165 if (profile.getOutputFileSetting().isAddComment()) {
166 if (!commentFile.isFile()) {
167 throw new IOException("入力コメントファイルが存在しません:" + commentFile.getPath());
174 final boolean isNotLow = (vf == null) ? true : (vf.getStatus() != Status.GET_LOW);
175 File convertedVideoFile = getOutputFileName(vi.getTitleInWatchPage(), isNotLow);
177 return new ConvertResult(true);
179 // TODO FFMPEG 実行開始は別タスクとして実装する.
180 // boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, videoFile,
181 // convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
185 /** @return 何か実行すべき処理があればtrue. */
186 private static boolean shouldRun(Profile profile) {
187 return profile.getOutputFileSetting().isConvert() || needsDownload(profile);
190 /** @return 何かダウンロードするものがあればtrue. */
191 private static boolean needsDownload(Profile profile) {
192 return (profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload());
196 * (ネットワーク設定以外の)設定を検証する.
197 * @throws IllegalArgumentException 設定に不備がある場合.
199 private void validSetting() {
200 if (profile.getOutputFileSetting().isConvert()) {
201 File a = profile.getFfmpeg().getFfmpeg();
203 throw new IllegalArgumentException("FFmpegが見つかりません。");
205 if (profile.getFfmpeg().getVhook().getPath().indexOf(' ') >= 0) {
206 throw new IllegalArgumentException("すいません。現在vhookライブラリには半角空白は使えません。");
208 a = profile.getFfmpeg().getVhook();
210 throw new IllegalArgumentException("Vhookライブラリが見つかりません。");
212 a = profile.getFfmpeg().getFont();
214 throw new IllegalArgumentException("フォントが見つかりません。");
220 * HttpClientを生成し, ニコニコ動画サーバへログインします.
221 * @return 生成したHttpClientインスタンス.
222 * @throws IOException ログイン失敗.
223 * @throws InterruptedException ログイン失敗.
225 // TODO HttpException を投げるのをやめたい. コンパイル時にHttpComponentが必要になるので.
226 private NicoHttpClient createClientAndLogin() throws IOException, InterruptedException, HttpException {
227 final NicoHttpClient client = createClient(profile.getProxySetting());
228 final boolean hasLogin;
230 hasLogin = client.login(profile.getLoginInfo().getMail(), profile.getLoginInfo().getPassword());
232 throw new IOException("login fail");
234 } catch (URISyntaxException ex) {
235 throw new IOException("login fail", ex);
240 private NicoHttpClient createClient(ProxyProfile proxy) {
242 return new NicoHttpClient(proxy.getHost(), proxy.getPort());
244 return new NicoHttpClient();
248 /** @return ログインする必要があればtrue. */
249 private boolean needsLogin() {
250 return profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload();
253 /** @return 過去ログ取得の必要があればtrue. */
254 private boolean needsBackLog() {
255 return profile.getCommentSetting().getBackLogPoint() >= 0L;
260 * @param title 動画タイトル.
261 * @param isNotLow 入力動画ファイルがlowでないかどうか.
262 * @return 出力ファイルの保存先.
264 private File getOutputFileName(String title, boolean isNotLow) {
265 final OutputProfile prof = profile.getOutputFileSetting();
266 final GeneralProfile gene = profile.getGeneralSetting();
267 final File dir = prof.getDir();
268 final String replaceFrom = gene.getReplaceFrom();
269 final String replaceTo = gene.getReplaceTo();
270 final NamePattern pattern = new NamePattern(prof.getFileName(), replaceFrom, replaceTo, title);
271 final String name = pattern.createFileName(movieId, isNotLow);
272 return new File(dir, name);
275 private void checkStop() throws InterruptedException {
276 if (Thread.interrupted()) {
277 throw new InterruptedException("中止要求を受け付けました");