1 package saccubus.converter;
4 import java.io.IOException;
5 import java.util.concurrent.Callable;
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
8 import saccubus.ConvertStopFlag;
9 import saccubus.converter.filegetter.FileInstanciator;
10 import saccubus.net.TextProgressListener;
11 import yukihane.saccubus.converter.profile.FfmpegOption;
12 import yukihane.saccubus.converter.profile.Profile;
17 * <p>説明: ニコニコ動画の動画をコメントつきで保存</p>
19 * <p>著作権: Copyright (c) 2007 PSI</p>
26 public class Converter extends AbstractCommand implements Runnable, Callable<Boolean> {
28 private final Profile profile;
29 private final String movieId;
30 private final String time;
34 * @param url 対象となる動画のURL.
40 public Converter(String url, String time, Profile profile,
41 TextProgressListener listener, ConvertStopFlag flag) {
42 super(listener, flag);
44 // TODO 入力欄の値から動画IDの切り出しはGUI側でやるべきだろう
45 final int startIdIdx = url.lastIndexOf("/") + 1;
46 final String altId = url.substring(startIdIdx);
47 final Pattern idPattern = Pattern.compile("([a-z]*\\d+)");
48 final Matcher idMatcher = idPattern.matcher(altId);
49 if (idMatcher.find()) {
50 this.movieId = idMatcher.group(1);
52 throw new IllegalArgumentException("URL/IDの指定が不正です: " + url);
56 this.profile = profile;
59 public Boolean call() throws Exception {
60 boolean result = false;
62 result = runConvert();
64 getStopFlag().finished();
66 return Boolean.valueOf(result);
72 } catch (Exception ex) {
73 String text = (ex.getMessage() != null) ? ex.getMessage() : "予期しないエラー発生のため中断しました。";
79 private boolean runConvert() throws IOException, InterruptedException {
80 if (!shouldRun(profile)) {
81 sendText("何もすることがありません");
86 final FfmpegOption ov = profile.getFfmpeg().getFfmpegOption();
90 final FileInstanciator fi = createInstanciator();
94 final File videoFile = fi.getVideoFile(getListener());
98 File commentFile = fi.getCommentFile(getListener());
102 File tcommFile = fi.getTcommFile(getListener());
104 if (!profile.needsConvert()) {
105 sendText("動画・コメントを保存し、変換は行いませんでした。");
109 if (!videoFile.isFile()) {
110 throw new IOException("入力動画ファイルが存在しません:" + videoFile.getPath());
113 if (profile.getOutputFileSetting().isAddComment()) {
114 if (!commentFile.isFile()) {
115 throw new IOException("入力コメントファイルが存在しません:" + commentFile.getPath());
121 if (profile.getOutputFileSetting().isAddTcomment()) {
122 if (!tcommFile.isFile()) {
123 throw new IOException("入力投稿者コメントファイルが存在しません" + tcommFile.getPath());
130 File convertedVideoFile;
131 if (!profile.getOutputFileSetting().getFile().isFile()) {
132 String conv_name = fi.getVideoTitle();
133 if (profile.getOutputFileSetting().isAppendPrefixVideoId()) {
134 conv_name = getVideoIDWithBracket() + conv_name;
136 convertedVideoFile = new File(profile.getOutputFileSetting().getFile().getFile(),
137 conv_name + ov.getExtOption());
139 String filename = profile.getOutputFileSetting().getFile().getFile().getPath();
140 if (!filename.endsWith(ov.getExtOption())) {
141 filename = filename.substring(0, filename.lastIndexOf('.')) + ov.getExtOption();
142 convertedVideoFile = new File(filename);
144 convertedVideoFile = profile.getOutputFileSetting().getFile().getFile();
148 boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, tcommFile, videoFile,
149 convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
153 private FileInstanciator createInstanciator() throws IOException {
156 FileInstanciator.InstanciationType videoType = new FileInstanciator.InstanciationType(profile.getVideoSetting());
158 FileInstanciator.CommentInstanciationType commentType = new FileInstanciator.CommentInstanciationType(profile.
159 getCommentSetting(), profile.getCommentSetting().getCommentGetInfo().isSelfAdjustCommentNum(), profile.getCommentSetting().getCommentGetInfo().
160 getBackComment(), profile.getCommentSetting().getCommentGetInfo().isReduceComment());
162 FileInstanciator.InstanciationType tcommType = new FileInstanciator.InstanciationType(
163 profile.getCommentSetting());
165 fi = FileInstanciator.create(getStopFlag(), videoType, commentType, tcommType, profile.getLoginInfo(), profile.
166 getProxySetting(), movieId, time);
171 * (ネットワーク設定以外の)設定を検証する.
172 * @throws IllegalArgumentException 設定に不備がある場合.
174 private void validSetting() {
175 if (profile.needsConvert()) {
176 File a = profile.getFfmpeg().getFfmpeg();
178 throw new IllegalArgumentException("FFmpegが見つかりません。");
180 if (profile.getFfmpeg().getVhook().getPath().indexOf(' ') >= 0) {
181 throw new IllegalArgumentException("すいません。現在vhookライブラリには半角空白は使えません。");
183 a = profile.getFfmpeg().getVhook();
185 throw new IllegalArgumentException("Vhookライブラリが見つかりません。");
187 a = profile.getFfmpeg().getFont();
189 throw new IllegalArgumentException("フォントが見つかりません。");
194 private String getVideoIDWithBracket() {
195 return "[" + movieId + "]";
198 public boolean isConverted() {
199 return getStopFlag().isFinished();
203 public ConvertStopFlag getStopFlag() {
204 return super.getStopFlag();
207 /** @return 何か実行すべき処理があればtrue. */
208 private static boolean shouldRun(Profile profile) {
209 return profile.getOutputFileSetting().isConvert() || needsDownload(profile);
212 /** @return 何かダウンロードするものがあればtrue. */
213 private static boolean needsDownload(Profile profile) {
214 return (profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload());