From 7ef4bff5c8c73f811227760bb737af8c1a8193f2 Mon Sep 17 00:00:00 2001 From: Jpsoaresfig Date: Mon, 12 Jan 2026 18:43:47 -0300 Subject: [PATCH] Fix RedGIFs 401 errors by refreshing expired auth token --- .../ripme/ripper/rippers/RedgifsRipper.java | 62 +++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/RedgifsRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/RedgifsRipper.java index d9657f273..8c64a5e3d 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/RedgifsRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/RedgifsRipper.java @@ -133,7 +133,7 @@ public JSONObject getFirstPage() throws IOException { @Override public void downloadURL(URL url, int index) { - // redgifs is easy to trigger rate limit, so be a little cautious + // redgifs is easy to trigger rate limit, so be a little cautious sleep(3000); addURLToDownload(url, getPrefix(index)); } @@ -276,34 +276,45 @@ private static List getURLsForGallery(String galleryID, String gifID) { */ public static String getVideoURL(URL url) throws IOException, URISyntaxException { logger.info("Retrieving " + url.toExternalForm()); + var m = SINGLETON_PATTERN.matcher(url.toExternalForm()); if (!m.matches()) { throw new IOException(String.format("Cannot fetch redgif url %s", url.toExternalForm())); } + + var gid = m.group(1).split("-")[0]; + var gifDetailsURL = String.format(GIFS_DETAIL_ENDPOINT, gid); + if (authToken == null || authToken.isBlank()) { fetchAuthToken(); } - var gid = m.group(1).split("-")[0]; - var gifDetailsURL = String.format(GIFS_DETAIL_ENDPOINT, gid); - var json = Http.url(gifDetailsURL).header("Authorization", "Bearer " + authToken).getJSON(); + + try { + return fetchGifUrl(gifDetailsURL, url); + } catch (org.jsoup.HttpStatusException e) { + if (e.getStatusCode() == 401) { + logger.warn("RedGIFs token expired, refreshing token and retrying..."); + fetchAuthToken(); + return fetchGifUrl(gifDetailsURL, url); + } + throw e; + } + } + + private static String fetchGifUrl(String gifDetailsURL, URL originalUrl) + throws IOException, URISyntaxException { + + var json = Http.url(gifDetailsURL) + .header("Authorization", "Bearer " + authToken) + .getJSON(); + var gif = json.getJSONObject("gif"); + if (!gif.isNull("gallery")) { - // TODO check how to handle a image gallery - throw new IOException(String.format("Multiple images found for url %s", url)); + throw new IOException(String.format("Multiple images found for url %s", originalUrl)); } - return gif.getJSONObject("urls").getString("hd"); - } - /** - * Fetch a temorary auth token for the rip - * - * @throws IOException - */ - private static void fetchAuthToken() throws IOException { - var json = Http.url(TEMPORARY_AUTH_ENDPOINT).getJSON(); - var token = json.getString("token"); - authToken = token; - logger.info("Incase of redgif 401 errors, please restart the app to refresh the auth token"); + return gif.getJSONObject("urls").getString("hd"); } /** @@ -318,6 +329,19 @@ private static void fetchAuthToken() throws IOException { * * @return Search or tags endpoint url */ + /** + * Fetch a temporary authentication token from RedGIFs API + */ + private static void fetchAuthToken() throws IOException { + try { + var json = Http.url(TEMPORARY_AUTH_ENDPOINT).getJSON(); + authToken = json.getString("token"); + } catch (IOException e) { + logger.error("Failed to fetch RedGIFs authentication token", e); + throw e; + } + } + private URL getSearchOrTagsURL() throws IOException, URISyntaxException { URIBuilder uri; Map endpointQueryParams = new HashMap<>(); @@ -390,4 +414,4 @@ private URL getSearchOrTagsURL() throws IOException, URISyntaxException { return uri.build().toURL(); } -} +} \ No newline at end of file