first commit
						commit
						0db6d87628
					
				| @ -0,0 +1,2 @@ | |||||||
|  | TOKEN=ODMyMjU1MjU4NDAyNjE5Mzky.GLf39U.JmrRbXvobEvpRzG1f9pUd6lvou2xhgKtThQzUk | ||||||
|  | OWNER_ID=435206857276260353 | ||||||
| @ -0,0 +1,41 @@ | |||||||
|  | import discord | ||||||
|  | from discord import Interaction, Intents, Embed | ||||||
|  | from discord.ext.commands import Bot, Context, when_mentioned | ||||||
|  | from dotenv import load_dotenv | ||||||
|  | from os import getenv | ||||||
|  | from sys import exit | ||||||
|  | from typing import Literal | ||||||
|  | import httpx | ||||||
|  | import nltk | ||||||
|  | import asyncio | ||||||
|  | 
 | ||||||
|  | load_dotenv() | ||||||
|  | 
 | ||||||
|  | if getenv('TOKEN') is None or getenv('OWNER_ID') is None: | ||||||
|  |     print('please set a TOKEN and OWNER_ID environment variable') | ||||||
|  |     exit(1) | ||||||
|  | 
 | ||||||
|  | class QBBBot(Bot): | ||||||
|  |     def __init__(self) -> None: | ||||||
|  |         super().__init__(command_prefix=when_mentioned, intents=Intents.default()) | ||||||
|  | 
 | ||||||
|  |     async def setup_hook(self): | ||||||
|  |         await self.load_extension('cogs.tossup') | ||||||
|  |         await self.load_extension('cogs.solo') | ||||||
|  |         await self.load_extension('jishaku') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | bot = QBBBot() | ||||||
|  | bot.qb_categories = Literal['Literature', 'History', 'Science', 'Fine Arts', 'Religion', 'Mythology', 'Philosophy', | ||||||
|  |                             'Social Science', 'Current Events', 'Geography', 'Other Academic', 'Trash'] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @bot.command() | ||||||
|  | async def sync(ctx: Context): | ||||||
|  |     if str(ctx.author.id) == getenv('OWNER_ID'): | ||||||
|  |         await bot.tree.sync() | ||||||
|  |         await ctx.send('ok') | ||||||
|  |     else: | ||||||
|  |         await ctx.send('no') | ||||||
|  | 
 | ||||||
|  | bot.run(getenv('TOKEN')) | ||||||
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,41 @@ | |||||||
|  | from discord.ext.commands import GroupCog, Bot | ||||||
|  | from discord.ui import View, Button, Modal, button, TextInput | ||||||
|  | from discord.app_commands import command | ||||||
|  | from discord import Interaction, Embed, User, Member, ButtonStyle, Color | ||||||
|  | from httpx import AsyncClient | ||||||
|  | from nltk import sent_tokenize | ||||||
|  | from typing import Union, Optional | ||||||
|  | from common.types import question_category | ||||||
|  | from components.TossupButtons import SoloTossupButtons | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Solo(GroupCog, name="solo"): | ||||||
|  |     def __init__(self, bot: Bot) -> None: | ||||||
|  |         self.bot = bot | ||||||
|  |         super().__init__() | ||||||
|  | 
 | ||||||
|  |     @command(description="Do a tossup in solo mode (only you can control the tossup)") | ||||||
|  |     async def tossup(self, ctx: Interaction, category: Optional[question_category] = None): | ||||||
|  |         c = AsyncClient() | ||||||
|  |         params = {'difficulties': [2,3,4,5]} | ||||||
|  |         if category is not None: | ||||||
|  |             params['categories'] = category | ||||||
|  | 
 | ||||||
