From a82ac148448dd6cebfcbbd386c270a5c28ee66b9 Mon Sep 17 00:00:00 2001 From: 4pr0n Date: Sun, 6 Apr 2014 17:26:30 -0700 Subject: [PATCH] Added icons, SystemTray menu, clipboard autorip --- pom.xml | 2 +- .../rarchives/ripme/ui/ClipboardUtils.java | 89 +++++++++++++ .../com/rarchives/ripme/ui/MainWindow.java | 126 ++++++++++++++---- src/main/resources/icon.ico | Bin 0 -> 4286 bytes src/main/resources/icon.png | Bin 0 -> 1381 bytes src/main/resources/rip.properties | 2 + 6 files changed, 194 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/rarchives/ripme/ui/ClipboardUtils.java create mode 100644 src/main/resources/icon.ico create mode 100644 src/main/resources/icon.png 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 0000000000000000000000000000000000000000..9ea980ddc26dcafb74135472a7d7f9279a375e32 GIT binary patch literal 4286 zcmds4OGsT;6umFnXydPgBuGoDZIheT<`N~{RB#nEcdxMo4rk~VUdEu}*ilAid!;+7RK6h3nYa|M zRsI5-Gvre1j>>EH0bdcoUw}kKMH%3;0(E#+wRn!_3+DC5j3HC;n55mosbbO9yTfJ+ zGVCzC4<0fGwi0Prx$=7;3bd_ z_yC@OH{cJuvoQ2joQ#9uyOYTBfOXrz3#t{5GBLlyX1JlDL2lf*p#zk=P*PIz=j7z1 z57ycguUXRPty{O=t*)+?^73-2sHiYNKUGy#0%*1NJz*oACZxfI%1Rl{(c!89PA_~ zW8gqMQ5_u}l9-sNM?^$8d)mA=#^d0Rz!Kg+E_U=)TU&dvprAm)!^3yYvp(n>$;->r zySuw(b#?Uv+Hnjp?y>lBZPpLO(AVIaGiN9E-w1P-?`DzQDZOG{Hs{G$E>U@>Fev0 zsi~>A>0^F={{5bwo}XDa?B9Bi81FMc4E)}O$vNw@$`^3Zq&xEm!Cr_RPWBqgX7<<*ahVP-Fp>p-=RmsfEH1^1N2-c3e zjEoHC(CGWU)>Fs)#>dA?b91xYzkmNrlAB_92X*Jprl z5XEbiGcz+k9f#k+Wz?GWAlTRJo%Z(jS2#cMqCQzP_HaA2;W4jwo3fb;ebrY?qgpKVdBz8yf|mEfNfQ7W3|R3E^f2HV vXuEwn!nWeIWn1xB(KfNEEqpH|wl&QI@B#wxgDgnb;75bM+wi*r4%7G>cfM4I literal 0 HcmV?d00001 diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..59192587bb81dc9c752301b5927d3d1177987322 GIT binary patch literal 1381 zcmV-r1)BPaP)qn0sT{KN|i;ZpDIC0{{=KxNZZCE%Qrd^+a1AhDV?SWJ(m0Vd_K{A;{KA$JIon=`x zFfhObK}ZLK!NR3WmwI+Wg4F}RdGlsZCX-pdapMN1(`hCM0vLPSgot3OlI-=_3Nc{I?W|X+IBa#ZIj>cXXnqKzw7mSr}FuHi)-2p z27^nLB&wc3EEbzwSy_pws#?-@oy)S^P&|nU0BCr4nDzJf!?LV5bDVRWJb7}+@Auzx zlMrh-`u_3b$Fvi00AP%Ph*&b2#M07|LkIw{XU`tkwmpC6&YjQve*c_9qE;4ch@!ZU zbH4MuW(<~PA)C!sj#D%m{Qy90VPWAyAQ1R55{ZCUD<+(C+D*}7jDd5$r2}BPu9K>& z;_~wH!ra{4$Ki1JUkx}%a_iQudx=D1aDILsqA0%iifWoBy1TneQ&Us?z<~q%xEuWb z{rjD-UcGA0<#G@Np_bC?_EM>|?deF8#05b>M@L6qbb%j9rBd^WMB>T>%knp@T;q@Fx_&p2NF09l z>>2&zb1S}OSvY?DI6|Qian4yHk?3n{YugLJ%x1I2(b3Ug7-QJn+$=?-QLgKH%~LEC z3h3?aEnU8RnTr4*ilRhBhu7EFiHKM=^%D`Ao13wJ|9N=t*3OYJEYBH~AO=WOLaU}pR#>dBv znVFgPTE&ZqAW0Gq9z4hxW6uHD8~`>pHoT^3!Y~YKfIvS0!_id57kzzwE!BLKcaEb+ zkJ9k)FgiOsClp2bivxfl2v1vDTE07X?i`b4nM~6}Wp~x}Uja~^G&7xSaN83R4Gs=M zQ4}W2@=UQ<{2c(qNF;)>v9UaWuT)j_SeErgHk+kt7Zqcy06+#{)goXR2DP@fVrXdS zjTTJPL{n1}8yy|}xxKx8B$vyXV`F25NF?%hB~(>)4#0(ST*Cks02Ip?mrO)*I2_KM zIdjHzi;alz@ZrO%>Qhy<0AO`;a6 zX_{EM{=E=z6DfzT06=mP$!VI_+9>cl6L1kZ1V97O1z=Irw9`8UZ%Bl7!m$S6QvlNd n`~Y?gzN=QL?(Nk6pKX5wcBGug3O-ZU00000NkvXXu0mjfMYw#w literal 0 HcmV?d00001 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