diff --git a/README.md b/README.md
index a913bdb028..3803b8dce6 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ TrustyJAID's Cogs for [Red-DiscordBot](https://github.com/Cog-Creators/Red-Disc
| ExtendedModLog | 2.12.3 | ExtendedModLog, track changes made in the server.
Log changes within the server using extended modlogs, an extension of RedBot cores modlog. | RePulsR and TrustyJAID |
| Fenrir | 1.2.0 | Give users the option to kick, ban, or insult themselves via reactions.
Create reaction messages to kick or ban users! https://tenor.com/view/order66-gif-9116581 | TrustyJAID |
| Fun | 1.3.0 | Various fun commands like react, textflip, and regional
All sorts of commands that users may find fun or useful | Appu and TrustyJAID |
-| Hockey | 3.4.1 | Hockey commands
A cog to gather hockey scores, schedules, player data and more! | TrustyJAID |
+| Hockey | 3.4.2 | Hockey commands
A cog to gather hockey scores, schedules, player data and more! | TrustyJAID |
| Hue | 1.3.0 | Control your philips hue lights with redbot!
Lets you control your philips hue lights with redbot. | TrustyJAID |
| Imagemaker | 1.6.0 | Create your own feels!
Show how you really feel. Make someone beautiful. Make something illegal. | TrustyJAID, Ivan Seidel (isnowillegal.com), Bruno Lemos (isnowillegal.com), and Joćo Pedro (isnowillegal.com) |
| Imgflip | 3.0.0 | Recreation of Red v1 meme generator
Recreation of Red v1 meme generator | Twentysix and TrustyJAID |
diff --git a/hockey/helper.py b/hockey/helper.py
index c1f5643f45..1a2f76960c 100644
--- a/hockey/helper.py
+++ b/hockey/helper.py
@@ -50,11 +50,14 @@
TIMEZONE_RE = re.compile(r"|".join(re.escape(zone) for zone in pytz.common_timezones), flags=re.I)
-ACTIVE_TEAM_RE_STR = r"|".join(
- rf"{team}|{data['tri_code']}|{'|'.join(n for n in data['nickname'])}"
- for team, data in TEAMS.items()
- if data["active"]
-)
+
+ACTIVE_TEAM_RE_STR = r""
+for team, data in TEAMS.items():
+ if not data["active"]:
+ continue
+ nicks = "|".join(f"\b{n}\b" for n in data["nickname"])
+ ACTIVE_TEAM_RE_STR += rf"\b{team}\b|\b{data['tri_code']}\b|{nicks}"
+
ACTIVE_TEAM_RE = re.compile(ACTIVE_TEAM_RE_STR, flags=re.I)
VERSUS_RE = re.compile(r"vs\.?|versus", flags=re.I)
diff --git a/hockey/hockey.py b/hockey/hockey.py
index 80e1d73713..716870f335 100644
--- a/hockey/hockey.py
+++ b/hockey/hockey.py
@@ -56,7 +56,7 @@ class Hockey(
Gather information and post goal updates for NHL hockey teams
"""
- __version__ = "3.4.1"
+ __version__ = "3.4.2"
__author__ = ["TrustyJAID"]
def __init__(self, bot):
diff --git a/hockey/hockeyset.py b/hockey/hockeyset.py
index 58a7eec414..2cf7da0827 100644
--- a/hockey/hockeyset.py
+++ b/hockey/hockeyset.py
@@ -1,13 +1,18 @@
+import asyncio
+import os
+import re
+from datetime import datetime, timedelta, timezone
from typing import Optional
import discord
from red_commons.logging import getLogger
from redbot.core import commands
+from redbot.core.data_manager import cog_data_path
from redbot.core.i18n import Translator
from redbot.core.utils.chat_formatting import humanize_list
from .abc import HockeyMixin
-from .constants import TEAMS
+from .constants import BASE_URL, TEAMS
from .helper import StandingsFinder, StateFinder, TeamFinder
from .standings import Conferences, Divisions, Standings
@@ -111,6 +116,105 @@ async def hockey_slash(self, ctx: commands.Context):
"""
pass
+ @commands.group(name="hockeyevents", aliases=["nhlevents"])
+ @commands.bot_has_permissions(manage_events=True)
+ @commands.admin_or_permissions(manage_guild=True)
+ @commands.guild_only()
+ async def hockey_events(self, ctx: commands.Context):
+ """
+ Commands for setting up discord guild events
+ """
+
+ @hockey_events.command(name="set")
+ @commands.bot_has_permissions(manage_events=True)
+ @commands.admin_or_permissions(manage_guild=True)
+ @commands.guild_only()
+ @commands.max_concurrency(1, commands.BucketType.guild)
+ async def set_team_events(self, ctx: commands.Context, team: TeamFinder):
+ """
+ Create a scheduled server event for all games in the season for one team.
+
+ This command can take a while to complete.
+ """
+ url = f"{BASE_URL}/api/v1/schedule"
+ start = datetime.now()
+ end = start + timedelta(days=350)
+ params = {
+ "startDate": start.strftime("%Y-%m-%d"),
+ "endDate": end.strftime("%Y-%m-%d"),
+ "expand": "schedule.teams,schedule.linescore,schedule.broadcasts",
+ }
+ if team not in ["all", None]:
+ # if a team is provided get just that TEAMS data
+ params["teamId"] = ",".join(str(TEAMS[t]["id"]) for t in [team])
+ async with self.session.get(url, params=params) as resp:
+ data = await resp.json()
+ number_of_games = str(len(data.get("dates", [])))
+ await ctx.send(f"Creating events for {number_of_games} games.")
+ images_path = cog_data_path(self) / "teamlogos"
+ if not os.path.isdir(images_path):
+ os.mkdir(images_path)
+ existing_events = {}
+ for event in ctx.guild.scheduled_events:
+ event_id = re.search(r"\n(\d{6,})", event.description)
+ existing_events[event_id.group(1)] = event
+ for date in data["dates"]:
+ for game in date["games"]:
+ start = datetime.strptime(game["gameDate"], "%Y-%m-%dT%H:%M:%SZ").replace(
+ tzinfo=timezone.utc
+ )
+ end = start + timedelta(hours=3)
+ away = game["teams"]["away"]["team"]["name"]
+ home = game["teams"]["home"]["team"]["name"]
+ image_team = away if team == home else home
+ image_file = images_path / f"{image_team}.png"
+ if not os.path.isfile(image_file):
+ async with self.session.get(TEAMS[image_team]["logo"]) as resp:
+ image = await resp.read()
+ with image_file.open("wb") as outfile:
+ outfile.write(image)
+ image = open(image_file, "rb")
+ name = f"{away} @ {home}"
+ broadcasts = humanize_list(
+ [b.get("name", "Unknown") for b in game.get("broadcasts", [])]
+ )
+ description = name
+ if broadcasts:
+ description += f"\nBroadcasts: {broadcasts}"
+ game_id = str(game["gamePk"])
+ if game_id in existing_events:
+ try:
+ if existing_events[game_id].start_time != start:
+ await existing_events[game_id].edit(
+ start_time=start, end_time=end, reason="Start time changed"
+ )
+ if existing_events[game_id].description != description:
+ await existing_events[game_id].edit(
+ description=description, reason="Description has changed"
+ )
+ except Exception:
+ # I don't care if these don't edit properly
+ pass
+ continue
+ description += f"\n\n{game_id}"
+ try:
+ await ctx.guild.create_scheduled_event(
+ name=f"{away} @ {home}",
+ description=description,
+ start_time=start,
+ location=game.get("venue", {}).get("name", "Unknown place"),
+ end_time=end,
+ entity_type=discord.EntityType.external,
+ image=image.read(),
+ privacy_level=discord.PrivacyLevel.guild_only,
+ )
+ except Exception:
+ log.exception(
+ "Error creating scheduled event in %s for team %s", ctx.guild.id, team
+ )
+ image.close()
+ await asyncio.sleep(1)
+
@hockey_slash.command(name="global")
@commands.is_owner()
async def hockey_global_slash(self, ctx: commands.Context):
diff --git a/hockey/standings.py b/hockey/standings.py
index deabe38f72..3915dc2cd1 100644
--- a/hockey/standings.py
+++ b/hockey/standings.py
@@ -423,11 +423,17 @@ def __str__(self) -> str:
@property
def gaa(self):
- return self.goals_against / self.games_played
+ try:
+ return self.goals_against / self.games_played
+ except ZeroDivisionError:
+ return 0.0
@property
def gpg(self):
- return self.goals_scored / self.games_played
+ try:
+ return self.goals_scored / self.games_played
+ except ZeroDivisionError:
+ return 0.0
@classmethod
def from_json(cls, data: dict, division: Division, conference: Conference) -> TeamRecord: