|
@@ -0,0 +1,111 @@
|
|
|
+
|
|
|
+
|
|
|
+"""Radio browser (music)
|
|
|
+"""
|
|
|
+
|
|
|
+from urllib.parse import urlencode
|
|
|
+import babel
|
|
|
+
|
|
|
+from searx.network import get
|
|
|
+from searx.enginelib.traits import EngineTraits
|
|
|
+from searx.locales import language_tag, region_tag
|
|
|
+
|
|
|
+traits: EngineTraits
|
|
|
+
|
|
|
+about = {
|
|
|
+ "website": 'https://www.radio-browser.info/',
|
|
|
+ "official_api_documentation": 'https://de1.api.radio-browser.info/',
|
|
|
+ "use_official_api": True,
|
|
|
+ "require_api_key": False,
|
|
|
+ "results": 'JSON',
|
|
|
+}
|
|
|
+paging = True
|
|
|
+categories = ['music']
|
|
|
+
|
|
|
+base_url = "https://de1.api.radio-browser.info"
|
|
|
+number_of_results = 10
|
|
|
+
|
|
|
+
|
|
|
+def request(query, params):
|
|
|
+ args = {
|
|
|
+ 'name': query,
|
|
|
+ 'order': 'votes',
|
|
|
+ 'offset': (params['pageno'] - 1) * number_of_results,
|
|
|
+ 'limit': number_of_results,
|
|
|
+ 'hidebroken': 'true',
|
|
|
+ 'reverse': 'true',
|
|
|
+ }
|
|
|
+ lang = traits.get_language(params['searxng_locale'], None)
|
|
|
+ if lang is not None:
|
|
|
+ args['language'] = lang
|
|
|
+
|
|
|
+ region = traits.get_region(params['searxng_locale'], None)
|
|
|
+ if region is not None:
|
|
|
+ args['countrycode'] = region.split('-')[1]
|
|
|
+
|
|
|
+ params['url'] = f"{base_url}/json/stations/search?{urlencode(args)}"
|
|
|
+ return params
|
|
|
+
|
|
|
+
|
|
|
+def response(resp):
|
|
|
+ results = []
|
|
|
+
|
|
|
+ for result in resp.json():
|
|
|
+ url = result['homepage']
|
|
|
+ if not url:
|
|
|
+ url = result['url_resolved']
|
|
|
+
|
|
|
+ results.append(
|
|
|
+ {
|
|
|
+ 'template': 'videos.html',
|
|
|
+ 'url': url,
|
|
|
+ 'title': result['name'],
|
|
|
+ 'thumbnail': result.get('favicon', '').replace("http://", "https://"),
|
|
|
+ 'content': result['country']
|
|
|
+ + " / "
|
|
|
+ + result["tags"]
|
|
|
+ + f" / {result['votes']} votes"
|
|
|
+ + f" / {result['clickcount']} clicks",
|
|
|
+ 'iframe_src': result['url_resolved'].replace("http://", "https://"),
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ return results
|
|
|
+
|
|
|
+
|
|
|
+def fetch_traits(engine_traits: EngineTraits):
|
|
|
+ language_list = get(f'{base_url}/json/languages').json()
|
|
|
+
|
|
|
+ country_list = get(f'{base_url}/json/countrycodes').json()
|
|
|
+
|
|
|
+ for lang in language_list:
|
|
|
+
|
|
|
+
|
|
|
+ if not lang['iso_639']:
|
|
|
+ continue
|
|
|
+
|
|
|
+ try:
|
|
|
+ lang_tag = lang['iso_639']
|
|
|
+ sxng_tag = language_tag(babel.Locale.parse(lang_tag, sep="-"))
|
|
|
+ except babel.UnknownLocaleError:
|
|
|
+ print("ERROR: %s is unknown by babel" % lang_tag)
|
|
|
+ continue
|
|
|
+
|
|
|
+ conflict = engine_traits.languages.get(sxng_tag)
|
|
|
+ if conflict:
|
|
|
+ continue
|
|
|
+
|
|
|
+ engine_traits.languages[sxng_tag] = lang['name']
|
|
|
+
|
|
|
+ for region in country_list:
|
|
|
+ try:
|
|
|
+ reg_tag = f"{lang['iso_639']}-{region['name']}"
|
|
|
+ sxng_tag = region_tag(babel.Locale.parse(reg_tag, sep="-"))
|
|
|
+ except babel.UnknownLocaleError:
|
|
|
+ continue
|
|
|
+
|
|
|
+ conflict = engine_traits.regions.get(sxng_tag)
|
|
|
+ if conflict:
|
|
|
+ continue
|
|
|
+
|
|
|
+ engine_traits.regions[sxng_tag] = reg_tag
|