it does birds now

main
nebula 2024-12-15 21:36:08 -06:00
parent a3700d588c
commit 186780ac25
2 changed files with 115 additions and 14 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@
/trivia.questions /trivia.questions
/trivia.scores /trivia.scores
/config.json /config.json
/brids.urls

122
main.py
View File

@ -1,3 +1,19 @@
# {
# 'speciesCode': 'dowwoo',
# 'comName': 'Downy Woodpecker',
# 'sciName': 'Dryobates pubescens',
# 'locId': 'L36986367',
# 'locName': 'Home',
# 'obsDt': '2024-12-14 17:06',
# 'howMany': 1,
# 'lat': 36.0006572,
# 'lng': -95.0865753,
# 'obsValid': True,
# 'obsReviewed': False,
# 'locationPrivate': True,
# 'subId': 'S205413945'
# }
from random import choice from random import choice
import requests import requests
from time import sleep from time import sleep
@ -15,7 +31,7 @@ host = "localhost"
port = 6667 port = 6667
nick = config["nick"] nick = config["nick"]
realname = "a bot by ~nebula" realname = "a bot by ~nebula"
helptext = "!trivia, !trscores, !aitrivia, !aiscores for trivia game. contact ~nebula for help, feedback or problem reports. https://git.tilde.town/nebula/mysterious_cube" helptext = "!birds, !trivia, !trscores, !aitrivia, !aiscores. contact ~nebula for help, feedback or problem reports. https://git.tilde.town/nebula/mysterious_cube"
channels = config["channels"] channels = config["channels"]
channel_re = re.compile(r"PRIVMSG (#*\w+)") channel_re = re.compile(r"PRIVMSG (#*\w+)")
@ -28,12 +44,23 @@ llama_headers = {
"Authorization": config["llama_key"] "Authorization": config["llama_key"]
} }
geonames_url = "http://api.geonames.org/searchJSON"
geonames_user = config["geonames_user"]
ebird_url = "https://api.ebird.org/v2/data/obs/geo/recent"
ebird_key = config["ebird_key"]
google_url = "https://customsearch.googleapis.com/customsearch/v1"
google_key = config["google_key"]
google_cx = config["google_cx"]
trivia_questions_file = "trivia.questions" trivia_questions_file = "trivia.questions"
trivia_state_file = "trivia.state" trivia_state_file = "trivia.state"
trivia_score_file = "trivia.scores" trivia_score_file = "trivia.scores"
trivia_unselected_file = "trivia.unselected" trivia_unselected_file = "trivia.unselected"
ai_state_file = "trivia.aistate" ai_state_file = "trivia.aistate"
ai_score_file = "trivia.aiscores" ai_score_file = "trivia.aiscores"
bird_url_file = "brids.urls"
try: try:
with open(trivia_questions_file, "r") as f: with open(trivia_questions_file, "r") as f:
@ -71,6 +98,12 @@ try:
except FileNotFoundError: except FileNotFoundError:
ai_scores = {} ai_scores = {}
try:
with open(bird_url_file, "r") as f:
bird_urls = load(f)
except FileNotFoundError:
bird_urls = {}
def write_state(): def write_state():
with open(trivia_state_file, "w") as f: with open(trivia_state_file, "w") as f:
dump(trivia_state, f) dump(trivia_state, f)
@ -82,6 +115,68 @@ def write_state():
dump(ai_scores, f) dump(ai_scores, f)
with open(ai_state_file, "w") as f: with open(ai_state_file, "w") as f:
dump(ai_state, f) dump(ai_state, f)
with open(bird_url_file, "w") as f:
dump(bird_urls, f)
def get_location(query):
params = {
"username": geonames_user,
"q": query,
"maxRows": 1
}
try:
response = requests.get(geonames_url, params=params)
data = response.json()["geonames"][0]
if "lat" not in data:
return None
else:
return data
except IndexError:
return None
def cache_bird_url(sciName):
global bird_urls
if sciName in bird_urls.keys():
return bird_urls[sciName]
search = requests.get(google_url, params={
"q": sciName,
"key": google_key,
"cx": google_cx
})
data = search.json()
try:
link = data["items"][0]["link"]
bird_urls[sciName] = link
write_state()
return link
except (IndexError, KeyError):
return None
def get_birds(location):
params = {
"key": ebird_key,
"dist": 50,
"lat": location["lat"],
"lng": location["lng"]
}
request = requests.get(ebird_url, params=params)
data = request.json()[:4]
line = f"Location: {location['name']}; "
for sighting in data:
url = cache_bird_url(sighting['sciName']).rstrip("/id")
line += f"{sighting['comName']} [ {url} ]; "
return line.rstrip("; ")
def post_birds(channel, username, arguments):
if not arguments:
return "Posts recently sighted birds. Give a location name with this command, eg !birds Dodge City, KS"
location = get_location(arguments)
if not location:
return f"No data found for {arguments}"
birds = get_birds(location)
if not birds:
return f"No data found for {arguments}"
return birds
def get_question(ai_enabled=False): def get_question(ai_enabled=False):
global trivia_questions global trivia_questions
@ -274,7 +369,9 @@ class IRCBot():
self.sendline(f"JOIN {channel}") self.sendline(f"JOIN {channel}")
def sendline(self, line): def sendline(self, line):
if line:
return self.s.send(bytes(f"{line}\r\n", "UTF-8")) return self.s.send(bytes(f"{line}\r\n", "UTF-8"))
return None
def send(self, channel, content): def send(self, channel, content):
if isinstance(content, list): if isinstance(content, list):
@ -310,8 +407,17 @@ class IRCBot():
name = None name = None
if name and not channel.startswith("#"): if name and not channel.startswith("#"):
channel = name channel = name
try:
message_body = line[line.index(" :") + 2:]
except (IndexError, ValueError):
message_body = ""
if message_body:
for callback in self.searchers:
result = callback(message_body)
if result:
self.send(channel, result)
for command, callback in self.commands: for command, callback in self.commands:
if line.lower().endswith(command): if message_body.lower().startswith(command):
try: try:
arguments = line[line.index(command) + len(command) + 1:] arguments = line[line.index(command) + len(command) + 1:]
except (IndexError, ValueError): except (IndexError, ValueError):
@ -319,13 +425,6 @@ class IRCBot():
result = callback(channel, name, arguments) result = callback(channel, name, arguments)
if result: if result:
self.send(channel, result) self.send(channel, result)
try:
message_body = line[line.index(" :") + 2:]
except (IndexError, ValueError):
message_body = ""
if message_body:
for callback in self.searchers:
callback(message_body)
def run(): def run():
bot = IRCBot( bot = IRCBot(
@ -335,6 +434,7 @@ def run():
[ # endswith commands [ # endswith commands
("!help", post_help), ("!help", post_help),
("!rollcall", post_help), ("!rollcall", post_help),
("!birds", post_birds),
("!trivia", post_question), ("!trivia", post_question),
("!aitrivia", post_ai_question), ("!aitrivia", post_ai_question),
("!trscores", post_top_scores), ("!trscores", post_top_scores),
@ -354,5 +454,5 @@ def run():
sleep(0.5) sleep(0.5)
bot.command_loop() bot.command_loop()
if __name__ == "__main__": # if __name__ == "__main__":
run() # run()