Add search function
This commit is contained in:
parent
6a6334b912
commit
03905756ca
121
FAAPI/FAAPI.py
121
FAAPI/FAAPI.py
@ -1,4 +1,5 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
|
||||
import requests
|
||||
@ -444,6 +445,64 @@ class User:
|
||||
return self.username
|
||||
|
||||
|
||||
class OrderByEnum(Enum):
|
||||
relevancy = 'relevancy'
|
||||
date = 'date'
|
||||
popularity = 'popularity'
|
||||
|
||||
|
||||
class OrderEnum(Enum):
|
||||
ascending = 'asc'
|
||||
descending = 'desc'
|
||||
|
||||
|
||||
class RangeEnum(Enum):
|
||||
day = 'day'
|
||||
three_days = '3days'
|
||||
week = 'week'
|
||||
month = 'month'
|
||||
all_time = 'all'
|
||||
|
||||
|
||||
class MatchModeEnum(Enum):
|
||||
all = 'all'
|
||||
any = 'any'
|
||||
extended = 'extended'
|
||||
|
||||
|
||||
class SearchOpts:
|
||||
"""
|
||||
A container for FurAffinity search options.
|
||||
"""
|
||||
|
||||
def __init__(self, order_by: OrderByEnum = OrderByEnum.relevancy,
|
||||
order_direction: OrderEnum = OrderEnum.descending,
|
||||
range: RangeEnum = RangeEnum.all_time,
|
||||
match_mode: MatchModeEnum = MatchModeEnum.extended,
|
||||
rating_general: bool = True,
|
||||
rating_mature: bool = True,
|
||||
rating_adult: bool = True,
|
||||
type_art: bool = True,
|
||||
type_music: bool = True,
|
||||
type_flash: bool = True,
|
||||
type_story: bool = True,
|
||||
type_photo: bool = True,
|
||||
type_poetry: bool = True):
|
||||
self.order_by: OrderByEnum = order_by
|
||||
self.order_direction: OrderEnum = order_direction
|
||||
self.range: RangeEnum = range
|
||||
self.match_mode: MatchModeEnum = match_mode
|
||||
self.rating_general: bool = rating_general
|
||||
self.rating_mature: bool = rating_mature
|
||||
self.rating_adult: bool = rating_adult
|
||||
self.type_art: bool = type_art
|
||||
self.type_music: bool = type_music
|
||||
self.type_flash: bool = type_flash
|
||||
self.type_story: bool = type_story
|
||||
self.type_photo: bool = type_photo
|
||||
self.type_poetry: bool = type_poetry
|
||||
|
||||
|
||||
class FAAPI:
|
||||
"""
|
||||
A basic FurAffinity API instance.
|
||||
@ -567,6 +626,68 @@ class FAAPI:
|
||||
submission._api = self
|
||||
return submission
|
||||
|
||||
def search(self, search: str, results: int = 48, opts: SearchOpts = SearchOpts()) -> List[Submission]:
|
||||
"""
|
||||
Searches FurAffinity with the given string.
|
||||
Results are
|
||||
:param search: Search term
|
||||
:param results: Number of results to return
|
||||
:param opts: Search options
|
||||
:return: List containing results
|
||||
"""
|
||||
url = FA_BASE_URL + '/search/'
|
||||
form_data = {
|
||||
'page': 1,
|
||||
'q': search,
|
||||
'do_search': 'Search',
|
||||
'order-by': opts.order_by,
|
||||
'order-direction': opts.order_direction,
|
||||
'range': opts.range,
|
||||
'mode': opts.match_mode
|
||||
}
|
||||
|
||||
# Set optional keys since they're judged on presence, not value
|
||||
if opts.rating_general: form_data['rating-general'] = 'on'
|
||||
if opts.rating_mature: form_data['rating-mature'] = 'on'
|
||||
if opts.rating_adult: form_data['rating-adult'] = 'on'
|
||||
if opts.type_art: form_data['type-art'] = 'on'
|
||||
if opts.type_music: form_data['type-music'] = 'on'
|
||||
if opts.type_flash: form_data['type-flash'] = 'on'
|
||||
if opts.type_story: form_data['type-story'] = 'on'
|
||||
if opts.type_photo: form_data['type-photo'] = 'on'
|
||||
if opts.type_poetry: form_data['type-poetry'] = 'on'
|
||||
|
||||
submissions = []
|
||||
while len(submissions) < results:
|
||||
# Get our search results
|
||||
res = self._req.post(url, data=form_data)
|
||||
if res.status_code >= 400:
|
||||
raise Exception('Got status code {} when trying to get URL {}'.format(res.status_code, url))
|
||||
soup = BeautifulSoup(res.content, 'lxml')
|
||||
|
||||
# Get all the submissions on this page
|
||||
items = soup.select('.gallery figure')
|
||||
for item in items:
|
||||
sub = self.get_submission(int(item.get('id')[4:])) # IDs look like 'sid-35908275', so we just skip the 'sid-'
|
||||
|
||||
# Try cache the preview URL early
|
||||
try:
|
||||
sub._preview_url = 'https:' + item.select('img')[0].get('src')
|
||||
sub._has_preview = True
|
||||
except IndexError:
|
||||
sub._has_preview = False
|
||||
|
||||
submissions.append(sub)
|
||||
|
||||
if not soup.select('input[name=next_page]:not(.hidden)'):
|
||||
# No further pages, stop searching
|
||||
break
|
||||
|
||||
# Increment our page number
|
||||
form_data['page'] = form_data['page'] + 1
|
||||
|
||||
return submissions[:results]
|
||||
|
||||
def __getstate__(self):
|
||||
# Get a copy of the object state without the requests session
|
||||
state = self.__dict__.copy()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user