Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions src/main/java/com/rarchives/ripme/ripper/rippers/Rule34Ripper.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,43 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

import com.rarchives.ripme.ripper.AbstractHTMLRipper;
import com.rarchives.ripme.ui.RipStatusMessage.STATUS;
import com.rarchives.ripme.utils.Http;
import com.rarchives.ripme.utils.Utils;

public class Rule34Ripper extends AbstractHTMLRipper {

private static final Logger logger = LogManager.getLogger(Rule34Ripper.class);
private static final String DOMAIN = "rule34.xxx";
private static final String API_BASE_URL = "https://" + DOMAIN + "/index.php";

public Rule34Ripper(URL url) throws IOException {
super(url);
}

private String apiUrl;
private int pageNumber = 0;
private String apiKey;
private String userId;

private void loadConfig() {
apiKey = Utils.getConfigString("rule34.api_key", "");
userId = Utils.getConfigString("rule34.user_id", "");
if (apiKey.isEmpty() || userId.isEmpty()) {
sendUpdate(STATUS.DOWNLOAD_WARN,
DOMAIN + " requires API credentials. Set rule34.api_key and rule34.user_id in config. "
+ "Get them from " + API_BASE_URL + "?page=account&s=options");
logger.warn("Missing rule34 API credentials. Requests may fail with 403.");
} else {
logger.info("Using rule34 API credentials for user_id: " + userId);
}
}

@Override
public String getHost() {
Expand All @@ -32,37 +55,43 @@ public String getHost() {

@Override
public String getDomain() {
return "rule34.xxx";
return DOMAIN;
}

@Override
public boolean canRip(URL url){
Pattern p = Pattern.compile("https?://rule34.xxx/index.php\\?page=post&s=list&tags=([\\S]+)");
Pattern p = Pattern.compile("https?://" + DOMAIN + "/index.php\\?page=post&s=list&tags=([\\S]+)");
Matcher m = p.matcher(url.toExternalForm());
return m.matches();
}

@Override
public String getGID(URL url) throws MalformedURLException {
Pattern p = Pattern.compile("https?://rule34.xxx/index.php\\?page=post&s=list&tags=([\\S]+)");
Pattern p = Pattern.compile("https?://" + DOMAIN + "/index.php\\?page=post&s=list&tags=([\\S]+)");
Matcher m = p.matcher(url.toExternalForm());
if (m.matches()) {
return m.group(1);
}
throw new MalformedURLException("Expected rule34.xxx URL format: " +
"rule34.xxx/index.php?page=post&s=list&tags=TAG - got " + url + " instead");
throw new MalformedURLException("Expected " + DOMAIN + " URL format: " +
DOMAIN + "/index.php?page=post&s=list&tags=TAG - got " + url + " instead");
}

public URL getAPIUrl() throws MalformedURLException, URISyntaxException {
URL urlToReturn = new URI("https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags=" + getGID(url)).toURL();
return urlToReturn;
if (apiKey == null || apiKey.isEmpty() || userId == null || userId.isEmpty()) {
throw new MalformedURLException(
DOMAIN + " requires API credentials. Set rule34.api_key and rule34.user_id in config. "
+ "Get them from " + API_BASE_URL + "?page=account&s=options");
}
String baseUrl = API_BASE_URL + "?page=dapi&s=post&q=index&limit=100&tags=" + getGID(url)
+ "&api_key=" + apiKey + "&user_id=" + userId;
return new URI(baseUrl).toURL();
}

@Override
public Document getFirstPage() throws IOException, URISyntaxException {
loadConfig();
apiUrl = getAPIUrl().toExternalForm();
// "url" is an instance field of the superclass
return Http.url(getAPIUrl()).get();
return Http.url(apiUrl).get();
}

@Override
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/rip.properties
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ twitter.auth = VW9Ybjdjb1pkd2J0U3kwTUh2VXVnOm9GTzVQVzNqM29LQU1xVGhnS3pFZzhKbGVqb
tumblr.auth = JFNLu3CbINQjRdUvZibXW9VpSEVYYtiPJ86o8YmvgLZIoKyuNX
gw.api = gonewild

# Rule34 API credentials - get from https://rule34.xxx/index.php?page=account&s=options
# rule34.api_key =
# rule34.user_id =

twitter.max_requests = 10
twitter.rip_retweets = false
twitter.exclude_replies = true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.rarchives.ripme.tst.ripper.rippers;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
Expand All @@ -10,11 +11,12 @@
import org.junit.jupiter.api.Test;

import com.rarchives.ripme.ripper.rippers.Rule34Ripper;
import com.rarchives.ripme.utils.Utils;

public class Rule34RipperTest extends RippersTest {
@Test
@Tag("flaky")
public void testShesFreakyRip() throws IOException, URISyntaxException {
public void testRule34Rip() throws IOException, URISyntaxException {
Rule34Ripper ripper = new Rule34Ripper(
new URI("https://rule34.xxx/index.php?page=post&s=list&tags=bimbo").toURL());
testRipper(ripper);
Expand All @@ -27,4 +29,46 @@ public void testGetGID() throws IOException, URISyntaxException {
Assertions.assertEquals("bimbo", ripper.getGID(url));
}

@Test
public void testGetAPIUrlWithCredentials() throws IOException, URISyntaxException {
Utils.setConfigString("rule34.api_key", "testapikey123");
Utils.setConfigString("rule34.user_id", "12345");
try {
URL url = new URI("https://rule34.xxx/index.php?page=post&s=list&tags=bimbo").toURL();
Rule34Ripper ripper = new Rule34Ripper(url);

// Trigger loadConfig() via getFirstPage(); HTTP call will fail in test env
try {
ripper.getFirstPage();
} catch (IOException e) {
// Expected in test environment
}

String apiUrlString = ripper.getAPIUrl().toExternalForm();
Assertions.assertTrue(apiUrlString.contains("api_key=testapikey123"),
"API URL should contain api_key parameter");
Assertions.assertTrue(apiUrlString.contains("user_id=12345"),
"API URL should contain user_id parameter");
} finally {
Utils.setConfigString("rule34.api_key", "");
Utils.setConfigString("rule34.user_id", "");
}
}

@Test
public void testGetAPIUrlThrowsWithoutCredentials() throws IOException, URISyntaxException {
Utils.setConfigString("rule34.api_key", "");
Utils.setConfigString("rule34.user_id", "");
try {
URL url = new URI("https://rule34.xxx/index.php?page=post&s=list&tags=bimbo").toURL();
Rule34Ripper ripper = new Rule34Ripper(url);

// Trigger loadConfig() via getFirstPage(); should throw due to missing credentials
Assertions.assertThrows(MalformedURLException.class, () -> ripper.getFirstPage(),
"getFirstPage should throw when API credentials are missing");
} finally {
Utils.setConfigString("rule34.api_key", "");
Utils.setConfigString("rule34.user_id", "");
}
}
}