diff --git a/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java b/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java index f680d8c4..1bc9f261 100644 --- a/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java @@ -42,6 +42,21 @@ public abstract class AbstractRipper public abstract String getHost(); public abstract String getGID(URL url) throws MalformedURLException; + private boolean shouldStop = false; + + public void stop() { + shouldStop = true; + } + public boolean isStopped() { + return shouldStop; + } + protected void stopCheck() throws IOException { + if (shouldStop) { + threadPool.waitForThreads(); + throw new IOException("Ripping interrupted"); + } + } + /** * Ensures inheriting ripper can rip this URL, raises exception if not. * Otherwise initializes working directory and thread pool. @@ -117,6 +132,11 @@ public abstract class AbstractRipper * Sub-directory of the working directory to save the images to. */ public void addURLToDownload(URL url, String prefix, String subdirectory) { + try { + stopCheck(); + } catch (IOException e) { + return; + } String saveAs = url.toExternalForm(); saveAs = saveAs.substring(saveAs.lastIndexOf('/')+1); if (saveAs.indexOf('?') >= 0) { saveAs = saveAs.substring(0, saveAs.indexOf('?')); } diff --git a/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java b/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java index eef29c40..8fdc2133 100644 --- a/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java +++ b/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java @@ -45,6 +45,12 @@ public class DownloadFileThread extends Thread { * Notifies observers upon completion/error/warn. */ public void run() { + try { + observer.stopCheck(); + } catch (IOException e) { + observer.downloadErrored(url, "Download interrupted"); + return; + } if (saveAs.exists()) { if (Utils.getConfigBoolean("file.overwrite", false)) { logger.info("[!] Deleting existing file" + prettySaveAs); diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/ImgurRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/ImgurRipper.java index 90061bf0..693f7729 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/ImgurRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/ImgurRipper.java @@ -100,6 +100,7 @@ public class ImgurRipper extends AbstractRipper { index = 0; ImgurAlbum album = getImgurAlbum(url); for (ImgurImage imgurImage : album.images) { + stopCheck(); String saveAs = workingDir.getCanonicalPath(); if (!saveAs.endsWith(File.separator)) { saveAs += File.separator; @@ -217,6 +218,7 @@ public class ImgurRipper extends AbstractRipper { logger.info("[ ] Retrieving " + url.toExternalForm()); Document doc = Jsoup.connect(url.toExternalForm()).get(); for (Element album : doc.select("div.cover a")) { + stopCheck(); if (!album.hasAttr("href") || !album.attr("href").contains("imgur.com/a/")) { continue; @@ -236,6 +238,7 @@ public class ImgurRipper extends AbstractRipper { private void ripSubreddit(URL url) throws IOException { int page = 0; while (true) { + stopCheck(); String pageURL = url.toExternalForm(); if (!pageURL.endsWith("/")) { pageURL += "/"; diff --git a/src/main/java/com/rarchives/ripme/ui/MainWindow.java b/src/main/java/com/rarchives/ripme/ui/MainWindow.java index 5610b850..d83f07ad 100644 --- a/src/main/java/com/rarchives/ripme/ui/MainWindow.java +++ b/src/main/java/com/rarchives/ripme/ui/MainWindow.java @@ -22,7 +22,6 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.awt.image.BufferedImage; import java.io.File; import java.net.MalformedURLException; import java.net.URL; @@ -30,7 +29,6 @@ import java.util.Arrays; import javax.imageio.ImageIO; import javax.swing.DefaultListModel; -import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -67,7 +65,8 @@ public class MainWindow implements Runnable, RipStatusHandler { private static JFrame mainFrame; private static JTextField ripTextfield; - private static JButton ripButton; + private static JButton ripButton, + stopButton; private static JLabel statusLabel; private static JButton openButton; @@ -198,14 +197,21 @@ public class MainWindow implements Runnable, RipStatusHandler { } ripTextfield = new JTextField("", 20); - ImageIcon ripIcon = new ImageIcon(mainIcon.getScaledInstance(20, 20, Image.SCALE_SMOOTH)); + 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); @@ -329,6 +335,23 @@ public class MainWindow implements Runnable, RipStatusHandler { private void setupHandlers() { ripButton.addActionListener(new RipButtonHandler()); ripTextfield.addActionListener(new RipButtonHandler()); + 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); + mainFrame.pack(); + statusProgress.setValue(0); + status("Ripping interrupted"); + appendLog("Ripper interrupted", Color.RED); + } + } + }); optionLog.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { @@ -574,7 +597,8 @@ public class MainWindow implements Runnable, RipStatusHandler { error("Given URL is not valid, expecting http://website.com/page/..."); return null; } - ripButton.setEnabled(false); + ripButton.setVisible(false); + stopButton.setVisible(true); ripTextfield.setEnabled(false); statusProgress.setValue(100); openButton.setVisible(false); @@ -612,7 +636,8 @@ public class MainWindow implements Runnable, RipStatusHandler { error("Unable to rip this URL: " + e.getMessage()); } } - ripButton.setEnabled(true); + ripButton.setVisible(true); + stopButton.setVisible(false); ripTextfield.setEnabled(true); statusProgress.setValue(0); mainFrame.pack(); @@ -640,6 +665,9 @@ public class MainWindow implements Runnable, RipStatusHandler { } private void handleEvent(StatusEvent evt) { + if (ripper.isStopped()) { + return; + } RipStatusMessage msg = evt.msg; int completedPercent = evt.ripper.getCompletionPercentage(); @@ -667,7 +695,8 @@ public class MainWindow implements Runnable, RipStatusHandler { historyListModel.addElement(ripTextfield.getText()); } saveHistory(); - ripButton.setEnabled(true); + ripButton.setVisible(true); + stopButton.setVisible(false); ripTextfield.setEnabled(true); statusProgress.setValue(0); statusProgress.setVisible(false); @@ -678,9 +707,7 @@ public class MainWindow implements Runnable, RipStatusHandler { try { Image folderIcon = ImageIO.read(getClass().getClassLoader().getResource("folder.png")); openButton.setIcon(new ImageIcon(folderIcon)); - } catch (Exception e) { - logger.error("Error while setting folder icon", e); - } + } catch (Exception e) { } appendLog( "Rip complete, saved to " + prettyFile, Color.GREEN); openButton.setActionCommand(f.toString()); openButton.addActionListener(new ActionListener() { diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png index 59192587..606ae39b 100644 Binary files a/src/main/resources/icon.png and b/src/main/resources/icon.png differ diff --git a/src/main/resources/stop.png b/src/main/resources/stop.png new file mode 100644 index 00000000..aba7a52c Binary files /dev/null and b/src/main/resources/stop.png differ