|  |         req = await c.get( | ||||||
|  |             "https://qbreader.org/api/random-tossup", params=params | ||||||
|  |         ) | ||||||
|  |         tossup: dict = req.json()["tossups"][0] | ||||||
|  |         tossup['sentences'] = await self.bot.loop.run_in_executor(None, sent_tokenize, tossup['question']) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         view: SoloTossupButtons = SoloTossupButtons(tossup, ctx.user) | ||||||
|  |         embed = Embed(title="Random Tossup", description=tossup["sentences"][0]) | ||||||
|  |         embed.set_author( | ||||||
|  |             name=f"{tossup['set']['name']} Packet {tossup['packetNumber']} Question {tossup['questionNumber']}" | ||||||
|  |         ) | ||||||
|  |         embed.set_footer(text="Questions obtained from qbreader.org") | ||||||
|  |         await ctx.response.send_message(embed=embed, view=view) | ||||||
|  |         await c.aclose() | ||||||
|  | 
 | ||||||
|  | async def setup(bot: Bot) -> None: | ||||||
|  |     await bot.add_cog(Solo(bot)) | ||||||
| @ -0,0 +1,42 @@ | |||||||
|  | from discord.ext.commands import Cog, Bot | ||||||
|  | from discord.app_commands import command, describe | ||||||
|  | from discord import Interaction, Embed, ButtonStyle | ||||||
|  | from discord.ui import View, Button, Modal, button, TextInput | ||||||
|  | from nltk import sent_tokenize | ||||||
|  | from httpx import AsyncClient | ||||||
|  | from typing import Literal, Optional | ||||||
|  | from common.types import question_category | ||||||
|  | from components.AnswerModal import Answer | ||||||
|  | from components.TossupButtons import TossupButtons | ||||||
|  | 
 | ||||||
|  | class Tossup(Cog): | ||||||
|  |     def __init__(self, bot: Bot) -> None: | ||||||
|  |         self.bot = bot | ||||||
|  | 
 | ||||||
|  |     @command(name="tossup", description="gives a random tossup") | ||||||
|  |     @describe(category="The category to choose the question from (optional)") | ||||||
|  |     async def tossup(self, ctx: Interaction, category: Optional[question_category] = None): | ||||||
|  |         c = AsyncClient() | ||||||
|  | 
 | ||||||
|  |         params = {"difficulties": [2, 3, 4, 5]} | ||||||
|  |         if category is not None: | ||||||
|  |             params["categories"] = category | ||||||
|  | 
 | ||||||
