mirror of
				https://github.com/searxng/searxng.git
				synced 2025-10-30 18:22:31 -04:00 
			
		
		
		
	In 25.1.0 [2] an old bug has been fixed: "Docstring formatting does not apply to module docstrings" [3]. [1] https://github.com/psf/black/blob/main/CHANGES.md#2590 [2] https://github.com/psf/black/blob/main/CHANGES.md#2510 [3] https://github.com/psf/black/issues/4094 Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
		
			
				
	
	
		
			151 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # SPDX-License-Identifier: AGPL-3.0-or-later
 | |
| """SensCritique (movies)"""
 | |
| 
 | |
| import typing as t
 | |
| 
 | |
| from json import dumps, loads
 | |
| from searx.result_types import EngineResults, MainResult
 | |
| 
 | |
| about = {
 | |
|     "website": 'https://www.senscritique.com/',
 | |
|     "wikidata_id": 'Q16676060',
 | |
|     "official_api_documentation": None,
 | |
|     "use_official_api": False,
 | |
|     "require_api_key": False,
 | |
|     "results": 'JSON',
 | |
|     'language': 'fr',
 | |
| }
 | |
| 
 | |
| categories = ['movies']
 | |
| paging = True
 | |
| page_size = 16
 | |
| graphql_url = 'https://apollo.senscritique.com/'
 | |
| 
 | |
| graphql_query = """query SearchProductExplorer($query: String, $offset: Int, $limit: Int,
 | |
|                     $sortBy: SearchProductExplorerSort) {
 | |
|   searchProductExplorer(
 | |
|     query: $query
 | |
|     filters: []
 | |
|     sortBy: $sortBy
 | |
|     offset: $offset
 | |
|     limit: $limit
 | |
|   ) {
 | |
|     items {
 | |
|       category
 | |
|       dateRelease
 | |
|       duration
 | |
|       id
 | |
|       originalTitle
 | |
|       rating
 | |
|       title
 | |
|       url
 | |
|       yearOfProduction
 | |
|       medias {
 | |
|         picture
 | |
|       }
 | |
|       countries {
 | |
|         name
 | |
|       }
 | |
|       genresInfos {
 | |
|         label
 | |
|       }
 | |
|       directors {
 | |
|         name
 | |
|       }
 | |
|       stats {
 | |
|         ratingCount
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }"""
 | |
| 
 | |
| 
 | |
| def request(query: str, params: dict[str, t.Any]) -> dict[str, t.Any]:
 | |
|     offset = (params['pageno'] - 1) * page_size
 | |
| 
 | |
|     data = {
 | |
|         "operationName": "SearchProductExplorer",
 | |
|         "variables": {"offset": offset, "limit": page_size, "query": query, "sortBy": "RELEVANCE"},
 | |
|         "query": graphql_query,
 | |
|     }
 | |
| 
 | |
|     params['url'] = graphql_url
 | |
|     params['method'] = 'POST'
 | |
|     params['headers']['Content-Type'] = 'application/json'
 | |
|     params['data'] = dumps(data)
 | |
| 
 | |
|     return params
 | |
| 
 | |
| 
 | |
| def response(resp) -> EngineResults:
 | |
|     res = EngineResults()
 | |
|     response_data = loads(resp.text)
 | |
| 
 | |
|     items = response_data.get('data', {}).get('searchProductExplorer', {}).get('items', [])
 | |
|     if not items:
 | |
|         return res
 | |
| 
 | |
|     for item in items:
 | |
|         result = parse_item(item)
 | |
|         if not result:
 | |
|             continue
 | |
|         res.add(result=result)
 | |
| 
 | |
|     return res
 | |
| 
 | |
| 
 | |
| def parse_item(item: dict[str, t.Any]) -> MainResult | None:
 | |
|     """Parse a single item from the SensCritique API response"""
 | |
|     title = item.get('title', '')
 | |
|     if not title:
 | |
|         return None
 | |
|     year = item.get('yearOfProduction')
 | |
|     original_title = item.get('originalTitle')
 | |
| 
 | |
|     thumbnail: str = ""
 | |
|     if item.get('medias', {}) and item['medias'].get('picture'):
 | |
|         thumbnail = item['medias']['picture']
 | |
| 
 | |
|     content_parts = build_content_parts(item, title, original_title)
 | |
|     url = f"https://www.senscritique.com{item['url']}"
 | |
| 
 | |
|     return MainResult(
 | |
|         url=url,
 | |
|         title=title + (f' ({year})' if year else ''),
 | |
|         content=' | '.join(content_parts),
 | |
|         thumbnail=thumbnail,
 | |
|     )
 | |
| 
 | |
| 
 | |
| def build_content_parts(item: dict[str, t.Any], title: str, original_title: str | None) -> list[str]:
 | |
|     """Build the content parts for an item"""
 | |
|     content_parts = []
 | |
| 
 | |
|     if item.get('category'):
 | |
|         content_parts.append(item['category'])
 | |
| 
 | |
|     if original_title and original_title != title:
 | |
|         content_parts.append(f"Original title: {original_title}")
 | |
| 
 | |
|     if item.get('directors'):
 | |
|         directors = [director['name'] for director in item['directors']]
 | |
|         content_parts.append(f"Director(s): {', '.join(directors)}")
 | |
| 
 | |
|     if item.get('countries'):
 | |
|         countries = [country['name'] for country in item['countries']]
 | |
|         content_parts.append(f"Country: {', '.join(countries)}")
 | |
| 
 | |
|     if item.get('genresInfos'):
 | |
|         genres = [genre['label'] for genre in item['genresInfos']]
 | |
|         content_parts.append(f"Genre(s): {', '.join(genres)}")
 | |
| 
 | |
|     if item.get('duration'):
 | |
|         minutes = item['duration'] // 60
 | |
|         if minutes > 0:
 | |
|             content_parts.append(f"Duration: {minutes} min")
 | |
| 
 | |
|     if item.get('rating') and item.get('stats', {}).get('ratingCount'):
 | |
|         content_parts.append(f"Rating: {item['rating']}/10 ({item['stats']['ratingCount']} votes)")
 | |
| 
 | |
|     return content_parts
 |