diff --git a/pom.xml b/pom.xml index fee9c304..b4cc8d00 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rarchives.ripme ripme jar - 1.0.56 + 1.0.57 ripme http://rip.rarchives.com diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java new file mode 100644 index 00000000..4159bafd --- /dev/null +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java @@ -0,0 +1,192 @@ +package com.rarchives.ripme.ripper.rippers; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import com.rarchives.ripme.ripper.AlbumRipper; +import com.rarchives.ripme.ripper.DownloadThreadPool; +import com.rarchives.ripme.ui.RipStatusMessage.STATUS; +import com.rarchives.ripme.utils.Utils; + +public class NfsfwRipper extends AlbumRipper { + + private static final String DOMAIN = "nfsfw.com", + HOST = "nfsfw"; + private static final Logger logger = Logger.getLogger(NfsfwRipper.class); + + private Document albumDoc = null; + + private DownloadThreadPool nfsfwThreadPool; + + public NfsfwRipper(URL url) throws IOException { + super(url); + nfsfwThreadPool = new DownloadThreadPool("NFSFW"); + } + + @Override + public String getHost() { + return HOST; + } + + @Override + public URL sanitizeURL(URL url) throws MalformedURLException { + return url; + } + + @Override + public String getAlbumTitle(URL url) throws MalformedURLException { + try { + // Attempt to use album title as GID + if (albumDoc == null) { + albumDoc = Jsoup.connect(url.toExternalForm()) + .userAgent(USER_AGENT) + .get(); + } + String title = albumDoc.select("h2").first().text().trim(); + return "nfsfw_" + Utils.filesystemSafe(title); + } catch (Exception e) { + // Fall back to default album naming convention + } + return super.getAlbumTitle(url); + } + + @Override + public String getGID(URL url) throws MalformedURLException { + Pattern p; Matcher m; + + p = Pattern.compile("https?://[wm.]*nfsfw.com/gallery/v/([a-zA-Z0-9\\-_]+).*"); + m = p.matcher(url.toExternalForm()); + if (m.matches()) { + return m.group(1); + } + + throw new MalformedURLException( + "Expected nfsfw.com gallery format: " + + "nfsfw.com/v/albumname" + + " Got: " + url); + } + + @Override + public void rip() throws IOException { + List subAlbums = new ArrayList(); + int index = 0; + subAlbums.add(new Pair(this.url.toExternalForm(), "")); + while (subAlbums.size() > 0) { + if (isStopped()) { + break; + } + Pair nextAlbum = subAlbums.remove(0); + String nextURL = nextAlbum.first; + String nextSubalbum = nextAlbum.second; + sendUpdate(STATUS.LOADING_RESOURCE, nextURL); + logger.info(" Retrieving " + nextURL); + if (albumDoc == null) { + albumDoc = Jsoup.connect(nextURL) + .userAgent(USER_AGENT) + .get(); + } + // Subalbums + for (Element suba : albumDoc.select("td.IMG > a")) { + String subURL = "http://nfsfw.com" + suba.attr("href"); + String subdir = subURL; + while (subdir.endsWith("/")) { + subdir = subdir.substring(0, subdir.length() - 1); + } + subdir = subdir.substring(subdir.lastIndexOf("/") + 1); + subAlbums.add(new Pair(subURL, subdir)); + } + // Images + for (Element thumb : albumDoc.select("td.giItemCell > div > a")) { + String imagePage = "http://nfsfw.com" + thumb.attr("href"); + try { + NfsfwImageThread t = new NfsfwImageThread(new URL(imagePage), nextSubalbum, ++index); + nfsfwThreadPool.addThread(t); + } catch (MalformedURLException mue) { + logger.warn("Invalid URL: " + imagePage); + } + } + // Get next page + for (Element a : albumDoc.select("a.next")) { + subAlbums.add(0, new Pair("http://nfsfw.com" + a.attr("href"), "")); + break; + } + // Insert next page at the top + albumDoc = null; + // Wait + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.error("Interrupted while waiting to load next page", e); + throw new IOException(e); + } + } + nfsfwThreadPool.waitForThreads(); + waitForThreads(); + } + + public boolean canRip(URL url) { + return url.getHost().endsWith(DOMAIN); + } + + /** + * Helper class to find and download images found on "image" pages + */ + private class NfsfwImageThread extends Thread { + private URL url; + private String subdir; + private int index; + + public NfsfwImageThread(URL url, String subdir, int index) { + super(); + this.url = url; + this.subdir = subdir; + this.index = index; + } + + @Override + public void run() { + try { + Document doc = Jsoup.connect(this.url.toExternalForm()) + .userAgent(USER_AGENT) + .timeout(5000) + .referrer(this.url.toExternalForm()) + .get(); + Elements images = doc.select(".gbBlock img"); + if (images.size() == 0) { + logger.error("Failed to find image at " + this.url); + return; + } + String file = images.first().attr("src"); + if (file.startsWith("/")) { + file = "http://nfsfw.com" + file; + } + String prefix = ""; + if (Utils.getConfigBoolean("download.save_order", true)) { + prefix = String.format("%03d_", index); + } + addURLToDownload(new URL(file), prefix, this.subdir); + } catch (IOException e) { + logger.error("[!] Exception while loading/parsing " + this.url, e); + } + } + } + + private class Pair { + public String first, second; + public Pair(String first, String second) { + this.first = first; + this.second = second; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java b/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java index 853ee43a..212a379c 100644 --- a/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java +++ b/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java @@ -21,7 +21,7 @@ import com.rarchives.ripme.utils.Utils; public class UpdateUtils { private static final Logger logger = Logger.getLogger(UpdateUtils.class); - private static final String DEFAULT_VERSION = "1.0.56"; + private static final String DEFAULT_VERSION = "1.0.57"; private static final String updateJsonURL = "http://rarchives.com/ripme.json"; private static final String updateJarURL = "http://rarchives.com/ripme.jar"; private static final String mainFileName = "ripme.jar";