diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/RedditRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/RedditRipper.java index e3d919dfd..e265e9e62 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/RedditRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/RedditRipper.java @@ -254,8 +254,9 @@ else if (kind.equals("t3")) { } else if (!data.isNull("gallery_data") && !data.isNull("media_metadata")) { handleGallery(data.getJSONObject("gallery_data").getJSONArray("items"), data.getJSONObject("media_metadata"), data.getString("id"), data.getString("title")); } else { - // Get link - handleURL(data.getString("url"), data.getString("id"), data.getString("title")); + // Reddit may set url to a still-image preview for video posts. Prefer + // the actual video URL when Reddit exposes it in secure_media. + handleURL(getPostMediaURL(data), data.getString("id"), data.getString("title")); } if (data.has("replies") && data.get("replies") instanceof JSONObject) { JSONArray replies = data.getJSONObject("replies") @@ -268,6 +269,22 @@ else if (kind.equals("t3")) { } } + private String getPostMediaURL(JSONObject data) { + if (data.optBoolean("is_video", false)) { + JSONObject secureMedia = data.optJSONObject("secure_media"); + if (secureMedia != null) { + JSONObject redditVideo = secureMedia.optJSONObject("reddit_video"); + if (redditVideo != null) { + String fallbackUrl = redditVideo.optString("fallback_url", ""); + if (!fallbackUrl.isEmpty()) { + return fallbackUrl; + } + } + } + } + return data.getString("url"); + } + private void handleBody(String body, String id, String title) { Pattern p = RipUtils.getURLRegex(); Matcher m = p.matcher(body); diff --git a/src/test/java/com/rarchives/ripme/tst/ripper/rippers/RedditRipperTest.java b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/RedditRipperTest.java index ae64055d0..ba59983d6 100644 --- a/src/test/java/com/rarchives/ripme/tst/ripper/rippers/RedditRipperTest.java +++ b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/RedditRipperTest.java @@ -9,6 +9,8 @@ import java.nio.file.Files; import java.nio.file.Path; +import org.json.JSONObject; + import com.rarchives.ripme.ripper.rippers.RedditRipper; import org.junit.jupiter.api.Assertions; @@ -20,6 +22,35 @@ public class RedditRipperTest extends RippersTest { + @Test + public void testVideoPostUsesRedditVideoURLInsteadOfPreview() throws Exception { + RedditRipper ripper = new RedditRipper(new URI("https://www.reddit.com/r/test/").toURL()); + Method getPostMediaURL = RedditRipper.class.getDeclaredMethod("getPostMediaURL", JSONObject.class); + getPostMediaURL.setAccessible(true); + + JSONObject post = new JSONObject("{" + + "\"url\":\"https://preview.redd.it/still-image.jpg\"," + + "\"is_video\":true," + + "\"secure_media\":{" + + "\"reddit_video\":{" + + "\"fallback_url\":\"https://v.redd.it/example/DASH_720.mp4?source=fallback\"" + + "}}}"); + + Assertions.assertEquals("https://v.redd.it/example/DASH_720.mp4?source=fallback", + getPostMediaURL.invoke(ripper, post)); + } + + @Test + public void testNonVideoPostKeepsOriginalURL() throws Exception { + RedditRipper ripper = new RedditRipper(new URI("https://www.reddit.com/r/test/").toURL()); + Method getPostMediaURL = RedditRipper.class.getDeclaredMethod("getPostMediaURL", JSONObject.class); + getPostMediaURL.setAccessible(true); + + JSONObject post = new JSONObject("{\"url\":\"https://i.imgur.com/image.jpg\"}"); + + Assertions.assertEquals("https://i.imgur.com/image.jpg", getPostMediaURL.invoke(ripper, post)); + } + @Test @Tag("flaky") // https://github.com/RipMeApp/ripme/issues/253 public void testRedditSubredditRip() throws IOException, URISyntaxException {