|  |         req = await c.get("https://qbreader.org/api/random-tossup", params=params) | ||||||
|  |         tossup: dict = req.json()["tossups"][0] | ||||||
|  |         tossup["sentences"] = await self.bot.loop.run_in_executor( | ||||||
|  |             None, sent_tokenize, tossup["question"] | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         view: TossupButtons = TossupButtons(tossup) | ||||||
|  |         embed = Embed(title="Random Tossup", description=tossup["sentences"][0]) | ||||||
|  |         embed.set_author( | ||||||
|  |             name=f"{tossup['set']['name']} Packet {tossup['packetNumber']} Question {tossup['questionNumber']} (Category: {tossup['category']})" | ||||||
|  |         ) | ||||||
|  |         embed.set_footer(text="Questions obtained from qbreader.org") | ||||||
|  |         await ctx.response.send_message(embed=embed, view=view) | ||||||
|  |         await c.aclose() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | async def setup(bot: Bot) -> None: | ||||||
|  |     await bot.add_cog(Tossup(bot)) | ||||||
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,16 @@ | |||||||
|  | from typing import Literal | ||||||
|  | 
 | ||||||
|  | question_category = Literal[ | ||||||
|  |     "Literature", | ||||||
|  |     "History", | ||||||
|  |     "Science", | ||||||
|  |     "Fine Arts", | ||||||
|  |     "Religion", | ||||||
|  |     "Mythology", | ||||||
|  |     "Philosophy", | ||||||
|  |     "Social Science", | ||||||
|  |     "Current Events", | ||||||
|  |     "Geography", | ||||||
|  |     "Other Academic", | ||||||
|  |     "Trash", | ||||||
|  | ] | ||||||
| @ -0,0 +1,85 @@ | |||||||
|  | from discord.ui import Modal, TextInput, View | ||||||
|  | from httpx import AsyncClient | ||||||
|  | from discord import Interaction, Color | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Answer(Modal, title="Submit Answer"): | ||||||
|  |     def __init__(self, correct_answer: str, view: View) -> None: | ||||||
|  |         self.correct_answer = correct_answer | ||||||
|  |         self.view = view | ||||||
|  |         super().__init__() | ||||||
|  | 
 | ||||||
|  |     answer = TextInput(label="Answer", placeholder="Your answer here") | ||||||
|  | 
 | ||||||
|  |     async def on_submit(self, interaction: Interaction) -> None: | ||||||
|  |         c = AsyncClient() | ||||||
|  |         answer_check_resp = await c.get( | ||||||
|  |             "https://qbreader.org/api/check-answer", | ||||||
|  |             params={ | ||||||
|  |                 "answerline": self.correct_answer, | ||||||
|  |                 "givenAnswer": self.answer.value, | ||||||
|  |             }, | ||||||
|  |         ) | ||||||
|  |         answer_check_data = answer_check_resp.json() | ||||||
|  | 
 | ||||||
|  |         if answer_check_data["directive"] == "accept": | ||||||
|  |             e = interaction.message.embeds[0] | ||||||
|  |             e.color = Color.green() | ||||||
|  |             e.title = '[CORRECT!] Random Tossup' | ||||||
|  |             e.description = ".".join(self.view.tossup['sentences'][0:self.view.i+1]) + " **(BUZZ)** " + ".".join(self.view.tossup['sentences'][self.view.i+1:]) | ||||||
|  |             e.add_field(name='Your answer', value=self.answer.value) | ||||||
|  |             e.add_field(name='Official answer', value=self.view.tossup['answer']) | ||||||
|  |             e.add_field(name='Answered by', value=interaction.user.mention) | ||||||
|  |             items = self.view.children | ||||||
|  |             for item in items: | ||||||
|  |                 item.disabled = True | ||||||
|  |             await interaction.response.edit_message(embed=e, view=self.view) | ||||||
|  |         elif answer_check_data['directive'] == 'prompt': | ||||||
|  |             await interaction.response.send_message("Prompt! Try answering the question again", ephemeral=True) | ||||||
|  |         else: | ||||||
|  |             await interaction.response.send_message(f"Incorrect! You've been locked out from the question. The correct answer was {self.view.tossup['answer']}", ephemeral=True) | ||||||
|  |             self.view.already_answered.append(interaction.user.id) | ||||||
|  |         await c.aclose() | ||||||
|  | 
 | ||||||
|  | class SoloAnswer(Modal, title="Submit Answer"): | ||||||
|  |     def __init__(self, correct_answer: str, view: View) -> None: | ||||||
|  |         self.correct_answer = correct_answer | ||||||
|  |         self.view = view | ||||||
|  |         super().__init__() | ||||||
|  | 
 | ||||||
|  |     answer = TextInput(label="Answer", placeholder="your answer here!") | ||||||
|  | 
 | ||||||
|  |     async def on_submit(self, interaction: Interaction) -> None: | ||||||
|  |         c = AsyncClient() | ||||||
|  |         answer_check_resp = await c.get( | ||||||
|  |             "https://qbreader.org/api/check-answer", | ||||||
|  |             params={ | ||||||
|  |                 "answerline": self.correct_answer, | ||||||
|  |                 "givenAnswer": self.answer.value, | ||||||
|  |             }, | ||||||
|  |         ) | ||||||
|  |         answer_check_data = answer_check_resp.json() | ||||||
|  | 
 | ||||||
|  |         if answer_check_data["directive"] == "accept": | ||||||
|  |             e = interaction.message.embeds[0] | ||||||
|  |             e.color = Color.green() | ||||||
|  |             e.title = '[CORRECT!] Random Tossup' | ||||||
|  |             e.description = ".".join(self.view.tossup['sentences'][0:self.view.i+1]) + " **(BUZZ)** " + ".".join(self.view.tossup['sentences'][self.view.i+1:]) | ||||||
|  |             e.add_field(name='Your answer', value=self.answer.value) | ||||||
|  |             e.add_field(name='Official answer', value=self.view.tossup['answer']) | ||||||
|  |             items = self.view.children | ||||||
|  |             for item in items: | ||||||
|  |                 item.disabled = True | ||||||
|  |             await interaction.response.edit_message(embed=e, view=self.view) | ||||||
|  |         else: | ||||||
|  |             e = interaction.message.embeds[0] | ||||||
|  |             e.color = Color.red() | ||||||
|  |             e.title = '[INCORRECT] Random Tossup' | ||||||
|  |             e.description = ".".join(self.view.tossup['sentences'][0:self.view.i+1]) + " **(BUZZ)** " + ".".join(self.view.tossup['sentences'][self.view.i+1:]) | ||||||
|  |             e.add_field(name='Correct answer was...', value=self.view.tossup['answer']) | ||||||
|  |             e.add_field(name='Your answer', value=self.answer.value) | ||||||
|  |             items = self.view.children | ||||||
|  |             for item in items: | ||||||
|  |                 item.disabled = True | ||||||
|  |             await interaction.response.edit_message(embed=e, view=self.view) | ||||||
|  |         await c.aclose() | ||||||
| @ -0,0 +1,99 @@ | |||||||
|  | from discord.ui import View, button, Button | ||||||
|  | from discord import ButtonStyle, Interaction, User, Member, Color | ||||||
|  | from .AnswerModal import Answer, SoloAnswer | ||||||
|  | from typing import Union | ||||||
|  | 
 | ||||||
|  | class TossupButtons(View): | ||||||
|  |     def __init__(self, tossup) -> None: | ||||||
|  |         self.tossup = tossup | ||||||
|  |         self.already_answered = [] | ||||||
|  |         self.already_voted = [] | ||||||
|  |         self.i = 0 | ||||||
|  |         self.final_answer_votes = 0 | ||||||
|  |         super().__init__() | ||||||
|  | 
 | ||||||
|  |     @button(label="Answer!", style=ButtonStyle.green) | ||||||
|  |     async def answer(self, interaction: Interaction, button: Button): | ||||||
|  |         if interaction.user.id not in self.already_answered: | ||||||
|  |             await interaction.response.send_modal( | ||||||
|  |                 Answer(self.tossup.get('formatted_answer', self.tossup['answer']), self) | ||||||
|  |             ) | ||||||
|  |         else: | ||||||
|  |             await interaction.response.send_message( | ||||||
|  |                 "you've already answered!", ephemeral=True | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |     @button(label="Add sentence", style=ButtonStyle.blurple) | ||||||
|  |     async def add_sentence(self, interaction: Interaction, button: Button): | ||||||
|  |         if interaction.user.id in self.already_answered: | ||||||
|  |             return await interaction.response.send_message( | ||||||
|  |                 "you've already answered!", ephemeral=True | ||||||
|  |             ) | ||||||
|  |         e = interaction.message.embeds[0] | ||||||
|  |         self.i += 1 | ||||||
|  |         if self.i == len(self.tossup["sentences"]): | ||||||
|  |             button.disabled = True | ||||||
|  |         e.description = "\n".join(self.tossup["sentences"][0 : self.i + 1]) | ||||||
|  |         await interaction.response.edit_message(embed=e, view=self) | ||||||
|  | 
 | ||||||
|  |     @button(label="Vote to Reveal Answer (0/3)", style=ButtonStyle.red) | ||||||
|  |     async def reveal_answer(self, interaction: Interaction, button: Button): | ||||||
|  |         if interaction.user.id in self.already_voted: | ||||||
|  |             return await interaction.response.send_message( | ||||||
|  |                 "you've already voted!", ephemeral=True | ||||||
|  |             ) | ||||||
|  |         self.already_voted.append(interaction.user.id) | ||||||
|  |         self.final_answer_votes += 1 | ||||||
|  |         button.label = f"vote to reveal answer ({self.final_answer_votes}/3)" | ||||||
|  |         if self.final_answer_votes >= 3: | ||||||
|  |             e = interaction.message.embeds[0] | ||||||
|  |             e.title = '[SKIPPED] Random Tossup' | ||||||
|  |             e.color = Color.orange() | ||||||
|  |             e.description = self.tossup["question"] | ||||||
|  |             e.add_field(name="Answer", value=self.tossup["answer"]) | ||||||
|  |             for item in self.children: | ||||||
|  |                 item.disabled = True | ||||||
|  |             return await interaction.response.edit_message(embed=e, view=self) | ||||||
|  |         await interaction.response.edit_message(view=self) | ||||||
|  |         await interaction.followup.send("you've voted!", ephemeral=True) | ||||||
|  | 
 | ||||||
|  | class SoloTossupButtons(View): | ||||||
|  |     def __init__(self, tossup, user: Union[User, Member]) -> None: | ||||||
|  |         self.user = user | ||||||
|  |         self.tossup = tossup | ||||||
|  |         self.i = 0 | ||||||
|  |         super().__init__() | ||||||
|  | 
 | ||||||
|  |     @button(label="Answer!", style=ButtonStyle.green) | ||||||
|  |     async def answer(self, interaction: Interaction, button: Button): | ||||||
|  |         if interaction.user.id != self.user.id: | ||||||
|  |             return interaction.response.send_message('This is not your tossup!', ephemeral=True) | ||||||
|  |         await interaction.response.send_modal(SoloAnswer(self.tossup.get('formatted_answer', self.tossup['answer']), self)) | ||||||
|  | 
 | ||||||
|  |     @button(label="Add sentence", style=ButtonStyle.blurple) | ||||||
|  |     async def add_sentence(self, interaction: Interaction, button: Button): | ||||||
|  |         if interaction.user.id != self.user.id: | ||||||
|  |             return await interaction.response.send_message( | ||||||
|  |                 "not your tossup!", ephemeral=True | ||||||
|  |             ) | ||||||
|  |         e = interaction.message.embeds[0] | ||||||
|  |         self.i += 1 | ||||||
|  |         if self.i == len(self.tossup["sentences"]) - 1: | ||||||
|  |             button.disabled = True | ||||||
|  |         e.description = "\n".join(self.tossup["sentences"][0 : self.i + 1]) | ||||||
|  |         await interaction.response.edit_message(embed=e, view=self) | ||||||
|  | 
 | ||||||
|  |     @button(label="Reveal Answer", style=ButtonStyle.red) | ||||||
|  |     async def reveal_answer(self, interaction: Interaction, button: Button): | ||||||
|  |         if interaction.user.id != self.user.id: | ||||||
|  |             return await interaction.response.send_message( | ||||||
|  |                 "not your tossup!", ephemeral=True | ||||||
|  |             ) | ||||||
|  |         e = interaction.message.embeds[0] | ||||||
|  |         e.title = f'[SKIPPED] Random Tossup' | ||||||
|  |         e.color = Color.orange() | ||||||
|  |         e.description = self.tossup["question"] | ||||||
|  |         e.add_field(name="Answer", value=self.tossup["answer"]) | ||||||
|  |         for item in self.children: | ||||||
|  |             item.disabled = True | ||||||
|  |         return await interaction.response.edit_message(embed=e, view=self) | ||||||
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,22 @@ | |||||||
|  | from bs4 import BeautifulSoup, Tag | ||||||
|  | import httpx as h | ||||||
|  | from tabulate import tabulate | ||||||
|  | 
 | ||||||
|  | r = h.get('https://www.naqt.com/stats/school/players.jsp?org_id=69304') | ||||||
|  | 
 | ||||||
|  | html = BeautifulSoup(r.text, 'lxml') | ||||||
|  | 
 | ||||||
|  | tbl = html.find('section', attrs={'id': 'players'}).table | ||||||
|  | 
 | ||||||
|  | headers = [e.text for e in tbl.thead.tr.find_all('th')] | ||||||
|  | 
 | ||||||
|  | data = [] | ||||||
|  | 
 | ||||||
|  | elem: Tag | ||||||
|  | for elem in tbl.tbody.find_all('tr'): | ||||||
|  |     temp = [] | ||||||
|  |     for z in elem.find_all(): | ||||||
|  |         temp.append(z.text) | ||||||
|  |     data.append(temp[1:]) | ||||||
|  | 
 | ||||||
|  | print(tabulate(data, headers, showindex=False)) | ||||||
					Loading…
					
					
				
		Reference in New Issue