package saccubus.converter;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.concurrent.Callable;
import java.util.logging.Logger;
import javax.swing.SwingWorker;
import nicobrowser.GetFlvResult;
import nicobrowser.NamePattern;
import nicobrowser.NicoHttpClient;
import nicobrowser.ProgressListener;
import nicobrowser.WayBackInfo;
import nicobrowser.entity.NicoContent.Status;
import org.apache.http.HttpException;
import saccubus.converter.profile.CommentProfile;
import saccubus.converter.profile.FfmpegProfile;
import saccubus.converter.profile.GeneralProfile;
import saccubus.converter.profile.OutputProfile;
import saccubus.converter.profile.Profile;
import saccubus.converter.profile.ProxyProfile;
/**
*
タイトル: さきゅばす
*
* 説明: ニコニコ動画の動画をコメントつきで保存
*
* 著作権: Copyright (c) 2007 PSI
*
* 会社名:
*
* @author 未入力
* @version 1.0
*/
public class Download extends SwingWorker implements Callable {
private static final Logger logger = Logger.getLogger(Download.class.getName());
private final Profile profile;
private final String movieId;
/**
* コンバータを構築します.
* @param id 対象となる動画のID.
* @param time
* @param profile
* @param listener
* @param flag
*/
public Download(String id, Profile profile) {
this.movieId = id;
this.profile = profile;
}
@Override
public Boolean call() throws Exception {
try {
final DownloadResult result = doInBackground();
return Boolean.valueOf(result.getResultValue());
} finally {
// TODO 何か処理が必要?
// getStopFlag().finished();
}
}
// // TODO Runnableを実装しなくなったので削除する
// public void run() {
// try {
// call();
// } catch (Exception ex) {
// String text = (ex.getMessage() != null) ? ex.getMessage() : "予期しないエラー発生のため中断しました。";
// sendText(text);
// logger.log(Level.SEVERE, null, ex);
// }
// }
@Override
protected DownloadResult doInBackground() throws Exception {
if (!shouldRun(profile)) {
publish(new DownloadProgress("何もすることがありません"));
return new DownloadResult(true);
}
validSetting();
final FfmpegProfile ov = profile.getFfmpeg().getFfmpegOption();
// TODO ログインしないで良い場合もある.
publish(new DownloadProgress("ログイン中"));
NicoHttpClient client = null;
nicobrowser.VideoInfo vi = null;
NamePattern videoNamePattern = null;
WayBackInfo wbi = null;
if (needsLogin()) {
client = createClientAndLogin();
vi = client.getVideoInfo(movieId);
final String name = profile.getVideoSetting().getFileName();
final String replaceFrom = profile.getGeneralSetting().getReplaceFrom();
final String replaceTo = profile.getGeneralSetting().getReplaceTo();
videoNamePattern = new NamePattern(name, replaceFrom, replaceTo, vi.getTitleInWatchPage());
if (needsBackLog()) {
final String key = client.getWayBackKey(vi);
wbi = new WayBackInfo(key, profile.getCommentSetting().getBackLogPoint());
}
}
checkStop();
File commentFile;
if (profile.getCommentSetting().isDownload()) {
final CommentProfile prof = profile.getCommentSetting();
final GeneralProfile gene = profile.getGeneralSetting();
final NamePattern pattern = new NamePattern(prof.getFileName(), gene.getReplaceFrom(), gene.getReplaceTo(),
vi.getTitleInWatchPage());
// TODO コメントファイルに{low}は使えないことをどこかに書くべきか
final String name = pattern.createFileName(movieId, true);
final File file = new File(profile.getCommentSetting().getDir(), name);
commentFile = client.getCommentFile(vi, file.getPath(), wbi, profile.getCommentSetting().
getLengthRelatedCommentSize(),
profile.getCommentSetting().isDisablePerMinComment());
} else {
commentFile = profile.getCommentSetting().getLocalFile();
}
checkStop();
File videoFile;
GetFlvResult vf = null;
if (profile.getVideoSetting().isDownload()) {
vf = client.getFlvFile(vi, profile.getVideoSetting().getDir(), videoNamePattern,
Status.GET_INFO, true, new ProgressListener() {
@Override
public void progress(long fileSize, long downloadSize) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public boolean getCancel() {
throw new UnsupportedOperationException("Not supported yet.");
}
});
videoFile = vf.getFile();
} else {
videoFile = profile.getVideoSetting().getLocalFile();
}
if (!profile.getOutputFileSetting().isConvert()) {
publish(new DownloadProgress("動画・コメントを保存し、変換は行いませんでした。"));
return new DownloadResult(true);
}
if (!videoFile.isFile()) {
throw new IOException("入力動画ファイルが存在しません:" + videoFile.getPath());
}
if (profile.getOutputFileSetting().isAddComment()) {
if (!commentFile.isFile()) {
throw new IOException("入力コメントファイルが存在しません:" + commentFile.getPath());
}
} else {
commentFile = null;
}
/*ビデオ名の確定*/
final boolean isNotLow = (vf == null) ? true : (vf.getStatus() != Status.GET_LOW);
File convertedVideoFile = getOutputFileName(vi.getTitleInWatchPage(), isNotLow);
return new DownloadResult(true);
// TODO FFMPEG 実行開始は別タスクとして実装する.
// boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, videoFile,
// convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
// return res;
}
/** @return 何か実行すべき処理があればtrue. */
private static boolean shouldRun(Profile profile) {
return profile.getOutputFileSetting().isConvert() || needsDownload(profile);
}
/** @return 何かダウンロードするものがあればtrue. */
private static boolean needsDownload(Profile profile) {
return (profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload());
}
/**
* (ネットワーク設定以外の)設定を検証する.
* @throws IllegalArgumentException 設定に不備がある場合.
*/
private void validSetting() {
if (profile.getOutputFileSetting().isConvert()) {
File a = profile.getFfmpeg().getFfmpeg();
if (!a.canRead()) {
throw new IllegalArgumentException("FFmpegが見つかりません。");
}
if (profile.getFfmpeg().getVhook().getPath().indexOf(' ') >= 0) {
throw new IllegalArgumentException("すいません。現在vhookライブラリには半角空白は使えません。");
}
a = profile.getFfmpeg().getVhook();
if (!a.canRead()) {
throw new IllegalArgumentException("Vhookライブラリが見つかりません。");
}
a = profile.getFfmpeg().getFont();
if (!a.canRead()) {
throw new IllegalArgumentException("フォントが見つかりません。");
}
}
}
/**
* HttpClientを生成し, ニコニコ動画サーバへログインします.
* @return 生成したHttpClientインスタンス.
* @throws IOException ログイン失敗.
* @throws InterruptedException ログイン失敗.
*/
// TODO HttpException を投げるのをやめたい. コンパイル時にHttpComponentが必要になるので.
private NicoHttpClient createClientAndLogin() throws IOException, InterruptedException, HttpException {
final NicoHttpClient client = createClient(profile.getProxySetting());
final boolean hasLogin;
try {
hasLogin = client.login(profile.getLoginInfo().getMail(), profile.getLoginInfo().getPassword());
if (!hasLogin) {
throw new IOException("login fail");
}
} catch (URISyntaxException ex) {
throw new IOException("login fail", ex);
}
return client;
}
private NicoHttpClient createClient(ProxyProfile proxy) {
if (proxy.use()) {
return new NicoHttpClient(proxy.getHost(), proxy.getPort());
} else {
return new NicoHttpClient();
}
}
/** @return ログインする必要があればtrue. */
private boolean needsLogin() {
return profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload();
}
/** @return 過去ログ取得の必要があればtrue. */
private boolean needsBackLog() {
return profile.getCommentSetting().getBackLogPoint() >= 0L;
}
/**
* 出力ファイルの保存先を確定します.
* @param title 動画タイトル.
* @param isNotLow 入力動画ファイルがlowでないかどうか.
* @return 出力ファイルの保存先.
*/
private File getOutputFileName(String title, boolean isNotLow) {
final OutputProfile prof = profile.getOutputFileSetting();
final GeneralProfile gene = profile.getGeneralSetting();
final File dir = prof.getDir();
final String replaceFrom = gene.getReplaceFrom();
final String replaceTo = gene.getReplaceTo();
final NamePattern pattern = new NamePattern(prof.getFileName(), replaceFrom, replaceTo, title);
final String name = pattern.createFileName(movieId, isNotLow);
return new File(dir, name);
}
private void checkStop() throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException("中止要求を受け付けました");
}
}
}