class Raspado_Radios(): def __init__(self): self.nombre_radios_pais = [] self.url_radios_pais = [] self.resultado_pais_busqueda_nombre = [] self.resultado_pais_busqueda_numero = [] self.resultado_pais_busqueda_abreviado = [] self.nombre_busqueda_general_radio = [] self.url_busqueda_general_radio = [] self.nombre_idioma = [] self.cantidad_idioma = [] self.busqueda_nombre_idioma = [] self.busqueda_cantidad_idioma = [] self.nombre_tag = [] self.cantidad_tag = [] self.busqueda_nombre_tag = [] self.busqueda_cantidad_tag = [] self.paises_radio_español = [] self.paises_radio_abreviado = [] self.paises_numero_emisoras = [] self.paises_numero_total_emisoras = "" self.rb = RadioBrowser() self.datos_pais = self.rb.countries() def Paises_Español(self): claves = Raspado_Radios.keys_only(diccionario) valores = Raspado_Radios.values_only(diccionario) for i in range(len(self.datos_pais)): self.paises_radio_abreviado.append(self.datos_pais[i]["name"]) for i in self.paises_radio_abreviado: try: indice = valores.index(i.upper()) self.paises_radio_español.append(claves[indice]) except: pass def Paises_Bandera(self): for i in range(len(self.datos_pais)): self.paises_radio_abreviado.append(self.datos_pais[i]["name"]) def Paises_Cantidad_Emisoras(self): for i in range(len(self.datos_pais)): self.paises_numero_emisoras.append( self.datos_pais[i]["stationcount"]) def Suma_Total_Emisoras_Paises(self): self.temporal = [] for i in range(len(self.datos_pais)): self.temporal.append(self.datos_pais[i]["stationcount"]) self.paises_numero_total_emisoras = 0 for i in self.temporal: self.paises_numero_total_emisoras = self.paises_numero_total_emisoras + i def Actualizar_Pais(self): self.paises_radio_español = [] self.paises_radio_abreviado = [] self.paises_numero_emisoras = [] self.paises_numero_total_emisoras = "" Raspado_Radios.Paises_Español(self) Raspado_Radios.Paises_Bandera(self) Raspado_Radios.Paises_Cantidad_Emisoras(self) Raspado_Radios.Suma_Total_Emisoras_Paises(self) def Buscar_Pais(self, valor): self.resultado_pais_busqueda_nombre = [] self.resultado_pais_busqueda_numero = [] self.resultado_pais_busqueda_abreviado = [] for item in self.paises_radio_español: if valor.lower() in item.lower(): self.resultado_pais_busqueda_nombre.append(item) for i in self.resultado_pais_busqueda_nombre: posicion = self.paises_radio_español.index(i) self.resultado_pais_busqueda_numero.append( self.paises_numero_emisoras[posicion]) self.resultado_pais_busqueda_abreviado.append( self.paises_radio_abreviado[posicion]) def Resultado_Paises(self, valor): datos_frame = self.rb.stations_by_countrycode(valor) self.nombre_radios_pais = [] self.url_radios_pais = [] for i in range(0, len(datos_frame)): self.nombre_radios_pais.append(datos_frame[i]["name"]) self.url_radios_pais.append(datos_frame[i]["url"]) def Buscar_Radio_General(self, valor, valor1=True): datos_frame = self.rb.search(name=valor, name_exact=valor1) self.nombre_busqueda_general_radio = [] self.url_busqueda_general_radio = [] for i in range(0, len(datos_frame)): self.nombre_busqueda_general_radio.append(datos_frame[i]["name"]) self.url_busqueda_general_radio.append(datos_frame[i]["url"]) def Resultado_Idioma(self): datos_lenguaje = self.rb.languages() self.nombre_idioma = [] self.cantidad_idioma = [] for i in range(len(datos_lenguaje)): self.nombre_idioma.append(datos_lenguaje[i]["name"]) self.cantidad_idioma.append(datos_lenguaje[i]["stationcount"]) def Buscar_Idioma(self, valor): datos_lenguaje = self.rb.languages() temp_name = [] temp_count = [] for i in range(len(datos_lenguaje)): temp_name.append(datos_lenguaje[i]["name"]) temp_count.append(datos_lenguaje[i]["stationcount"]) self.busqueda_nombre_idioma = [] self.busqueda_cantidad_idioma = [] for item in temp_name: if valor.lower() in item.lower(): self.busqueda_nombre_idioma.append(item) for i in self.busqueda_nombre_idioma: posicion = temp_name.index(i) self.busqueda_cantidad_idioma.append(temp_count[posicion]) def Resultado_Idioma_Global(self, valor): pandas_radio_lenguaje = self.rb.stations_by_language(valor) self.nombre_radios_pais = [] self.url_radios_pais = [] for i in range(0, len(pandas_radio_lenguaje)): self.nombre_radios_pais.append(pandas_radio_lenguaje[i]["name"]) self.url_radios_pais.append(pandas_radio_lenguaje[i]["url"]) def Resultado_Tag(self): datos_genero = self.rb.tags() self.nombre_tag = [] self.cantidad_tag = [] for i in range(len(datos_genero)): self.nombre_tag.append(datos_genero[i]["name"]) self.cantidad_tag.append(datos_genero[i]["stationcount"]) def Buscar_Tag(self, valor): datos_genero = self.rb.tags() temp_name = [] temp_count = [] for i in range(len(datos_genero)): temp_name.append(datos_genero[i]["name"]) temp_count.append(datos_genero[i]["stationcount"]) self.busqueda_nombre_tag = [] self.busqueda_cantidad_tag = [] for item in temp_name: if valor.lower() in item.lower(): self.busqueda_nombre_tag.append(item) for i in self.busqueda_nombre_tag: posicion = temp_name.index(i) self.busqueda_cantidad_tag.append(temp_count[posicion]) def Resultado_Tag_Global(self, valor): pandas_tag = self.rb.stations_by_tag(valor) self.nombre_radios_pais = [] self.url_radios_pais = [] for i in range(0, len(pandas_tag)): self.nombre_radios_pais.append(pandas_tag[i]["name"]) self.url_radios_pais.append(pandas_tag[i]["url"]) def saber_pais_conexion(self): url = 'http://ipinfo.io/json' response = urlopen(url) data = json.load(response) IP = data['ip'] org = data['org'] city = data['city'] country = data['country'] region = data['region'] return country def load_obj(name): with open(name, 'rb') as f: return pickle.load(f) def save_obj(obj, name): with open(name, 'wb') as f: pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL) def keys_only(flat_dict): return [k for k, v in flat_dict.items()] def values_only(flat_dict): return [v for k, v in flat_dict.items()]
class Module(ModuleBase): def init(self, settings, q): self.module_path = os.path.dirname(os.path.abspath(__file__)) try: lang = gettext.translation('pext_module_radio', localedir=os.path.join( self.module_path, 'locale'), languages=[settings['_locale']]) except FileNotFoundError: lang = gettext.NullTranslations() print("No {} translation available for pext_module_radio".format( settings['_locale'])) lang.install() self.rb = RadioBrowser() self.settings = settings self.q = q self.favourites = [] try: with open(os.path.join(self.module_path, "_user_favourites.txt"), "r") as favourites_file: for favourite in favourites_file: self.favourites.append(favourite.strip()) except IOError: pass self.cached = { 'countries': { 'time': 0 }, 'codecs': { 'time': 0 }, 'languages': { 'time': 0 }, 'tags': { 'time': 0 } } self.cachedStations = { '_favourites': { 'time': 0 }, 'countries': {}, 'codecs': {}, 'languages': {}, 'tags': {}, 'topvote': { 'time': 0 }, 'topclick': { 'time': 0 }, 'lastclick': { 'time': 0 }, 'lastchange': { 'time': 0 } } self.nowPlaying = None if not which("ffplay"): self.q.put([ Action.critical_error, _("ffplay is not installed, please install it.") ]) return self._get_entries() def _cache_expired(self, cache): return cache['time'] < time.time() - 600 def _entry_depth(self, text): if self._menu_to_type(text) in self.cached: return 2 else: return 1 def _menu_to_type(self, text): if text == _('Favourites'): return '_favourites' elif text == _('By Country'): return 'countries' elif text == _('By Codec'): return 'codecs' elif text == _('By Language'): return 'languages' elif text == _('By Tags'): return 'tags' elif text == _('By Votes'): return 'topvote' elif text == _('By Most Tune-Ins'): return 'topclick' elif text == _('By Most Recent Listener'): return 'lastclick' elif text == _('By Most Recent Change'): return 'lastchange' else: raise ValueError("Invalid text") def _get_stations_by_menu_type(self, search_type): if search_type == 'countries': return self.rb.countries() elif search_type == 'codecs': return self.rb.codecs() elif search_type == 'languages': return self.rb.languages() elif search_type == 'tags': return self.rb.tags() else: return self._search_stations_by_type(search_type) def _search_stations_by_type(self, search_type, search_term=None): if search_type == 'countries': return self.rb.stations_by_country(search_term, True) elif search_type == 'codecs': return self.rb.stations_by_codec(search_term, True) elif search_type == 'languages': return self.rb.stations_by_language(search_term, True) elif search_type == 'tags': return self.rb.stations_by_tag(search_term, True) elif search_type == 'topvote': return self.rb.stations(order='votes') elif search_type == 'topclick': return self.rb.stations(order='clickcount') elif search_type == 'lastclick': return self.rb.stations(order='clicktimestamp') elif search_type == 'lastchange': return self.rb.stations(order='lastchangetime') else: raise ValueError("Invalid type") def _get_entries(self): if self.favourites: self.q.put([Action.add_entry, _('Favourites')]) self.q.put([Action.add_entry, _('By Country')]) self.q.put([Action.add_entry, _('By Codec')]) self.q.put([Action.add_entry, _('By Language')]) self.q.put([Action.add_entry, _('By Tags')]) self.q.put([Action.add_entry, _('By Votes')]) self.q.put([Action.add_entry, _('By Most Tune-Ins')]) self.q.put([Action.add_entry, _('By Most Recent Listener')]) self.q.put([Action.add_entry, _('By Most Recent Change')]) if self.settings['_api_version'] < [0, 11, 0] and self.nowPlaying: if self.nowPlaying['process']: self.q.put([Action.add_command, _('mute')]) else: self.q.put([Action.add_command, _('unmute')]) self.q.put([Action.add_command, _('stop')]) self.q.put([Action.add_command, _('vote')]) def _get_list(self, path): self.q.put([Action.replace_entry_list, []]) if self._cache_expired(self.cached[path]): self.cached[path] = { 'time': time.time(), 'data': self._get_stations_by_menu_type(path) } for entry in self.cached[path]['data']: self.q.put([ Action.add_entry, _('{} ({} stations)').format(entry['name'], entry['stationcount']) ]) def _get_stations(self, search_type, search_term): if search_type == '_favourites': if self._cache_expired(self.cachedStations[search_type]): data = [] for favourite in self.favourites: station_data = self.rb.station_by_uuid(favourite) if station_data: data.append(station_data[0]) self.cachedStations[search_type] = { 'time': time.time(), 'data': data } return self.cachedStations[search_type] if search_term: if search_term not in self.cachedStations[ search_type] or self._cache_expired( self.cachedStations[search_type][search_term]): self.cachedStations[search_type][search_term] = { 'time': time.time(), 'data': self._search_stations_by_type(search_type, search_term) } return self.cachedStations[search_type][search_term] if self._cache_expired(self.cachedStations[search_type]): self.cachedStations[search_type] = { 'time': time.time(), 'data': self._search_stations_by_type(search_type) } return self.cachedStations[search_type] def _list_stations(self, search_type, search_term): self.q.put([Action.replace_entry_list, []]) cache = self._get_stations(search_type, search_term) for entry in cache['data']: self.q.put([Action.add_entry, entry['name']]) if self.settings['_api_version'] >= [0, 3, 1]: self.q.put([ Action.set_entry_info, entry['name'], _("<b>{}</b><br/><br/><b>Bitrate: </b>{} kbps<br/><b>Codec: </b>{}<br/><b>Language: </b>{}<br/><b>Location: </b>{}<br/><b>Tags: </b>{}<br/><b>Homepage: </b><a href='{}'>{}</a>" ).format( html.escape(entry['name']), html.escape(str(entry['bitrate'])), html.escape(entry['codec']), html.escape(entry['language']), "{}, {}".format(html.escape(entry['state']), html.escape(entry['country'])) if entry['state'] else html.escape(entry['country']), html.escape(", ".join(entry['tags'].split(",")) if entry['tags'] else "None"), html.escape(entry['homepage']), html.escape(entry['homepage'])) ]) if self.settings['_api_version'] >= [ 0, 6, 0 ] and search_type == '_favourites': self.q.put([ Action.set_entry_context, entry['name'], [_("Unfavourite")] ]) def _play_station(self, byType, searchTerm, stationName): self._stop_playing() if searchTerm: cache = self.cachedStations[byType][searchTerm] else: cache = self.cachedStations[byType] for station in cache['data']: if station['name'] == stationName: station_uuid = station['stationuuid'] station_info = station break response = self.rb.click_counter(station_uuid) if response['ok'] == 'false': self.q.put([Action.add_error, response['message']]) return False # TODO: Replace ffplay with something more easily scriptable that # preferably notifies us of song changes on the station. self.nowPlaying = { 'id': station_uuid, 'name': stationName, 'url': response['url'], 'process': None } if self.settings['_api_version'] >= [0, 6, 0]: self.q.put([ Action.set_base_info, _("<b>Tuned into:</b><br/>{}<br/><br/><b>Bitrate: </b>{} kbps<br/><b>Codec: </b>{}<br/><b>Language: </b>{}<br/><b>Location: </b>{}<br/><b>Tags: </b>{}<br/><b>Homepage: </b><a href='{}'>{}</a>" ).format( html.escape(station_info['name']), html.escape(str(station_info['bitrate'])), html.escape(station_info['codec']), html.escape(station_info['language']), "{}, {}".format(html.escape(station_info['state']), html.escape(station_info['country'])) if station_info['state'] else html.escape( station_info['country']), html.escape(", ".join(station_info['tags'].split(",")) if station_info['tags'] else "None"), html.escape(station_info['homepage']), html.escape(station_info['homepage'])) ]) self._toggle_mute() return True def _toggle_mute(self): """Toggle mute. While this function technically disconnects or connects to the station, instead of just muting, it is simpler code-wise and has the added benefit of saving bandwidth. TODO: Replace this with an actual mute function. """ if self.nowPlaying: if self.nowPlaying['process']: os.kill(self.nowPlaying['process'].pid, SIGTERM) self.nowPlaying['process'] = None self.q.put([ Action.set_header, _('Tuned into {} (muted)').format(self.nowPlaying['name']) ]) if self.settings['_api_version'] >= [0, 6, 0]: self.q.put([ Action.set_base_context, [_("Unmute"), _("Stop"), _("Favourite"), _("Vote up")] ]) else: self.q.put([ Action.set_header, _('Tuned into {}').format(self.nowPlaying['name']) ]) self.nowPlaying['process'] = Popen([ 'ffplay', '-nodisp', '-nostats', '-loglevel', '0', self.nowPlaying['url'] ]) if self.settings['_api_version'] >= [0, 6, 0]: self.q.put([ Action.set_base_context, [_("Mute"), _("Stop"), _("Favourite"), _("Vote up")] ]) def _stop_playing(self): if self.nowPlaying: if self.nowPlaying['process']: os.kill(self.nowPlaying['process'].pid, SIGTERM) self.nowPlaying = None self.q.put([Action.set_header]) if self.settings['_api_version'] >= [0, 6, 0]: self.q.put([Action.set_base_info]) self.q.put([Action.set_base_context]) def _add_to_favourites(self, station_id): with open(os.path.join(self.module_path, "_user_favourites.txt"), "a") as favourites_file: favourites_file.write('{}\n'.format(station_id)) self.favourites.append(station_id) self.cachedStations['_favourites'] = {'time': 0} def _remove_from_favourites(self, station_name): for station in self._get_stations('_favourites', '')['data']: if station['name'] == station_name: self.favourites.remove(station['stationuuid']) with open( os.path.join(self.module_path, "_user_favourites.txt"), "w") as favourites_file: for favourite in self.favourites: favourites_file.write('{}\n'.format(favourite)) self.cachedStations['_favourites'] = {'time': 0} return self.q.put([ Action.add_error, _('Could not find {} in favourites').format(station_name) ]) def _vote_station(self): result = self.rb.client.get('vote/{}'.format(self.nowPlaying['id'])) if result['ok']: self.q.put([ Action.add_message, _('Voted for station {}').format(self.nowPlaying['name']) ]) else: self.q.put([ Action.add_error, _('Failed to vote for {}: {}').format(self.nowPlaying['name'], result['message']) ]) def stop(self): self._stop_playing() def selection_made(self, selection): if self.settings['_api_version'] >= [ 0, 6, 0 ] and len(selection) > 0 and selection[-1]['context_option']: if selection[-1]['type'] == SelectionType.none: if selection[-1]['context_option'] in [_('Mute'), _('Unmute')]: self._toggle_mute() elif selection[-1]['context_option'] == _('Stop'): self._stop_playing() elif selection[-1]['context_option'] == _('Favourite'): self._add_to_favourites(self.nowPlaying['id']) elif selection[-1]['context_option'] == _('Vote up'): self._vote_station() elif selection[-1]['context_option'] == _("Unfavourite"): self._remove_from_favourites(selection[-1]['value']) if not self.favourites: self.q.put([Action.set_selection, []]) return self.q.put([Action.set_selection, selection[:-1]]) return self.q.put([Action.replace_command_list, []]) if len(selection) == 0: self.q.put([Action.replace_entry_list, []]) self._get_entries() elif len(selection) == 1: # Force station list when no subcategories if self._entry_depth(selection[0]['value']) == 1: self._list_stations(self._menu_to_type(selection[0]['value']), '') return menu_text = selection[0]['value'] self._get_list(self._menu_to_type(menu_text)) elif len(selection) == 2: # Force playing when no subcategories if self._entry_depth(selection[0]['value']) == 1: if self._play_station( self._menu_to_type(selection[0]['value']), '', selection[1]['value']): self.q.put([Action.close]) else: self.q.put([Action.set_selection, selection[:-1]]) return # Remove station count from search term search_term = selection[1]['value'][:selection[1]['value']. rfind('(')].rstrip() self._list_stations(self._menu_to_type(selection[0]['value']), search_term) elif len(selection) == 3: # Remove station count from search term search_term = selection[1]['value'][:selection[1]['value']. rfind('(')].rstrip() if self._play_station(self._menu_to_type(selection[0]['value']), search_term, selection[2]['value']): self.q.put([Action.close]) else: self.q.put([Action.set_selection, selection[:-1]]) else: self.q.put([ Action.critical_error, _('Unexpected selection_made value: {}').format(selection) ]) def process_response(self, response): pass