import java.io.File;
import java.io.IOException;
+import java.net.URISyntaxException;
import java.util.concurrent.Callable;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import saccubus.ConvertStopFlag;
-import saccubus.converter.filegetter.FileInstanciator;
-import saccubus.net.TextProgressListener;
-import yukihane.saccubus.converter.profile.FfmpegOption;
-import yukihane.saccubus.converter.profile.Profile;
+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;
/**
* <p>タイトル: さきゅばす</p>
* @author 未入力
* @version 1.0
*/
-public class Converter extends AbstractCommand implements Runnable, Callable<Boolean> {
+public class Converter extends SwingWorker<ConvertResult, ConvertProgress> implements Callable<Boolean> {
+ private static final Logger logger = Logger.getLogger(Converter.class.getName());
private final Profile profile;
private final String movieId;
- private final String time;
/**
* コンバータを構築します.
- * @param url 対象となる動画のURL.
+ * @param id 対象となる動画のID.
* @param time
* @param profile
* @param listener
* @param flag
*/
- public Converter(String url, String time, Profile profile,
- TextProgressListener listener, ConvertStopFlag flag) {
- super(listener, flag);
-
- // TODO 入力欄の値から動画IDの切り出しはGUI側でやるべきだろう
- final int startIdIdx = url.lastIndexOf("/") + 1;
- final String altId = url.substring(startIdIdx);
- final Pattern idPattern = Pattern.compile("([a-z]*\\d+)");
- final Matcher idMatcher = idPattern.matcher(altId);
- if (idMatcher.find()) {
- this.movieId = idMatcher.group(1);
- } else {
- throw new IllegalArgumentException("URL/IDの指定が不正です: " + url);
- }
-
- this.time = time;
+ public Converter(String id, Profile profile) {
+ this.movieId = id;
this.profile = profile;
}
+ @Override
public Boolean call() throws Exception {
- boolean result = false;
try {
- result = runConvert();
+ final ConvertResult result = doInBackground();
+ return Boolean.valueOf(result.getResultValue());
} finally {
- getStopFlag().finished();
- }
- return Boolean.valueOf(result);
- }
-
- public void run() {
- try {
- call();
- } catch (Exception ex) {
- String text = (ex.getMessage() != null) ? ex.getMessage() : "予期しないエラー発生のため中断しました。";
- sendText(text);
- ex.printStackTrace();
+ // TODO 何か処理が必要?
+// getStopFlag().finished();
}
}
- private boolean runConvert() throws IOException, InterruptedException {
+// // 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 ConvertResult doInBackground() throws Exception {
if (!shouldRun(profile)) {
- sendText("何もすることがありません");
- return true;
+ publish(new ConvertProgress("何もすることがありません"));
+ return new ConvertResult(true);
}
validSetting();
- final FfmpegOption ov = profile.getFfmpeg().getFfmpegOption();
+ final FfmpegProfile ov = profile.getFfmpeg().getFfmpegOption();
+
+ // TODO ログインしないで良い場合もある.
+ publish(new ConvertProgress("ログイン中"));
- sendText("ログイン中");
- final FileInstanciator fi = createInstanciator();
- stopFlagReturn();
+ NicoHttpClient client = null;
+ nicobrowser.VideoInfo vi = null;
+ NamePattern videoNamePattern = null;
+ WayBackInfo wbi = null;
+ if (needsLogin()) {
+ client = createClientAndLogin();
+ vi = client.getVideoInfo(movieId);
- final File videoFile = fi.getVideoFile(getListener());
+ 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());
- stopFlagReturn();
+ if (needsBackLog()) {
+ final String key = client.getWayBackKey(vi);
+ wbi = new WayBackInfo(key, profile.getCommentSetting().getBackLogPoint());
+ }
+ }
- File commentFile = fi.getCommentFile(getListener());
+ checkStop();
- stopFlagReturn();
+ File commentFile;
+ if (profile.getCommentSetting().isDownload()) {
+ final CommentProfile prof = profile.getCommentSetting();
+ final GeneralProfile gene = profile.getGeneralSetting();
- File tcommFile = fi.getTcommFile(getListener());
+ 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);
- if (!profile.needsConvert()) {
- sendText("動画・コメントを保存し、変換は行いませんでした。");
- return true;
+ 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 ConvertProgress("動画・コメントを保存し、変換は行いませんでした。"));
+ return new ConvertResult(true);
}
if (!videoFile.isFile()) {
commentFile = null;
}
- if (profile.getOutputFileSetting().isAddTcomment()) {
- if (!tcommFile.isFile()) {
- throw new IOException("入力投稿者コメントファイルが存在しません" + tcommFile.getPath());
- }
- } else {
- tcommFile = null;
- }
-
/*ビデオ名の確定*/
- File convertedVideoFile;
- if (!profile.getOutputFileSetting().getFile().isFile()) {
- String conv_name = fi.getVideoTitle();
- if (profile.getOutputFileSetting().isAppendPrefixVideoId()) {
- conv_name = getVideoIDWithBracket() + conv_name;
- }
- convertedVideoFile = new File(profile.getOutputFileSetting().getFile().getFile(),
- conv_name + ov.getExtOption());
- } else {
- String filename = profile.getOutputFileSetting().getFile().getFile().getPath();
- if (!filename.endsWith(ov.getExtOption())) {
- filename = filename.substring(0, filename.lastIndexOf('.')) + ov.getExtOption();
- convertedVideoFile = new File(filename);
- } else {
- convertedVideoFile = profile.getOutputFileSetting().getFile().getFile();
- }
- }
-
- boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, tcommFile, videoFile,
- convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
- return res;
- }
-
- private FileInstanciator createInstanciator() throws IOException {
- FileInstanciator fi;
+ final boolean isNotLow = (vf == null) ? true : (vf.getStatus() != Status.GET_LOW);
+ File convertedVideoFile = getOutputFileName(vi.getTitleInWatchPage(), isNotLow);
- FileInstanciator.InstanciationType videoType = new FileInstanciator.InstanciationType(profile.getVideoSetting());
+ return new ConvertResult(true);
- FileInstanciator.CommentInstanciationType commentType = new FileInstanciator.CommentInstanciationType(profile.
- getCommentSetting(), profile.getCommentGetInfo().isSelfAdjustCommentNum(), profile.getCommentGetInfo().
- getBackComment(), profile.getCommentGetInfo().isReduceComment());
+ // TODO FFMPEG 実行開始は別タスクとして実装する.
+// boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, videoFile,
+// convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
+// return res;
+ }
- FileInstanciator.InstanciationType tcommType = new FileInstanciator.InstanciationType(
- profile.getTcommentSetting());
+ /** @return 何か実行すべき処理があればtrue. */
+ private static boolean shouldRun(Profile profile) {
+ return profile.getOutputFileSetting().isConvert() || needsDownload(profile);
+ }
- fi = FileInstanciator.create(getStopFlag(), videoType, commentType, tcommType, profile.getLoginInfo(), profile.
- getProxySetting(), movieId, time);
- return fi;
+ /** @return 何かダウンロードするものがあればtrue. */
+ private static boolean needsDownload(Profile profile) {
+ return (profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload());
}
/**
* @throws IllegalArgumentException 設定に不備がある場合.
*/
private void validSetting() {
- if (profile.needsConvert()) {
+ if (profile.getOutputFileSetting().isConvert()) {
File a = profile.getFfmpeg().getFfmpeg();
if (!a.canRead()) {
throw new IllegalArgumentException("FFmpegが見つかりません。");
}
}
- private String getVideoIDWithBracket() {
- return "[" + movieId + "]";
+ /**
+ * 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;
}
- public boolean isConverted() {
- return getStopFlag().isFinished();
+ private NicoHttpClient createClient(ProxyProfile proxy) {
+ if (proxy.use()) {
+ return new NicoHttpClient(proxy.getHost(), proxy.getPort());
+ } else {
+ return new NicoHttpClient();
+ }
}
- @Override
- public ConvertStopFlag getStopFlag() {
- return super.getStopFlag();
+ /** @return ログインする必要があればtrue. */
+ private boolean needsLogin() {
+ return profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload();
}
- /** @return 何か実行すべき処理があればtrue. */
- private static boolean shouldRun(Profile profile) {
- return profile.getOutputFileSetting().isConvert() || needsDownload(profile);
+ /** @return 過去ログ取得の必要があればtrue. */
+ private boolean needsBackLog() {
+ return profile.getCommentSetting().getBackLogPoint() >= 0L;
}
- /** @return 何かダウンロードするものがあればtrue. */
- private static boolean needsDownload(Profile profile) {
- return (profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload() || profile.
- getTcommentSetting().isDownload());
+ /**
+ * 出力ファイルの保存先を確定します.
+ * @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("中止要求を受け付けました");
+ }
}
}