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
50 changes: 47 additions & 3 deletions redgifs/aio.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@

from .http import AsyncHttp, ProxyAuth
from .tags import Tags
from .enums import Order, MediaType
from .enums import Order, MediaType, NicheOrder, NicheGifOrder
from .utils import _async_read_tags_json, build_file_url, _gifs_iter, _images_iter, to_embed_url, to_web_url
from .parser import parse_search, parse_creator, parse_creators, parse_search_image
from .models import GIF, URL, CreatorResult, Image, SearchResult, CreatorsResult, TagSuggestion, User
from .parser import parse_search, parse_creator, parse_creators, parse_search_image, parse_search_niche
from .models import GIF, URL, CreatorResult, Image, SearchResult, CreatorsResult, TagSuggestion, User, NicheResult

if TYPE_CHECKING:
from redgifs.types.tags import TagInfo
Expand Down Expand Up @@ -419,6 +419,50 @@ async def download(self, url: str, fp: Union[str, bytes, os.PathLike[Any], io.Bu
"""
return await self.http.download(url, fp)

async def search_niches(self, query: str, *, order: NicheOrder = NicheOrder.BEST_MATCH, count: int = 40, page: int = 1) -> NicheResult:
"""
Search for niches.

Parameters
----------
query: :class:`str`
The niches to search for.
order: Optional[:class:`.NicheOrder`]
The order of the niches to return.
count: Optional[:class:`int`]
The amount of images to return.
page: Optional[:class:`int`]
The page number of the images to return.

Returns
-------
:class:`.NicheResult` - The search result.
"""
resp = await self.http.search_niches(query, order, count, page)
return parse_search_niche(query, resp)

async def search_niche(self, niche_id: str, *, order: NicheGifOrder = NicheGifOrder.TRENDING, count: int = 40, page: int = 1) -> SearchResult:
"""
Search for a single niche's GIFs

Parameters
----------
niche_id: :class:`str`
The ID of the niche. If the URL is ``https://redgifs.com/niches/abcxyz`` then the ID is ``abcxyz``.
order: Optional[:class:`.NicheGifOrder`]
The order of the GIFs to return.
count: Optional[:class:`int`]
The amount of GIFs to return.
page: Optional[:class:`int`]
The page number of the GIFs to return.

Returns
-------
:class:`.SearchResult` - The search result.
"""
resp = await self.http.search_niche(niche_id, order, count, page)
return parse_search(niche_id, resp, MediaType.GIF)

async def close(self) -> None:
"""Closes the API session."""
return await self.http.close()
50 changes: 47 additions & 3 deletions redgifs/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
import requests

from .tags import Tags
from .enums import Order, MediaType
from .enums import Order, NicheOrder, NicheGifOrder, MediaType
from .http import HTTP, ProxyAuth
from .utils import _read_tags_json, build_file_url, _gifs_iter, _images_iter, to_embed_url, to_web_url
from .parser import parse_creator, parse_search, parse_creators, parse_search_image
from .models import URL, GIF, CreatorResult, Image, SearchResult, CreatorsResult, TagSuggestion, User
from .parser import parse_creator, parse_search, parse_creators, parse_search_image, parse_search_niche
from .models import URL, GIF, CreatorResult, Image, SearchResult, CreatorsResult, TagSuggestion, User, NicheResult

if TYPE_CHECKING:
from redgifs.types.tags import TagInfo
Expand Down Expand Up @@ -412,6 +412,50 @@ def download(self, url: str, fp: Union[str, bytes, os.PathLike[Any], io.Buffered
"""
return self.http.download(url, fp)

def search_niches(self, query: str, *, order: NicheOrder = NicheOrder.BEST_MATCH, count: int = 40, page: int = 1) -> NicheResult:
"""
Search for niches.

Parameters
----------
query: :class:`str`
The niches to search for.
order: Optional[:class:`.NicheOrder`]
The order of the niches to return.
count: Optional[:class:`int`]
The amount of images to return.
page: Optional[:class:`int`]
The page number of the images to return.

Returns
-------
:class:`.NicheResult` - The search result.
"""
resp = self.http.search_niches(query, order, count, page)
return parse_search_niche(query, resp)

def search_niche(self, niche_id: str, *, order: NicheGifOrder = NicheGifOrder.TRENDING, count: int = 40, page: int = 1) -> SearchResult:
"""
Search for a single niche's GIFs

Parameters
----------
niche_id: :class:`str`
The ID of the niche. If the URL is ``https://redgifs.com/niches/abcxyz`` then the ID is ``abcxyz``.
order: Optional[:class:`.NicheGifOrder`]
The order of the GIFs to return.
count: Optional[:class:`int`]
The amount of GIFs to return.
page: Optional[:class:`int`]
The page number of the GIFs to return.

Returns
-------
:class:`.SearchResult` - The search result.
"""
resp = self.http.search_niche(niche_id, order, count, page)
return parse_search(niche_id, resp, MediaType.GIF)

def close(self) -> None:
"""Closes the API session."""
return self.http.close()
19 changes: 18 additions & 1 deletion redgifs/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import warnings
from enum import Enum, EnumMeta

__all__ = ('Order', 'MediaType')
__all__ = ('Order', 'NicheOrder', 'NicheGifOrder', 'MediaType')


class OrderMeta(EnumMeta):
Expand Down Expand Up @@ -57,6 +57,23 @@ class Order(Enum, metaclass=OrderMeta):
NEW = LATEST
BEST = TRENDING

class NicheOrder(Enum):
"""An enum representing the order of the results for niches."""

POSTS = 'posts'
SUBSCRIBERS = 'subscribers'
BEST_MATCH = 'best_match'
ALPHABETICAL_ASC = 'alphabetical_asc'
ALPHABETICAL_DESC = 'alphabetical_desc'

class NicheGifOrder(Enum):
"""An enum representing the order of the results for niche gifs."""

TRENDING = 'trending'
OLDEST = 'oldest'
LATEST = 'latest'
BEST = 'best'
HOT = 'hot'

class MediaType(Enum):
"""An enum representing the media type of the results."""
Expand Down
51 changes: 50 additions & 1 deletion redgifs/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

from . import __version__
from .errors import HTTPException
from .enums import Order, MediaType
from .enums import Order, MediaType, NicheOrder, NicheGifOrder
from .utils import strip_ip

__all__ = ('ProxyAuth',)
Expand All @@ -47,6 +47,7 @@
if TYPE_CHECKING:
from redgifs.types.gif import GetGifResponse, GifResponse
from redgifs.types.image import ImageResponse, TrendingImagesResponse
from redgifs.types.niches import NicheResponse
from redgifs.types.tags import TagsResponse, TagSuggestion
from redgifs.types.user import CreatorResponse, CreatorsResponse, UserInfo

Expand Down Expand Up @@ -236,6 +237,30 @@ def get_tag_suggestions(self, query: str) -> List[TagSuggestion]:
r = Route('GET', '/v2/search/suggest?query={query}', query=query)
return self.request(r)

# Niche methods

def search_niches(self, query: str, order: NicheOrder, count: int, page: int, **params: Any) -> NicheResponse:
r = Route(
'GET',
'/v2/niches/search?query={query}&order={order}&count={count}&page={page}',
query=query,
order=order.value,
count=count,
page=page,
)
return self.request(r, **params)

def search_niche(self, niche_id: str, order: NicheGifOrder, count: int, page: int, **params: Any) -> GifResponse:
r = Route(
'GET',
'/v2/niches/{niche_id}/gifs?order={order}&count={count}&page={page}',
niche_id=niche_id,
order=order.value,
count=count,
page=page,
)
return self.request(r, **params)

# download

def download(
Expand Down Expand Up @@ -433,6 +458,30 @@ def get_tag_suggestions(self, query: str) -> Response[List[TagSuggestion]]:
r = Route('GET', '/v2/search/suggest?query={query}', query=query)
return self.request(r)

# Niche methods

def search_niches(self, query: str, order: NicheOrder, count: int, page: int, **params: Any) -> Response[NicheResponse]:
r = Route(
'GET',
'/v2/niches/search?query={query}&order={order}&count={count}&page={page}',
query=query,
order=order.value,
count=count,
page=page,
)
return self.request(r, **params)

def search_niche(self, niche_id: str, order: NicheGifOrder, count: int, page: int, **params: Any) -> Response[GifResponse]:
r = Route(
'GET',
'/v2/niches/{niche_id}/gifs?order={order}&count={count}&page={page}',
niche_id=niche_id,
order=order.value,
count=count,
page=page,
)
return self.request(r, **params)

# download

async def download(self, url: str, fp: Union[str, bytes, os.PathLike[Any], io.BufferedIOBase]) -> int:
Expand Down
52 changes: 52 additions & 0 deletions redgifs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,55 @@ class TagSuggestion(TypedDict):

name: str
count: int

class Niche(TypedDict):
"""The niche information returned from RedGifs.

Attributes
----------
id: :class:`str`
The niche ID.
name: :class:`str`
The niche name.
gifs: :class:`int`
The amount of GIFs in this niche.
subscribers: :class:`int`
The amount of subscribers for this niche.
tags: List[:class:`str`]
A list of tags for this niche.
preferences: List[:class:`str`]
A list of preferences for this niche.
thumbnail: :class:`str`
The thumbnail URL for this niche.
"""

id: str
name: str
gifs: int
subscribers: int
tags: List[str]
preferences: List[str]
thumbnail: str

class NicheResult(TypedDict):
"""The niche result searched for.

Attributes
----------
searched_for: :class:`str`
The result of what you have searched for.
page: :class:`int`
The current page number.
pages: :class:`int`
The total number of pages available.
total: :class:`int`
The total number of niches for the query.
niches: List[:class:`Niche`]
The niches for the query.
"""

searched_for: str
page: int
pages: int
total: int
niches: List[Niche]
24 changes: 23 additions & 1 deletion redgifs/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@
from .enums import MediaType
from .errors import RedGifsError
from .utils import _users_iter, build_file_url, to_embed_url, to_web_url
from .models import GIF, URL, CreatorResult, Image, User, SearchResult, CreatorsResult
from .models import GIF, URL, CreatorResult, Image, User, SearchResult, CreatorsResult, NicheResult, Niche

if TYPE_CHECKING:
from redgifs.types.gif import GifResponse
from redgifs.types.image import ImageResponse
from redgifs.types.niches import NicheResponse
from redgifs.types.user import CreatorResponse, CreatorsResponse

_log = logging.getLogger(__name__)
Expand Down Expand Up @@ -288,3 +289,24 @@ def parse_creator(json: CreatorResponse, media_type: MediaType) -> CreatorResult
if media_type == MediaType.IMAGE # RedGifs return the key for this data as "gifs" even though it's an image...
],
)

def parse_search_niche(query: str, json: NicheResponse) -> NicheResult:
_log.debug('Using `parse_search_niche`')
return NicheResult(
searched_for=query,
page=int(json['page']),
pages=int(json['pages']),
total=int(json['total']),
niches=[
Niche(
id = niche['id'],
name = niche['name'],
gifs = int(niche['gifs']),
subscribers = int(niche['subscribers']),
tags = niche['tags'],
preferences = niche['preferences'],
thumbnail = niche['thumbnail'],
)
for niche in json['niches']
],
)
23 changes: 18 additions & 5 deletions redgifs/types/niches.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
from typing import TypedDict
from typing import TypedDict, List


class NichesInfo(TypedDict):
cover: str
description: str
class BaseNicheInfo(TypedDict):
gifs: int
id: str
name: str
owner: str
subscribers: int
thumbnail: str

class NichesInfo(BaseNicheInfo):
cover: str
description: str
owner: str
rules: str

class NicheBriefInfo(BaseNicheInfo):
tags: List[str]
preferences: List[str]

class NicheResponse(TypedDict):
page: int
pages: int
total: int
niches: List[NicheBriefInfo]