summaryrefslogtreecommitdiff
path: root/searx/engines/niconico.py
diff options
context:
space:
mode:
authorZhijie He <hezhijie0327@hotmail.com>2025-03-19 20:18:15 +0800
committerMarkus Heiser <markus.heiser@darmarIT.de>2025-03-30 12:42:31 +0200
commitb231cb4b5941c62310fc08d8307f28ce5d04a91c (patch)
treed2149ae2d7642a915ecd2cc7a9ad46d7be7c647a /searx/engines/niconico.py
parentc8b419fcbb937e1f3da45dddbc4edc6b64d43d2c (diff)
[feat] engines: add Niconico videos engine
Co-authored-by: Bnyro <bnyro@tutanota.com>
Diffstat (limited to 'searx/engines/niconico.py')
-rw-r--r--searx/engines/niconico.py90
1 files changed, 90 insertions, 0 deletions
diff --git a/searx/engines/niconico.py b/searx/engines/niconico.py
new file mode 100644
index 000000000..b421a9806
--- /dev/null
+++ b/searx/engines/niconico.py
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+"""Niconico search engine for searxng"""
+
+from urllib.parse import urlencode
+from datetime import datetime, timedelta
+from lxml import html
+
+from searx.utils import eval_xpath_getindex, eval_xpath_list, eval_xpath, extract_text
+
+about = {
+ "website": "https://www.nicovideo.jp/",
+ "wikidata_id": "Q697233",
+ "use_official_api": False,
+ "require_api_key": False,
+ "results": "HTML",
+ "language": "ja",
+}
+
+categories = ["videos"]
+paging = True
+
+time_range_support = True
+time_range_dict = {"day": 1, "week": 7, "month": 30, "year": 365}
+
+base_url = "https://www.nicovideo.jp"
+embed_url = "https://embed.nicovideo.jp"
+
+results_xpath = '//li[@data-video-item]'
+url_xpath = './/a[@class="itemThumbWrap"]/@href'
+video_length_xpath = './/span[@class="videoLength"]'
+upload_time_xpath = './/p[@class="itemTime"]//span[@class="time"]/text()'
+title_xpath = './/p[@class="itemTitle"]/a'
+content_xpath = './/p[@class="itemDescription"]/@title'
+thumbnail_xpath = './/img[@class="thumb"]/@src'
+
+
+def request(query, params):
+ query_params = {"page": params['pageno']}
+
+ if time_range_dict.get(params['time_range']):
+ time_diff_days = time_range_dict[params['time_range']]
+ start_date = datetime.now() - timedelta(days=time_diff_days)
+ query_params['start'] = start_date.strftime('%Y-%m-%d')
+
+ params['url'] = f"{base_url}/search/{query}?{urlencode(query_params)}"
+ return params
+
+
+def response(resp):
+ results = []
+ dom = html.fromstring(resp.text)
+
+ for item in eval_xpath_list(dom, results_xpath):
+ relative_url = eval_xpath_getindex(item, url_xpath, 0)
+ video_id = relative_url.rsplit('?', maxsplit=1)[0].split('/')[-1]
+
+ url = f"{base_url}/watch/{video_id}"
+ iframe_src = f"{embed_url}/watch/{video_id}"
+
+ length = None
+ video_length = eval_xpath_getindex(item, video_length_xpath, 0)
+ if len(video_length) > 0:
+ try:
+ timediff = datetime.strptime(video_length, "%M:%S")
+ length = timedelta(minutes=timediff.minute, seconds=timediff.second)
+ except ValueError:
+ pass
+
+ published_date = None
+ upload_time = eval_xpath_getindex(item, upload_time_xpath, 0)
+ if len(upload_time) > 0:
+ try:
+ published_date = datetime.strptime(upload_time, "%Y/%m/%d %H:%M")
+ except ValueError:
+ pass
+
+ results.append(
+ {
+ 'template': 'videos.html',
+ 'title': extract_text(eval_xpath(item, title_xpath)),
+ 'content': eval_xpath_getindex(item, content_xpath, 0),
+ 'url': url,
+ "iframe_src": iframe_src,
+ 'thumbnail': eval_xpath_getindex(item, thumbnail_xpath, 0),
+ 'length': length,
+ "publishedDate": published_date,
+ }
+ )
+
+ return results