.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
senscritique.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2"""SensCritique (movies)
3"""
4from __future__ import annotations
5
6from json import dumps, loads
7from typing import Any, Optional
8from searx.result_types import EngineResults, MainResult
9
10about = {
11 "website": 'https://www.senscritique.com/',
12 "wikidata_id": 'Q16676060',
13 "official_api_documentation": None,
14 "use_official_api": False,
15 "require_api_key": False,
16 "results": 'JSON',
17 'language': 'fr',
18}
19
20categories = ['movies']
21paging = True
22page_size = 16
23graphql_url = 'https://apollo.senscritique.com/'
24
25graphql_query = """query SearchProductExplorer($query: String, $offset: Int, $limit: Int,
26 $sortBy: SearchProductExplorerSort) {
27 searchProductExplorer(
28 query: $query
29 filters: []
30 sortBy: $sortBy
31 offset: $offset
32 limit: $limit
33 ) {
34 items {
35 category
36 dateRelease
37 duration
38 id
39 originalTitle
40 rating
41 title
42 url
43 yearOfProduction
44 medias {
45 picture
46 }
47 countries {
48 name
49 }
50 genresInfos {
51 label
52 }
53 directors {
54 name
55 }
56 stats {
57 ratingCount
58 }
59 }
60 }
61}"""
62
63
64def request(query: str, params: dict[str, Any]) -> dict[str, Any]:
65 offset = (params['pageno'] - 1) * page_size
66
67 data = {
68 "operationName": "SearchProductExplorer",
69 "variables": {"offset": offset, "limit": page_size, "query": query, "sortBy": "RELEVANCE"},
70 "query": graphql_query,
71 }
72
73 params['url'] = graphql_url
74 params['method'] = 'POST'
75 params['headers']['Content-Type'] = 'application/json'
76 params['data'] = dumps(data)
77
78 return params
79
80
81def response(resp) -> EngineResults:
82 res = EngineResults()
83 response_data = loads(resp.text)
84
85 items = response_data.get('data', {}).get('searchProductExplorer', {}).get('items', [])
86 if not items:
87 return res
88
89 for item in items:
90 result = parse_item(item)
91 if not result:
92 continue
93 res.add(result=result)
94
95 return res
96
97
98def parse_item(item: dict[str, Any]) -> MainResult | None:
99 """Parse a single item from the SensCritique API response"""
100 title = item.get('title', '')
101 if not title:
102 return None
103 year = item.get('yearOfProduction')
104 original_title = item.get('originalTitle')
105
106 thumbnail: str = ""
107 if item.get('medias', {}) and item['medias'].get('picture'):
108 thumbnail = item['medias']['picture']
109
110 content_parts = build_content_parts(item, title, original_title)
111 url = f"https://www.senscritique.com{item['url']}"
112
113 return MainResult(
114 url=url,
115 title=title + (f' ({year})' if year else ''),
116 content=' | '.join(content_parts),
117 thumbnail=thumbnail,
118 )
119
120
121def build_content_parts(item: dict[str, Any], title: str, original_title: Optional[str]) -> list[str]:
122 """Build the content parts for an item"""
123 content_parts = []
124
125 if item.get('category'):
126 content_parts.append(item['category'])
127
128 if original_title and original_title != title:
129 content_parts.append(f"Original title: {original_title}")
130
131 if item.get('directors'):
132 directors = [director['name'] for director in item['directors']]
133 content_parts.append(f"Director(s): {', '.join(directors)}")
134
135 if item.get('countries'):
136 countries = [country['name'] for country in item['countries']]
137 content_parts.append(f"Country: {', '.join(countries)}")
138
139 if item.get('genresInfos'):
140 genres = [genre['label'] for genre in item['genresInfos']]
141 content_parts.append(f"Genre(s): {', '.join(genres)}")
142
143 if item.get('duration'):
144 minutes = item['duration'] // 60
145 if minutes > 0:
146 content_parts.append(f"Duration: {minutes} min")
147
148 if item.get('rating') and item.get('stats', {}).get('ratingCount'):
149 content_parts.append(f"Rating: {item['rating']}/10 ({item['stats']['ratingCount']} votes)")
150
151 return content_parts
EngineResults response(resp)
dict[str, Any] request(str query, dict[str, Any] params)
list[str] build_content_parts(dict[str, Any] item, str title, Optional[str] original_title)
MainResult|None parse_item(dict[str, Any] item)