diff --git a/bdfr/__main__.py b/bdfr/__main__.py index dadba517..2f660e32 100644 --- a/bdfr/__main__.py +++ b/bdfr/__main__.py @@ -7,7 +7,7 @@ import click import requests -from bdfr import __version__ +from bdfr.__init__ import __version__ from bdfr.archiver import Archiver from bdfr.cloner import RedditCloner from bdfr.completion import Completion diff --git a/bdfr/downloader.py b/bdfr/downloader.py index 20984e69..156337e0 100644 --- a/bdfr/downloader.py +++ b/bdfr/downloader.py @@ -17,6 +17,7 @@ import prawcore from bdfr import exceptions as errors +from bdfr.site_downloaders import redgifs from bdfr.configuration import Configuration from bdfr.connector import RedditConnector from bdfr.site_downloaders.download_factory import DownloadFactory @@ -107,7 +108,22 @@ def _download_submission(self, submission: praw.models.Submission): content = downloader.find_resources(self.authenticator) except errors.SiteDownloaderError as e: logger.error(f"Site {downloader_class.__name__} failed to download submission {submission.id}: {e}") - return + # Redgifs 401 error / temporary auth token handler + if (downloader_class.__name__ == "Redgifs") and (str(e).startswith("Server responded with 401")): + print("\n-=-=-=-=-=-=-=-=-=-=-=-\nRedgifs temporary API token out of date") + + # Extracting URL from the error message + url_start_index = str(e).rfind("https://") + redgifs_url = str(e)[url_start_index:] + + # Getting new temp API token + redgifs.Redgifs._get_token(redgifs.Redgifs, redgifs_url) + + # Attempted redownload of link that hit the 401 error. Don't think it works though. + redgifs.Redgifs._get_link(redgifs_url) + return + else: + return for destination, res in self.file_name_formatter.format_resource_paths(content, self.download_directory): if destination.exists(): logger.debug(f"File {destination} from submission {submission.id} already exists, continuing") diff --git a/bdfr/site_downloaders/base_downloader.py b/bdfr/site_downloaders/base_downloader.py index e4ac111c..b90dc13d 100644 --- a/bdfr/site_downloaders/base_downloader.py +++ b/bdfr/site_downloaders/base_downloader.py @@ -32,6 +32,8 @@ def retrieve_url(url: str, cookies: dict = None, headers: dict = None) -> reques except requests.exceptions.RequestException as e: logger.exception(e) raise SiteDownloaderError(f"Failed to get page {url}") + if res.status_code == 429: + raise ResourceNotFound("\n\nToo many requests\nTry again in a little while\n") if res.status_code != 200: raise ResourceNotFound(f"Server responded with {res.status_code} to {url}") return res diff --git a/bdfr/site_downloaders/redgifs.py b/bdfr/site_downloaders/redgifs.py index 9c469bc5..3fefe19c 100644 --- a/bdfr/site_downloaders/redgifs.py +++ b/bdfr/site_downloaders/redgifs.py @@ -3,6 +3,8 @@ import json import re +import os +import tempfile from typing import Optional import requests @@ -15,6 +17,9 @@ class Redgifs(BaseDownloader): + # Setting temp token path. Probably would be better somewhere else, but os temp works. + TOKEN_FILE_PATH = os.path.join(tempfile.gettempdir(), "redgifs_token.txt") + def __init__(self, post: Submission): super().__init__(post) @@ -22,6 +27,36 @@ def find_resources(self, authenticator: Optional[SiteAuthenticator] = None) -> l media_urls = self._get_link(self.post.url) return [Resource(self.post, m, Resource.retry_download(m), None) for m in media_urls] + ### Temporary auth token handling ### + def _load_token(self, url) -> Optional[str]: + try: + with open(self.TOKEN_FILE_PATH, "r") as file: + return file.read().strip() + except FileNotFoundError: + print("\n-=-=-=-=-=-=-=-=-=-=-=-\nRedgifs API token file not found, retrieving new token") + self._get_token(self, url) + with open(self.TOKEN_FILE_PATH, "r") as file: + return file.read().strip() + + def _save_token(self, token: str, url): + print(f"Writing Redgifs temporary API token to {self.TOKEN_FILE_PATH}") + with open(self.TOKEN_FILE_PATH, "w") as file: + file.write(token) + print(f"Success!\n\nNew temporary token is: {token}\n-=-=-=-=-=-=-=-=-=-=-=-\n") + return token + + def _get_token(self, redgif_id, other=None) -> str: + try: + print("Attempting to retrieve new temporary Redgifs API token") + response = self.retrieve_url("https://api.redgifs.com/v2/auth/temporary") + auth_token = json.loads(response.text)["token"] + + self._save_token(self, auth_token, redgif_id) + except Exception as e: + raise SiteDownloaderError(f"Failed to retrieve Redgifs API token: {e}") + return auth_token + ### End temporary auth token handling ### + @staticmethod def _get_id(url: str) -> str: try: @@ -38,9 +73,8 @@ def _get_id(url: str) -> str: def _get_link(url: str) -> set[str]: redgif_id = Redgifs._get_id(url) - auth_token = json.loads(Redgifs.retrieve_url("https://api.redgifs.com/v2/auth/temporary").text)["token"] - if not auth_token: - raise SiteDownloaderError("Unable to retrieve Redgifs API token") + # Passing url here. Probably don't need to. + auth_token = Redgifs._load_token(Redgifs, url) headers = { "referer": "https://www.redgifs.com/",