Document *all* the things
This commit is contained in:
parent
8b7e471b1c
commit
43948fd320
@ -32,7 +32,6 @@ public abstract class AbstractRipper
|
|||||||
protected DownloadThreadPool threadPool;
|
protected DownloadThreadPool threadPool;
|
||||||
protected Observer observer = null;
|
protected Observer observer = null;
|
||||||
|
|
||||||
protected int itemsTotal;
|
|
||||||
protected Map<URL, File> itemsPending = new HashMap<URL, File>();
|
protected Map<URL, File> itemsPending = new HashMap<URL, File>();
|
||||||
protected Map<URL, File> itemsCompleted = new HashMap<URL, File>();
|
protected Map<URL, File> itemsCompleted = new HashMap<URL, File>();
|
||||||
protected Map<URL, String> itemsErrored = new HashMap<URL, String>();
|
protected Map<URL, String> itemsErrored = new HashMap<URL, String>();
|
||||||
@ -107,6 +106,15 @@ public abstract class AbstractRipper
|
|||||||
threadPool.addThread(new DownloadFileThread(url, saveAs, this));
|
threadPool.addThread(new DownloadFileThread(url, saveAs, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues file to be downloaded and saved. With options.
|
||||||
|
* @param url
|
||||||
|
* URL to download.
|
||||||
|
* @param prefix
|
||||||
|
* Prefix to prepend to the saved filename.
|
||||||
|
* @param subdirectory
|
||||||
|
* Sub-directory of the working directory to save the images to.
|
||||||
|
*/
|
||||||
public void addURLToDownload(URL url, String prefix, String subdirectory) {
|
public void addURLToDownload(URL url, String prefix, String subdirectory) {
|
||||||
String saveAs = url.toExternalForm();
|
String saveAs = url.toExternalForm();
|
||||||
saveAs = saveAs.substring(saveAs.lastIndexOf('/')+1);
|
saveAs = saveAs.substring(saveAs.lastIndexOf('/')+1);
|
||||||
@ -137,17 +145,32 @@ public abstract class AbstractRipper
|
|||||||
addURLToDownload(url, saveFileAs);
|
addURLToDownload(url, saveFileAs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for downloading threads to complete.
|
||||||
|
*/
|
||||||
protected void waitForThreads() {
|
protected void waitForThreads() {
|
||||||
completed = false;
|
completed = false;
|
||||||
threadPool.waitForThreads();
|
threadPool.waitForThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies observers that source is being retrieved.
|
||||||
|
* @param url
|
||||||
|
* URL being retrieved
|
||||||
|
*/
|
||||||
public void retrievingSource(URL url) {
|
public void retrievingSource(URL url) {
|
||||||
RipStatusMessage msg = new RipStatusMessage(STATUS.LOADING_RESOURCE, url);
|
RipStatusMessage msg = new RipStatusMessage(STATUS.LOADING_RESOURCE, url);
|
||||||
observer.update(this, msg);
|
observer.update(this, msg);
|
||||||
observer.notifyAll();
|
observer.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies observers that a file download has completed.
|
||||||
|
* @param url
|
||||||
|
* URL that was completed.
|
||||||
|
* @param saveAs
|
||||||
|
* Where the downloaded file is stored.
|
||||||
|
*/
|
||||||
public void downloadCompleted(URL url, File saveAs) {
|
public void downloadCompleted(URL url, File saveAs) {
|
||||||
if (observer == null) {
|
if (observer == null) {
|
||||||
return;
|
return;
|
||||||
@ -167,6 +190,11 @@ public abstract class AbstractRipper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies observers that a file could not be downloaded (includes a reason).
|
||||||
|
* @param url
|
||||||
|
* @param reason
|
||||||
|
*/
|
||||||
public void downloadErrored(URL url, String reason) {
|
public void downloadErrored(URL url, String reason) {
|
||||||
if (observer == null) {
|
if (observer == null) {
|
||||||
return;
|
return;
|
||||||
@ -180,6 +208,12 @@ public abstract class AbstractRipper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify observers that a download could not be completed,
|
||||||
|
* but was not technically an "error".
|
||||||
|
* @param url
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
public void downloadProblem(URL url, String message) {
|
public void downloadProblem(URL url, String message) {
|
||||||
if (observer == null) {
|
if (observer == null) {
|
||||||
return;
|
return;
|
||||||
@ -193,6 +227,9 @@ public abstract class AbstractRipper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies observers and updates state if all files have been ripped.
|
||||||
|
*/
|
||||||
private void checkIfComplete() {
|
private void checkIfComplete() {
|
||||||
if (!completed && itemsPending.size() == 0) {
|
if (!completed && itemsPending.size() == 0) {
|
||||||
completed = true;
|
completed = true;
|
||||||
@ -209,10 +246,20 @@ public abstract class AbstractRipper
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* Path to the directory in which all files
|
||||||
|
* ripped via this ripper will be stored.
|
||||||
|
*/
|
||||||
public File getWorkingDir() {
|
public File getWorkingDir() {
|
||||||
return workingDir;
|
return workingDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets directory to save all ripped files to.
|
||||||
|
* @param url
|
||||||
|
* URL to define how the workin directory should be saved.
|
||||||
|
*/
|
||||||
public void setWorkingDir(URL url) throws IOException {
|
public void setWorkingDir(URL url) throws IOException {
|
||||||
String path = Utils.getWorkingDirectory().getCanonicalPath();
|
String path = Utils.getWorkingDirectory().getCanonicalPath();
|
||||||
if (!path.endsWith(File.separator)) {
|
if (!path.endsWith(File.separator)) {
|
||||||
@ -243,12 +290,16 @@ public abstract class AbstractRipper
|
|||||||
return ripper;
|
return ripper;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Incompatible rippers *will* throw exceptions during instantiation.
|
// Incompatible rippers *will* throw exceptions during instantiation.
|
||||||
//logger.error("Exception while instantiating: " + constructor.getName(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Exception("No compatible ripper found");
|
throw new Exception("No compatible ripper found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* List of constructors for all eligible Rippers.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
private static List<Constructor<?>> getRipperConstructors() throws Exception {
|
private static List<Constructor<?>> getRipperConstructors() throws Exception {
|
||||||
List<Constructor<?>> constructors = new ArrayList<Constructor<?>>();
|
List<Constructor<?>> constructors = new ArrayList<Constructor<?>>();
|
||||||
for (Class<?> clazz : Utils.getClassesForPackage("com.rarchives.ripme.ripper.rippers")) {
|
for (Class<?> clazz : Utils.getClassesForPackage("com.rarchives.ripme.ripper.rippers")) {
|
||||||
@ -259,6 +310,11 @@ public abstract class AbstractRipper
|
|||||||
return constructors;
|
return constructors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an update message to the relevant observer(s) on this ripper.
|
||||||
|
* @param status
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
public void sendUpdate(STATUS status, Object message) {
|
public void sendUpdate(STATUS status, Object message) {
|
||||||
if (observer == null) {
|
if (observer == null) {
|
||||||
return;
|
return;
|
||||||
@ -269,11 +325,19 @@ public abstract class AbstractRipper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* Integer between 0 and 100 defining the progress of the album rip.
|
||||||
|
*/
|
||||||
public int getCompletionPercentage() {
|
public int getCompletionPercentage() {
|
||||||
double total = itemsPending.size() + itemsErrored.size() + itemsCompleted.size();
|
double total = itemsPending.size() + itemsErrored.size() + itemsCompleted.size();
|
||||||
return (int) (100 * ( (total - itemsPending.size()) / total));
|
return (int) (100 * ( (total - itemsPending.size()) / total));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* Human-readable information on the status of the current rip.
|
||||||
|
*/
|
||||||
public String getStatusText() {
|
public String getStatusText() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(getCompletionPercentage())
|
sb.append(getCompletionPercentage())
|
||||||
@ -284,6 +348,9 @@ public abstract class AbstractRipper
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rips the album when the thread is invoked.
|
||||||
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
rip();
|
rip();
|
||||||
|
@ -12,6 +12,10 @@ import org.jsoup.Jsoup;
|
|||||||
import com.rarchives.ripme.ui.RipStatusMessage.STATUS;
|
import com.rarchives.ripme.ui.RipStatusMessage.STATUS;
|
||||||
import com.rarchives.ripme.utils.Utils;
|
import com.rarchives.ripme.utils.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread for downloading files.
|
||||||
|
* Includes retry logic, observer notifications, and other goodies.
|
||||||
|
*/
|
||||||
public class DownloadFileThread extends Thread {
|
public class DownloadFileThread extends Thread {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DownloadFileThread.class);
|
private static final Logger logger = Logger.getLogger(DownloadFileThread.class);
|
||||||
@ -31,8 +35,11 @@ public class DownloadFileThread extends Thread {
|
|||||||
this.retries = Utils.getConfigInteger("download.retries", 1);
|
this.retries = Utils.getConfigInteger("download.retries", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to download the file. Retries as needed.
|
||||||
|
* Notifies observers upon completion/error/warn.
|
||||||
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
// Check if file already exists
|
|
||||||
if (saveAs.exists()) {
|
if (saveAs.exists()) {
|
||||||
if (Utils.getConfigBoolean("file.overwrite", false)) {
|
if (Utils.getConfigBoolean("file.overwrite", false)) {
|
||||||
logger.info("[!] Deleting existing file" + prettySaveAs);
|
logger.info("[!] Deleting existing file" + prettySaveAs);
|
||||||
|
@ -8,6 +8,9 @@ import org.apache.log4j.Logger;
|
|||||||
|
|
||||||
import com.rarchives.ripme.utils.Utils;
|
import com.rarchives.ripme.utils.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple wrapper around a FixedThreadPool.
|
||||||
|
*/
|
||||||
public class DownloadThreadPool {
|
public class DownloadThreadPool {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DownloadThreadPool.class);
|
private static final Logger logger = Logger.getLogger(DownloadThreadPool.class);
|
||||||
@ -34,9 +37,10 @@ public class DownloadThreadPool {
|
|||||||
public void waitForThreads() {
|
public void waitForThreads() {
|
||||||
threadPool.shutdown();
|
threadPool.shutdown();
|
||||||
try {
|
try {
|
||||||
threadPool.awaitTermination(60, TimeUnit.SECONDS);
|
// XXX What if some rips take longer than 120 seconds to complete?
|
||||||
|
threadPool.awaitTermination(120, TimeUnit.SECONDS);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.error("Interrupted while waiting for threads to finish: ", e);
|
logger.error("[!] Interrupted while waiting for threads to finish: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,10 @@ import java.io.IOException;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I have no idea why I made this interface. Everything is captured within the AbstractRipper.
|
||||||
|
* Oh well, here's to encapsulation and abstraction! (raises glass)
|
||||||
|
*/
|
||||||
public interface RipperInterface {
|
public interface RipperInterface {
|
||||||
public void rip() throws IOException;
|
public void rip() throws IOException;
|
||||||
public boolean canRip(URL url);
|
public boolean canRip(URL url);
|
||||||
|
@ -43,6 +43,9 @@ import org.apache.log4j.Logger;
|
|||||||
import com.rarchives.ripme.ripper.AbstractRipper;
|
import com.rarchives.ripme.ripper.AbstractRipper;
|
||||||
import com.rarchives.ripme.utils.Utils;
|
import com.rarchives.ripme.utils.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Everything UI-related starts and ends here.
|
||||||
|
*/
|
||||||
public class MainWindow implements Runnable {
|
public class MainWindow implements Runnable {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(MainWindow.class);
|
private static final Logger logger = Logger.getLogger(MainWindow.class);
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.rarchives.ripme.ui;
|
package com.rarchives.ripme.ui;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains information about downloaded files and rips, and their states.
|
||||||
|
*/
|
||||||
public class RipStatusMessage {
|
public class RipStatusMessage {
|
||||||
|
|
||||||
public enum STATUS {
|
public enum STATUS {
|
||||||
|
@ -14,9 +14,12 @@ import org.apache.commons.configuration.ConfigurationException;
|
|||||||
import org.apache.commons.configuration.PropertiesConfiguration;
|
import org.apache.commons.configuration.PropertiesConfiguration;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common utility functions used in various places throughout the project.
|
||||||
|
*/
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
public static final String RIP_DIRECTORY = "rips";
|
public static final String RIP_DIRECTORY = "rips";
|
||||||
private static final File configFile = new File("src/main/resources/rip.properties");
|
private static final File configFile = new File("src/main/resources/rip.properties");
|
||||||
private static final Logger logger = Logger.getLogger(Utils.class);
|
private static final Logger logger = Logger.getLogger(Utils.class);
|
||||||
|
|
||||||
@ -29,6 +32,12 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the root rips directory.
|
||||||
|
* @return
|
||||||
|
* Root directory to save rips to.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public static File getWorkingDirectory() throws IOException {
|
public static File getWorkingDirectory() throws IOException {
|
||||||
String path = new File(".").getCanonicalPath() + File.separator;
|
String path = new File(".").getCanonicalPath() + File.separator;
|
||||||
path += RIP_DIRECTORY + File.separator;
|
path += RIP_DIRECTORY + File.separator;
|
||||||
@ -75,10 +84,25 @@ public class Utils {
|
|||||||
return prettySaveAs;
|
return prettySaveAs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the current working directory from a given filename
|
||||||
|
* @param file
|
||||||
|
* @return
|
||||||
|
* 'file' without the leading current working directory
|
||||||
|
*/
|
||||||
public static String removeCWD(String file) {
|
public static String removeCWD(String file) {
|
||||||
return removeCWD(new File(file));
|
return removeCWD(new File(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all Classes within a package.
|
||||||
|
* Works with file system projects and jar files!
|
||||||
|
* Borrowed from StackOverflow, but I don't have a link :[
|
||||||
|
* @param pkgname
|
||||||
|
* The name of the package
|
||||||
|
* @return
|
||||||
|
* List of classes within the package
|
||||||
|
*/
|
||||||
public static ArrayList<Class<?>> getClassesForPackage(String pkgname) {
|
public static ArrayList<Class<?>> getClassesForPackage(String pkgname) {
|
||||||
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
|
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
|
||||||
String relPath = pkgname.replace('.', '/');
|
String relPath = pkgname.replace('.', '/');
|
||||||
|
Loading…
Reference in New Issue
Block a user