OSDN Git Service

ConvertStopFlag, TextProgressListenerクラス削除
[coroid/inqubus.git] / frontend / src / saccubus / converter / Converter.java
index e9f9cb5..a208b8b 100644 (file)
@@ -2,14 +2,23 @@ package saccubus.converter;
 
 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>
@@ -23,87 +32,127 @@ import yukihane.saccubus.converter.profile.Profile;
  * @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()) {
@@ -118,53 +167,26 @@ public class Converter extends AbstractCommand implements Runnable, Callable<Boo
             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());
     }
 
     /**
@@ -172,7 +194,7 @@ public class Converter extends AbstractCommand implements Runnable, Callable<Boo
      * @throws IllegalArgumentException 設定に不備がある場合.
      */
     private void validSetting() {
-        if (profile.needsConvert()) {
+        if (profile.getOutputFileSetting().isConvert()) {
             File a = profile.getFfmpeg().getFfmpeg();
             if (!a.canRead()) {
                 throw new IllegalArgumentException("FFmpegが見つかりません。");
@@ -191,27 +213,65 @@ public class Converter extends AbstractCommand implements Runnable, Callable<Boo
         }
     }
 
-    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("中止要求を受け付けました");
+        }
     }
 }