# -*- coding: utf-8 -*- # Copyright 2020 Mike Fährmann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. """Extractors for https://redgifs.com/""" from .gfycat import GfycatExtractor from ..cache import cache class RedgifsExtractor(GfycatExtractor): """Base class for redgifs extractors""" category = "redgifs" root = "https://www.redgifs.com/" class RedgifsUserExtractor(RedgifsExtractor): """Extractor for redgifs user profiles""" subcategory = "user" directory_fmt = ("{category}", "{userName}") pattern = r"(?:https?://)?(?:www\.)?redgifs\.com/users/([^/?&#]+)" test = ("https://www.redgifs.com/users/Natalifiction", { "pattern": r"https://thcf\d+\.redgifs\.com/[A-Za-z]+\.mp4", "count": ">= 100", }) def gfycats(self): return RedgifsAPI(self).user(self.key) class RedgifsSearchExtractor(RedgifsExtractor): """Extractor for redgifs search results""" subcategory = "search" directory_fmt = ("{category}", "Search", "{search}") pattern = r"(?:https?://)?(?:www\.)?redgifs\.com/gifs/browse/([^/?&#]+)" test = ("https://www.redgifs.com/gifs/browse/jav", { "pattern": r"https://thcf\d+\.redgifs\.com/[A-Za-z]+\.mp4", "range": "100-300", "count": "> 200", }) def metadata(self): self.key = self.key.replace("-", " ") return {"search": self.key} def gfycats(self): return RedgifsAPI(self).search(self.key) class RedgifsImageExtractor(RedgifsExtractor): """Extractor for individual gifs from redgifs.com""" subcategory = "image" pattern = (r"(?:https?://)?(?:www\.)?(?:redgifs\.com/watch" r"|gifdeliverynetwork.com)/([A-Za-z]+)") test = ( ("https://redgifs.com/watch/foolishforkedabyssiniancat", { "pattern": r"https://\w+.redgifs.com/FoolishForkedAbyss.+.mp4", "content": "f6e03f1df9a2ff2a74092f53ee7580d2fb943533", }), ("https://www.gifdeliverynetwork.com/foolishforkedabyssiniancat"), ) def gfycats(self): return (RedgifsAPI(self).gfycat(self.key),) class RedgifsAPI(): def __init__(self, extractor): self.extractor = extractor self.headers = {} def gfycat(self, gfycat_id): endpoint = "v1/gfycats/" + gfycat_id return self._call(endpoint)["gfyItem"] def user(self, user): endpoint = "v1/users/{}/gfycats".format(user.lower()) params = {"count": 100} return self._pagination(endpoint, params) def search(self, query): endpoint = "v1/gfycats/search" params = {"search_text": query, "count": 150} return self._pagination(endpoint, params) @cache(maxage=3600) def _authenticate_impl(self): url = "https://weblogin.redgifs.com/oauth/webtoken" headers = { "Referer": "https://www.redgifs.com/", "Origin" : "https://www.redgifs.com", } data = { "access_key": "dBLwVuGn9eq4dtXLs8WSfpjcYFY7bPQe" "AqGPSFgqeW5B9uzj2cMVhF63pTFF4Rg9", } response = self.extractor.request( url, method="POST", headers=headers, json=data) return "Bearer " + response.json()["access_token"] def _call(self, endpoint, params=None): self.headers["Authorization"] = self._authenticate_impl() url = "https://napi.redgifs.com/" + endpoint return self.extractor.request( url, params=params, headers=self.headers).json() def _pagination(self, endpoint, params): while True: data = self._call(endpoint, params) gfycats = data["gfycats"] yield from gfycats if "found" not in data and len(gfycats) < params["count"] or \ not data["gfycats"]: return params["cursor"] = data["cursor"]