OSDN Git Service

84c934fff98ab303ee053e9ae8449e9604acf2c7
[coroid/inqubus.git] / frontend / src / saccubus / converter / Converter.java
1 package saccubus.converter;
2
3 import java.io.File;
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;
13
14 /**
15  * <p>タイトル: さきゅばす</p>
16  *
17  * <p>説明: ニコニコ動画の動画をコメントつきで保存</p>
18  *
19  * <p>著作権: Copyright (c) 2007 PSI</p>
20  *
21  * <p>会社名: </p>
22  *
23  * @author 未入力
24  * @version 1.0
25  */
26 public class Converter extends AbstractCommand implements Callable<Boolean> {
27
28     private final Profile profile;
29     private final String movieId;
30
31     /**
32      * コンバータを構築します.
33      * @param url 対象となる動画のURL.
34      * @param time
35      * @param profile
36      * @param listener
37      * @param flag
38      */
39     public Converter(String url, Profile profile,
40             TextProgressListener listener, ConvertStopFlag flag) {
41         super(listener, flag);
42
43         // TODO 入力欄の値から動画IDの切り出しはGUI側でやるべきだろう
44         final int startIdIdx = url.lastIndexOf("/") + 1;
45         final String altId = url.substring(startIdIdx);
46         final Pattern idPattern = Pattern.compile("([a-z]*\\d+)");
47         final Matcher idMatcher = idPattern.matcher(altId);
48         if (idMatcher.find()) {
49             this.movieId = idMatcher.group(1);
50         } else {
51             throw new IllegalArgumentException("URL/IDの指定が不正です: " + url);
52         }
53
54         this.profile = profile;
55     }
56
57     @Override
58     public Boolean call() throws Exception {
59         boolean result = false;
60         try {
61             result = runConvert();
62         } finally {
63             getStopFlag().finished();
64         }
65         return Boolean.valueOf(result);
66     }
67
68     // TODO Runnableを実装しなくなったので削除する
69     public void run() {
70         try {
71             call();
72         } catch (Exception ex) {
73             String text = (ex.getMessage() != null) ? ex.getMessage() : "予期しないエラー発生のため中断しました。";
74             sendText(text);
75             ex.printStackTrace();
76         }
77     }
78
79     private boolean runConvert() throws IOException, InterruptedException {
80         if (!shouldRun(profile)) {
81             sendText("何もすることがありません");
82             return true;
83         }
84
85         validSetting();
86         final FfmpegOption ov = profile.getFfmpeg().getFfmpegOption();
87
88         sendText("ログイン中");
89
90         final FileInstanciator fi = createInstanciator();
91
92         stopFlagReturn();
93
94         final File videoFile = fi.getVideoFile(getListener());
95
96         stopFlagReturn();
97
98         File commentFile = fi.getCommentFile(getListener());
99
100         stopFlagReturn();
101
102         File tcommFile = fi.getTcommFile(getListener());
103
104         if (!profile.getOutputFileSetting().isConvert()) {
105             sendText("動画・コメントを保存し、変換は行いませんでした。");
106             return true;
107         }
108
109         if (!videoFile.isFile()) {
110             throw new IOException("入力動画ファイルが存在しません:" + videoFile.getPath());
111         }
112
113         if (profile.getOutputFileSetting().isAddComment()) {
114             if (!commentFile.isFile()) {
115                 throw new IOException("入力コメントファイルが存在しません:" + commentFile.getPath());
116             }
117         } else {
118             commentFile = null;
119         }
120
121         if (profile.getOutputFileSetting().isAddTcomment()) {
122             if (!tcommFile.isFile()) {
123                 throw new IOException("入力投稿者コメントファイルが存在しません" + tcommFile.getPath());
124             }
125         } else {
126             tcommFile = null;
127         }
128
129         /*ビデオ名の確定*/
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;
135             }
136             convertedVideoFile = new File(profile.getOutputFileSetting().getFile().getFile(),
137                     conv_name + ov.getExtOption());
138         } else {
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);
143             } else {
144                 convertedVideoFile = profile.getOutputFileSetting().getFile().getFile();
145             }
146         }
147
148         boolean res = new FfmpegCommand(getListener(), getStopFlag(), commentFile, tcommFile, videoFile,
149                 convertedVideoFile, profile.getFfmpeg(), profile.getGeneralSetting()).execute();
150         return res;
151     }
152
153     private FileInstanciator createInstanciator() throws IOException {
154         FileInstanciator fi;
155
156         FileInstanciator.InstanciationType videoType = new FileInstanciator.InstanciationType(profile.getVideoSetting());
157
158         FileInstanciator.CommentInstanciationType commentType = new FileInstanciator.CommentInstanciationType(profile.
159                 getCommentSetting(), profile.getCommentSetting().isSelfAdjustCommentNum(), profile.getCommentSetting().
160                 getBackComment(), profile.getCommentSetting().isReduceComment());
161
162         FileInstanciator.InstanciationType tcommType = new FileInstanciator.InstanciationType(
163                 profile.getCommentSetting());
164
165         fi = FileInstanciator.create(getStopFlag(), videoType, commentType, tcommType, profile.getLoginInfo(), profile.
166                 getProxySetting(), movieId, profile.getCommentSetting().getBackLogPoint());
167         return fi;
168     }
169
170     /**
171      * (ネットワーク設定以外の)設定を検証する.
172      * @throws IllegalArgumentException 設定に不備がある場合.
173      */
174     private void validSetting() {
175         if (profile.getOutputFileSetting().isConvert()) {
176             File a = profile.getFfmpeg().getFfmpeg();
177             if (!a.canRead()) {
178                 throw new IllegalArgumentException("FFmpegが見つかりません。");
179             }
180             if (profile.getFfmpeg().getVhook().getPath().indexOf(' ') >= 0) {
181                 throw new IllegalArgumentException("すいません。現在vhookライブラリには半角空白は使えません。");
182             }
183             a = profile.getFfmpeg().getVhook();
184             if (!a.canRead()) {
185                 throw new IllegalArgumentException("Vhookライブラリが見つかりません。");
186             }
187             a = profile.getFfmpeg().getFont();
188             if (!a.canRead()) {
189                 throw new IllegalArgumentException("フォントが見つかりません。");
190             }
191         }
192     }
193
194     private String getVideoIDWithBracket() {
195         return "[" + movieId + "]";
196     }
197
198     public boolean isConverted() {
199         return getStopFlag().isFinished();
200     }
201
202     @Override
203     public ConvertStopFlag getStopFlag() {
204         return super.getStopFlag();
205     }
206
207     /** @return 何か実行すべき処理があればtrue. */
208     private static boolean shouldRun(Profile profile) {
209         return profile.getOutputFileSetting().isConvert() || needsDownload(profile);
210     }
211
212     /** @return 何かダウンロードするものがあればtrue. */
213     private static boolean needsDownload(Profile profile) {
214         return (profile.getVideoSetting().isDownload() || profile.getCommentSetting().isDownload());
215     }
216 }