Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ NerdyPy/*.dll
NerdyPy/tmp/
NerdyPy/config.yaml
NerdyPy/config_humanmusic.yaml
NerdyPy/weather_cache.sqlite
NerpyBot.code-workspace

### macOS template
Expand Down
1 change: 1 addition & 0 deletions NerdyPy/modules/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from discord.app_commands import CommandSyncFailure, MissingApplicationID, TranslationError, checks
from discord.ext.commands import Cog, Context, Greedy, command, group, guild_only
from models.admin import GuildPrefix

from utils.errors import NerpyException


Expand Down
20 changes: 11 additions & 9 deletions NerdyPy/modules/moderation.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
# -*- coding: utf-8 -*-
from datetime import UTC, datetime, time, timedelta, timezone

from datetime import UTC, datetime, time, timedelta
from typing import Optional, Union

from discord import Embed, Member, TextChannel
from discord.app_commands import checks, rename
from discord.ext import tasks
from discord.ext.commands import Cog, Context, command, hybrid_command, hybrid_group
from humanize import naturaldate
from models.moderation import AutoDelete, AutoKicker
from pytimeparse2 import parse
from utils import format as fmt

from models.moderation import AutoDelete, AutoKicker

import utils.format as fmt
from utils.errors import NerpyException
from utils.helpers import empty_subcommand, send_hidden_message

utc = timezone.utc
# If no tzinfo is given then UTC is assumed.
loop_run_time = time(hour=12, minute=30, tzinfo=utc)
LOOP_RUN_TIME = time(hour=12, minute=30, tzinfo=UTC)


class Moderation(Cog):
Expand All @@ -32,7 +34,7 @@ def cog_unload(self):
self._autokicker_loop.cancel()
self._autodeleter_loop.cancel()

@tasks.loop(time=loop_run_time)
@tasks.loop(time=LOOP_RUN_TIME)
async def _autokicker_loop(self):
self.bot.log.debug("Start Autokicker Loop!")
try:
Expand All @@ -49,9 +51,9 @@ async def _autokicker_loop(self):
if len(member.roles) == 1:
self.bot.log.debug(f"Found member without role: {member.display_name}")
kick_reminder = datetime.now(UTC) - timedelta(seconds=(configuration.KickAfter / 2))
kick_reminder = kick_reminder.replace(tzinfo=timezone.utc)
kick_reminder = kick_reminder.replace(tzinfo=UTC)
kick_after = datetime.now(UTC) - timedelta(seconds=configuration.KickAfter)
kick_after = kick_after.replace(tzinfo=timezone.utc)
kick_after = kick_after.replace(tzinfo=UTC)

if member.joined_at < kick_after:
self.bot.log.debug(f"Kick member {member.display_name}!")
Expand Down Expand Up @@ -85,7 +87,7 @@ async def _autodeleter_loop(self):
list_before = None
else:
list_before = datetime.now(UTC) - timedelta(seconds=configuration.DeleteOlderThan)
list_before = list_before.replace(tzinfo=timezone.utc)
list_before = list_before.replace(tzinfo=UTC)
channel = guild.get_channel(configuration.ChannelId)

messages = []
Expand Down
3 changes: 2 additions & 1 deletion NerdyPy/modules/music.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
hybrid_command,
hybrid_group,
)
from utils import format as fmt

import utils.format as fmt
from utils.audio import QueuedSong
from utils.checks import is_connected_to_voice
from utils.download import download, fetch_yt_infos
Expand Down
2 changes: 2 additions & 0 deletions NerdyPy/modules/raidplaner.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

from discord import Embed
from discord.ext.commands import Cog, Context, command

from models.raidplaner import RaidEncounter, RaidEncounterRole, RaidEvent, RaidTemplate

from utils.conversation import Conversation


Expand Down
3 changes: 2 additions & 1 deletion NerdyPy/modules/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from aiohttp import ClientSession
from discord import Embed
from discord.ext.commands import Cog, Context, bot_has_permissions, hybrid_command
from utils import format as fmt

import utils.format as fmt
from utils.errors import NerpyException


Expand Down
2 changes: 2 additions & 0 deletions NerdyPy/modules/reminder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
from discord import TextChannel
from discord.ext import tasks
from discord.ext.commands import Context, GroupCog, hybrid_command

from models.reminder import ReminderMessage

from utils.format import box, pagify
from utils.helpers import send_hidden_message

Expand Down
3 changes: 2 additions & 1 deletion NerdyPy/modules/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
from discord.ext.commands import Context, GroupCog, bot_has_permissions, hybrid_command
from igdb.wrapper import IGDBWrapper
from requests import post
from utils import format as fmt

import utils.format as fmt
from utils.errors import NerpyException
from utils.helpers import youtube

Expand Down
3 changes: 2 additions & 1 deletion NerdyPy/modules/tagging.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
hybrid_group,
)
from models.tagging import Tag, TagType, TagTypeConverter
from utils import format as fmt

import utils.format as fmt
from utils.audio import QueuedSong
from utils.checks import is_connected_to_voice
from utils.download import download
Expand Down
132 changes: 60 additions & 72 deletions NerdyPy/modules/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

from datetime import UTC, datetime

from aiohttp import ClientSession
from discord import Embed, app_commands
from discord.ext.commands import Cog, Context, bot_has_permissions, hybrid_command
from utils import format as fmt
from openweather.weather import OpenWeather

import utils.format as fmt
from utils.errors import NerpyException
from utils.helpers import send_hidden_message

Expand All @@ -16,7 +17,7 @@ def __init__(self, bot):
bot.log.info(f"loaded {__name__}")

self.bot = bot
self.weather_api_key = self.bot.config.get("utility", "openweather")
self.weather_api = OpenWeather(self.bot.config["utility"]["openweather"])

@hybrid_command(name="ping", hidden=True)
@bot_has_permissions(send_messages=True)
Expand All @@ -37,75 +38,62 @@ async def _uptime(self, ctx: Context):
@bot_has_permissions(embed_links=True)
async def _get_weather(self, ctx: Context, *, query: str):
"""outputs weather information"""
location_url = f"http://api.openweathermap.org/geo/1.0/direct?q={query}&appid={self.weather_api_key}"

for umlaut in ["ä", "ö", "ü"]:
if umlaut in query:
await send_hidden_message(ctx, "Please use english names only!")
return

async with ClientSession() as session:
async with session.get(location_url) as response:
if response.status != 200:
err = f"The api-webserver responded with a code: {response.status} - {response.reason}"
raise NerpyException(err)
location = await response.json()

if location is None:
return

lat = location[0].get("lat")
lon = location[0].get("lon")
weather_url = f"http://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={self.weather_api_key}&units=metric"

async with ClientSession() as session:
async with session.get(weather_url) as response:
if response.status != 200:
err = f"The api-webserver responded with a code: {response.status} - {response.reason}"
raise NerpyException(err)
weather = await response.json()

conditions = []
for w in weather.get("weather", dict()):
conditions.append(w.get("main"))

sunrise = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunrise"))).strftime("%H:%M")
sunset = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunset"))).strftime("%H:%M")

emb = Embed()
emb.add_field(
name=f":earth_africa: {fmt.bold('location')}",
value=f"""[{weather.get("name")},
{weather.get("sys", dict()).get("country")}](https://openweathermap.org/city/{weather.get("id")})""",
)
emb.add_field(
name=f":thermometer: {fmt.bold('temperature')}",
value=f"{weather['main']['temp']}°C",
)
emb.add_field(
name=f":cloud: {fmt.bold('condition')}",
value=str.join(", ", conditions),
)
emb.add_field(
name=f":sweat_drops: {fmt.bold('humidity')}",
value=f"{weather['main']['humidity']}%",
)
emb.add_field(
name=f":wind_chime: {fmt.bold('wind')}",
value=f"{weather['wind']['speed']} m/s",
)
emb.add_field(
name=f"🔆 {fmt.bold('min-max')}",
value=f"{weather['main']['temp_min']}°C - {weather['main']['temp_max']}°C",
)
emb.add_field(name=f":city_sunrise: {fmt.bold('sunrise')}", value=f"{sunrise} UTC")
emb.add_field(name=f":city_sunset: {fmt.bold('sunset')}", value=f"{sunset} UTC")
emb.set_footer(
text="Powered by openweathermap.org",
icon_url=f"http://openweathermap.org/img/w/{weather.get('weather', list())[0].get('icon')}.png",
)

await ctx.send(embed=emb)
try:
async with ctx.typing():
for umlaut in ["ä", "ö", "ü"]:
if umlaut in query:
await send_hidden_message(ctx, "Please use english names only!")
return

weather = self.weather_api.get_weather(city=query)

conditions = []
for w in weather.get("weather", dict()):
conditions.append(w.get("main"))

sunrise = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunrise"))).strftime("%H:%M")
sunset = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunset"))).strftime("%H:%M")

emb = Embed()
emb.add_field(
name=f":earth_africa: {fmt.bold('location')}",
value=f"""[{weather.get("name")},
{weather.get("sys", dict()).get("country")}](https://openweathermap.org/city/{weather.get("id")})""",
)
temp = self.weather_api.convert_temperature(weather["main"]["temp"])
emb.add_field(
name=f":thermometer: {fmt.bold('temperature')}",
value=f"{temp:.2f}°C",
)
emb.add_field(
name=f":cloud: {fmt.bold('condition')}",
value=str.join(", ", conditions),
)
emb.add_field(
name=f":sweat_drops: {fmt.bold('humidity')}",
value=f"{weather['main']['humidity']}%",
)
emb.add_field(
name=f":wind_chime: {fmt.bold('wind')}",
value=f"{weather['wind']['speed']} m/s",
)
temp_min = self.weather_api.convert_temperature(weather["main"]["temp_min"])
temp_max = self.weather_api.convert_temperature(weather["main"]["temp_max"])
emb.add_field(
name=f"🔆 {fmt.bold('min-max')}",
value=f"{temp_min:.2f}°C - {temp_max:.2f}°C",
)
emb.add_field(name=f":city_sunrise: {fmt.bold('sunrise')}", value=f"{sunrise} UTC")
emb.add_field(name=f":city_sunset: {fmt.bold('sunset')}", value=f"{sunset} UTC")
emb.set_footer(
text="Powered by openweathermap.org",
icon_url=f"http://openweathermap.org/img/w/{weather.get('weather', list())[0].get('icon')}.png",
)

await ctx.send(embed=emb)
except Exception as ex:
self.bot.log.error(f"Error while fetching weather: {ex}")
await send_hidden_message(ctx, "An error occurred while fetching the weather information.")


async def setup(bot):
Expand Down
7 changes: 4 additions & 3 deletions NerdyPy/modules/wow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
from blizzapi import Language, Region, RetailClient
from discord import Color, Embed
from discord.ext.commands import Context, GroupCog, bot_has_permissions, hybrid_command, hybrid_group

from models.wow import WoW

from utils.errors import NerpyException
from utils.helpers import send_hidden_message
from utils.helpers import empty_subcommand, send_hidden_message


class WowApiLanguage(Enum):
Expand Down Expand Up @@ -125,8 +127,7 @@ def _get_best_mythic_keys(region, realm, name):

@hybrid_group(name="language", aliases=["lang", "locale"])
async def _wow_language(self, ctx: Context):
if ctx.invoked_subcommand is None:
await ctx.send_help(ctx.command)
empty_subcommand(ctx)

@_wow_language.command(name="get")
async def _wow_language_get(self, ctx: Context):
Expand Down
1 change: 1 addition & 0 deletions NerdyPy/utils/checks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-

from utils.helpers import send_hidden_message


Expand Down
20 changes: 11 additions & 9 deletions NerdyPy/utils/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@

import ffmpeg
import requests
import youtube_dl
from cachetools import TTLCache
from discord import FFmpegOpusAudio
from yt_dlp import YoutubeDL
from yt_dlp.utils import DownloadError

from utils.errors import NerpyException

LOG = logging.getLogger("nerpybot")
Expand All @@ -38,7 +40,7 @@
"default_search": "auto",
"source_address": "0.0.0.0", # bind to ipv4 since ipv6 addresses cause issues sometimes
}
YTDL = youtube_dl.YoutubeDL(YTDL_ARGS)
YTDL = YoutubeDL(YTDL_ARGS)


def convert(source, tag=False, is_stream=True):
Expand All @@ -65,7 +67,7 @@ def lookup_file(file_name):


def fetch_yt_infos(url: str):
"""Fetches information about a youtube video"""
"""Fetches information about a YouTube video"""
if url in CACHE:
LOG.info("Using cached information for URL: %s", url)
return CACHE[url]
Expand All @@ -74,7 +76,7 @@ def fetch_yt_infos(url: str):
data = None
try:
data = YTDL.extract_info(url, download=False)
except youtube_dl.utils.DownloadError as e:
except DownloadError as e:
if "Sign in to confirm you’re not a bot" in str(e):
data = YTDL.extract_info(url, download=False)

Expand All @@ -95,14 +97,14 @@ def download(url: str, tag: bool = False, video_id: str = None):
audio_bytes = BytesIO(response.content)

if audio_bytes is None:
raise NerpyException(f"could not find a valid source in: {url}")
raise NerpyException(f"Could not find a valid source in: {url}")

return convert(audio_bytes, tag)
else:
dlfile = lookup_file(video_id)
dl_file = lookup_file(video_id)

if dlfile is None:
if dl_file is None:
_ = YTDL.download([url])
dlfile = lookup_file(video_id)
dl_file = lookup_file(video_id)

return convert(dlfile, is_stream=False)
return convert(dl_file, is_stream=False)
Loading
Loading