diff --git a/pom.xml b/pom.xml
index cb8ca1f0..1f4c1b42 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.rarchives.ripme
ripme
jar
- 1.0.6
+ 1.0.7
ripme
http://rip.rarchives.com
diff --git a/src/main/java/com/rarchives/ripme/ui/ClipboardUtils.java b/src/main/java/com/rarchives/ripme/ui/ClipboardUtils.java
new file mode 100644
index 00000000..1cae501b
--- /dev/null
+++ b/src/main/java/com/rarchives/ripme/ui/ClipboardUtils.java
@@ -0,0 +1,89 @@
+package com.rarchives.ripme.ui;
+
+import java.awt.HeadlessException;
+import java.awt.Toolkit;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ClipboardUtils {
+ private static AutoripThread autoripThread = new AutoripThread();
+
+ public static void setClipboardAutoRip(boolean enabled) {
+ if (enabled) {
+ autoripThread.kill();
+ autoripThread = new AutoripThread();
+ autoripThread.isRunning = true;
+ autoripThread.start();
+ } else {
+ autoripThread.kill();
+ }
+ }
+ public static boolean getClipboardAutoRip() {
+ return autoripThread.isRunning;
+ }
+
+ public static String getClipboardString() {
+ try {
+ return (String) Toolkit
+ .getDefaultToolkit()
+ .getSystemClipboard()
+ .getData(DataFlavor.stringFlavor);
+ } catch (HeadlessException e) {
+ e.printStackTrace();
+ } catch (UnsupportedFlavorException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
+
+class AutoripThread extends Thread {
+ public volatile boolean isRunning = false;
+ Set rippedURLs = new HashSet();
+
+ public void run() {
+ isRunning = true;
+ try {
+ while (isRunning) {
+ // Check clipboard
+ String clipboard = ClipboardUtils.getClipboardString();
+ if (clipboard != null) {
+ Pattern p = Pattern.compile(
+ "\\b(((ht|f)tp(s?)\\:\\/\\/|~\\/|\\/)|www.)" +
+ "(\\w+:\\w+@)?(([-\\w]+\\.)+(com|org|net|gov" +
+ "|mil|biz|info|mobi|name|aero|jobs|museum" +
+ "|travel|[a-z]{2}))(:[\\d]{1,5})?" +
+ "(((\\/([-\\w~!$+|.,=]|%[a-f\\d]{2})+)+|\\/)+|\\?|#)?" +
+ "((\\?([-\\w~!$+|.,*:]|%[a-f\\d{2}])+=?" +
+ "([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)" +
+ "(&(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=?" +
+ "([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)*)*" +
+ "(#([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)?\\b");
+ Matcher m = p.matcher(clipboard);
+ while (m.find()) {
+ String url = m.group();
+ if (!rippedURLs.contains(url)) {
+ rippedURLs.add(url);
+ // TODO Start rip
+ MainWindow.ripAlbumStatic(url);
+ }
+ }
+ }
+ Thread.sleep(1000);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void kill() {
+ isRunning = false;
+ }
+}
diff --git a/src/main/java/com/rarchives/ripme/ui/MainWindow.java b/src/main/java/com/rarchives/ripme/ui/MainWindow.java
index db427499..b7d14c39 100644
--- a/src/main/java/com/rarchives/ripme/ui/MainWindow.java
+++ b/src/main/java/com/rarchives/ripme/ui/MainWindow.java
@@ -1,26 +1,36 @@
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.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.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
+import javax.imageio.ImageIO;
import javax.swing.DefaultListModel;
-import javax.swing.UIManager;
+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;
@@ -28,6 +38,7 @@ 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.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
@@ -83,13 +94,16 @@ public class MainWindow implements Runnable, RipStatusHandler {
private static JButton configSaveDirButton;
private static JTextField configRetriesText;
- // TODO Configuration components
-
+ private static MenuItem trayMenuAbout;
+ private static MenuItem trayMenuExit;
+ private static CheckboxMenuItem trayMenuAutorip;
+
+ private static Image mainIcon;
+
public MainWindow() {
mainFrame = new JFrame("RipMe v" + UpdateUtils.getThisJarVersion());
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- //mainFrame.setPreferredSize(new Dimension(400, 180));
- //mainFrame.setResizable(false);
+ mainFrame.setResizable(false);
mainFrame.setLayout(new GridBagLayout());
createUI(mainFrame.getContentPane());
@@ -99,10 +113,12 @@ public class MainWindow implements Runnable, RipStatusHandler {
Thread shutdownThread = new Thread() {
@Override
public void run() {
- saveConfig();
+ shutdownCleanup();
}
};
Runtime.getRuntime().addShutdownHook(shutdownThread);
+
+ ClipboardUtils.setClipboardAutoRip(Utils.getConfigBoolean("clipboard.autorip", false));
}
public void run() {
@@ -111,13 +127,15 @@ public class MainWindow implements Runnable, RipStatusHandler {
mainFrame.setVisible(true);
}
- public void saveConfig() {
- saveHistory();
+ 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());
+ saveHistory();
Utils.saveConfig();
+ ClipboardUtils.setClipboardAutoRip(false);
}
private void status(String text) {
@@ -135,6 +153,50 @@ public class MainWindow implements Runnable, RipStatusHandler {
}
private void createUI(Container pane) {
+ // System tray
+ PopupMenu trayMenu = new PopupMenu();
+ trayMenuAbout = new MenuItem("About " + mainFrame.getTitle());
+ trayMenuAbout.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ String aboutBlurb = " Download albums from various websites. rarchives.com";
+ JOptionPane.showMessageDialog(null,
+ aboutBlurb,
+ mainFrame.getTitle(),
+ JOptionPane.PLAIN_MESSAGE,
+ new ImageIcon(mainIcon));
+ }
+ });
+ 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(trayMenuAbout);
+ trayMenu.addSeparator();
+ trayMenu.add(trayMenuAutorip);
+ trayMenu.addSeparator();
+ trayMenu.add(trayMenuExit);
+ try {
+ mainIcon = ImageIO.read(getClass().getClassLoader().getResource("icon.png"));
+ TrayIcon trayIcon = new TrayIcon(mainIcon);
+ trayIcon.setToolTip(mainFrame.getTitle());
+ trayIcon.setPopupMenu(trayMenu);
+ SystemTray.getSystemTray().add(trayIcon);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
EmptyBorder emptyBorder = new EmptyBorder(5, 5, 5, 5);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
@@ -148,7 +210,8 @@ public class MainWindow implements Runnable, RipStatusHandler {
}
ripTextfield = new JTextField("", 20);
- ripButton = new JButton("Rip");
+ ImageIcon ripIcon = new ImageIcon(mainIcon.getScaledInstance(20, 20, Image.SCALE_SMOOTH));
+ ripButton = new JButton("Rip", ripIcon);
JPanel ripPanel = new JPanel(new GridBagLayout());
ripPanel.setBorder(emptyBorder);
@@ -397,7 +460,7 @@ public class MainWindow implements Runnable, RipStatusHandler {
}
private Thread ripAlbum(String urlString) {
- saveConfig();
+ shutdownCleanup();
if (urlString.toLowerCase().startsWith("gonewild:")) {
urlString = "http://gonewild.com/user/" + urlString.substring(urlString.indexOf(':') + 1);
}
@@ -418,23 +481,33 @@ public class MainWindow implements Runnable, RipStatusHandler {
openButton.setVisible(false);
statusLabel.setVisible(true);
mainFrame.pack();
+ AbstractRipper ripper = null;
+ boolean failed = false;
try {
- AbstractRipper ripper = AbstractRipper.getRipper(url);
- ripTextfield.setText(ripper.getURL().toExternalForm());
- status("Starting rip...");
- ripper.setObserver((RipStatusHandler) this);
- Thread t = new Thread(ripper);
- t.start();
- return t;
+ ripper = AbstractRipper.getRipper(url);
} catch (Exception e) {
- logger.error("[!] Error while ripping: " + e.getMessage(), e);
- error("Unable to rip this URL: " + e.getMessage());
- ripButton.setEnabled(true);
- ripTextfield.setEnabled(true);
- statusProgress.setValue(0);
- mainFrame.pack();
- return null;
+ failed = true;
+ logger.error("Could not find ripper for URL " + url);
+ error("Could not find ripper for given URL");
}
+ if (!failed) {
+ try {
+ ripTextfield.setText(ripper.getURL().toExternalForm());
+ status("Starting rip...");
+ ripper.setObserver((RipStatusHandler) this);
+ Thread t = new Thread(ripper);
+ t.start();
+ return t;
+ } catch (Exception e) {
+ logger.error("[!] Error while ripping: " + e.getMessage(), e);
+ error("Unable to rip this URL: " + e.getMessage());
+ }
+ }
+ ripButton.setEnabled(true);
+ ripTextfield.setEnabled(true);
+ statusProgress.setValue(0);
+ mainFrame.pack();
+ return null;
}
class RipButtonHandler implements ActionListener {
@@ -523,4 +596,9 @@ public class MainWindow implements Runnable, RipStatusHandler {
return false;
}
}
+
+ public static void ripAlbumStatic(String url) {
+ ripTextfield.setText(url);
+ ripButton.doClick();
+ }
}
\ No newline at end of file
diff --git a/src/main/resources/icon.ico b/src/main/resources/icon.ico
new file mode 100644
index 00000000..9ea980dd
Binary files /dev/null and b/src/main/resources/icon.ico differ
diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png
new file mode 100644
index 00000000..59192587
Binary files /dev/null and b/src/main/resources/icon.png differ
diff --git a/src/main/resources/rip.properties b/src/main/resources/rip.properties
index cb3240f8..020c464f 100644
--- a/src/main/resources/rip.properties
+++ b/src/main/resources/rip.properties
@@ -20,3 +20,5 @@ tumblr.auth = v5kUqGQXUtmF7K0itri1DGtgTs0VQpbSEbh1jxYgj9d2Sq18F8
gw.api = gonewild
twitter.max_requests = 10
+
+clipboard.autorip = false
\ No newline at end of file