async def google_search(self, message: discord.Message, argument: str) -> None: if not argument: return google_config = get_config_section('search.google') results = await self.http_get_request_json( 'https://www.googleapis.com/customsearch/v1', params={ 'q': argument, 'key': google_config['api_key'], 'cx': google_config['search_engine_id'], 'safe': 'off' if message.channel.is_nsfw() else 'active', 'num': '1', }) search_result, *rest = results.get('items', [None]) if not search_result: return await message.channel.send( f'No results found for `{argument}`') return await message.channel.send( f'**{search_result["title"]}**\n' f'<{search_result["link"]}>\n' f'{search_result["snippet"]}', )
async def google_search(self, message: discord.Message, argument: str) -> None: if not argument: return google_config = get_config_section('search.google') results = await self.http_get_request( 'https://www.googleapis.com/customsearch/v1?' + urlencode({ 'q': argument, 'key': google_config['api_key'], 'cx': google_config['search_engine_id'], 'num': '1', })) json_results = json.loads(results) search_result, *rest = json_results.get('items', [None]) if not search_result: return await message.channel.send( f'No results found for `{argument}`') return await message.channel.send( f'**{search_result["title"]}**\n' f'<{search_result["link"]}>' f'\n' f'{search_result["snippet"]}\n', )
async def youtube_search(self, message: discord.Message, argument: str) -> None: if not argument: return youtube_config = get_config_section('search.youtube') results = await self.http_get_request( 'https://www.googleapis.com/youtube/v3/search', params={ 'q': argument, 'part': 'id', 'type': 'video', 'key': youtube_config['api_key'], 'maxResults': '1', }) json_results = json.loads(results) search_result, *rest = json_results.get('items', [None]) if not search_result: return await message.channel.send( f'No results found for `{argument}`') return await message.channel.send( f'https://www.youtube.com/watch?v={search_result["id"]["videoId"]}' )
def is_rate_limited(self, action: str, user_id: int) -> bool: rate_limits = self.get_rate_limits(action) if not user_id in rate_limits: return False rate_limit_config = get_config_section('ratelimits') duration = timedelta(seconds=rate_limit_config.getint(action)) return rate_limits[user_id] + duration > datetime.now()
def __init__(self, *, loop=None, **options): discord_config = get_config_section('discord') options.setdefault('max_messages', discord_config.getint('max_messages')) super().__init__( loop=loop, **options, )
async def get_connection_pool(): qdb_config = get_config_section('quotes') return await aiomysql.create_pool( host=qdb_config['hostname'], port=qdb_config.getint('post', 3306), user=qdb_config['username'], password=qdb_config['password'], db=qdb_config['database'], )
def is_rate_limited(self, user_id: int, action: str, *sections: Union[str, int]) -> bool: rate_limits = self.get_rate_limits(action, *sections) if user_id not in rate_limits: return False rate_limit_config = get_config_section('ratelimits') duration = timedelta(seconds=rate_limit_config.getint(action)) return rate_limits[user_id] + duration > datetime.now()
async def metar(self, message: discord.Message, argument: str) -> None: if not argument: return avwx_config = get_config_section('search.avwx') results = await self.http_get_request(f'https://avwx.rest/api/metar/{argument}', params={ 'format': 'json', 'token': avwx_config['api_key'] }) json_results = json.loads(results) if 'error' in json_results: return await message.channel.send(f'```{json_results["error"]}```') return await message.channel.send(f'```{json_results["raw"]}```')
def __init__(self, *, loop=None, **options): discord_config = get_config_section('discord') options.setdefault('max_messages', discord_config.getint('max_messages')) intents = discord.Intents.default() intents.members = True super().__init__( loop=loop, intents=intents, **options, ) with open('brain.json', 'rt') as f: self.chat_brain = markovify.Text.from_json(f.read())
async def stock(self, message: discord.Message, argument: str) -> None: if not argument: return argument = argument.upper() alpha_vantage_config = get_config_section('search.alpha-vantage') results = await self.http_get_request('https://www.alphavantage.co/query', params={ 'function': 'TIME_SERIES_DAILY', 'symbol': argument, 'apikey': alpha_vantage_config['api_key'], }) json_results = json.loads(results) time_series = json_results.get('Time Series (Daily)', {}) if not time_series: return await message.channel.send(f'No results found for `{argument}`') latest_time_stamp = max(time_series, key=datetime.fromisoformat) return await message.channel.send(f"**{argument}**: {time_series[latest_time_stamp]['4. close']}")
async def metar(self, message: discord.Message, argument: str) -> None: if not argument: return avwx_config = get_config_section('search.avwx') try: results = await self.http_get_request_json( f'https://avwx.rest/api/metar/{argument}', params={ 'format': 'json', 'token': avwx_config['api_key'], }) if 'error' in results: return await message.channel.send(f'```{results["error"]}```') return await message.channel.send(f'```{results["raw"]}```') except JSONDecodeError: return await message.channel.send( f'```{argument.upper()} does not publish METAR```')
async def stock(self, message: discord.Message, argument: str) -> None: if not argument: return argument = argument.upper() finnhub_config = get_config_section('search.finnhub') result = await self.http_get_request_json( 'https://finnhub.io/api/v1/quote', params={ 'symbol': argument, 'token': finnhub_config['api_key'], }) if not result: return await message.channel.send( f'No results found for `{argument}`') if 'error' in result: return await message.channel.send( f'API returned an error: `{result["error"]}`') daily_delta = ((result['c'] / result['pc']) - 1) * 100 return await message.channel.send( f"**{argument}**: {result['c']:.2f} ({daily_delta:+.2f}%)")
async def google_image_search(self, message: discord.Message, argument: str) -> None: if not argument: return google_config = get_config_section('search.google') results = await self.http_get_request( 'https://www.googleapis.com/customsearch/v1?' + urlencode({ 'q': argument, 'searchType': 'image', 'key': google_config['api_key'], 'cx': google_config['search_engine_id'], 'safe': 'off' if message.channel.is_nsfw() else 'active', 'num': '1', })) json_results = json.loads(results) search_result, *rest = json_results.get('items', [None]) if not search_result: return await message.channel.send( f'No results found for `{argument}`') return await message.channel.send(search_result["link"])
def run(self): discord_config = get_config_section('discord') super().run(discord_config['token'])
async def convert(self, message: discord.Message, argument: str) -> None: fixer_config = get_config_section('search.fixer') aliases = { 'inches': 'inch', 'cm': 'centimeter', 'centimeters': 'centimeter', 'ft': 'feet', 'c': 'celsius', 'f': 'fahrenheit', 'k': 'kelvin', 'mi': 'miles', 'km': 'kilometers', 'lbs': 'pounds', 'kg': 'kilograms', 'g': 'grams', 'm': 'meters', 'hectopascal': 'hPa', 'inch of mercury': 'inHg', 'inches of mercury': 'inHg', 'inhg': 'inHg', 'hpa': 'hPa', } conversions = { 'feet': { 'centimeter': lambda ft: ft * 30.48, 'inch': lambda inch: inch * 12.0, 'meters': lambda m: m / 3.2808, }, 'inch': { 'centimeter': lambda inch: inch * 2.54, 'feet': lambda ft: ft / 12.0, 'meters': lambda m: m / 39.37, }, 'centimeter': { 'inch': lambda cm: cm / 2.54, 'feet': lambda ft: ft / 30.48, 'meters': lambda m: m / 100, }, 'fahrenheit': { 'celsius': lambda c: (c - 32) * 5 / 9, 'kelvin': lambda k: (k - 32) * 5 / 9 + 273.15, }, 'celsius': { 'fahrenheit': lambda f: (f * 9 / 5) + 32, 'kelvin': lambda k: k + 273.15, }, 'kelvin': { 'fahrenheit': lambda f: (f - 273.15) * 9 / 5 + 32, 'celsius': lambda c: c - 273.15, }, 'miles': { 'kilometers': lambda km: km * 1.609344, 'meters': lambda m: m * 1609.344, }, 'kilometers': { 'miles': lambda mi: mi / 1.609344, 'meters': lambda m: m * 1000, }, 'pounds': { 'kilograms': lambda kg: kg / 2.2046226218, 'grams': lambda g: g / 0.0022046, }, 'kilograms': { 'pounds': lambda lbs: lbs * 2.2046226218, 'grams': lambda g: g * 1000, }, 'grams': { 'pounds': lambda lbs: lbs * 453.59237, 'kilograms': lambda kg: kg / 1000, }, 'inHg': { 'hPa': lambda hPa: hPa * 33.8639, }, 'hPa': { 'inHg': lambda inHg: inHg / 33.8639, }, 'meters': { 'centimeter': lambda cm: cm * 100, 'inch': lambda inch: inch * 39.37, 'feet': lambda ft: ft * 3.2808, 'miles': lambda mi: mi * 0.00062137, 'kilometers': lambda km: km / 1000, }, } @memoize async def get_supported_symbols() -> set[str]: results = await self.http_get_request_json( 'http://data.fixer.io/api/symbols', params={ 'access_key': fixer_config.get('api_key'), }) return set(results['symbols'].keys()) try: left, to_unit = re.split(r'\s+(?:to|in)\s+', argument, flags=re.IGNORECASE, maxsplit=1) amount, from_unit = filter( None, re.split(r'(\-?\d+(?:\.?\d+)?)\s*', left)) amount, from_unit, to_unit = float( amount), from_unit.lower(), to_unit.lower() except (KeyError, ValueError): return await message.add_reaction('❓') try: # Unit conversion to_unit = aliases.get(to_unit, to_unit) from_unit = aliases.get(from_unit, from_unit) return await message.channel.send( f'{amount:.2f} {from_unit} = {conversions[from_unit][to_unit](amount):.2f} {to_unit}', ) except (KeyError, ValueError): # Currency conversion from_unit = from_unit.upper() to_unit = to_unit.upper() supported_symbols = await get_supported_symbols() if from_unit not in supported_symbols or to_unit not in supported_symbols: return await message.add_reaction('❓') result = await self.http_get_request_json( 'http://data.fixer.io/api/latest', params={ 'access_key': fixer_config.get('api_key'), 'symbols': f"{from_unit},{to_unit}", }) if not result['success']: return await message.channel.send( f'API returned error: ```{result["error"]["info"]}```') converted = amount / result["rates"][from_unit] * result["rates"][ to_unit] return await message.channel.send( f'{amount:.2f} {from_unit} = {converted:.2f} {to_unit}', )