package com.rarchives.ripme.ui; import java.awt.CheckboxMenuItem; import java.awt.Color; import java.awt.Container; import java.awt.Desktop; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Image; import java.awt.MenuItem; import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.Arrays; import java.util.List; import javax.imageio.ImageIO; import javax.swing.DefaultListModel; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import org.apache.log4j.Logger; import com.rarchives.ripme.ripper.AbstractRipper; import com.rarchives.ripme.utils.Utils; /** * Everything UI-related starts and ends here. */ public class MainWindow implements Runnable, RipStatusHandler { private static final Logger logger = Logger.getLogger(MainWindow.class); private static JFrame mainFrame; private static JTextField ripTextfield; private static JButton ripButton, stopButton; private static JLabel statusLabel; private static JButton openButton; private static JProgressBar statusProgress; // Log private static JButton optionLog; private static JPanel logPanel; private static JTextPane logText; private static JScrollPane logTextScroll; // History private static JButton optionHistory; private static JPanel historyPanel; private static JList historyList; private static DefaultListModel historyListModel; private static JScrollPane historyListScroll; private static JPanel historyButtonPanel; private static JButton historyButtonRemove, historyButtonClear, historyButtonRerip; // Configuration private static JButton optionConfiguration; private static JPanel configurationPanel; private static JButton configUpdateButton; private static JLabel configUpdateLabel; private static JTextField configTimeoutText; private static JTextField configThreadsText; private static JCheckBox configOverwriteCheckbox; private static JLabel configSaveDirLabel; private static JButton configSaveDirButton; private static JTextField configRetriesText; private static JCheckBox configAutoupdateCheckbox; private static JCheckBox configPlaySound; private static JCheckBox configSaveOrderCheckbox; private static JCheckBox configShowPopup; private static JCheckBox configSaveLogs; private static TrayIcon trayIcon; private static MenuItem trayMenuMain; private static MenuItem trayMenuAbout; private static MenuItem trayMenuExit; private static CheckboxMenuItem trayMenuAutorip; private static Image mainIcon; private static AbstractRipper ripper; public MainWindow() { mainFrame = new JFrame("RipMe v" + UpdateUtils.getThisJarVersion()); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.setResizable(false); mainFrame.setLayout(new GridBagLayout()); createUI(mainFrame.getContentPane()); loadHistory(); setupHandlers(); Thread shutdownThread = new Thread() { @Override public void run() { shutdownCleanup(); } }; Runtime.getRuntime().addShutdownHook(shutdownThread); if (Utils.getConfigBoolean("auto.update", true)) { upgradeProgram(); } ClipboardUtils.setClipboardAutoRip(Utils.getConfigBoolean("clipboard.autorip", false)); } public void upgradeProgram() { if (!configurationPanel.isVisible()) { optionConfiguration.doClick(); } Runnable r = new Runnable() { @Override public void run() { UpdateUtils.updateProgram(configUpdateLabel); } }; new Thread(r).start(); } public void run() { pack(); mainFrame.setLocationRelativeTo(null); mainFrame.setVisible(true); } public void shutdownCleanup() { Utils.setConfigBoolean("file.overwrite", configOverwriteCheckbox.isSelected()); Utils.setConfigInteger("threads.size", Integer.parseInt(configThreadsText.getText())); Utils.setConfigInteger("download.retries", Integer.parseInt(configRetriesText.getText())); Utils.setConfigInteger("download.timeout", Integer.parseInt(configTimeoutText.getText())); Utils.setConfigBoolean("clipboard.autorip", ClipboardUtils.getClipboardAutoRip()); Utils.setConfigBoolean("auto.update", configAutoupdateCheckbox.isSelected()); Utils.setConfigBoolean("play.sound", configPlaySound.isSelected()); Utils.setConfigBoolean("download.save_order", configSaveOrderCheckbox.isSelected()); Utils.setConfigBoolean("download.show_popup", configShowPopup.isSelected()); Utils.setConfigBoolean("log.save", configSaveLogs.isSelected()); saveHistory(); Utils.saveConfig(); } private void status(String text) { statusWithColor(text, Color.BLACK); } private void error(String text) { statusWithColor(text, Color.RED); } private void statusWithColor(String text, Color color) { statusLabel.setForeground(color); statusLabel.setText(text); pack(); } private void pack() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { mainFrame.pack(); } }); } private void createUI(Container pane) { setupTrayIcon(); EmptyBorder emptyBorder = new EmptyBorder(5, 5, 5, 5); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 2; gbc.ipadx = 2; gbc.gridx = 0; gbc.weighty = 2; gbc.ipady = 2; gbc.gridy = 0; try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { logger.error("[!] Exception setting system theme:", e); } ripTextfield = new JTextField("", 20); ripTextfield.addMouseListener(new ContextMenuMouseListener()); ImageIcon ripIcon = new ImageIcon(mainIcon); ripButton = new JButton("Rip", ripIcon); stopButton = new JButton("Stop"); stopButton.setVisible(false); try { Image stopIcon = ImageIO.read(getClass().getClassLoader().getResource("stop.png")); stopButton.setIcon(new ImageIcon(stopIcon)); } catch (Exception e) { } JPanel ripPanel = new JPanel(new GridBagLayout()); ripPanel.setBorder(emptyBorder); gbc.gridx = 0; ripPanel.add(new JLabel("URL:", JLabel.RIGHT), gbc); gbc.gridx = 1; ripPanel.add(ripTextfield, gbc); gbc.gridx = 2; ripPanel.add(ripButton, gbc); ripPanel.add(stopButton, gbc); statusLabel = new JLabel("Inactive"); statusLabel.setHorizontalAlignment(JLabel.CENTER); openButton = new JButton(); openButton.setVisible(false); JPanel statusPanel = new JPanel(new GridBagLayout()); statusPanel.setBorder(emptyBorder); gbc.gridx = 0; statusPanel.add(statusLabel, gbc); gbc.gridy = 1; statusPanel.add(openButton, gbc); gbc.gridy = 0; JPanel progressPanel = new JPanel(new GridBagLayout()); progressPanel.setBorder(emptyBorder); statusProgress = new JProgressBar(0, 100); progressPanel.add(statusProgress, gbc); JPanel optionsPanel = new JPanel(new GridBagLayout()); optionsPanel.setBorder(emptyBorder); optionLog = new JButton("Log"); optionHistory = new JButton("History"); optionConfiguration = new JButton("Configuration"); try { Image icon; icon = ImageIO.read(getClass().getClassLoader().getResource("comment.png")); optionLog.setIcon(new ImageIcon(icon)); icon = ImageIO.read(getClass().getClassLoader().getResource("time.png")); optionHistory.setIcon(new ImageIcon(icon)); icon = ImageIO.read(getClass().getClassLoader().getResource("gear.png")); optionConfiguration.setIcon(new ImageIcon(icon)); } catch (Exception e) { } gbc.gridx = 0; optionsPanel.add(optionLog, gbc); gbc.gridx = 1; optionsPanel.add(optionHistory, gbc); gbc.gridx = 2; optionsPanel.add(optionConfiguration, gbc); logPanel = new JPanel(new GridBagLayout()); logPanel.setBorder(emptyBorder); logText = new JTextPaneNoWrap(); logTextScroll = new JScrollPane(logText); logPanel.setVisible(false); logPanel.setPreferredSize(new Dimension(300, 250)); logPanel.add(logTextScroll, gbc); historyPanel = new JPanel(new GridBagLayout()); historyPanel.setBorder(emptyBorder); historyPanel.setVisible(false); historyPanel.setPreferredSize(new Dimension(300, 250)); historyListModel = new DefaultListModel(); historyList = new JList(historyListModel); historyList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); historyListScroll = new JScrollPane(historyList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); historyButtonRemove = new JButton("Remove"); historyButtonClear = new JButton("Clear"); historyButtonRerip = new JButton("Re-rip All"); gbc.gridx = 0; JPanel historyListPanel = new JPanel(new GridBagLayout()); historyListPanel.add(historyListScroll, gbc); gbc.ipady = 150; historyPanel.add(historyListPanel, gbc); gbc.ipady = 0; historyButtonPanel = new JPanel(new GridBagLayout()); historyButtonPanel.setPreferredSize(new Dimension(300, 10)); historyButtonPanel.setBorder(emptyBorder); gbc.gridx = 0; historyButtonPanel.add(historyButtonRemove, gbc); gbc.gridx = 1; historyButtonPanel.add(historyButtonClear, gbc); gbc.gridx = 2; historyButtonPanel.add(historyButtonRerip, gbc); gbc.gridy = 1; gbc.gridx = 0; historyPanel.add(historyButtonPanel, gbc); configurationPanel = new JPanel(new GridBagLayout()); configurationPanel.setBorder(emptyBorder); configurationPanel.setVisible(false); configurationPanel.setPreferredSize(new Dimension(300, 250)); // TODO Configuration components configUpdateButton = new JButton("Check for updates"); configUpdateLabel = new JLabel("Current version: " + UpdateUtils.getThisJarVersion(), JLabel.RIGHT); JLabel configThreadsLabel = new JLabel("Maximum download threads:", JLabel.RIGHT); JLabel configTimeoutLabel = new JLabel("Timeout (in milliseconds):", JLabel.RIGHT); JLabel configRetriesLabel = new JLabel("Retry download count:", JLabel.RIGHT); configThreadsText = new JTextField(Integer.toString(Utils.getConfigInteger("threads.size", 3))); configTimeoutText = new JTextField(Integer.toString(Utils.getConfigInteger("download.timeout", 60000))); configRetriesText = new JTextField(Integer.toString(Utils.getConfigInteger("download.retries", 3))); configOverwriteCheckbox = new JCheckBox("Overwrite existing files?", Utils.getConfigBoolean("file.overwrite", false)); configOverwriteCheckbox.setHorizontalAlignment(JCheckBox.RIGHT); configOverwriteCheckbox.setHorizontalTextPosition(JCheckBox.LEFT); configAutoupdateCheckbox = new JCheckBox("Auto-update?", Utils.getConfigBoolean("auto.update", true)); configAutoupdateCheckbox.setHorizontalAlignment(JCheckBox.RIGHT); configAutoupdateCheckbox.setHorizontalTextPosition(JCheckBox.LEFT); configPlaySound = new JCheckBox("Sound when rip completes", Utils.getConfigBoolean("play.sound", false)); configPlaySound.setHorizontalAlignment(JCheckBox.RIGHT); configPlaySound.setHorizontalTextPosition(JCheckBox.LEFT); configSaveOrderCheckbox = new JCheckBox("Preserve order", Utils.getConfigBoolean("download.save_order", true)); configSaveOrderCheckbox.setHorizontalAlignment(JCheckBox.RIGHT); configSaveOrderCheckbox.setHorizontalTextPosition(JCheckBox.LEFT); configShowPopup = new JCheckBox("Notification when rip starts", Utils.getConfigBoolean("download.show_popup", false)); configShowPopup.setHorizontalAlignment(JCheckBox.RIGHT); configShowPopup.setHorizontalTextPosition(JCheckBox.LEFT); configSaveLogs = new JCheckBox("Save logs", Utils.getConfigBoolean("log.save", false)); configSaveLogs.setHorizontalAlignment(JCheckBox.RIGHT); configSaveLogs.setHorizontalTextPosition(JCheckBox.LEFT); configSaveDirLabel = new JLabel(); try { String workingDir = (Utils.shortenPath(Utils.getWorkingDirectory())); configSaveDirLabel.setText(workingDir); } catch (Exception e) { } configSaveDirLabel.setToolTipText(configSaveDirLabel.getText()); configSaveDirLabel.setHorizontalAlignment(JLabel.RIGHT); configSaveDirButton = new JButton("Browse..."); gbc.gridy = 0; gbc.gridx = 0; configurationPanel.add(configUpdateLabel, gbc); gbc.gridx = 1; configurationPanel.add(configUpdateButton, gbc); gbc.gridy = 1; gbc.gridx = 0; configurationPanel.add(configAutoupdateCheckbox, gbc); gbc.gridy = 2; gbc.gridx = 0; configurationPanel.add(configThreadsLabel, gbc); gbc.gridx = 1; configurationPanel.add(configThreadsText, gbc); gbc.gridy = 3; gbc.gridx = 0; configurationPanel.add(configTimeoutLabel, gbc); gbc.gridx = 1; configurationPanel.add(configTimeoutText, gbc); gbc.gridy = 4; gbc.gridx = 0; configurationPanel.add(configRetriesLabel, gbc); gbc.gridx = 1; configurationPanel.add(configRetriesText, gbc); gbc.gridy = 5; gbc.gridx = 0; configurationPanel.add(configOverwriteCheckbox, gbc); gbc.gridx = 1; configurationPanel.add(configSaveOrderCheckbox, gbc); gbc.gridy = 6; gbc.gridx = 0; configurationPanel.add(configPlaySound, gbc); gbc.gridx = 1; configurationPanel.add(configSaveLogs, gbc); gbc.gridy = 7; gbc.gridx = 0; configurationPanel.add(configShowPopup, gbc); gbc.gridy = 8; gbc.gridx = 0; configurationPanel.add(configSaveDirLabel, gbc); gbc.gridx = 1; configurationPanel.add(configSaveDirButton, gbc); gbc.gridy = 0; pane.add(ripPanel, gbc); gbc.gridy = 1; pane.add(statusPanel, gbc); gbc.gridy = 2; pane.add(progressPanel, gbc); gbc.gridy = 3; pane.add(optionsPanel, gbc); gbc.gridy = 4; pane.add(logPanel, gbc); gbc.gridy = 5; pane.add(historyPanel, gbc); gbc.gridy = 5; pane.add(configurationPanel, gbc); } private void setupHandlers() { ripButton.addActionListener(new RipButtonHandler()); ripTextfield.addActionListener(new RipButtonHandler()); ripTextfield.getDocument().addDocumentListener(new DocumentListener() { @Override public void removeUpdate(DocumentEvent e) { update(); } @Override public void insertUpdate(DocumentEvent e) { update(); } @Override public void changedUpdate(DocumentEvent e) { update(); } private void update() { if (!ripTextfield.isEnabled()) { return; } try { String urlText = ripTextfield.getText().trim(); if (!urlText.startsWith("http")) { urlText = "http://" + urlText; } URL url = new URL(urlText); AbstractRipper ripper = AbstractRipper.getRipper(url); statusWithColor(ripper.getHost() + " album detected", Color.GREEN); } catch (Exception e) { statusWithColor("Can't rip this URL", Color.RED); } } }); stopButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { if (ripper != null) { ripper.stop(); ripButton.setVisible(true); stopButton.setVisible(false); ripTextfield.setEnabled(true); statusProgress.setValue(0); statusProgress.setVisible(false); pack(); statusProgress.setValue(0); status("Ripping interrupted"); appendLog("Ripper interrupted", Color.RED); } } }); optionLog.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { logPanel.setVisible(!logPanel.isVisible()); historyPanel.setVisible(false); configurationPanel.setVisible(false); optionLog.setFont(optionLog.getFont().deriveFont(Font.BOLD)); optionHistory.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionConfiguration.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); pack(); } }); optionHistory.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { logPanel.setVisible(false); historyPanel.setVisible(!historyPanel.isVisible()); configurationPanel.setVisible(false); optionLog.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionHistory.setFont(optionLog.getFont().deriveFont(Font.BOLD)); optionConfiguration.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); pack(); } }); optionConfiguration.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { logPanel.setVisible(false); historyPanel.setVisible(false); configurationPanel.setVisible(!configurationPanel.isVisible()); optionLog.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionHistory.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionConfiguration.setFont(optionLog.getFont().deriveFont(Font.BOLD)); pack(); } }); historyButtonRemove.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { int[] indices = historyList.getSelectedIndices(); for (int i = indices.length - 1; i >= 0; i--) { historyListModel.remove(indices[i]); } saveHistory(); } }); historyButtonClear.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { historyListModel.clear(); saveHistory(); } }); // Re-rip all history historyButtonRerip.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { Runnable ripAllThread = new Runnable() { @Override public void run() { historyButtonPanel.setEnabled(false); historyList.setEnabled(false); for (int i = 0; i < historyListModel.size(); i++) { historyList.clearSelection(); historyList.setSelectedIndex(i); Thread t = ripAlbum( (String) historyListModel.get(i) ); if (t == null) { continue; } try { synchronized (t) { t.wait(); } t.join(); } catch (InterruptedException e) { logger.error("[!] Exception while waiting for ripper to finish:", e); } } historyList.setEnabled(true); historyButtonPanel.setEnabled(true); } }; new Thread(ripAllThread).start(); } }); configUpdateButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Thread t = new Thread() { @Override public void run() { UpdateUtils.updateProgram(configUpdateLabel); } }; t.start(); } }); configSaveDirButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { JFileChooser jfc = new JFileChooser(Utils.getWorkingDirectory()); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = jfc.showDialog(null, "select directory"); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } File chosenFile = jfc.getSelectedFile(); String chosenPath = null; try { chosenPath = chosenFile.getCanonicalPath(); } catch (Exception e) { logger.error("Error while getting selected path: ", e); return; } configSaveDirLabel.setText(Utils.shortenPath(chosenPath)); Utils.setConfigString("rips.directory", chosenPath); } }); configOverwriteCheckbox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Utils.setConfigBoolean("file.overwrite", configOverwriteCheckbox.isSelected()); } }); configSaveOrderCheckbox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Utils.setConfigBoolean("download.save_order", configSaveOrderCheckbox.isSelected()); } }); configSaveLogs.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Utils.setConfigBoolean("log.save", configSaveLogs.isSelected()); Utils.configureLogger(); } }); } private void setupTrayIcon() { mainFrame.addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { trayMenuMain.setLabel("Hide"); } public void windowDeactivated(WindowEvent e) { trayMenuMain.setLabel("Show"); } public void windowDeiconified(WindowEvent e) { trayMenuMain.setLabel("Hide"); } public void windowIconified(WindowEvent e) { trayMenuMain.setLabel("Show"); } }); PopupMenu trayMenu = new PopupMenu(); trayMenuMain = new MenuItem("Hide"); trayMenuMain.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { toggleTrayClick(); } }); trayMenuAbout = new MenuItem("About " + mainFrame.getTitle()); trayMenuAbout.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { StringBuilder about = new StringBuilder(); about.append("

") .append(mainFrame.getTitle()) .append("

"); about.append("Download albums from various websites:"); try { List rippers = Utils.getListOfAlbumRippers(); about.append(""); } catch (Exception e) { } about.append("
And download videos from video sites:"); try { List rippers = Utils.getListOfVideoRippers(); about.append(""); } catch (Exception e) { } about.append("Do you want to visit the project homepage on Github?"); about.append(""); int response = JOptionPane.showConfirmDialog(null, about.toString(), mainFrame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, new ImageIcon(mainIcon)); if (response == JOptionPane.YES_OPTION) { try { Desktop.getDesktop().browse(URI.create("http://github.com/4pr0n/ripme")); } catch (IOException e) { logger.error("Exception while opening project home page", e); } } } }); trayMenuExit = new MenuItem("Exit"); trayMenuExit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { System.exit(0); } }); trayMenuAutorip = new CheckboxMenuItem("Clipboard Autorip"); trayMenuAutorip.setState(ClipboardUtils.getClipboardAutoRip()); trayMenuAutorip.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent arg0) { ClipboardUtils.setClipboardAutoRip(trayMenuAutorip.getState()); } }); trayMenu.add(trayMenuMain); trayMenu.add(trayMenuAbout); trayMenu.addSeparator(); trayMenu.add(trayMenuAutorip); trayMenu.addSeparator(); trayMenu.add(trayMenuExit); try { mainIcon = ImageIO.read(getClass().getClassLoader().getResource("icon.png")); trayIcon = new TrayIcon(mainIcon); trayIcon.setToolTip(mainFrame.getTitle()); trayIcon.setImageAutoSize(true); trayIcon.setPopupMenu(trayMenu); SystemTray.getSystemTray().add(trayIcon); trayIcon.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { toggleTrayClick(); if (mainFrame.getExtendedState() != JFrame.NORMAL) { mainFrame.setExtendedState(JFrame.NORMAL); } mainFrame.setAlwaysOnTop(true); mainFrame.setAlwaysOnTop(false); } }); } catch (Exception e) { e.printStackTrace(); } } private void toggleTrayClick() { if (mainFrame.getExtendedState() == JFrame.ICONIFIED || !mainFrame.isActive() || !mainFrame.isVisible()) { mainFrame.setVisible(true); mainFrame.setAlwaysOnTop(true); mainFrame.setAlwaysOnTop(false); trayMenuMain.setLabel("Hide"); } else { mainFrame.setVisible(false); trayMenuMain.setLabel("Show"); } } private void appendLog(final String text, final Color color) { SimpleAttributeSet sas = new SimpleAttributeSet(); StyleConstants.setForeground(sas, color); StyledDocument sd = logText.getStyledDocument(); try { synchronized (this) { sd.insertString(sd.getLength(), text + "\n", sas); } } catch (BadLocationException e) { } logText.setCaretPosition(sd.getLength()); } private void loadHistory() { for (String url : Utils.getConfigList("download.history")) { historyListModel.addElement(url.trim()); } } private void saveHistory() { Utils.setConfigList("download.history", Arrays.asList(historyListModel.toArray())); } private Thread ripAlbum(String urlString) { //shutdownCleanup(); if (!logPanel.isVisible()) { optionLog.doClick(); } urlString = urlString.trim(); if (urlString.toLowerCase().startsWith("gonewild:")) { urlString = "http://gonewild.com/user/" + urlString.substring(urlString.indexOf(':') + 1); } if (!urlString.startsWith("http")) { urlString = "http://" + urlString; } URL url = null; try { url = new URL(urlString); } catch (MalformedURLException e) { logger.error("[!] Could not generate URL for '" + urlString + "'", e); error("Given URL is not valid, expecting http://website.com/page/..."); return null; } ripButton.setVisible(false); stopButton.setVisible(true); ripTextfield.setEnabled(false); statusProgress.setValue(100); openButton.setVisible(false); statusLabel.setVisible(true); pack(); boolean failed = false; try { ripper = AbstractRipper.getRipper(url); ripper.setup(); } catch (Exception e) { failed = true; logger.error("Could not find ripper for URL " + url, e); error("Error: " + e.getMessage()); } if (!failed) { try { synchronized (this) { ripTextfield.setText(ripper.getURL().toExternalForm()); } status("Starting rip..."); ripper.setObserver((RipStatusHandler) this); Thread t = new Thread(ripper); t.start(); if (configShowPopup.isSelected() && (!mainFrame.isVisible() || !mainFrame.isActive())) { mainFrame.toFront(); mainFrame.setAlwaysOnTop(true); trayIcon.displayMessage(mainFrame.getTitle(), "Started ripping " + ripper.getURL().toExternalForm(), MessageType.INFO); mainFrame.setAlwaysOnTop(false); } return t; } catch (Exception e) { logger.error("[!] Error while ripping: " + e.getMessage(), e); error("Unable to rip this URL: " + e.getMessage()); } } ripButton.setVisible(true); stopButton.setVisible(false); ripTextfield.setEnabled(true); statusProgress.setValue(0); pack(); return null; } class RipButtonHandler implements ActionListener { public void actionPerformed(ActionEvent event) { ripAlbum(ripTextfield.getText()); } } private class StatusEvent implements Runnable { private final AbstractRipper ripper; private final RipStatusMessage msg; public StatusEvent(AbstractRipper ripper, RipStatusMessage msg) { this.ripper = ripper; this.msg = msg; } public void run() { handleEvent(this); } } private synchronized void handleEvent(StatusEvent evt) { if (ripper.isStopped()) { return; } RipStatusMessage msg = evt.msg; int completedPercent = evt.ripper.getCompletionPercentage(); statusProgress.setValue(completedPercent); statusProgress.setVisible(true); status( evt.ripper.getStatusText() ); switch(msg.getStatus()) { case LOADING_RESOURCE: case DOWNLOAD_STARTED: appendLog( "Downloading: " + (String) msg.getObject(), Color.BLACK); break; case DOWNLOAD_COMPLETE: appendLog( "Completed: " + (String) msg.getObject(), Color.GREEN); break; case DOWNLOAD_ERRORED: appendLog( "Error: " + (String) msg.getObject(), Color.RED); break; case DOWNLOAD_WARN: appendLog( "Warn: " + (String) msg.getObject(), Color.ORANGE); break; case RIP_ERRORED: appendLog( "Error: " + (String) msg.getObject(), Color.RED); ripButton.setVisible(true); stopButton.setVisible(false); ripTextfield.setEnabled(true); statusProgress.setValue(0); statusProgress.setVisible(false); openButton.setVisible(false); pack(); statusWithColor("Error: " + (String) msg.getObject(), Color.RED); break; case RIP_COMPLETE: if (!historyListModel.contains(ripTextfield.getText())) { historyListModel.addElement(ripTextfield.getText()); } if (configPlaySound.isSelected()) { Utils.playSound("camera.wav"); } saveHistory(); ripButton.setVisible(true); stopButton.setVisible(false); ripTextfield.setEnabled(true); statusProgress.setValue(0); statusProgress.setVisible(false); openButton.setVisible(true); File f = (File) msg.getObject(); String prettyFile = Utils.shortenPath(f); openButton.setText("Open " + prettyFile); try { Image folderIcon = ImageIO.read(getClass().getClassLoader().getResource("folder.png")); openButton.setIcon(new ImageIcon(folderIcon)); } catch (Exception e) { } appendLog( "Rip complete, saved to " + prettyFile, Color.GREEN); openButton.setActionCommand(f.toString()); openButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { try { Desktop.getDesktop().open(new File(event.getActionCommand())); } catch (Exception e) { logger.error(e); } } }); pack(); break; case COMPLETED_BYTES: // Update completed bytes break; case TOTAL_BYTES: // Update total bytes break; } } public void update(AbstractRipper ripper, RipStatusMessage message) { StatusEvent event = new StatusEvent(ripper, message); SwingUtilities.invokeLater(event); } /** Simple TextPane that allows horizontal scrolling. */ class JTextPaneNoWrap extends JTextPane { private static final long serialVersionUID = 1L; @Override public boolean getScrollableTracksViewportWidth() { return false; } } public static void ripAlbumStatic(String url) { ripTextfield.setText(url.trim()); ripButton.doClick(); } }