.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
adobe_stock.py
Go to the documentation of this file.
1
# SPDX-License-Identifier: AGPL-3.0-or-later
2
"""`Adobe Stock`_ is a service that gives access to millions of royalty-free
3
assets. Assets types include photos, vectors, illustrations, templates, 3D
4
assets, videos, motion graphics templates and audio tracks.
5
6
.. Adobe Stock: https://stock.adobe.com/
7
8
Configuration
9
=============
10
11
The engine has the following mandatory setting:
12
13
- SearXNG's :ref:`engine categories`
14
- Adobe-Stock's :py:obj:`adobe_order`
15
- Adobe-Stock's :py:obj:`adobe_content_types`
16
17
.. code:: yaml
18
19
- name: adobe stock
20
engine: adobe_stock
21
shortcut: asi
22
categories: [images]
23
adobe_order: relevance
24
adobe_content_types: ["photo", "illustration", "zip_vector", "template", "3d", "image"]
25
26
- name: adobe stock video
27
engine: adobe_stock
28
network: adobe stock
29
shortcut: asi
30
categories: [videos]
31
adobe_order: relevance
32
adobe_content_types: ["video"]
33
34
Implementation
35
==============
36
37
"""
38
from
__future__
import
annotations
39
40
from
typing
import
TYPE_CHECKING
41
from
datetime
import
datetime, timedelta
42
from
urllib.parse
import
urlencode
43
44
import
isodate
45
46
if
TYPE_CHECKING:
47
import
logging
48
49
logger: logging.Logger
50
51
about = {
52
"website"
:
"https://stock.adobe.com/"
,
53
"wikidata_id"
:
"Q5977430"
,
54
"official_api_documentation"
:
None
,
55
"use_official_api"
:
False
,
56
"require_api_key"
:
False
,
57
"results"
:
"JSON"
,
58
}
59
60
categories = []
61
paging =
True
62
send_accept_language_header =
True
63
results_per_page = 10
64
65
base_url =
"https://stock.adobe.com"
66
67
adobe_order: str =
""
68
"""Sort order, can be one of:
69
70
- ``relevance`` or
71
- ``featured`` or
72
- ``creation`` (most recent) or
73
- ``nb_downloads`` (number of downloads)
74
"""
75
76
ADOBE_VALID_TYPES = [
"photo"
,
"illustration"
,
"zip_vector"
,
"video"
,
"template"
,
"3d"
,
"audio"
,
"image"
]
77
adobe_content_types: list = []
78
"""A list of of content types. The following content types are offered:
79
80
- Images: ``image``
81
- Videos: ``video``
82
- Templates: ``template``
83
- 3D: ``3d``
84
- Audio ``audio``
85
86
Additional subcategories:
87
88
- Photos: ``photo``
89
- Illustrations: ``illustration``
90
- Vectors: ``zip_vector`` (Vectors),
91
"""
92
93
# Do we need support for "free_collection" and "include_stock_enterprise"?
94
95
96
def
init
(_):
97
if
not
categories:
98
raise
ValueError(
"adobe_stock engine: categories is unset"
)
99
100
# adobe_order
101
if
not
adobe_order:
102
raise
ValueError(
"adobe_stock engine: adobe_order is unset"
)
103
if
adobe_order
not
in
[
"relevance"
,
"featured"
,
"creation"
,
"nb_downloads"
]:
104
raise
ValueError(f
"unsupported adobe_order: {adobe_order}"
)
105
106
# adobe_content_types
107
if
not
adobe_content_types:
108
raise
ValueError(
"adobe_stock engine: adobe_content_types is unset"
)
109
110
if
isinstance(adobe_content_types, list):
111
for
t
in
adobe_content_types:
112
if
t
not
in
ADOBE_VALID_TYPES:
113
raise
ValueError(
"adobe_stock engine: adobe_content_types: '%s' is invalid"
% t)
114
else
:
115
raise
ValueError(
116
"adobe_stock engine: adobe_content_types must be a list of strings not %s"
% type(adobe_content_types)
117
)
118
119
120
def
request
(query, params):
121
122
args = {
123
"k"
: query,
124
"limit"
: results_per_page,
125
"order"
: adobe_order,
126
"search_page"
: params[
"pageno"
],
127
"search_type"
:
"pagination"
,
128
}
129
130
for
content_type
in
ADOBE_VALID_TYPES:
131
args[f
"filters[content_type:{content_type}]"
] = 1
if
content_type
in
adobe_content_types
else
0
132
133
params[
"url"
] = f
"{base_url}/de/Ajax/Search?{urlencode(args)}"
134
135
# headers required to bypass bot-detection
136
if
params[
"searxng_locale"
] ==
"all"
:
137
params[
"headers"
][
"Accept-Language"
] =
"en-US,en;q=0.5"
138
139
return
params
140
141
142
def
parse_image_item
(item):
143
return
{
144
"template"
:
"images.html"
,
145
"url"
: item[
"content_url"
],
146
"title"
: item[
"title"
],
147
"content"
: item[
"asset_type"
],
148
"img_src"
: item[
"content_thumb_extra_large_url"
],
149
"thumbnail_src"
: item[
"thumbnail_url"
],
150
"resolution"
: f
"{item['content_original_width']}x{item['content_original_height']}"
,
151
"img_format"
: item[
"format"
],
152
"author"
: item[
"author"
],
153
}
154
155
156
def
parse_video_item
(item):
157
158
# in video items, the title is more or less a "content description", we try
159
# to reduce the lenght of the title ..
160
161
title = item[
"title"
]
162
content =
""
163
if
"."
in
title.strip()[:-1]:
164
content = title
165
title = title.split(
"."
, 1)[0]
166
elif
","
in
title:
167
content = title
168
title = title.split(
","
, 1)[0]
169
elif
len(title) > 50:
170
content = title
171
title =
""
172
for
w
in
content.split(
" "
):
173
title += f
" {w}"
174
if
len(title) > 50:
175
title = title.strip() +
"\u2026"
176
break
177
178
return
{
179
"template"
:
"videos.html"
,
180
"url"
: item[
"content_url"
],
181
"title"
: title,
182
"content"
: content,
183
# https://en.wikipedia.org/wiki/ISO_8601#Durations
184
"length"
: isodate.parse_duration(item[
"time_duration"
]),
185
"publishedDate"
: datetime.strptime(item[
"creation_date"
],
"%Y-%m-%d"
),
186
"thumbnail"
: item[
"thumbnail_url"
],
187
"iframe_src"
: item[
"video_small_preview_url"
],
188
"metadata"
: item[
"asset_type"
],
189
}
190
191
192
def
parse_audio_item
(item):
193
audio_data = item[
"audio_data"
]
194
content = audio_data.get(
"description"
)
or
""
195
if
audio_data.get(
"album"
):
196
content = audio_data[
"album"
] +
" - "
+ content
197
198
return
{
199
"url"
: item[
"content_url"
],
200
"title"
: item[
"title"
],
201
"content"
: content,
202
# "thumbnail": base_url + item["thumbnail_url"],
203
"iframe_src"
: audio_data[
"preview"
][
"url"
],
204
"publishedDate"
: datetime.fromisoformat(audio_data[
"release_date"
])
if
audio_data[
"release_date"
]
else
None
,
205
"length"
: timedelta(seconds=round(audio_data[
"duration"
] / 1000))
if
audio_data[
"duration"
]
else
None
,
206
"author"
: item.get(
"artist_name"
),
207
}
208
209
210
def
response
(resp):
211
results = []
212
213
json_resp = resp.json()
214
215
if
isinstance(json_resp[
"items"
], list):
216
return
None
217
for
item
in
json_resp[
"items"
].values():
218
if
item[
"asset_type"
].lower()
in
[
"image"
,
"premium-image"
,
"illustration"
,
"vector"
]:
219
result =
parse_image_item
(item)
220
elif
item[
"asset_type"
].lower() ==
"video"
:
221
result =
parse_video_item
(item)
222
elif
item[
"asset_type"
].lower() ==
"audio"
:
223
result =
parse_audio_item
(item)
224
else
:
225
logger.error(
"no handle for %s --> %s"
, item[
"asset_type"
], item)
226
continue
227
results.append(result)
228
229
return
results
searx.engines.adobe_stock.request
request(query, params)
Definition
adobe_stock.py:120
searx.engines.adobe_stock.parse_image_item
parse_image_item(item)
Definition
adobe_stock.py:142
searx.engines.adobe_stock.response
response(resp)
Definition
adobe_stock.py:210
searx.engines.adobe_stock.parse_video_item
parse_video_item(item)
Definition
adobe_stock.py:156
searx.engines.adobe_stock.init
init(_)
Definition
adobe_stock.py:96
searx.engines.adobe_stock.parse_audio_item
parse_audio_item(item)
Definition
adobe_stock.py:192
searxng
searx
engines
adobe_stock.py
Generated on Thu Jan 16 2025 22:17:39 for .oO SearXNG Developer Documentation Oo. by
1.12.0