Browse Source

[feat] engine: implementation of radio-browser.info

Bnyro 1 year ago
parent
commit
3e2ae756f0
2 changed files with 115 additions and 0 deletions
  1. 111 0
      searx/engines/radio_browser.py
  2. 4 0
      searx/settings.yml

+ 111 - 0
searx/engines/radio_browser.py

@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+# lint: pylint
+"""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"  # see https://api.radio-browser.info/ for all nodes
+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:
+
+        # the language doesn't have any iso code, and hence can't be parsed
+        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

+ 4 - 0
searx/settings.yml

@@ -1345,6 +1345,10 @@ engines:
   #   categories: files
   #   disabled: true
 
+  - name: radio browser
+    engine: radio_browser
+    shortcut: rb
+
   - name: reddit
     engine: reddit
     shortcut: re