mirror of https://github.com/stijndcl/didier
Check for free games
parent
41b5efd12d
commit
deefeb1106
|
@ -0,0 +1,30 @@
|
||||||
|
"""Add free games
|
||||||
|
|
||||||
|
Revision ID: 9fb84b4d9f0b
|
||||||
|
Revises: 11388e39bb90
|
||||||
|
Create Date: 2022-10-13 19:17:58.032182
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "9fb84b4d9f0b"
|
||||||
|
down_revision = "11388e39bb90"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table(
|
||||||
|
"free_games", sa.Column("free_game_id", sa.Integer(), nullable=False), sa.PrimaryKeyConstraint("free_game_id")
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table("free_games")
|
||||||
|
# ### end Alembic commands ###
|
|
@ -0,0 +1,20 @@
|
||||||
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from database.schemas import FreeGame
|
||||||
|
|
||||||
|
__all__ = ["add_free_games", "filter_present_games"]
|
||||||
|
|
||||||
|
|
||||||
|
async def add_free_games(session: AsyncSession, game_ids: list[int]):
|
||||||
|
"""Bulk-add a list of IDs into the database"""
|
||||||
|
games = [FreeGame(free_game_id=game_id) for game_id in game_ids]
|
||||||
|
session.add_all(games)
|
||||||
|
await session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
async def filter_present_games(session: AsyncSession, game_ids: list[int]) -> list[int]:
|
||||||
|
"""Filter a list of game IDs down to the ones that aren't in the database yet"""
|
||||||
|
query = select(FreeGame.free_game_id).where(FreeGame.free_game_id.in_(game_ids))
|
||||||
|
matches: list[int] = (await session.execute(query)).scalars().all()
|
||||||
|
return list(set(game_ids).difference(matches))
|
|
@ -33,6 +33,7 @@ __all__ = [
|
||||||
"DadJoke",
|
"DadJoke",
|
||||||
"Deadline",
|
"Deadline",
|
||||||
"EasterEgg",
|
"EasterEgg",
|
||||||
|
"FreeGame",
|
||||||
"GitHubLink",
|
"GitHubLink",
|
||||||
"Link",
|
"Link",
|
||||||
"MemeTemplate",
|
"MemeTemplate",
|
||||||
|
@ -174,6 +175,14 @@ class EasterEgg(Base):
|
||||||
startswith: bool = Column(Boolean, nullable=False, server_default="1")
|
startswith: bool = Column(Boolean, nullable=False, server_default="1")
|
||||||
|
|
||||||
|
|
||||||
|
class FreeGame(Base):
|
||||||
|
"""A temporarily free game"""
|
||||||
|
|
||||||
|
__tablename__ = "free_games"
|
||||||
|
|
||||||
|
free_game_id: int = Column(Integer, primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
class GitHubLink(Base):
|
class GitHubLink(Base):
|
||||||
"""A user's GitHub link"""
|
"""A user's GitHub link"""
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,8 @@ from didier.data.embeds.schedules import (
|
||||||
get_schedule_for_day,
|
get_schedule_for_day,
|
||||||
parse_schedule_from_content,
|
parse_schedule_from_content,
|
||||||
)
|
)
|
||||||
from didier.data.embeds.ufora.announcements import fetch_ufora_announcements
|
from didier.data.rss_feeds.free_games import fetch_free_games
|
||||||
|
from didier.data.rss_feeds.ufora import fetch_ufora_announcements
|
||||||
from didier.decorators.tasks import timed_task
|
from didier.decorators.tasks import timed_task
|
||||||
from didier.utils.discord.checks import is_owner
|
from didier.utils.discord.checks import is_owner
|
||||||
from didier.utils.types.datetime import LOCAL_TIMEZONE, tz_aware_now
|
from didier.utils.types.datetime import LOCAL_TIMEZONE, tz_aware_now
|
||||||
|
@ -48,6 +49,7 @@ class Tasks(commands.Cog):
|
||||||
|
|
||||||
self._tasks = {
|
self._tasks = {
|
||||||
"birthdays": self.check_birthdays,
|
"birthdays": self.check_birthdays,
|
||||||
|
"free_games": self.pull_free_games,
|
||||||
"schedules": self.pull_schedules,
|
"schedules": self.pull_schedules,
|
||||||
"reminders": self.reminders,
|
"reminders": self.reminders,
|
||||||
"ufora": self.pull_ufora_announcements,
|
"ufora": self.pull_ufora_announcements,
|
||||||
|
@ -61,6 +63,10 @@ class Tasks(commands.Cog):
|
||||||
if settings.BIRTHDAY_ANNOUNCEMENT_CHANNEL is not None:
|
if settings.BIRTHDAY_ANNOUNCEMENT_CHANNEL is not None:
|
||||||
self.check_birthdays.start()
|
self.check_birthdays.start()
|
||||||
|
|
||||||
|
# Only pull free gmaes if a channel was provided
|
||||||
|
if settings.FREE_GAMES_CHANNEL is not None:
|
||||||
|
self.pull_free_games.start()
|
||||||
|
|
||||||
# Only pull announcements if a token was provided
|
# Only pull announcements if a token was provided
|
||||||
if settings.UFORA_RSS_TOKEN is not None and settings.UFORA_ANNOUNCEMENTS_CHANNEL is not None:
|
if settings.UFORA_RSS_TOKEN is not None and settings.UFORA_ANNOUNCEMENTS_CHANNEL is not None:
|
||||||
self.pull_ufora_announcements.start()
|
self.pull_ufora_announcements.start()
|
||||||
|
@ -128,6 +134,26 @@ class Tasks(commands.Cog):
|
||||||
async def _before_check_birthdays(self):
|
async def _before_check_birthdays(self):
|
||||||
await self.client.wait_until_ready()
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
|
@tasks.loop(minutes=15)
|
||||||
|
async def pull_free_games(self, **kwargs):
|
||||||
|
"""Task that checks for free games occasionally"""
|
||||||
|
_ = kwargs
|
||||||
|
|
||||||
|
# No channel to send the embeds to
|
||||||
|
if settings.FREE_GAMES_CHANNEL is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
async with self.client.postgres_session as session:
|
||||||
|
games = await fetch_free_games(self.client.http_session, session)
|
||||||
|
channel = self.client.get_channel(settings.FREE_GAMES_CHANNEL)
|
||||||
|
|
||||||
|
for game in games:
|
||||||
|
await channel.send(embed=game.to_embed())
|
||||||
|
|
||||||
|
@pull_free_games.before_loop
|
||||||
|
async def _before_free_games(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
@tasks.loop(time=DAILY_RESET_TIME)
|
@tasks.loop(time=DAILY_RESET_TIME)
|
||||||
@timed_task(enums.TaskType.SCHEDULES)
|
@timed_task(enums.TaskType.SCHEDULES)
|
||||||
async def pull_schedules(self, **kwargs):
|
async def pull_schedules(self, **kwargs):
|
||||||
|
@ -166,6 +192,10 @@ class Tasks(commands.Cog):
|
||||||
# Only replace cached version if all schedules succeeded
|
# Only replace cached version if all schedules succeeded
|
||||||
self.client.schedules = new_schedules
|
self.client.schedules = new_schedules
|
||||||
|
|
||||||
|
@pull_schedules.before_loop
|
||||||
|
async def _before_pull_schedules(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
@tasks.loop(minutes=10)
|
@tasks.loop(minutes=10)
|
||||||
@timed_task(enums.TaskType.UFORA_ANNOUNCEMENTS)
|
@timed_task(enums.TaskType.UFORA_ANNOUNCEMENTS)
|
||||||
async def pull_ufora_announcements(self, **kwargs):
|
async def pull_ufora_announcements(self, **kwargs):
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import html
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from overrides import overrides
|
||||||
|
from pydantic import validator
|
||||||
|
|
||||||
|
from didier.data.embeds.base import EmbedPydantic
|
||||||
|
from didier.utils.discord import colours
|
||||||
|
|
||||||
|
__all__ = ["SEPARATOR", "FreeGameEmbed"]
|
||||||
|
|
||||||
|
SEPARATOR = " • Free • "
|
||||||
|
|
||||||
|
|
||||||
|
def _get_store_info(store: str) -> tuple[Optional[str], discord.Colour]:
|
||||||
|
"""Get the image url for a given store"""
|
||||||
|
store = store.lower()
|
||||||
|
|
||||||
|
if "epic" in store:
|
||||||
|
return (
|
||||||
|
"https://cdn2.unrealengine.com/"
|
||||||
|
"Unreal+Engine%2Feg-logo-filled-1255x1272-0eb9d144a0f981d1cbaaa1eb957de7a3207b31bb.png",
|
||||||
|
colours.epic_games_white(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if "gog" in store:
|
||||||
|
return (
|
||||||
|
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2e/GOG.com_logo.svg/1679px-GOG.com_logo.svg.png",
|
||||||
|
colours.gog_purple(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if "steam" in store:
|
||||||
|
return (
|
||||||
|
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/"
|
||||||
|
"Steam_icon_logo.svg/2048px-Steam_icon_logo.svg.png",
|
||||||
|
colours.steam_blue(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return None, discord.Colour.random()
|
||||||
|
|
||||||
|
|
||||||
|
class FreeGameEmbed(EmbedPydantic):
|
||||||
|
"""Embed for free games"""
|
||||||
|
|
||||||
|
dc_identifier: int
|
||||||
|
link: str
|
||||||
|
summary: str = ""
|
||||||
|
title: str
|
||||||
|
|
||||||
|
@validator("title")
|
||||||
|
def _clean_title(cls, value: str) -> str:
|
||||||
|
return html.unescape(value)
|
||||||
|
|
||||||
|
@overrides
|
||||||
|
def to_embed(self, **kwargs) -> discord.Embed:
|
||||||
|
name, store = self.title.split(SEPARATOR)
|
||||||
|
embed = discord.Embed(title=name, url=self.link, description=self.summary or None)
|
||||||
|
embed.set_author(name=store)
|
||||||
|
|
||||||
|
image, colour = _get_store_info(store)
|
||||||
|
if image is not None:
|
||||||
|
embed.set_thumbnail(url=image)
|
||||||
|
|
||||||
|
embed.colour = colour
|
||||||
|
|
||||||
|
return embed
|
|
@ -1,18 +1,11 @@
|
||||||
import re
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import async_timeout
|
|
||||||
import discord
|
import discord
|
||||||
import feedparser
|
|
||||||
from aiohttp import ClientSession
|
|
||||||
from markdownify import markdownify as md
|
from markdownify import markdownify as md
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
|
|
||||||
import settings
|
|
||||||
from database.crud import ufora_announcements as crud
|
|
||||||
from database.schemas import UforaCourse
|
from database.schemas import UforaCourse
|
||||||
from didier.data.embeds.base import EmbedBaseModel
|
from didier.data.embeds.base import EmbedBaseModel
|
||||||
from didier.utils.discord.colours import ghent_university_blue
|
from didier.utils.discord.colours import ghent_university_blue
|
||||||
|
@ -20,8 +13,6 @@ from didier.utils.types.datetime import LOCAL_TIMEZONE, int_to_weekday
|
||||||
from didier.utils.types.string import leading
|
from didier.utils.types.string import leading
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"fetch_ufora_announcements",
|
|
||||||
"parse_ids",
|
|
||||||
"UforaNotification",
|
"UforaNotification",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -107,68 +98,3 @@ class UforaNotification(EmbedBaseModel):
|
||||||
":"
|
":"
|
||||||
f"{leading('0', str(self.published_dt.second))}"
|
f"{leading('0', str(self.published_dt.second))}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_ids(url: str) -> Optional[tuple[int, int]]:
|
|
||||||
"""Parse the notification & course id out of a notification url"""
|
|
||||||
match = re.search(r"\d+-\d+$", url)
|
|
||||||
|
|
||||||
if not match:
|
|
||||||
return None
|
|
||||||
|
|
||||||
spl = match[0].split("-")
|
|
||||||
return int(spl[0]), int(spl[1])
|
|
||||||
|
|
||||||
|
|
||||||
async def fetch_ufora_announcements(
|
|
||||||
http_session: ClientSession, database_session: AsyncSession
|
|
||||||
) -> list[UforaNotification]:
|
|
||||||
"""Fetch all new announcements"""
|
|
||||||
notifications: list[UforaNotification] = []
|
|
||||||
|
|
||||||
# No token provided, don't fetch announcements
|
|
||||||
if settings.UFORA_RSS_TOKEN is None:
|
|
||||||
return notifications
|
|
||||||
|
|
||||||
courses = await crud.get_courses_with_announcements(database_session)
|
|
||||||
|
|
||||||
for course in courses:
|
|
||||||
course_announcement_ids = list(map(lambda announcement: announcement.announcement_id, course.announcements))
|
|
||||||
|
|
||||||
course_url = (
|
|
||||||
f"https://ufora.ugent.be/d2l/le/news/rss/{course.course_id}/course?token={settings.UFORA_RSS_TOKEN}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get the updated feed
|
|
||||||
with async_timeout.timeout(10):
|
|
||||||
async with http_session.get(course_url) as response:
|
|
||||||
feed = feedparser.parse(await response.text())
|
|
||||||
|
|
||||||
# Remove old notifications
|
|
||||||
fresh_feed: list[dict] = []
|
|
||||||
for entry in feed["entries"]:
|
|
||||||
parsed = parse_ids(entry["id"])
|
|
||||||
if parsed is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if parsed[0] not in course_announcement_ids:
|
|
||||||
fresh_feed.append(entry)
|
|
||||||
|
|
||||||
if fresh_feed:
|
|
||||||
for item in fresh_feed:
|
|
||||||
# Parse id's out
|
|
||||||
# Technically this can't happen but Mypy angry
|
|
||||||
parsed = parse_ids(item["id"])
|
|
||||||
|
|
||||||
if parsed is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Create a new notification
|
|
||||||
notification_id, course_id = parsed
|
|
||||||
notification = UforaNotification(item, course, notification_id, course_id)
|
|
||||||
notifications.append(notification)
|
|
||||||
|
|
||||||
# Create new db entry
|
|
||||||
await crud.create_new_announcement(database_session, notification_id, course, notification.published_dt)
|
|
||||||
|
|
||||||
return notifications
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import logging
|
||||||
|
from http import HTTPStatus
|
||||||
|
|
||||||
|
import feedparser
|
||||||
|
from aiohttp import ClientSession
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from database.crud.free_games import add_free_games, filter_present_games
|
||||||
|
from didier.data.embeds.free_games import SEPARATOR, FreeGameEmbed
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["fetch_free_games"]
|
||||||
|
|
||||||
|
|
||||||
|
async def fetch_free_games(http_session: ClientSession, database_session: AsyncSession) -> list[FreeGameEmbed]:
|
||||||
|
"""Get a fresh list of free games"""
|
||||||
|
url = "https://pepeizqdeals.com/?call_custom_simple_rss=1&csrp_cat=12"
|
||||||
|
async with http_session.get(url) as response:
|
||||||
|
if response.status != HTTPStatus.OK:
|
||||||
|
logger.error("Free games GET-request failed with status code %d." % response.status)
|
||||||
|
return []
|
||||||
|
|
||||||
|
feed = feedparser.parse(await response.text())
|
||||||
|
|
||||||
|
games: list[FreeGameEmbed] = []
|
||||||
|
game_ids: list[int] = []
|
||||||
|
|
||||||
|
for entry in feed["entries"]:
|
||||||
|
# Game isn't free
|
||||||
|
if SEPARATOR not in entry["title"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
game = FreeGameEmbed.parse_obj(entry)
|
||||||
|
games.append(game)
|
||||||
|
game_ids.append(game.dc_identifier)
|
||||||
|
|
||||||
|
# Filter out games that we already know
|
||||||
|
filtered_ids = await filter_present_games(database_session, game_ids)
|
||||||
|
|
||||||
|
# Insert new games into the database
|
||||||
|
await add_free_games(database_session, filtered_ids)
|
||||||
|
|
||||||
|
return list(filter(lambda x: x.dc_identifier in filtered_ids, games))
|
|
@ -0,0 +1,78 @@
|
||||||
|
import re
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
|
import feedparser
|
||||||
|
from aiohttp import ClientSession
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
import settings
|
||||||
|
from database.crud import ufora_announcements as crud
|
||||||
|
from didier.data.embeds.ufora.announcements import UforaNotification
|
||||||
|
|
||||||
|
__all__ = ["parse_ids", "fetch_ufora_announcements"]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ids(url: str) -> Optional[tuple[int, int]]:
|
||||||
|
"""Parse the notification & course id out of a notification url"""
|
||||||
|
match = re.search(r"\d+-\d+$", url)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
|
||||||
|
spl = match[0].split("-")
|
||||||
|
return int(spl[0]), int(spl[1])
|
||||||
|
|
||||||
|
|
||||||
|
async def fetch_ufora_announcements(
|
||||||
|
http_session: ClientSession, database_session: AsyncSession
|
||||||
|
) -> list[UforaNotification]:
|
||||||
|
"""Fetch all new announcements"""
|
||||||
|
notifications: list[UforaNotification] = []
|
||||||
|
|
||||||
|
# No token provided, don't fetch announcements
|
||||||
|
if settings.UFORA_RSS_TOKEN is None:
|
||||||
|
return notifications
|
||||||
|
|
||||||
|
courses = await crud.get_courses_with_announcements(database_session)
|
||||||
|
|
||||||
|
for course in courses:
|
||||||
|
course_announcement_ids = list(map(lambda announcement: announcement.announcement_id, course.announcements))
|
||||||
|
|
||||||
|
course_url = (
|
||||||
|
f"https://ufora.ugent.be/d2l/le/news/rss/{course.course_id}/course?token={settings.UFORA_RSS_TOKEN}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get the updated feed
|
||||||
|
with async_timeout.timeout(10):
|
||||||
|
async with http_session.get(course_url) as response:
|
||||||
|
feed = feedparser.parse(await response.text())
|
||||||
|
|
||||||
|
# Remove old notifications
|
||||||
|
fresh_feed: list[dict] = []
|
||||||
|
for entry in feed["entries"]:
|
||||||
|
parsed = parse_ids(entry["id"])
|
||||||
|
if parsed is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if parsed[0] not in course_announcement_ids:
|
||||||
|
fresh_feed.append(entry)
|
||||||
|
|
||||||
|
if fresh_feed:
|
||||||
|
for item in fresh_feed:
|
||||||
|
# Parse id's out
|
||||||
|
# Technically this can't happen but Mypy angry
|
||||||
|
parsed = parse_ids(item["id"])
|
||||||
|
|
||||||
|
if parsed is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Create a new notification
|
||||||
|
notification_id, course_id = parsed
|
||||||
|
notification = UforaNotification(item, course, notification_id, course_id)
|
||||||
|
notifications.append(notification)
|
||||||
|
|
||||||
|
# Create new db entry
|
||||||
|
await crud.create_new_announcement(database_session, notification_id, course, notification.published_dt)
|
||||||
|
|
||||||
|
return notifications
|
|
@ -1,15 +1,21 @@
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
"epic_games_white",
|
||||||
"error_red",
|
"error_red",
|
||||||
"github_white",
|
"github_white",
|
||||||
"ghent_university_blue",
|
"ghent_university_blue",
|
||||||
"ghent_university_yellow",
|
"ghent_university_yellow",
|
||||||
"google_blue",
|
"google_blue",
|
||||||
|
"steam_blue",
|
||||||
"urban_dictionary_green",
|
"urban_dictionary_green",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def epic_games_white() -> discord.Colour:
|
||||||
|
return discord.Colour.from_rgb(255, 255, 255)
|
||||||
|
|
||||||
|
|
||||||
def error_red() -> discord.Colour:
|
def error_red() -> discord.Colour:
|
||||||
return discord.Colour.red()
|
return discord.Colour.red()
|
||||||
|
|
||||||
|
@ -26,9 +32,17 @@ def ghent_university_yellow() -> discord.Colour:
|
||||||
return discord.Colour.from_rgb(255, 210, 0)
|
return discord.Colour.from_rgb(255, 210, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def gog_purple() -> discord.Colour:
|
||||||
|
return discord.Colour.purple()
|
||||||
|
|
||||||
|
|
||||||
def google_blue() -> discord.Colour:
|
def google_blue() -> discord.Colour:
|
||||||
return discord.Colour.from_rgb(66, 133, 244)
|
return discord.Colour.from_rgb(66, 133, 244)
|
||||||
|
|
||||||
|
|
||||||
|
def steam_blue() -> discord.Colour:
|
||||||
|
return discord.Colour.from_rgb(102, 192, 244)
|
||||||
|
|
||||||
|
|
||||||
def urban_dictionary_green() -> discord.Colour:
|
def urban_dictionary_green() -> discord.Colour:
|
||||||
return discord.Colour.from_rgb(220, 255, 0)
|
return discord.Colour.from_rgb(220, 255, 0)
|
||||||
|
|
|
@ -27,6 +27,8 @@ __all__ = [
|
||||||
"DISCORD_TEST_GUILDS",
|
"DISCORD_TEST_GUILDS",
|
||||||
"DISCORD_BOOS_REACT",
|
"DISCORD_BOOS_REACT",
|
||||||
"DISCORD_CUSTOM_COMMAND_PREFIX",
|
"DISCORD_CUSTOM_COMMAND_PREFIX",
|
||||||
|
"ERRORS_CHANNEL",
|
||||||
|
"FREE_GAMES_CHANNEL",
|
||||||
"UFORA_ANNOUNCEMENTS_CHANNEL",
|
"UFORA_ANNOUNCEMENTS_CHANNEL",
|
||||||
"UFORA_RSS_TOKEN",
|
"UFORA_RSS_TOKEN",
|
||||||
"IMGFLIP_NAME",
|
"IMGFLIP_NAME",
|
||||||
|
@ -65,6 +67,7 @@ DISCORD_BOOS_REACT: str = env.str("DISCORD_BOOS_REACT", "<:boos:6296037858402631
|
||||||
DISCORD_CUSTOM_COMMAND_PREFIX: str = env.str("DISCORD_CUSTOM_COMMAND_PREFIX", "?")
|
DISCORD_CUSTOM_COMMAND_PREFIX: str = env.str("DISCORD_CUSTOM_COMMAND_PREFIX", "?")
|
||||||
BIRTHDAY_ANNOUNCEMENT_CHANNEL: Optional[int] = env.int("BIRTHDAY_ANNOUNCEMENT_CHANNEL", None)
|
BIRTHDAY_ANNOUNCEMENT_CHANNEL: Optional[int] = env.int("BIRTHDAY_ANNOUNCEMENT_CHANNEL", None)
|
||||||
ERRORS_CHANNEL: Optional[int] = env.int("ERRORS_CHANNEL", None)
|
ERRORS_CHANNEL: Optional[int] = env.int("ERRORS_CHANNEL", None)
|
||||||
|
FREE_GAMES_CHANNEL: Optional[int] = env.int("FREE_GAMES_CHANNEL", None)
|
||||||
UFORA_ANNOUNCEMENTS_CHANNEL: Optional[int] = env.int("UFORA_ANNOUNCEMENTS_CHANNEL", None)
|
UFORA_ANNOUNCEMENTS_CHANNEL: Optional[int] = env.int("UFORA_ANNOUNCEMENTS_CHANNEL", None)
|
||||||
|
|
||||||
"""Discord Role ID's"""
|
"""Discord Role ID's"""
|
||||||
|
|
Loading…
Reference in New Issue