radio_browser.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. # SPDX-License-Identifier: AGPL-3.0-or-later
  2. # lint: pylint
  3. """Radio browser (music)
  4. """
  5. from urllib.parse import urlencode
  6. import babel
  7. from searx.network import get
  8. from searx.enginelib.traits import EngineTraits
  9. from searx.locales import language_tag, region_tag
  10. traits: EngineTraits
  11. about = {
  12. "website": 'https://www.radio-browser.info/',
  13. "official_api_documentation": 'https://de1.api.radio-browser.info/',
  14. "use_official_api": True,
  15. "require_api_key": False,
  16. "results": 'JSON',
  17. }
  18. paging = True
  19. categories = ['music']
  20. base_url = "https://de1.api.radio-browser.info" # see https://api.radio-browser.info/ for all nodes
  21. number_of_results = 10
  22. def request(query, params):
  23. args = {
  24. 'name': query,
  25. 'order': 'votes',
  26. 'offset': (params['pageno'] - 1) * number_of_results,
  27. 'limit': number_of_results,
  28. 'hidebroken': 'true',
  29. 'reverse': 'true',
  30. }
  31. lang = traits.get_language(params['searxng_locale'], None)
  32. if lang is not None:
  33. args['language'] = lang
  34. region = traits.get_region(params['searxng_locale'], None)
  35. if region is not None:
  36. args['countrycode'] = region.split('-')[1]
  37. params['url'] = f"{base_url}/json/stations/search?{urlencode(args)}"
  38. return params
  39. def response(resp):
  40. results = []
  41. for result in resp.json():
  42. url = result['homepage']
  43. if not url:
  44. url = result['url_resolved']
  45. results.append(
  46. {
  47. 'template': 'videos.html',
  48. 'url': url,
  49. 'title': result['name'],
  50. 'thumbnail': result.get('favicon', '').replace("http://", "https://"),
  51. 'content': result['country']
  52. + " / "
  53. + result["tags"]
  54. + f" / {result['votes']} votes"
  55. + f" / {result['clickcount']} clicks",
  56. 'iframe_src': result['url_resolved'].replace("http://", "https://"),
  57. }
  58. )
  59. return results
  60. def fetch_traits(engine_traits: EngineTraits):
  61. language_list = get(f'{base_url}/json/languages').json()
  62. country_list = get(f'{base_url}/json/countrycodes').json()
  63. for lang in language_list:
  64. # the language doesn't have any iso code, and hence can't be parsed
  65. if not lang['iso_639']:
  66. continue
  67. try:
  68. lang_tag = lang['iso_639']
  69. sxng_tag = language_tag(babel.Locale.parse(lang_tag, sep="-"))
  70. except babel.UnknownLocaleError:
  71. print("ERROR: %s is unknown by babel" % lang_tag)
  72. continue
  73. conflict = engine_traits.languages.get(sxng_tag)
  74. if conflict:
  75. continue
  76. engine_traits.languages[sxng_tag] = lang['name']
  77. for region in country_list:
  78. try:
  79. reg_tag = f"{lang['iso_639']}-{region['name']}"
  80. sxng_tag = region_tag(babel.Locale.parse(reg_tag, sep="-"))
  81. except babel.UnknownLocaleError:
  82. continue
  83. conflict = engine_traits.regions.get(sxng_tag)
  84. if conflict:
  85. continue
  86. engine_traits.regions[sxng_tag] = reg_tag