4 * Created on 2011/05/28, 18:14:51
6 package yukihane.inqubus.gui;
9 import java.awt.ItemSelectable;
10 import java.awt.Toolkit;
11 import java.awt.datatransfer.DataFlavor;
12 import java.awt.datatransfer.Transferable;
13 import java.awt.event.ActionEvent;
14 import java.awt.event.ActionListener;
15 import java.awt.event.ItemEvent;
16 import java.awt.event.ItemListener;
17 import java.awt.event.KeyEvent;
18 import java.beans.PropertyChangeEvent;
19 import java.beans.PropertyChangeListener;
21 import java.io.FilenameFilter;
22 import java.io.IOException;
24 import java.nio.file.FileSystem;
25 import java.nio.file.FileSystems;
26 import java.nio.file.Path;
27 import java.util.ArrayList;
28 import java.util.HashSet;
29 import java.util.List;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33 import java.util.regex.Pattern;
34 import javax.swing.BorderFactory;
35 import javax.swing.DropMode;
36 import javax.swing.GroupLayout;
37 import javax.swing.GroupLayout.Alignment;
38 import javax.swing.JButton;
39 import javax.swing.JCheckBox;
40 import javax.swing.JFrame;
41 import javax.swing.JLabel;
42 import javax.swing.JMenu;
43 import javax.swing.JMenuBar;
44 import javax.swing.JMenuItem;
45 import javax.swing.JOptionPane;
46 import javax.swing.JPanel;
47 import javax.swing.JScrollPane;
48 import javax.swing.JTabbedPane;
49 import javax.swing.JTable;
50 import javax.swing.JTextField;
51 import javax.swing.KeyStroke;
52 import javax.swing.LayoutStyle.ComponentPlacement;
53 import javax.swing.SwingUtilities;
54 import javax.swing.TransferHandler;
55 import javax.swing.WindowConstants;
56 import javax.swing.border.BevelBorder;
57 import org.apache.commons.lang.StringUtils;
58 import org.apache.commons.lang.builder.ToStringBuilder;
59 import saccubus.FfmpegOption;
60 import saccubus.MainFrame_AboutBox;
61 import saccubus.util.WayBackTimeParser;
62 import saccubus.worker.impl.convert.ConvertProgress;
63 import saccubus.worker.impl.download.DownloadProgress;
64 import saccubus.worker.WorkerListener;
65 import saccubus.worker.impl.convert.ConvertResult;
66 import saccubus.worker.impl.download.DownloadResult;
67 import saccubus.worker.profile.CommentProfile;
68 import saccubus.worker.profile.ConvertProfile;
69 import saccubus.worker.profile.DownloadProfile;
70 import saccubus.worker.profile.FfmpegProfile;
71 import saccubus.worker.profile.GeneralProfile;
72 import saccubus.worker.profile.LoginProfile;
73 import saccubus.worker.profile.OutputProfile;
74 import saccubus.worker.profile.ProxyProfile;
75 import saccubus.worker.profile.VideoProfile;
77 import yukihane.inqubus.Config;
78 import yukihane.inqubus.filewatch.FileWatch;
79 import yukihane.inqubus.manager.RequestProcess;
80 import yukihane.inqubus.manager.TaskKind;
81 import yukihane.inqubus.manager.TaskManage;
82 import yukihane.inqubus.manager.TaskManageListener;
83 import yukihane.inqubus.manager.TaskStatus;
84 import yukihane.inqubus.model.Target;
85 import yukihane.inqubus.model.TargetsTableModel;
91 public class MainFrame extends JFrame {
93 private static final long serialVersionUID = 1L;
94 private static final Logger logger = Logger.getLogger(MainFrame.class.getName());
95 private static final String ID_FIELD_TOOLTIP = "動画のIDまたはURLを入力します。";
96 private static final String FILE_LOCALBUTTON_TOOLTIP
97 = "<html>ダウンロードする場合はチェックを外します。<br/>ローカルファイルを使用する場合はチェックを入れます。</html>";
98 private static final String FILE_INPUTFIELD_TOOLTIP
99 = "<html>ダウンロードする場合はファイル命名規則を入力します。<br/>"
100 + "ローカルファイルを使用する場合はパスを含むファイル名を入力します。</html>";
101 private static final String FILE_OUTPUTFIELD_TOOLTIP
103 private final TargetsTableModel targetModel = new TargetsTableModel();
104 private final TaskManage taskManager;
105 private final Thread videoFileWatcher;
107 /** Creates new form MainFrame */
109 final URL url = MainFrame_AboutBox.class.getResource("icon.png");
110 final Image icon1 = Toolkit.getDefaultToolkit().createImage(url);
111 final URL url32 = MainFrame_AboutBox.class.getResource("icon32.png");
112 final Image icon2 = Toolkit.getDefaultToolkit().createImage(url32);
113 final List<Image> images = new ArrayList<>(2);
116 setIconImages(images);
118 final JPanel pnlMain = new JPanel();
119 final JScrollPane scrDisplay = new JScrollPane();
120 tblDisplay = new JTable(targetModel, new TargetsColumnModel());
121 tblDisplay.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
122 final JPanel pnlButton = new JPanel();
123 final JTabbedPane tbpInput = new JTabbedPane();
124 final JPanel pnlInputMain = new JPanel();
125 final JLabel lblId = new JLabel();
126 fldId.setToolTipText(ID_FIELD_TOOLTIP);
127 final JLabel lblVideo = new JLabel();
128 cbVideoLocal = new JCheckBox();
129 cbVideoLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
130 fldVideo = new JTextField();
131 fldVideo.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
132 final JLabel lblComment = new JLabel();
134 fldBackLog.setToolTipText("YYYY/MM/DD hh:mm:ss形式、あるいは1970/01/01からの経過秒を入力します。");
135 cbBackLog.addItemListener(new ItemListener() {
138 public void itemStateChanged(ItemEvent e) {
139 final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
140 fldBackLog.setEnabled(selected);
143 cbBackLog.addPropertyChangeListener("enabled", new PropertyChangeListener() {
146 public void propertyChange(PropertyChangeEvent evt) {
147 final boolean enabled = ((Boolean) evt.getNewValue()).booleanValue();
148 final boolean fldEnabled = enabled ? cbBackLog.isSelected() : false;
149 fldBackLog.setEnabled(fldEnabled);
152 cbBackLogReduce.setToolTipText("「コメントの量を減らす」場合はチェックを付けます。");
154 cbCommentLocal = new JCheckBox();
155 cbCommentLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
156 cbCommentLocal.addItemListener(new ItemListener() {
159 public void itemStateChanged(ItemEvent e) {
160 final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
161 cbBackLogReduce.setEnabled(!selected);
162 cbBackLog.setEnabled(!selected);
165 fldComment = new JTextField();
166 fldComment.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
167 final JLabel lblOutput = new JLabel();
168 cbOutputEnable = new JCheckBox();
169 fldOutput = new JTextField();
170 fldOutput.setToolTipText(FILE_OUTPUTFIELD_TOOLTIP);
172 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
174 btnStop.addActionListener(new StopActionListener());
175 final ApplyActionListener applyListener = new ApplyActionListener();
176 btnApply.addActionListener(applyListener);
178 pnlMain.setBorder(BorderFactory.createEtchedBorder());
180 tblDisplay.setDropMode(DropMode.INSERT_ROWS);
181 scrDisplay.setViewportView(tblDisplay);
183 pnlButton.setBorder(BorderFactory.createEtchedBorder());
185 GroupLayout gl_pnlButton = new GroupLayout(pnlButton);
186 pnlButton.setLayout(gl_pnlButton);
187 gl_pnlButton.setHorizontalGroup(
188 gl_pnlButton.createParallelGroup(Alignment.LEADING)
189 .addGroup(gl_pnlButton.createSequentialGroup()
191 .addComponent(btnStart)
192 .addPreferredGap(ComponentPlacement.RELATED)
193 .addComponent(btnStop)
194 .addPreferredGap(ComponentPlacement.RELATED, 250, Short.MAX_VALUE)
195 .addComponent(btnDeselect)
198 gl_pnlButton.setVerticalGroup(
199 gl_pnlButton.createParallelGroup(Alignment.LEADING)
200 .addGroup(gl_pnlButton.createSequentialGroup()
202 .addGroup(gl_pnlButton.createParallelGroup(Alignment.BASELINE)
203 .addComponent(btnStart)
204 .addComponent(btnStop)
205 .addComponent(btnDeselect))
206 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
211 fldId.addActionListener(applyListener);
212 fldId.addFocusListener(new java.awt.event.FocusAdapter() {
214 public void focusLost(java.awt.event.FocusEvent evt) {
215 idFieldFocusLost(evt);
219 lblVideo.setText("動画");
221 cbVideoLocal.setText("local");
222 cbVideoLocal.addItemListener(new java.awt.event.ItemListener() {
224 public void itemStateChanged(java.awt.event.ItemEvent evt) {
225 useMovieLocalCheckBoxItemStateChanged(evt);
229 lblComment.setText("コメント");
231 cbCommentLocal.setText("local");
232 cbCommentLocal.addItemListener(new java.awt.event.ItemListener() {
234 public void itemStateChanged(java.awt.event.ItemEvent evt) {
235 useMovieLocalCheckBoxItemStateChanged(evt);
239 lblOutput.setText("出力");
241 cbOutputEnable.setText("変換");
242 cbOutputEnable.addItemListener(new java.awt.event.ItemListener() {
244 public void itemStateChanged(java.awt.event.ItemEvent evt) {
245 outputConvertCheckBoxItemStateChanged(evt);
250 final GroupLayout glInputMain = new GroupLayout(pnlInputMain);
251 pnlInputMain.setLayout(glInputMain);
252 glInputMain.setHorizontalGroup(
253 glInputMain.createParallelGroup(Alignment.LEADING)
254 .addGroup(glInputMain.createSequentialGroup()
257 .addPreferredGap(ComponentPlacement.RELATED)
258 .addComponent(fldId, GroupLayout.PREFERRED_SIZE, 100, Short.MAX_VALUE)
259 .addPreferredGap(ComponentPlacement.UNRELATED)
260 .addComponent(cbBackLogReduce)
261 .addPreferredGap(ComponentPlacement.UNRELATED)
262 .addComponent(cbBackLog)
263 .addPreferredGap(ComponentPlacement.RELATED)
264 .addComponent(fldBackLog, GroupLayout.PREFERRED_SIZE, 150, GroupLayout.PREFERRED_SIZE)
267 .addGroup(glInputMain.createSequentialGroup()
269 .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
270 .addComponent(lblVideo)
271 .addComponent(lblComment)
272 .addComponent(lblOutput)
274 .addPreferredGap(ComponentPlacement.RELATED)
275 .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
276 .addComponent(cbVideoLocal)
277 .addComponent(cbCommentLocal)
278 .addComponent(cbOutputEnable)
280 .addPreferredGap(ComponentPlacement.RELATED)
281 .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
282 .addComponent(fldVideo, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
283 .addComponent(fldComment, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
284 .addComponent(fldOutput, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
290 glInputMain.setVerticalGroup(
291 glInputMain.createParallelGroup(Alignment.LEADING)
292 .addGroup(glInputMain.createSequentialGroup()
294 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
295 .addComponent(fldId, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
297 .addComponent(cbBackLogReduce)
298 .addComponent(cbBackLog)
299 .addComponent(fldBackLog)
301 .addPreferredGap(ComponentPlacement.RELATED)
302 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
303 .addComponent(lblVideo)
304 .addComponent(fldVideo, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
305 .addComponent(cbVideoLocal))
306 .addPreferredGap(ComponentPlacement.RELATED)
307 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
308 .addComponent(lblComment)
309 .addComponent(fldComment, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
310 .addComponent(cbCommentLocal))
311 .addPreferredGap(ComponentPlacement.RELATED)
312 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
313 .addComponent(lblOutput)
314 .addComponent(fldOutput, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
315 .addComponent(cbOutputEnable)
321 pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(false);
322 pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(false);
323 pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(false);
324 pnlInputFfmpeg.cmbFfmpegOptionFile.addActionListener(new ActionListener() {
327 public void actionPerformed(ActionEvent e) {
328 final boolean notFile = !pnlInputFfmpeg.mdlFfmpegOption.isFile();
329 pnlInputFfmpeg.fldFfmpegOptionExtension.setEnabled(notFile);
330 pnlInputFfmpeg.fldFfmpegOptionMain.setEnabled(notFile);
331 pnlInputFfmpeg.fldFfmpegOptionIn.setEnabled(notFile);
332 pnlInputFfmpeg.fldFfmpegOptionOut.setEnabled(notFile);
333 pnlInputFfmpeg.fldFfmpegOptionAv.setEnabled(notFile);
334 pnlInputFfmpeg.cbFfmpegOptionResize.setEnabled(notFile);
337 pnlInputFfmpeg.cbFfmpegOptionResize.addItemListener(new ItemListener() {
340 public void itemStateChanged(ItemEvent e) {
341 final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
342 pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(selected);
343 pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(selected);
344 pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(selected);
347 pnlInputFfmpeg.cbFfmpegOptionResize.addPropertyChangeListener("enabled", new PropertyChangeListener() {
350 public void propertyChange(PropertyChangeEvent evt) {
351 final boolean enabled = ((Boolean) evt.getNewValue()).booleanValue();
352 final boolean fldEnabled = enabled ? pnlInputFfmpeg.cbFfmpegOptionResize.isSelected() : false;
353 pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(fldEnabled);
354 pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(fldEnabled);
355 pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(fldEnabled);
360 tbpInput.add("メイン", pnlInputMain);
361 tbpInput.add("ffmpeg", pnlInputFfmpeg);
364 fldInputMessage.setEditable(false);
365 fldInputMessage.setEnabled(false);
366 fldInputMessage.setBorder(BorderFactory.createEmptyBorder());
368 final JPanel pnlInputButton = new JPanel();
369 final GroupLayout glInputButton = new GroupLayout(pnlInputButton);
370 pnlInputButton.setLayout(glInputButton);
371 glInputButton.setHorizontalGroup(glInputButton.createSequentialGroup()
373 .addComponent(fldInputMessage, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
374 .addPreferredGap(ComponentPlacement.UNRELATED)
375 .addComponent(btnApply)
378 glInputButton.setVerticalGroup(glInputButton.createSequentialGroup()
380 .addGroup(glInputButton.createParallelGroup(Alignment.BASELINE)
381 .addComponent(fldInputMessage, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
382 .addComponent(btnApply)
388 final JPanel pnlInputAll = new JPanel();
389 pnlInputAll.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
390 final GroupLayout glInputAll = new GroupLayout(pnlInputAll);
391 pnlInputAll.setLayout(glInputAll);
392 glInputAll.setHorizontalGroup(glInputAll.createParallelGroup()
393 .addComponent(tbpInput)
394 .addComponent(pnlInputButton)
396 glInputAll.setVerticalGroup(glInputAll.createSequentialGroup()
397 .addComponent(tbpInput)
398 .addComponent(pnlInputButton)
401 GroupLayout gl_pnlMain = new GroupLayout(pnlMain);
402 pnlMain.setLayout(gl_pnlMain);
403 gl_pnlMain.setHorizontalGroup(
404 gl_pnlMain.createParallelGroup(Alignment.LEADING)
405 .addGroup(Alignment.TRAILING, gl_pnlMain.createSequentialGroup()
407 .addGroup(gl_pnlMain.createParallelGroup(Alignment.TRAILING)
408 .addComponent(scrDisplay, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
409 .addComponent(pnlButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
410 .addComponent(pnlInputAll, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
414 gl_pnlMain.setVerticalGroup(
415 gl_pnlMain.createParallelGroup(Alignment.LEADING)
416 .addGroup(Alignment.TRAILING, gl_pnlMain.createSequentialGroup()
418 .addComponent(scrDisplay, GroupLayout.DEFAULT_SIZE, 197, Short.MAX_VALUE)
419 .addPreferredGap(ComponentPlacement.RELATED)
420 .addComponent(pnlButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
421 .addPreferredGap(ComponentPlacement.RELATED)
422 .addComponent(pnlInputAll, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
428 JMenuBar menuBar = initMenuBar();
429 setJMenuBar(menuBar);
431 GroupLayout layout = new GroupLayout(getContentPane());
432 getContentPane().setLayout(layout);
433 layout.setHorizontalGroup(
434 layout.createParallelGroup(Alignment.LEADING)
435 .addComponent(pnlMain, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
437 layout.setVerticalGroup(
438 layout.createParallelGroup(Alignment.LEADING)
439 .addComponent(pnlMain, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
444 pnlMain.setTransferHandler(new DownloadListTransferHandler());
445 tblDisplay.setTransferHandler(new TableTransferHandler());
447 final Config p = Config.INSTANCE;
450 final int thDownload = p.getSystemDownloadThread();
451 final int secDownload = p.getSystemDownloadWait();
452 final int thConvert = p.getSystemConvertThread();
453 taskManager = new TaskManage(thDownload, secDownload,thConvert, new GuiTaskManageListener());
455 // TODO ディレクトリ監視スレッド生成
456 final List<String> videoSearchDirs = p.getSearchVideoDirs();
457 videoSearchDirs.add(p.getVideoDir());
458 final FileSystem fs = FileSystems.getDefault();
459 final Set<Path> videoPaths = new HashSet<>(videoSearchDirs.size());
460 for(String s : videoSearchDirs) {
461 videoPaths.add(fs.getPath(s));
463 final FileWatch videoFileWatch = new FileWatch(videoPaths);
464 this.videoFileWatcher = new Thread(videoFileWatch);
465 this.videoFileWatcher.setDaemon(true);
468 public void startWatcher() {
469 videoFileWatcher.start();
472 private class GuiTaskManageListener implements TaskManageListener {
475 public void process(final int id, final TaskKind kind, final TaskStatus status, final double percentage,
476 final String message) {
477 SwingUtilities.invokeLater(new Runnable() {
481 targetModel.setStatus(id, kind, status, percentage, message);
487 private class StopActionListener implements ActionListener {
490 public void actionPerformed(ActionEvent e) {
491 final int row = tblDisplay.getSelectedRow();
492 final Target t = targetModel.getTarget(row);
493 final boolean res = taskManager.cancel(t.getRowId());
494 logger.log(Level.FINE, "停止: {0} {1}", new Object[]{t.getVideoId(), res});
496 targetModel.setStatus(t.getRowId(), null, TaskStatus.CANCELLED, -1.0, "キャンセル");
501 private class ApplyActionListener implements ActionListener {
504 public void actionPerformed(ActionEvent e) {
506 final DownloadProfile downProf = new InqubusDownloadProfile();
507 final String id = Util.getVideoId(fldId.getText());
508 final InqubusConvertProfile convProf = new InqubusConvertProfile();
509 logger.log(Level.INFO, downProf.toString());
510 logger.log(Level.INFO, convProf.toString());
511 final RequestProcess rp = new RequestProcess(downProf, id, convProf);
513 targetModel.addTarget(new Target(rp));
515 } catch (Throwable th) {
516 logger.log(Level.SEVERE, null, th);
517 JOptionPane.showMessageDialog(MainFrame.this, th.getMessage(), "中断しました", JOptionPane.ERROR_MESSAGE);
522 private File searchFileMatchId(final File dir, final String id) {
523 // TODO 候補は複数返すようにして、その後の対処は呼び出しもとで行ってもらった方が良いかも
528 final File[] lists = dir.listFiles(new FilenameFilter() {
530 final Pattern pattern = Pattern.compile(id + "\\D");
533 public boolean accept(File dir, String name) {
534 return pattern.matcher(name).find();
538 if (lists.length == 1) {
540 } else if (lists.length > 1) {
541 throw new UnsupportedOperationException();
548 * 動画, コメントの"local"チェックボックス更新時の処理.
550 private void useMovieLocalCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_useMovieLocalCheckBoxItemStateChanged
551 final Config p = Config.INSTANCE;
553 final ItemSelectable source = evt.getItemSelectable();
557 if (source == cbVideoLocal) {
559 dir = new File(p.getVideoDir());
562 dir = new File(p.getCommentDir());
565 final boolean useLocal = (evt.getStateChange() == ItemEvent.SELECTED);
569 final File f = searchFileMatchId(dir, fldId.getText());
576 text = p.getVideoFileNamePattern();
580 }//GEN-LAST:event_useMovieLocalCheckBoxItemStateChanged
582 private void outputConvertCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_outputConvertCheckBoxItemStateChanged
583 final boolean convert = (evt.getStateChange() == ItemEvent.SELECTED);
584 fldOutput.setEnabled(convert);
585 }//GEN-LAST:event_outputConvertCheckBoxItemStateChanged
587 private void idFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_idFieldFocusLost
588 final Config p = Config.INSTANCE;
589 final String id = fldId.getText();
594 if (cbVideoLocal.isSelected() && fldVideo.getText().isEmpty()) {
595 final File dir = new File(p.getVideoDir());
596 final File file = searchFileMatchId(dir, id);
598 fldVideo.setText(file.getPath());
602 if (cbCommentLocal.isSelected() && fldComment.getText().isEmpty()) {
603 final File dir = new File(p.getCommentDir());
604 final File file = searchFileMatchId(dir, id);
606 fldComment.setText(file.getPath());
610 }//GEN-LAST:event_idFieldFocusLost
611 // Variables declaration - do not modify//GEN-BEGIN:variables
612 private final JTable tblDisplay;
614 private final JButton btnStart = new JButton("開始");
615 private final JButton btnStop = new JButton("停止");
616 private final JButton btnDeselect = new JButton("選択解除");
618 private final JTextField fldId = new JTextField();
619 private final JCheckBox cbBackLogReduce = new JCheckBox("コメ数減少");
620 private final JCheckBox cbBackLog = new JCheckBox("過去ログ");
621 private final JTextField fldBackLog = new JTextField();
622 private final JCheckBox cbVideoLocal;
623 private final JTextField fldVideo;
624 private final JCheckBox cbCommentLocal;
625 private final JTextField fldComment;
626 private final JCheckBox cbOutputEnable;
627 private final JTextField fldOutput;
629 private final FfmpegParamPanel pnlInputFfmpeg = new FfmpegParamPanel();
631 private final JTextField fldInputMessage = new JTextField();
632 private final JButton btnApply = new JButton("適用");
633 // End of variables declaration//GEN-END:variables
635 private void initInputPanel() {
640 private void initMainTab() {
641 final Config p = Config.INSTANCE;
644 fldBackLog.setEnabled(false);
645 cbBackLog.setEnabled(true);
647 final boolean movieLocal = p.getVideoUseLocal();
648 cbVideoLocal.setSelected(movieLocal);
650 fldVideo.setText(p.getVideoFileNamePattern());
653 final boolean commentLocal = p.getCommentUseLocal();
654 cbCommentLocal.setSelected(commentLocal);
656 fldComment.setText(p.getCommentFileNamePattern());
659 final boolean convert = p.getOutputEnable();
660 cbOutputEnable.setSelected(convert);
661 fldOutput.setEnabled(convert);
662 fldOutput.setText(p.getOutputFileNamePattern());
665 private void initFfmpegTab() {
666 pnlInputFfmpeg.init(Config.INSTANCE);
669 private JMenuBar initMenuBar() {
670 final JMenuBar menuBar = new JMenuBar();
672 final JMenu mnFile = new JMenu("ファイル(F)");
675 final JMenuItem itExit = new JMenuItem("終了(X)", KeyEvent.VK_X);
676 itExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
677 itExit.addActionListener(new ActionListener() {
680 public void actionPerformed(ActionEvent e) {
681 throw new UnsupportedOperationException("Not supported yet.");
686 final JMenu mnTool = new JMenu("ツール(T)");
689 final JMenuItem itOption = new JMenuItem("オプション(O)...", KeyEvent.VK_O);
691 itOption.addActionListener(new ActionListener() {
694 public void actionPerformed(ActionEvent e) {
695 final yukihane.inqubus.gui.ConfigDialog dlg = new yukihane.inqubus.gui.ConfigDialog(MainFrame.this);
696 dlg.setLocationRelativeTo(MainFrame.this);
698 dlg.setVisible(true);
701 mnTool.add(itOption);
703 final JMenu mnHelp = new JMenu("ヘルプ(H)");
706 final JMenuItem itAbout = new JMenuItem("このソフトウェアについて(A)...", KeyEvent.VK_A);
707 itAbout.addActionListener(new ActionListener() {
710 public void actionPerformed(ActionEvent e) {
711 MainFrame_AboutBox dlg = new MainFrame_AboutBox(MainFrame.this);
713 dlg.setLocationRelativeTo(MainFrame.this);
715 dlg.setVisible(true);
723 private class DownloadProgressListener implements WorkerListener<DownloadResult, DownloadProgress> {
726 public void process(DownloadProgress progress) {
727 throw new UnsupportedOperationException("Not supported yet.");
731 public void cancelled() {
732 throw new UnsupportedOperationException("Not supported yet.");
736 public void done(DownloadResult result) {
737 throw new UnsupportedOperationException("Not supported yet.");
741 public void error(Throwable th) {
742 throw new UnsupportedOperationException("Not supported yet.");
746 private class ConvertProgressListener implements WorkerListener<ConvertResult, ConvertProgress> {
749 public void process(ConvertProgress progress) {
750 throw new UnsupportedOperationException("Not supported yet.");
754 public void cancelled() {
755 throw new UnsupportedOperationException("Not supported yet.");
759 public void done(ConvertResult result) {
760 throw new UnsupportedOperationException("Not supported yet.");
764 public void error(Throwable th) {
765 throw new UnsupportedOperationException("Not supported yet.");
771 private class DownloadListTransferHandler extends TransferHandler {
773 private static final long serialVersionUID = 1L;
774 private final Pattern movieIdPattern = Pattern.compile("(\\w\\w\\d+)");
777 public boolean canImport(TransferHandler.TransferSupport support) {
778 Transferable transferable = support.getTransferable();
779 if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
780 || transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
787 public boolean importData(TransferHandler.TransferSupport support) {
789 // Transferable transferable = support.getTransferable();
790 // if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
791 // @SuppressWarnings("unchecked")
792 // final List<File> data = (List<File>) transferable.getTransferData(DataFlavor.javaFileListFlavor);
793 // Collection<Target> targets = Target.from(data);
794 // targetModel.addTarget(targets);
795 // } else if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
796 // String data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
797 // Matcher matcher = movieIdPattern.matcher(data);
798 // if (matcher.find()) {
799 // String movieId = matcher.group(1);
800 // Target target = Target.fromId(movieId);
801 // targetModel.addTarget(target);
808 // } catch (Exception e) {
809 // logger.log(Level.SEVERE, null, e);
812 // TODO 上記実装見直し(Locationは削除された)
817 private class TableTransferHandler extends DownloadListTransferHandler {
819 private static final long serialVersionUID = 1L;
822 public boolean canImport(TransferHandler.TransferSupport support) {
823 return super.canImport(support);
827 public boolean importData(TransferHandler.TransferSupport support) {
828 return super.importData(support);
833 * ここからDownloadProfile作成用クラスの定義
836 private class InqubusDownloadProfile implements DownloadProfile {
838 private final LoginProfile loginProfile;
839 private final ProxyProfile proxyProfile;
840 private final VideoProfile videoProfile;
841 private final CommentProfile commentProfile;
842 private final GeneralProfile generalProfile;
844 private InqubusDownloadProfile() {
845 this.loginProfile = new InqubusLoginProfile();
846 this.proxyProfile = new InqubusProxyProfile();
847 this.videoProfile = new InqubusVideoProfile();
848 this.commentProfile = new InqubusCommentProfile();
849 this.generalProfile = new InqubusGeneralProfile();
853 public LoginProfile getLoginInfo() {
854 return this.loginProfile;
858 public ProxyProfile getProxyProfile() {
859 return this.proxyProfile;
863 public VideoProfile getVideoProfile() {
864 return this.videoProfile;
868 public CommentProfile getCommentProfile() {
869 return this.commentProfile;
873 public GeneralProfile getGeneralProfile() {
874 return this.generalProfile;
878 public String toString(){
879 return ToStringBuilder.reflectionToString(this);
883 private class InqubusLoginProfile implements LoginProfile {
884 private final String mail;
885 private final String password;
887 private InqubusLoginProfile(){
888 final Config p = Config.INSTANCE;
889 this.mail = p.getId();
890 this.password = p.getPassword();
894 public String getMail() {
899 public String getPassword() {
900 return this.password;
904 public String toString(){
905 return ToStringBuilder.reflectionToString(this);
909 private class InqubusProxyProfile implements ProxyProfile {
910 private final boolean use;
911 private final String host;
912 private final int port;
914 private InqubusProxyProfile(){
915 final Config p = Config.INSTANCE;
916 this.use = p.getProxyUse();
917 this.host = p.getProxyHost();
918 final String pp = p.getProxyPort();
919 this.port = StringUtils.isBlank(pp) ? -1 : Integer.parseInt(pp);
923 public boolean use() {
928 public String getHost() {
933 public int getPort() {
938 public String toString(){
939 return ToStringBuilder.reflectionToString(this);
943 private class InqubusVideoProfile implements VideoProfile {
944 private final boolean download;
945 private final File dir;
946 private final String fileName;
947 private final File localFile;
949 private InqubusVideoProfile(){
950 final Config p = Config.INSTANCE;
951 this.download = !cbVideoLocal.isSelected();
953 this.dir = new File(p.getVideoDir());
954 this.fileName = fldVideo.getText();
955 this.localFile = null;
958 this.fileName = null;
959 this.localFile = new File(fldVideo.getText());
964 public boolean isDownload() {
965 return this.download;
969 public File getDir() {
974 public String getFileName() {
975 return this.fileName;
979 public File getLocalFile() {
980 return this.localFile;
984 public String toString(){
985 return ToStringBuilder.reflectionToString(this);
989 private class InqubusCommentProfile implements CommentProfile {
990 private final boolean download;
991 private final File dir;
992 private final String fileName;
993 private final File localFile;
994 private final int lengthRelatedCommentSize;
995 private final boolean disablePerMinComment;
996 private final int perMinCommentSize;
997 private final long backLogPoint;
999 private InqubusCommentProfile() {
1000 final Config p = Config.INSTANCE;
1001 this.download = !cbCommentLocal.isSelected();
1002 if (this.download) {
1003 this.dir = new File(p.getCommentDir());
1004 this.fileName = fldComment.getText();
1005 this.localFile = null;
1008 this.fileName = null;
1009 this.localFile = new File(fldComment.getText());
1012 if(cbBackLog.isSelected()) {
1014 this.backLogPoint = WayBackTimeParser.parse(fldBackLog.getText());
1015 } catch (IOException ex) {
1016 throw new IllegalArgumentException("過去ログ時刻指定が誤っています。", ex);
1019 this.backLogPoint = -1L;
1022 this.disablePerMinComment = cbBackLogReduce.isSelected();
1023 this.lengthRelatedCommentSize
1024 = (p.getCommentSizeAutosize()) ? -1 : Integer.parseInt(p.getCommentSizeManual());
1025 this.perMinCommentSize
1026 = (p.getCommentMinSizeAutosize()) ? -1 : Integer.parseInt(p.getCommentMinSizeManual());
1030 public boolean isDownload() {
1031 return this.download;
1035 public File getDir() {
1040 public String getFileName() {
1041 return this.fileName;
1045 public File getLocalFile() {
1046 return this.localFile;
1050 public int getLengthRelatedCommentSize() {
1051 return this.lengthRelatedCommentSize;
1055 public boolean isDisablePerMinComment() {
1056 return this.disablePerMinComment;
1060 public int getPerMinCommentSize() {
1061 return this.perMinCommentSize;
1065 public long getBackLogPoint() {
1066 return this.backLogPoint;
1070 public String toString(){
1071 return ToStringBuilder.reflectionToString(this);
1075 private class InqubusGeneralProfile implements GeneralProfile {
1076 private final String replaceFrom;
1077 private final String replaceTo;
1078 private InqubusGeneralProfile() {
1079 final Config p = Config.INSTANCE;
1080 this.replaceFrom = p.getReplaceFrom();
1081 this.replaceTo = p.getReplaceTo();
1085 public String getReplaceFrom() {
1086 return this.replaceFrom;
1090 public String getReplaceTo() {
1091 return this.replaceTo;
1095 public String toString(){
1096 return ToStringBuilder.reflectionToString(this);
1101 * ここからConvertProfile作成用クラスの定義
1103 private class InqubusConvertProfile implements ConvertProfile {
1104 private final OutputProfile outputProfile;
1105 private final GeneralProfile generalProfile;
1106 private final FfmpegProfile ffmpegProfile;
1107 private final boolean convert;
1108 private final File ffmpeg;
1109 private final boolean vhookDisabled;
1110 private final boolean commentOverlay;
1111 private final File vhook;
1112 private final File tmpDir;
1113 private final File font;
1114 private final int fontIndex;
1115 private final boolean commentOpaque;
1116 private final boolean disableFontSizeArrange;
1117 private final int shadowIndex;
1118 private final boolean showConvrting;
1119 private final int maxNumOfComment;
1120 private final HideCondition ngSetting;
1122 private InqubusConvertProfile() throws IOException {
1123 final Config p = Config.INSTANCE;
1124 this.outputProfile = new InqubusOutputProfile();
1125 this.generalProfile = new InqubusGeneralProfile();
1126 this.ffmpegProfile = new InqubusFfmpegProfile();
1127 this.convert = cbOutputEnable.isSelected();
1128 this.ffmpeg = new File(p.getFfmpegPath());
1130 this.vhookDisabled = false;
1131 this.commentOverlay = p.getOutputCommentOverlay();
1132 this.vhook = new File(p.getFfmpegDllPath());
1133 this.tmpDir = new File(p.getSystemTempDir());
1134 this.font = new File(p.getFontPath());
1135 this.fontIndex = Integer.parseInt(p.getFontIndex());
1136 this.commentOpaque = p.getCommentOpaque();
1137 this.disableFontSizeArrange = p.getFontSizeArrangeDisable();
1138 this.shadowIndex = p.getFontShadow();
1140 this.showConvrting = true;
1141 this.maxNumOfComment = (p.getCommentDisplaySizeDefault()) ? -1 : Integer.parseInt(p.
1142 getCommentDisplaySizeManual());
1143 this.ngSetting = new InqubusHideCondition();
1147 public OutputProfile getOutputProfile() {
1148 return this.outputProfile;
1152 public GeneralProfile getGeneralProfile() {
1153 return this.generalProfile;
1157 public FfmpegProfile getFfmpegOption() {
1158 return this.ffmpegProfile;
1162 public boolean isConvert() {
1163 return this.convert;
1167 public File getFfmpeg() {
1172 public boolean isVhookDisabled() {
1173 return this.vhookDisabled;
1177 public boolean isCommentOverlay() {
1178 return this.commentOverlay;
1182 public File getVhook() {
1187 public File getTempDir() {
1192 public File getFont() {
1197 public int getFontIndex() {
1198 return this.fontIndex;
1202 public boolean isCommentOpaque() {
1203 return this.commentOpaque;
1207 public boolean isDisableFontSizeArrange() {
1208 return this.disableFontSizeArrange;
1212 public int getShadowIndex() {
1213 return this.shadowIndex;
1217 public boolean isShowConverting() {
1218 return this.showConvrting;
1222 public int getMaxNumOfComment() {
1223 return this.maxNumOfComment;
1227 public HideCondition getNgSetting() {
1228 return this.ngSetting;
1232 public String toString(){
1233 return ToStringBuilder.reflectionToString(this);
1237 private class InqubusOutputProfile implements OutputProfile {
1238 private final File dir;
1239 private final String fileName;
1240 private final String videoId;
1241 private final String title;
1244 private InqubusOutputProfile(){
1245 final Config p = Config.INSTANCE;
1246 this.dir = new File(p.getOutputDir());
1247 this.fileName = fldOutput.getText();
1248 // TODO この時点でのID/Titleはどうするか…
1254 public File getDir() {
1259 public String getFileName() {
1260 return this.fileName;
1264 public String getVideoId() {
1265 return this.videoId;
1269 public String getTitile() {
1274 public String toString(){
1275 return ToStringBuilder.reflectionToString(this);
1279 private class InqubusFfmpegProfile implements FfmpegProfile {
1280 private final String extOption;
1281 private final String inOption;
1282 private final String mainOption;
1283 private final String outOption;
1284 private final String avOption;
1285 private final boolean resize;
1286 private final int resizeWidth;
1287 private final int resizeHeight;
1288 private final boolean adjustRatio;
1290 private InqubusFfmpegProfile() throws IOException {
1291 final File file = pnlInputFfmpeg.mdlFfmpegOption.getSelectedFile();
1293 final FfmpegOption ffop = FfmpegOption.load(file);
1294 this.extOption = ffop.getExtOption();
1295 this.inOption = ffop.getInOption();
1296 this.mainOption = ffop.getMainOption();
1297 this.outOption = ffop.getMainOption();
1298 this.avOption = ffop.getAvfilterOption();
1299 this.resize = ffop.isResize();
1300 this.resizeWidth = ffop.getResizeWidth();
1301 this.resizeHeight = ffop.getResizeHeight();
1302 this.adjustRatio = ffop.isAdjustRatio();
1304 this.extOption = pnlInputFfmpeg.fldFfmpegOptionExtension.getText();
1305 this.inOption = pnlInputFfmpeg.fldFfmpegOptionIn.getText();
1306 this.mainOption = pnlInputFfmpeg.fldFfmpegOptionMain.getText();
1307 this.outOption = pnlInputFfmpeg.fldFfmpegOptionOut.getText();
1308 this.avOption = pnlInputFfmpeg.fldFfmpegOptionAv.getText();
1309 this.resize = pnlInputFfmpeg.cbFfmpegOptionResize.isSelected();
1310 this.resizeWidth = Integer.parseInt(pnlInputFfmpeg.fldFfmpegOptionResizeWidth.getText());
1311 this.resizeHeight = Integer.parseInt(pnlInputFfmpeg.fldFfmpegOptionResizeHeight.getText());
1312 this.adjustRatio = pnlInputFfmpeg.cbFfmpegOptionKeepAspect.isSelected();
1317 public String getExtOption() {
1318 return this.extOption;
1322 public String getInOption() {
1323 return this.inOption;
1327 public String getMainOption() {
1328 return this.mainOption;
1332 public String getOutOption() {
1333 return this.outOption;
1337 public String getAvfilterOption() {
1338 return this.avOption;
1342 public boolean isResize() {
1347 public int getResizeWidth() {
1348 return this.resizeWidth;
1352 public int getResizeHeight() {
1353 return this.resizeHeight;
1357 public boolean isAdjustRatio() {
1358 return this.adjustRatio;
1362 public String toString(){
1363 return ToStringBuilder.reflectionToString(this);
1367 private class InqubusHideCondition implements ConvertProfile.HideCondition{
1370 public String getWord() {
1376 public String getId() {
1382 public String toString(){
1383 return ToStringBuilder.reflectionToString(this);