Compare commits
32 Commits
96e9b11bdf
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5219bc433 | ||
|
|
839ee6306c | ||
|
|
4b636eed7a | ||
|
|
069d2ca7d0 | ||
|
|
72f96a493b | ||
|
|
e11b2396b6 | ||
|
|
0c7d721ddd | ||
|
|
58fe1cdda6 | ||
|
|
9dd76e16b7 | ||
|
|
a0be0c7607 | ||
|
|
50a45e40d5 | ||
|
|
5b3ade2863 | ||
|
|
93364b8580 | ||
|
|
4d288e871c | ||
|
|
c3716613fe | ||
|
|
f853f6c220 | ||
|
|
fabecd836b | ||
|
|
09bdd939f2 | ||
|
|
c85d850218 | ||
|
|
083fd06395 | ||
|
|
2f9b0af5d8 | ||
|
|
b5c4c988f0 | ||
|
|
082c4c16b9 | ||
|
|
0e837958d9 | ||
|
|
116d69ece9 | ||
|
|
35f818d00d | ||
|
|
3f3b8c53b2 | ||
|
|
f197ae3ab5 | ||
|
|
5b58bfbb84 | ||
|
|
b9f10ebb0e | ||
|
|
cf2af10110 | ||
|
|
745300c921 |
@@ -2,4 +2,4 @@
|
||||
|
||||
Discord bot for reporting F1 information.
|
||||
|
||||
Makes use of code from fastf1 python library (https://github.com/theOehrly/Fast-F1)
|
||||
Makes use of code from fastf1 python library (https://github.com/theOehrly/Fast-F1)
|
||||
|
||||
@@ -5,7 +5,10 @@ import logging
|
||||
import requests
|
||||
import time
|
||||
import sqlite3
|
||||
import sys
|
||||
|
||||
from contextlib import closing
|
||||
from filelock import Timeout, FileLock
|
||||
from fastf1.signalr_aio import Connection
|
||||
|
||||
import fastf1
|
||||
@@ -84,6 +87,8 @@ class SignalRClient:
|
||||
"SessionData", "LapCount"]
|
||||
|
||||
self.debug = debug
|
||||
self.messages_db = 'messages.db'
|
||||
self.messages_lock = FileLock('messages.lock')
|
||||
self.filename = filename
|
||||
self.filemode = filemode
|
||||
self.timeout = timeout
|
||||
@@ -91,9 +96,11 @@ class SignalRClient:
|
||||
|
||||
if not logger:
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(levelname)s: %(message)s"
|
||||
format="%(asctime)s - %(levelname)s: %(message)s", \
|
||||
stream=sys.stderr
|
||||
)
|
||||
self.logger = logging.getLogger('SignalR')
|
||||
self.logger.warning("Created logger for SignalR")
|
||||
else:
|
||||
self.logger = logger
|
||||
|
||||
@@ -101,17 +108,15 @@ class SignalRClient:
|
||||
self._t_last_message = None
|
||||
|
||||
def _to_file(self, msg):
|
||||
"""
|
||||
self._output_file.write(msg + '\n')
|
||||
self._output_file.flush()
|
||||
"""
|
||||
#print(msg)
|
||||
con = sqlite3.connect('messages.db')
|
||||
cur = con.cursor()
|
||||
cur.execute("insert into messages (message) values(?)", (msg,))
|
||||
con.commit()
|
||||
cur.close()
|
||||
con.close()
|
||||
try:
|
||||
with self.messages_lock:
|
||||
with closing(sqlite3.connect(self.messages_db)) as con:
|
||||
with closing(con.cursor()) as cur:
|
||||
#self.logger.warning("about to log: " + msg)
|
||||
cur.execute("insert into messages (message) values(?)", (msg,))
|
||||
con.commit()
|
||||
except:
|
||||
print(f'Error writing message to db.')
|
||||
|
||||
async def _on_do_nothing(self, msg):
|
||||
# just do nothing with the message; intended for debug mode where some
|
||||
@@ -186,7 +191,7 @@ class SignalRClient:
|
||||
f"[v{fastf1.__version__}]")
|
||||
await asyncio.gather(asyncio.ensure_future(self._supervise()),
|
||||
asyncio.ensure_future(self._run()))
|
||||
self._output_file.close()
|
||||
#self._output_file.close()
|
||||
self.logger.warning("Exiting...")
|
||||
|
||||
def start(self):
|
||||
|
||||
BIN
bing/1.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
bing/10.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
bing/2.png
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
bing/3.png
Normal file
|
After Width: | Height: | Size: 444 KiB |
BIN
bing/4.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
bing/5.png
Normal file
|
After Width: | Height: | Size: 281 KiB |
BIN
bing/6.png
Normal file
|
After Width: | Height: | Size: 356 KiB |
BIN
bing/7.png
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
bing/8.png
Normal file
|
After Width: | Height: | Size: 329 KiB |
BIN
bing/9.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
26
binger.py
Executable file
@@ -0,0 +1,26 @@
|
||||
import glob
|
||||
from random import randrange
|
||||
import sqlite3
|
||||
|
||||
BING_IMGS_PATH = "bing/*"
|
||||
DB = "bing.db"
|
||||
|
||||
def get_image_count():
|
||||
# Choose a random image
|
||||
bing_files = glob.glob(BING_IMGS_PATH)
|
||||
image_idx = randrange(len(bing_files))
|
||||
image = bing_files[image_idx]
|
||||
|
||||
# Get the latest count and increment
|
||||
con = sqlite3.connect(DB)
|
||||
cur = con.cursor()
|
||||
cur.execute("UPDATE BING_COUNT SET COUNT = COUNT + 1")
|
||||
con.commit()
|
||||
result = cur.execute("SELECT COUNT FROM BING_COUNT")
|
||||
count = result.fetchone()
|
||||
count = count[0]
|
||||
|
||||
cur.close()
|
||||
con.close()
|
||||
|
||||
return(image, count)
|
||||
56
bingo.py
Executable file
@@ -0,0 +1,56 @@
|
||||
import glob
|
||||
from PIL import Image
|
||||
from random import randrange
|
||||
from uuid import uuid4
|
||||
|
||||
class Bingo:
|
||||
"""Class which allows creation and cleanup of F1 bingo card images."""
|
||||
def __init__(self):
|
||||
self.LAYOUT_WIDTH = 88
|
||||
self.X_OFFSET = 10
|
||||
self.Y_OFFSET = 110
|
||||
self.SQUARES_PATH = "bingo_images/squares/*.png"
|
||||
self.FREE_SQUARES_PATH = "bingo_images/free_squares/*.png"
|
||||
self.BLANK_CARD_PATH = "bingo_images/card_blank.png"
|
||||
self.TEMP_FOLDER = "bingo_images/temp/"
|
||||
|
||||
def get_card(self):
|
||||
square_files = glob.glob(self.SQUARES_PATH)
|
||||
free_square_files = glob.glob(self.FREE_SQUARES_PATH)
|
||||
used_files = set()
|
||||
|
||||
with Image.open(self.BLANK_CARD_PATH) as card_img:
|
||||
card_img.load()
|
||||
card_img = card_img.convert('RGBA')
|
||||
|
||||
# Fill the grid
|
||||
for y in range(5):
|
||||
for x in range(5):
|
||||
square_file = ""
|
||||
# If this is the center square, pick a random free square
|
||||
if x == 2 and y == 2:
|
||||
square_file = \
|
||||
free_square_files[randrange(len(free_square_files))]
|
||||
|
||||
# otherwise, find a random file that hasn't been used yet
|
||||
else:
|
||||
rand_file_idx = randrange(len(square_files))
|
||||
while rand_file_idx in used_files:
|
||||
rand_file_idx = randrange(len(square_files))
|
||||
|
||||
square_file = square_files[rand_file_idx]
|
||||
used_files.add(rand_file_idx)
|
||||
|
||||
with Image.open(square_file) as square:
|
||||
|
||||
position = (self.X_OFFSET + (x * self.LAYOUT_WIDTH),
|
||||
self.Y_OFFSET + (y * self.LAYOUT_WIDTH))
|
||||
|
||||
card_img.paste(square, position, square)
|
||||
|
||||
# Write image to temp file
|
||||
outfile = "".join((self.TEMP_FOLDER, str(uuid4()), ".png"))
|
||||
print(f"{outfile=}")
|
||||
card_img.save(outfile)
|
||||
return outfile
|
||||
|
||||
BIN
bingo_images/card_blank.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
bingo_images/card_blank.xcf
Normal file
BIN
bingo_images/free_space.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
bingo_images/free_squares/free_buxton_pause.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
bingo_images/free_squares/free_cofty_sir_lewis.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
bingo_images/free_squares/free_rosanna_towers.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
bingo_images/squares/a_driver_does_no_laps.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
bingo_images/squares/aerorake.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
bingo_images/squares/anyone_but_max_p1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
bingo_images/squares/big_changes.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
bingo_images/squares/big_spin_t12.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
bingo_images/squares/car_debris_on_track.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
bingo_images/squares/car_different.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
bingo_images/squares/carbon_fiber.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
bingo_images/squares/chadlonso_time_life.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
bingo_images/squares/commentator_car_confused.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
bingo_images/squares/dnf.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
bingo_images/squares/driver_complains_impeding.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
bingo_images/squares/driver_crashes_no_contact.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
bingo_images/squares/driver_says_shutup.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
bingo_images/squares/flowviz.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
bingo_images/squares/haas_stops.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
bingo_images/squares/honda_engine_dies.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
bingo_images/squares/its_only_testing.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
bingo_images/squares/lockup_t1.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
bingo_images/squares/mercedes_downplays.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
bingo_images/squares/no_power.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
bingo_images/squares/puncture.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
bingo_images/squares/radical_concept_fails.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
bingo_images/squares/radical_concept_works.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
bingo_images/squares/red_flag.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
bingo_images/squares/redbull_run_most.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
bingo_images/squares/sandbagging.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
bingo_images/squares/silly_season.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
bingo_images/squares/square_template.xcf
Normal file
BIN
bingo_images/squares/team_hides_work.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
bingo_images/squares/team_misnamed.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
bingo_images/squares/teammates_collide.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
bingo_images/squares/tifosi.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
bingo_images/squares/torro_rosso_or_vcarb.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
bingo_images/squares/williams_first_out.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
bingo_images/squares/williams_top_speed_trap.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
1
requirements.txt
Executable file → Normal file
@@ -3,3 +3,4 @@ discord==2.2.3
|
||||
fastf1==3.0.3
|
||||
jdata==0.5.3
|
||||
Requests==2.31.0
|
||||
websockets==11.0.3
|
||||
|
||||
619
robottas.py
@@ -1,11 +1,14 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import asyncio
|
||||
from bingo import Bingo
|
||||
import binger
|
||||
import collections.abc
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
@@ -14,9 +17,12 @@ from subprocess import Popen
|
||||
import time
|
||||
import discord
|
||||
|
||||
from contextlib import closing
|
||||
from filelock import Timeout, FileLock
|
||||
from discord.ext import commands, tasks
|
||||
|
||||
|
||||
|
||||
class Robottas(commands.Bot):
|
||||
|
||||
# The following section is adapted from code by theOehrly on GitHub FastF1 project
|
||||
@@ -24,15 +30,16 @@ class Robottas(commands.Bot):
|
||||
# the Livetiming client.
|
||||
|
||||
@staticmethod
|
||||
def convert_message(raw):
|
||||
def convert_message(raw, logger):
|
||||
data = raw.replace("'", '"') \
|
||||
.replace('True', 'true') \
|
||||
.replace('False', 'false')
|
||||
|
||||
try:
|
||||
data = json.loads(data)
|
||||
#logger.warn(f"convert_message returning: {data}")
|
||||
return data
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("json decode error for")
|
||||
return ""
|
||||
|
||||
# End section adapted from FastF1
|
||||
@@ -74,8 +81,9 @@ class Robottas(commands.Bot):
|
||||
while len(self.message_queue) > 0 and \
|
||||
self.message_queue[0][0] < time.time() - self.delay:
|
||||
message = self.message_queue.pop(0)[1]
|
||||
self.logger.warning(f'process_delay_messages: {message[:50]}')
|
||||
await self.send_message(message)
|
||||
await asyncio.sleep(1)
|
||||
await asyncio.sleep(3)
|
||||
|
||||
async def send_status_report(self, report):
|
||||
self.send_delay_message(report)
|
||||
@@ -118,49 +126,74 @@ class Robottas(commands.Bot):
|
||||
# Return None or flag message
|
||||
return report
|
||||
|
||||
|
||||
async def load_rcm_messages_helper(self, msg):
|
||||
|
||||
self.logger.warning(f'helper msg: {msg}')
|
||||
report = None
|
||||
if 'Category' in msg.keys():
|
||||
category = msg['Category']
|
||||
category = category.upper()
|
||||
|
||||
if category == "FLAG":
|
||||
report = await self.load_flag_message(msg)
|
||||
|
||||
elif category == "OTHER":
|
||||
|
||||
if self.session_type == "RACE" and "DELETED" in msg['Message']:
|
||||
pass
|
||||
|
||||
elif "SLIPPERY" in msg['Message'] and \
|
||||
not self.is_slippery_reported:
|
||||
self.is_slippery_reported = True
|
||||
report = "It's slippery out there!"
|
||||
else:
|
||||
report = msg['Message']
|
||||
|
||||
elif category == "DRS":
|
||||
report = msg['Message']
|
||||
|
||||
elif category == "CAREVENT" and \
|
||||
(self.session_type == "PRACTICE" or
|
||||
self.session_type == "QUALI"):
|
||||
report = msg['Message']
|
||||
|
||||
elif category == "SAFETYCAR":
|
||||
if msg["Mode"] == 'VIRTUAL SAFETY CAR':
|
||||
report = f"{self.flag_dict['VSC']}" + \
|
||||
f"{msg['Message']}" + \
|
||||
f"{self.flag_dict['VSC']}"
|
||||
elif msg["Mode"] == 'SAFETY CAR':
|
||||
report = f"{self.flag_dict['SC']}" + \
|
||||
f"{msg['Message']}" + \
|
||||
f"{self.flag_dict['SC']}"
|
||||
|
||||
self.logger.warning(f'rcm helper - report: {report}')
|
||||
return report
|
||||
|
||||
async def load_rcm_messages(self, data):
|
||||
if "Messages" in data.keys():
|
||||
report = None
|
||||
for key in data['Messages'].keys():
|
||||
message = data['Messages'][key]
|
||||
if 'Category' in message.keys():
|
||||
category = message["Category"]
|
||||
category = category.upper()
|
||||
|
||||
if category == "FLAG":
|
||||
report = await self.load_flag_message(message)
|
||||
self.logger.warning(f'load_rcm_messages - data: {data}')
|
||||
# Value of 'Messages' can be scalar or array.
|
||||
# If scalar, pass to helper. If array, loop and send to helper
|
||||
msgs_value = data['Messages']
|
||||
self.logger.warning(f'load_rcm_messages - msgs_value: {msgs_value} type: {type(msgs_value)}')
|
||||
|
||||
elif category == "OTHER":
|
||||
if self.session_type == "RACE" and "DELETED" in message['Message']:
|
||||
pass
|
||||
elif "SLIPPERY" in message['Message'] and \
|
||||
not self.is_slippery_reported:
|
||||
self.is_slippery_reported = True
|
||||
report = "It's slippery out there!"
|
||||
else:
|
||||
report = message['Message']
|
||||
|
||||
elif category == "DRS":
|
||||
report = message['Message']
|
||||
|
||||
elif category == "CAREVENT" and \
|
||||
(self.session_type == "PRACTICE" or
|
||||
self.session_type == "QUALI"):
|
||||
report = message['Message']
|
||||
|
||||
elif category == "SAFETYCAR":
|
||||
if message["Mode"] == 'VIRTUAL SAFETY CAR':
|
||||
report = f"{self.flag_dict['VSC']}" + \
|
||||
f"{message['Message']}" + \
|
||||
f"{self.flag_dict['VSC']}"
|
||||
|
||||
elif message["Mode"] == 'SAFETY CAR':
|
||||
report = f"{self.flag_dict['SC']}" + \
|
||||
f"{message['Message']}" + \
|
||||
f"{self.flag_dict['SC']}"
|
||||
|
||||
if report is not None:
|
||||
await self.send_status_report(report)
|
||||
# If value is a list
|
||||
if isinstance(msgs_value, list):
|
||||
for msg in msgs_value:
|
||||
self.logger.warning(f'load_rcm_messages array msg: {msg}')
|
||||
report = await self.load_rcm_messages_helper(msg)
|
||||
if report is not None:
|
||||
await self.send_status_report(report)
|
||||
else:
|
||||
self.logger.warning(f'load_rcm_messages scalar msg: {msgs_value}')
|
||||
for msg in msgs_value.values():
|
||||
report = await self.load_rcm_messages_helper(msg)
|
||||
if report is not None:
|
||||
await self.send_status_report(report)
|
||||
|
||||
async def load_lap_data(self, data):
|
||||
if "CurrentLap" in data.keys():
|
||||
@@ -173,6 +206,11 @@ class Robottas(commands.Bot):
|
||||
# i.e. shortened due to rain.
|
||||
if "TotalLaps" in data.keys():
|
||||
self.total_laps = int(data["TotalLaps"])
|
||||
|
||||
#Check to see about sending half distance message
|
||||
if self.current_lap == int(self.total_laps / 2) + 1:
|
||||
await self.send_message("We've passed half distance! Has Lance binned it yet?")
|
||||
|
||||
# Notify on lap change if matches a driver
|
||||
key = str(self.total_laps - int(current_lap))
|
||||
if key in self.driver_dict.keys():
|
||||
@@ -326,6 +364,7 @@ class Robottas(commands.Bot):
|
||||
self.weather = weather_txt
|
||||
|
||||
def load_timing_stats_data(self, data):
|
||||
self.logger.warning(f'load_timing_stats_data: {data}')
|
||||
if "Lines" in data.keys():
|
||||
lines = data["Lines"]
|
||||
for driver_num in lines.keys():
|
||||
@@ -370,6 +409,7 @@ class Robottas(commands.Bot):
|
||||
await self.print_driver_range(ctx, 10, 20)
|
||||
|
||||
def load_initial(self, message):
|
||||
#self.logger.warning("in load_initial")
|
||||
# Load podium data
|
||||
if 'R' in message.keys():
|
||||
if 'TopThree' in message['R'].keys():
|
||||
@@ -382,6 +422,7 @@ class Robottas(commands.Bot):
|
||||
|
||||
# Load driver list
|
||||
if 'DriverList' in message['R'].keys():
|
||||
#self.logger.warning("loading DriverList")
|
||||
for driver_num in message['R']['DriverList'].keys():
|
||||
if driver_num == '_kf':
|
||||
continue
|
||||
@@ -419,6 +460,8 @@ class Robottas(commands.Bot):
|
||||
async def process_message(self, message):
|
||||
try:
|
||||
if isinstance(message, collections.abc.Sequence):
|
||||
self.logger.warning(f"in process_message {message[:50]}")
|
||||
|
||||
if message[0] == 'Heartbeat':
|
||||
return
|
||||
|
||||
@@ -449,41 +492,65 @@ class Robottas(commands.Bot):
|
||||
self.load_initial(message)
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
self.logger.warning(f"Error in process_message: {e}")
|
||||
|
||||
def get_messages_from_db(self):
|
||||
try:
|
||||
messages = []
|
||||
con = sqlite3.connect(self.dbfile)
|
||||
cur = con.cursor()
|
||||
cur2 = con.cursor()
|
||||
for row in cur.execute('select id, message from messages order by id asc'):
|
||||
messages.append(self.convert_message(row[1]))
|
||||
with self.messages_lock:
|
||||
with closing(sqlite3.connect(self.dbfile)) as con:
|
||||
with closing(con.cursor()) as cur:
|
||||
with closing(con.cursor()) as cur2:
|
||||
for row in cur.execute('select id, message from messages order by id asc'):
|
||||
msg = row[1]
|
||||
messages.append(self.convert_message(msg, self.logger))
|
||||
self.logger.warning(f"get_messages_from_db: {msg[:50]}")
|
||||
|
||||
# Now that we have the message, delete this row from the dbfile
|
||||
cur2.execute(f"delete from messages where id = {row[0]}")
|
||||
# Now that we have the message, delete this row from the dbfile
|
||||
cur2.execute(f"delete from messages where id = {row[0]}")
|
||||
|
||||
con.commit()
|
||||
cur.close()
|
||||
cur2.close()
|
||||
con.close()
|
||||
con.commit()
|
||||
|
||||
return messages
|
||||
except:
|
||||
self.logger.warning(f"Error retrieving messages.")
|
||||
return []
|
||||
|
||||
|
||||
def clear_messages_from_db(self):
|
||||
try:
|
||||
with self.messages_lock:
|
||||
with closing(sqlite3.connect(self.dbfile)) as con:
|
||||
with closing(con.cursor()) as cur:
|
||||
cur.execute('delete from messages')
|
||||
con.commit()
|
||||
except Exception as e:
|
||||
self.logger.warning(f"error in clear_messages_from_db: {e}")
|
||||
|
||||
async def _race_report(self, ctx):
|
||||
if self.is_reporting:
|
||||
await self.rbstop()
|
||||
|
||||
self.clear_messages_from_db()
|
||||
self.report_deleted_lap = False
|
||||
self.session_type = 'RACE'
|
||||
await self._report(ctx)
|
||||
|
||||
async def _quali_report(self, ctx):
|
||||
if self.is_reporting:
|
||||
await self.rbstop()
|
||||
|
||||
self.clear_messages_from_db()
|
||||
self.report_deleted_lap = True
|
||||
self.session_type = 'QUALI'
|
||||
|
||||
await self._report(ctx)
|
||||
|
||||
async def _practice_report(self, ctx):
|
||||
if self.is_reporting:
|
||||
await self.rbstop()
|
||||
|
||||
self.clear_messages_from_db()
|
||||
self.report_deleted_lap = True
|
||||
self.session_type = 'PRACTICE'
|
||||
await self._report(ctx)
|
||||
@@ -495,16 +562,19 @@ class Robottas(commands.Bot):
|
||||
|
||||
while self.is_reporting:
|
||||
# Do processing
|
||||
await asyncio.sleep(5)
|
||||
|
||||
#self.logger.warning("in is_reporting")
|
||||
|
||||
# process any new messages in the db
|
||||
messages = self.get_messages_from_db()
|
||||
try:
|
||||
for message in messages:
|
||||
self.logger.warning(f"processing message: {message}")
|
||||
await self.process_message(message)
|
||||
|
||||
await asyncio.sleep(3)
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
self.logger.warning(f'Error in _report: {e}')
|
||||
|
||||
# process any messages in the delay queue
|
||||
await self.process_delay_messages()
|
||||
@@ -598,49 +668,120 @@ class Robottas(commands.Bot):
|
||||
command_txt += self.collector_params
|
||||
self.collector_proc = Popen(command_txt.split())
|
||||
|
||||
|
||||
async def start_test_collect(self, ctx):
|
||||
await self.stop_test_collect()
|
||||
self.is_test_collecting = True
|
||||
self.channel = ctx.channel
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
command_txt = os.path.join(dir_path, self.test_collector_command)
|
||||
self.collector_proc = Popen(command_txt.split())
|
||||
|
||||
while self.is_test_collecting:
|
||||
await asyncio.sleep(10)
|
||||
|
||||
messages = self.get_messages_from_db()
|
||||
try:
|
||||
for msg in messages:
|
||||
self.logger.warning(f"processing message{msg}")
|
||||
await self.process_message(msg)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Error in start_test_collect: {e}")
|
||||
|
||||
await self.process_delay_messages()
|
||||
|
||||
|
||||
async def stop_collect(self):
|
||||
self.is_collecting = False
|
||||
self.is_test_collecting = False
|
||||
try:
|
||||
if self.collector_proc != None:
|
||||
self.collector_proc.kill()
|
||||
self.clear_messages_from_db()
|
||||
except:
|
||||
pass
|
||||
self.logger.warning("error in stop_collect.")
|
||||
|
||||
try:
|
||||
if self.test_collector_proc != None:
|
||||
self.collector_proc.kill()
|
||||
self.clear_messages_from_db()
|
||||
except:
|
||||
self.logger.warning("error in stop_collect for test.")
|
||||
|
||||
async def stop_test_collect(self):
|
||||
self.is_test_collecting = False
|
||||
try:
|
||||
if self.test_collector_proc != None:
|
||||
self.test_collector_proc.kill()
|
||||
self.clear_messages_from_db()
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Error in stop_test_collect: {e}")
|
||||
|
||||
|
||||
def decode_watched(self, w):
|
||||
if w == 0:
|
||||
return 'Not Watched Yet'
|
||||
else:
|
||||
return 'Watched Already'
|
||||
|
||||
def get_delta_str(self, delta):
|
||||
min_str = "minute"
|
||||
hour_str = "hour"
|
||||
day_str = "day"
|
||||
|
||||
(hours, minutes, seconds) = (-1, -1, -1)
|
||||
(days, rest) = (0, "")
|
||||
|
||||
delta_str = str(delta)
|
||||
if " " in delta_str:
|
||||
(days, _, rest) = delta_str.split(" ")
|
||||
rest = rest.split(".")[0]
|
||||
(hours, minutes, seconds) = rest.split(":")
|
||||
else:
|
||||
rest = delta_str.split(".")[0]
|
||||
(hours, minutes, seconds) = rest.split(":")
|
||||
|
||||
|
||||
if int(days) != 1:
|
||||
day_str = "days"
|
||||
|
||||
if int(minutes) != 1:
|
||||
min_str = "minutes"
|
||||
|
||||
if int(hours) != 1:
|
||||
hour_str = "hours"
|
||||
|
||||
return f"{days} {day_str} {hours} {hour_str} {minutes} {min_str}"
|
||||
|
||||
|
||||
async def report_next_event(self, ctx):
|
||||
try:
|
||||
|
||||
tz = datetime.timezone.utc
|
||||
con = sqlite3.connect('schedule.db')
|
||||
cur = con.cursor()
|
||||
now_str = datetime.datetime.now(tz=tz).isoformat(sep=' ')
|
||||
now_str = now_str.split(".")[0]
|
||||
t1 = datetime.datetime.now(tz=tz)
|
||||
now_str = f"{t1.year}-{t1.month:02d}-{t1.day:02d} {t1.hour:02d}:{t1.minute:02d}:{t1.second}"
|
||||
|
||||
query = 'select * from schedule where date_start > ? ' + \
|
||||
'order by date_start asc limit 1'
|
||||
|
||||
|
||||
cur.execute(query, (now_str,))
|
||||
rows = cur.fetchall()
|
||||
|
||||
for row in rows:
|
||||
|
||||
t1 = datetime.datetime.fromisoformat(now_str)
|
||||
t2 = datetime.datetime.fromisoformat(row[3])
|
||||
t2 = datetime.datetime.fromisoformat(row[3] + "+00:00")
|
||||
delta = t2 - t1
|
||||
delta_str = self.get_delta_str(delta)
|
||||
|
||||
message = f"The next event is the {row[1]} - {row[2]} which is {delta} from now."
|
||||
message = f"The next event is Round {row[5]}: {row[1]} in {row[4]} which is {delta_str} from now."
|
||||
await ctx.send(message)
|
||||
|
||||
break # There should only be one row anyway
|
||||
|
||||
except:
|
||||
except Exception as e:
|
||||
await ctx.send("Sorry, hit the wall trying to find the answer...")
|
||||
print(e, file=sys.stderr)
|
||||
|
||||
|
||||
async def report_next_race(self, ctx):
|
||||
@@ -648,8 +789,8 @@ class Robottas(commands.Bot):
|
||||
tz = datetime.timezone.utc
|
||||
con = sqlite3.connect('schedule.db')
|
||||
cur = con.cursor()
|
||||
now_str = datetime.datetime.now(tz=tz).isoformat(sep=' ')
|
||||
now_str = now_str.split(".")[0]
|
||||
t1 = datetime.datetime.now(tz=tz)
|
||||
now_str = f"{t1.year}-{t1.month:02d}-{t1.day:02d} {t1.hour:02d}:{t1.minute}:{t1.second}"
|
||||
|
||||
query = "SELECT * FROM schedule WHERE date_start > ? AND " + \
|
||||
"session_type = 'Race' ORDER BY date_start ASC LIMIT 1"
|
||||
@@ -658,11 +799,12 @@ class Robottas(commands.Bot):
|
||||
rows = cur.fetchall()
|
||||
|
||||
for row in rows:
|
||||
t1 = datetime.datetime.fromisoformat(now_str)
|
||||
t2 = datetime.datetime.fromisoformat(row[3])
|
||||
t2 = datetime.datetime.fromisoformat(row[3] + "+00:00")
|
||||
delta = t2 - t1
|
||||
|
||||
message = f"The next race is the {row[1]} which is {delta} from now."
|
||||
delta_str = self.get_delta_str(delta)
|
||||
|
||||
message = f"The next race is Round {row[5]}: {row[1]} in {row[4]} which is {delta_str} from now."
|
||||
await ctx.send(message)
|
||||
|
||||
break
|
||||
@@ -670,6 +812,25 @@ class Robottas(commands.Bot):
|
||||
except:
|
||||
await ctx.send("Sorry, hit the wall tring to find the next race.")
|
||||
|
||||
|
||||
async def report_all_races(self, ctx):
|
||||
try:
|
||||
con = sqlite3.connect('schedule.db')
|
||||
cur = con.cursor()
|
||||
|
||||
query = "SELECT * FROM schedule where session_type = 'Race' ORDER BY date_start ASC"
|
||||
|
||||
cur.execute(query)
|
||||
rows = cur.fetchall()
|
||||
|
||||
await ctx.send( "All times UTC\n" )
|
||||
for row in rows:
|
||||
await ctx.send( f"Round {row[5]}: {row[1]} in {row[4]} which takes place {row[3]}\n" )
|
||||
|
||||
except:
|
||||
await ctx.send("Sorry, hit the wall tring to show all races.")
|
||||
|
||||
|
||||
# Register to alert for next race
|
||||
|
||||
async def register_next_race_alerts(self, ctx):
|
||||
@@ -771,16 +932,34 @@ class Robottas(commands.Bot):
|
||||
con.close()
|
||||
|
||||
|
||||
async def show_bing(self, ctx):
|
||||
(image, count) = binger.get_image_count()
|
||||
await self.send_image(ctx, image)
|
||||
await ctx.send(f"Bing count: {count}")
|
||||
|
||||
|
||||
def __init__(self):
|
||||
# Set debug or not
|
||||
self.debug = True
|
||||
|
||||
self.messages_lock = FileLock('messages.lock')
|
||||
|
||||
#configure logging
|
||||
logging.basicConfig(stream=sys.stderr, \
|
||||
format="%(asctime)s - %(levelname)s: %(message)s")
|
||||
self.logger = logging.getLogger('robottas')
|
||||
|
||||
self.bingo = Bingo()
|
||||
|
||||
# Discord authentication token
|
||||
self.token = self.get_token("token.txt")
|
||||
self.collector_command = "robottas_collector.py"
|
||||
self.test_collector_command = "test_messager.py"
|
||||
self.collector_params = " save dummy.txt"
|
||||
self.collector_proc = None
|
||||
self.test_collector_proc = None
|
||||
self.is_collecting = False
|
||||
self.test_collecting = False
|
||||
|
||||
# Preface messages with the following
|
||||
self.report_preamble = ':robot::peach: Alert!'
|
||||
@@ -819,52 +998,60 @@ class Robottas(commands.Bot):
|
||||
self.driver_dict = {
|
||||
'1': '<:VER:1067541523748630570>',
|
||||
'3': '<:RIC:1067870312949108887>',
|
||||
'5': '<:VET:1067964065516884079>',
|
||||
'4': '<:NOR:1067840487593082941>',
|
||||
'5': '<:BOR:1345026018938716161>',
|
||||
'6': '<:HAD:1345027038104387674>',
|
||||
'7': '<:DOO:1289936390993215601>',
|
||||
'10': '<:GAS:1067836596495327283>',
|
||||
'11': '<:PER:1067822335123525732>',
|
||||
'12': '<:ANT:1289237308805222491>',
|
||||
'14': '<:ALO:1067876094033793054>',
|
||||
'40': ':kiwi:',
|
||||
'16': '<:LEC:1067544797050585198>',
|
||||
'18': '<:STR:1067871582854336663>',
|
||||
'20': '<:MAG:1067883814992486510>',
|
||||
'22': '<:TSU:1067888851676315660>',
|
||||
'23': '<:ALB:1067874026871074887>',
|
||||
'24': '<:ZHO:1067865955117568010>',
|
||||
'27': '<:HUL:1067880110918742187>',
|
||||
'30': '<:LAW:1289237140051464204>',
|
||||
'31': '<:OCO:1067834157465612398>',
|
||||
'43': '<:COL:1289237227049844849>',
|
||||
'44': '<:HAM:1067828533746991165>',
|
||||
'55': '<:SAI:1067824776502067270>',
|
||||
'63': '<:RUS:1067831294748274728>',
|
||||
'16': '<:LEC:1067544797050585198>',
|
||||
'18': '<:STR:1067871582854336663>',
|
||||
'4': '<:NOR:1067840487593082941>',
|
||||
'10': '<:GAS:1067836596495327283>',
|
||||
'27': '<:HUL:1067880110918742187>',
|
||||
'31': '<:OCO:1067834157465612398>',
|
||||
'77': '<:BOT:1067819716527276032>',
|
||||
'81': '<:PIA:1067844998369914961>',
|
||||
'24': '<:ZHO:1067865955117568010>',
|
||||
'22': '<:TSU:1067888851676315660>',
|
||||
'20': '<:MAG:1067883814992486510>',
|
||||
'23': '<:ALB:1067874026871074887>',
|
||||
'2': '<:SAR:1067890949197414410>',
|
||||
'87': '<:BEA:1289237392649224278>'
|
||||
}
|
||||
|
||||
# Holds dictionary for driver 3-letter code to icon
|
||||
self.name_dict = {
|
||||
'VER': '<:VER:1067541523748630570>',
|
||||
'RIC': '<:RIC:1067870312949108887>',
|
||||
'VET': '<:VET:1067964065516884079>',
|
||||
'PER': '<:PER:1067822335123525732>',
|
||||
'ALO': '<:ALO:1067876094033793054>',
|
||||
'HAM': '<:HAM:1067828533746991165>',
|
||||
'SAI': '<:SAI:1067824776502067270>',
|
||||
'RUS': '<:RUS:1067831294748274728>',
|
||||
'LEC': '<:LEC:1067544797050585198>',
|
||||
'STR': '<:STR:1067871582854336663>',
|
||||
'NOR': '<:NOR:1067840487593082941>',
|
||||
'GAS': '<:GAS:1067836596495327283>',
|
||||
'HUL': '<:HUL:1067880110918742187>',
|
||||
'LAW': ':kiwi:',
|
||||
'OCO': '<:OCO:1067834157465612398>',
|
||||
'BOT': '<:BOT:1067819716527276032>',
|
||||
'PIA': '<:PIA:1067844998369914961>',
|
||||
'ZHO': '<:ZHO:1067865955117568010>',
|
||||
'TSU': '<:TSU:1067888851676315660>',
|
||||
'MAG': '<:MAG:1067883814992486510>',
|
||||
'ALB': '<:ALB:1067874026871074887>',
|
||||
'SAR': '<:SAR:1067890949197414410>',
|
||||
'ALO': '<:ALO:1067876094033793054>',
|
||||
'ANT': '<:ANT:1289237308805222491>',
|
||||
'BEA': '<:BEA:1289237392649224278>',
|
||||
'BOR': '<:BOR:1345026018938716161>',
|
||||
'BOT': '<:BOT:1067819716527276032>',
|
||||
'COL': '<:COL:1289237227049844849>',
|
||||
'DOO': '<:DOO:1289936390993215601>',
|
||||
'GAS': '<:GAS:1067836596495327283>',
|
||||
'HAD': '<:HAD:1345027038104387674>',
|
||||
'HAM': '<:HAM:1067828533746991165>',
|
||||
'HUL': '<:HUL:1067880110918742187>',
|
||||
'LAW': '<:LAW:1289237140051464204>',
|
||||
'LEC': '<:LEC:1067544797050585198>',
|
||||
'MAG': '<:MAG:1067883814992486510>',
|
||||
'NOR': '<:NOR:1067840487593082941>',
|
||||
'OCO': '<:OCO:1067834157465612398>',
|
||||
'PIA': '<:PIA:1067844998369914961>',
|
||||
'RIC': '<:RIC:1067870312949108887>',
|
||||
'RUS': '<:RUS:1067831294748274728>',
|
||||
'SAI': '<:SAI:1067824776502067270>',
|
||||
'STR': '<:STR:1067871582854336663>',
|
||||
'TSU': '<:TSU:1067888851676315660>',
|
||||
'VER': '<:VER:1067541523748630570>',
|
||||
'VET': '<:VET:1067964065516884079>',
|
||||
'ZHO': '<:ZHO:1067865955117568010>'
|
||||
}
|
||||
|
||||
# Holds dictionary for race states to icons
|
||||
@@ -897,7 +1084,7 @@ class Robottas(commands.Bot):
|
||||
self.started = False
|
||||
|
||||
# Hold message delay
|
||||
self.delay = 45
|
||||
self.delay = 20
|
||||
self.message_queue = []
|
||||
|
||||
# Hold whether to report deleted lap messages
|
||||
@@ -921,40 +1108,68 @@ class Robottas(commands.Bot):
|
||||
@self.command()
|
||||
async def rbhelp(ctx):
|
||||
|
||||
await ctx.send("commands: \n" +
|
||||
"!rbhelp - Print this help message " +
|
||||
"(but you knew that already)\n" +
|
||||
"!next_event - Prints time until the next event.\n" +
|
||||
"!next_race - Prints time until the next race.\n" +
|
||||
"!rbname - I will tell you my name.\n" +
|
||||
"!rbroot - I will tell you who I root for.\n" +
|
||||
"!rbreport - I will start race reporting in this channel. " +
|
||||
"I will try to tell you about current flags, laps left,\n" +
|
||||
"and safety cars.\n" +
|
||||
"!rbstop - Stop reporting.\n" +
|
||||
"!podium - Display podium positions.\n" +
|
||||
"!q1cut - Show drivers in Q1 cut positions.\n" +
|
||||
"!q2cut - Show drivers in Q2 cut positions.\n" +
|
||||
"!rbdelay - Set the race messaging delay in seconds.\n" +
|
||||
"The following display race control messages:\n" +
|
||||
" !animal\n" +
|
||||
" !bwoken\n" +
|
||||
" !calm\n" +
|
||||
" !forecast\n" +
|
||||
" !grandma\n" +
|
||||
" !grass\n" +
|
||||
" !no\n" +
|
||||
" !noengine\n" +
|
||||
" !pants\n" +
|
||||
" !paddock\n" +
|
||||
" !penalty\n" +
|
||||
" !stupid\n" +
|
||||
" !undercut\n" +
|
||||
"The following register / unregister scheduled next race / event messages.\n" +
|
||||
"!register_next_race_alerts - get an alert for the next race on Monday.\n" +
|
||||
"!register_next_event_alerts - get an alert for the next event on Monday.\n" +
|
||||
"!unregister_alerts - stop getting alerts on this channel.\n"
|
||||
)
|
||||
await ctx.send("Robottas commands:\n" +
|
||||
" !rbhelp - show this help message (but you knew that)")
|
||||
|
||||
await ctx.send("race reporting:\n" +
|
||||
" !rbstop - stop reporting. If you started reporting on an event " +
|
||||
"please run this when you are done." +
|
||||
" !race - start reporting on a race\n" +
|
||||
" !quali - start reporting on quali\n" +
|
||||
" !practice - start reporting on practice\n" +
|
||||
" !podium - show the podium positions\n" +
|
||||
" !q1cut - show drivers cut in q1 positions\n" +
|
||||
" !q2cut - show drivers cut in q2 positions")
|
||||
|
||||
await ctx.send("event info:\n" +
|
||||
" !next_event - Prints time until the next event.\n" +
|
||||
" !next_race - Prints time until the next race.\n" +
|
||||
" !all_races - Prints the loation and date of all races in the schedule.")
|
||||
|
||||
await ctx.send("meme type commands:\n" +
|
||||
" !animal - animal on the track\n" +
|
||||
" !bing - count Max bings\n" +
|
||||
" !bwoken - it's bwoken\n" +
|
||||
" !calm - keep calm but come on.\n" +
|
||||
" !censored\n" +
|
||||
" !ciao\n" +
|
||||
" !danger\n" +
|
||||
" !dangerbull\n" +
|
||||
" !encouragement\n" +
|
||||
" !forecast - what happened to that podium...\n" +
|
||||
" !grandma\n" +
|
||||
" !grass\n" +
|
||||
" !hard\n" +
|
||||
" !inin - in in in in in\n" +
|
||||
" !liked\n" +
|
||||
" !mariachi\n" +
|
||||
" !no\n" +
|
||||
" !noengine\n" +
|
||||
" !pants\n" +
|
||||
" !paddock\n" +
|
||||
" !penalty\n" +
|
||||
" !rain\n" +
|
||||
" !ricky\n" +
|
||||
" !rude - Charles thinks it's rude.\n" +
|
||||
" !slight - Charles did a slight touch.\n" +
|
||||
" !stupid\n" +
|
||||
" !steer\n" +
|
||||
" !tm\n" +
|
||||
" !undercut\n" +
|
||||
" !wall - Lance is in the wall\n" +
|
||||
" !yuki")
|
||||
|
||||
await ctx.send("bot commands:\n" +
|
||||
" !register_next_race_alerts - get an alert for the next race on Monday.\n" +
|
||||
" !register_next_event_alerts - get an alert for the next event on Monday.\n" +
|
||||
" !unregister_alerts - stop getting alerts on this channel.\n" +
|
||||
" !rbname - I will tell you my name.\n" +
|
||||
" !rbroot - I will tell you who I root for.\n" +
|
||||
" !rbdelay - Set the race messaging delay in seconds.")
|
||||
|
||||
await ctx.send("bingo:\n" +
|
||||
" !bingo_card - get a random bingo card.\n" +
|
||||
" !bingo - announce that you've won bingo.")
|
||||
|
||||
@self.command()
|
||||
async def rbroot(ctx):
|
||||
@@ -1012,21 +1227,24 @@ class Robottas(commands.Bot):
|
||||
|
||||
@self.command()
|
||||
async def race(ctx):
|
||||
if str(ctx.author) == "tamservo#0" or ctx.author.guild_permissions.administrator:
|
||||
await ctx.send(":robot::peach: Ready to report for the race!")
|
||||
await self._race_report(ctx)
|
||||
#if ctx.author.id == 581960756271251457 or \
|
||||
# ctx.author.guild_permissions.administrator:
|
||||
await ctx.send(":robot::peach: Ready to report for the race!")
|
||||
await self._race_report(ctx)
|
||||
|
||||
@self.command()
|
||||
async def quali(ctx):
|
||||
if str(ctx.author) == "tamservo#0" or ctx.author.guild_permissions.administrator:
|
||||
await ctx.send(":robot::peach: Ready to report on quali!")
|
||||
await self._quali_report(ctx)
|
||||
#if ctx.author.id == 581960756271251457 or \
|
||||
# ctx.author.guild_permissions.administrator:
|
||||
await ctx.send(":robot::peach: Ready to report on quali!")
|
||||
await self._quali_report(ctx)
|
||||
|
||||
@self.command()
|
||||
async def practice(ctx):
|
||||
if str(ctx.author) == "tamservo#0" or ctx.author.guild_permissions.administrator:
|
||||
await ctx.send(":robot::peach: Ready to report on practice!")
|
||||
await self._practice_report(ctx)
|
||||
#if ctx.author.id == 581960756271251457 or \
|
||||
# ctx.author.guild_permissions.administrator:
|
||||
await ctx.send(":robot::peach: Ready to report on practice!")
|
||||
await self._practice_report(ctx)
|
||||
|
||||
@self.command()
|
||||
async def flap(ctx):
|
||||
@@ -1043,7 +1261,9 @@ class Robottas(commands.Bot):
|
||||
|
||||
@self.command()
|
||||
async def start_collect(ctx):
|
||||
if str(ctx.author) == "tamservo#0" or ctx.author.guild_permissions.administrator:
|
||||
# Check id for tamservo or admin on channel
|
||||
if ctx.author.id == 581960756271251457 or \
|
||||
ctx.author.guild_permissions.administrator:
|
||||
# if an authorized user, start the collection script that
|
||||
# puts records into the database
|
||||
await self.start_collect()
|
||||
@@ -1052,6 +1272,10 @@ class Robottas(commands.Bot):
|
||||
async def danger(ctx):
|
||||
await ctx.send("That's some dangerous driving! " + self.name_dict["HAM"])
|
||||
|
||||
@self.command()
|
||||
async def dangerbull(ctx):
|
||||
await self.send_image(ctx, "images/dangerbull.png")
|
||||
|
||||
@self.command()
|
||||
async def dotd(ctx):
|
||||
await ctx.send("I don't know, probably " + self.name_dict["ALB"])
|
||||
@@ -1147,10 +1371,27 @@ class Robottas(commands.Bot):
|
||||
await ctx.send("Bono, my tyres are gone " + self.name_dict["HAM"])
|
||||
|
||||
# Commands that send images
|
||||
|
||||
@self.command()
|
||||
async def bingo(ctx):
|
||||
await self.send_image(ctx, "images/bingo_win.png")
|
||||
|
||||
@self.command()
|
||||
async def calm(ctx):
|
||||
await self.send_image(ctx, "images/calm.png")
|
||||
|
||||
@self.command()
|
||||
async def censored(ctx):
|
||||
await self.send_image(ctx, "images/censored.png")
|
||||
|
||||
@self.command()
|
||||
async def ciao(ctx):
|
||||
await self.send_image(ctx, "images/ciao.png")
|
||||
|
||||
@self.command()
|
||||
async def encouragement(ctx):
|
||||
await self.send_image(ctx, "images/encouragement.png")
|
||||
|
||||
@self.command()
|
||||
async def grandma(ctx):
|
||||
await self.send_image(ctx, "images/grandma.png")
|
||||
@@ -1163,6 +1404,22 @@ class Robottas(commands.Bot):
|
||||
async def forecast(ctx):
|
||||
await self.send_image(ctx, "images/forecast.png")
|
||||
|
||||
@self.command()
|
||||
async def hard(ctx):
|
||||
await self.send_image(ctx, "images/hard.gif")
|
||||
|
||||
@self.command()
|
||||
async def inin(ctx):
|
||||
await self.send_image(ctx, "images/in.png")
|
||||
|
||||
@self.command()
|
||||
async def liked(ctx):
|
||||
await self.send_image(ctx, "images/liked.png")
|
||||
|
||||
@self.command()
|
||||
async def mariachi(ctx):
|
||||
await self.send_image(ctx, "images/mariachi.mp4")
|
||||
|
||||
@self.command()
|
||||
async def no(ctx):
|
||||
await self.send_image(ctx, "images/no.png")
|
||||
@@ -1184,10 +1441,34 @@ class Robottas(commands.Bot):
|
||||
async def penalty(ctx):
|
||||
await self.send_image(ctx, "images/penalty.png")
|
||||
|
||||
@self.command()
|
||||
async def rain(ctx):
|
||||
await self.send_image(ctx, "images/rain.gif")
|
||||
|
||||
@self.command()
|
||||
async def ricky(ctx):
|
||||
await self.send_image(ctx, "images/ricky.gif")
|
||||
|
||||
@self.command()
|
||||
async def rude(ctx):
|
||||
await self.send_image(ctx, "images/rude.mp4")
|
||||
|
||||
@self.command()
|
||||
async def slight(ctx):
|
||||
await self.send_image(ctx, "images/slight.png")
|
||||
|
||||
@self.command()
|
||||
async def stupid(ctx):
|
||||
await self.send_image(ctx, "images/stupid.png")
|
||||
|
||||
@self.command()
|
||||
async def steer(ctx):
|
||||
await self.send_image(ctx, "images/steer.png")
|
||||
|
||||
@self.command()
|
||||
async def tm(ctx):
|
||||
await self.send_image(ctx, "images/tm.png")
|
||||
|
||||
@self.command()
|
||||
async def undercut(ctx):
|
||||
await self.send_image(ctx, "images/undercut.png")
|
||||
@@ -1202,6 +1483,15 @@ class Robottas(commands.Bot):
|
||||
await self.send_image(ctx, "images/bwoken.png")
|
||||
await self.send_audio(ctx, "bwoken.mp3", "audio/bwoken.mp3")
|
||||
|
||||
|
||||
@self.command()
|
||||
async def wall(ctx):
|
||||
await self.send_image(ctx, "images/wall.mp4")
|
||||
|
||||
@self.command()
|
||||
async def yuki(ctx):
|
||||
await self.send_image(ctx, "images/yuki.mp4")
|
||||
|
||||
## Calendar Commands
|
||||
|
||||
# Give days, hours, minutes until the next event
|
||||
@@ -1214,6 +1504,11 @@ class Robottas(commands.Bot):
|
||||
async def next_race(ctx):
|
||||
await self.report_next_race(ctx)
|
||||
|
||||
# Show all races
|
||||
@self.command()
|
||||
async def all_races(ctx):
|
||||
await self.report_all_races(ctx)
|
||||
|
||||
# Register to get monday next race alerts
|
||||
@self.command()
|
||||
async def register_next_race_alerts(ctx):
|
||||
@@ -1224,12 +1519,38 @@ class Robottas(commands.Bot):
|
||||
async def register_next_event_alerts(ctx):
|
||||
await self.register_next_event_alerts(ctx)
|
||||
|
||||
# Set total laps ( like when they shorten the race laps )
|
||||
@self.command()
|
||||
async def set_total_laps(ctx, laps):
|
||||
self.total_laps = laps
|
||||
await ctx.send(f"Total laps set to {self.total_laps}")
|
||||
|
||||
# Unregister to get monday alerts
|
||||
@self.command()
|
||||
async def unregister_alerts(ctx):
|
||||
await self.unregister_alerts(ctx)
|
||||
|
||||
|
||||
# Bingo card
|
||||
@self.command()
|
||||
async def bingo_card(ctx):
|
||||
card_file = self.bingo.get_card()
|
||||
await self.send_image(ctx, card_file)
|
||||
os.remove(card_file)
|
||||
|
||||
|
||||
# Big counter
|
||||
@self.command()
|
||||
async def bing(ctx):
|
||||
await self.show_bing(ctx)
|
||||
|
||||
|
||||
# test processing messages
|
||||
@self.command()
|
||||
async def test_message_processing(ctx):
|
||||
await self.start_test_collect(ctx)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
rb = Robottas()
|
||||
rb.run_robottas()
|
||||
|
||||