import random import urllib.parse import requests from edmond.plugin import Plugin BASE_URL = "https://taxref.mnhn.fr/api" class TaxrefPlugin(Plugin): REQUIRED_CONFIGS = [ "commands", "not_found_reply", "reply", "ambiguous_reply", "unnamed_species" ] def __init__(self, bot): super().__init__(bot) def on_pubmsg(self, event): if not self.should_handle_command(event.arguments[0]): return False if self.command.ident == self.config["commands"][0]: self.search_by_name(self.command.content, event.target) return True def search_by_name(self, name, target): name = name.lower() enc_name = urllib.parse.quote(name) url = ( f"{BASE_URL}/taxa/search?scientificNames={enc_name}" "&page=1&size=100" ) response = requests.get(url) if response.status_code != 200: self.signal_failure(target) return data = response.json() items = data.get("_embedded", {}).get("taxa", []) if not items: self.bot.say(target, self.config["not_found_reply"]) return if len(items) == 1: # Only one result: use it. item_to_use = items[0] else: # More than one result: if the results contain a corresponding # species, use it, else return names for sub-species etc. species_items = [] for item in items: if item["rankId"] == "ES": species_items.append(item) num_species = len(species_items) self.bot.log_d(f"{num_species} species.") if num_species == 1: item_to_use = species_items[0] else: # If there are several species, check if one of them has the # exact same name; else show an ambiguous reply. species_with_same_name = [ item for item in species_items if item["scientificName"].lower() == name ] if len(species_with_same_name) != 1: self.show_ambiguous_reply(species_items, target) return item_to_use = species_with_same_name[0] unnamed = self.config["unnamed_species"] reply = self.config["reply"].format( sci_name=item_to_use["scientificName"], fr_name=item_to_use["frenchVernacularName"] or unnamed, family=item_to_use["familyName"], cd_nom=item_to_use["id"], cd_ref=item_to_use["referenceId"], ) self.bot.say(target, reply) self.show_images(item_to_use, target) def show_ambiguous_reply(self, items, target): """Show a reply with potential species.""" reply = self.config["ambiguous_reply"] append = "" if len(items) > 5: append = f"… (+{len(items)})" items = items[:5] reply += ", ".join(item["scientificName"] for item in items) if append: reply += append self.bot.say(target, reply) def show_images(self, item, target): """If there are media available, show one!""" m_url = item.get("_links", {}) .get("media", {}) .get("href") if not m_url: return response = requests.get(m_url) if response.status_code != 200: self.signal_failure(target) return media_data = response.json() items = media_data.get("_embedded", {}).get("media", []) if not items: return random_item = random.choice(items) media_href = random_item.get("_links", {}).get("file", {}).get("href") if not media_href: return self.bot.say(target, "📷 " + media_href)