├── runtime.txt ├── requirements.txt ├── .github ├── dependabot.yml └── FUNDING.yml ├── LICENSE ├── PRIVACY_POLICY.md ├── .gitignore ├── README.md ├── cogs ├── devtools.py └── neetcode.py ├── TERMS_OF_SERVICE.md └── main.py /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.11.1 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.9.1 2 | discord.py==2.3.2 3 | python-dotenv==1.0.0 4 | utils==1.0.1 5 | GitPython==3.1.40 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [abe-101] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 NYC Code & Coffee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PRIVACY_POLICY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | Last updated: February 11, 2025 4 | 5 | ## Introduction 6 | This Privacy Policy describes how the Leetcode Bot ("we", "us", or "our") collects, uses, and handles your information when you use our Discord bot service. 7 | 8 | ## Information We Collect 9 | ### Automatically Collected Information 10 | - Discord User ID 11 | - Discord Server ID 12 | - Command usage data 13 | - Leetcode problem numbers and programming languages requested 14 | 15 | ### We DO NOT Collect 16 | - Personal messages 17 | - Direct message content 18 | - User profile information 19 | - Any information outside of bot interactions 20 | 21 | ## How We Use Information 22 | We use the collected information for: 23 | - Providing leetcode solutions 24 | - Tracking command usage for service improvements 25 | - Generating anonymous usage statistics 26 | - Debugging and error monitoring 27 | 28 | ## Data Storage 29 | - All data is stored temporarily in memory and log files 30 | - Command usage statistics are reset daily 31 | - We do not maintain any permanent user databases 32 | - Log files are automatically rotated and old logs are deleted 33 | 34 | ## Data Sharing 35 | We do not share any user data with third parties. The only data visible to other users are: 36 | - Public command interactions in Discord channels 37 | - Solutions to leetcode problems (which are publicly available) 38 | 39 | ## Security 40 | We implement appropriate security measures to protect the limited data we collect: 41 | - Secure bot token storage 42 | - Regular security updates 43 | - Limited access to log files 44 | 45 | ## User Rights 46 | You have the right to: 47 | - Use the bot privately through ephemeral messages 48 | - Request deletion of your data (though we store minimal data) 49 | - Opt out of using the bot at any time 50 | 51 | ## Changes to This Policy 52 | We may update this Privacy Policy from time to time. We will notify users of any material changes by posting the new Privacy Policy in our GitHub repository. 53 | 54 | ## Contact 55 | If you have any questions about this Privacy Policy, please contact us: 56 | - Through our GitHub repository: https://github.com/abe-101/abe-101-leetcode-bot 57 | - Discord: Join our support server at https://discord.gg/2vqUzSpt6N 58 | 59 | ## Open Source 60 | This bot is open source, and you can verify our data practices by reviewing our code on GitHub. 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | leetcode 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leetcode bot Buy Me A Coffee 2 | [![Actively Maintained](https://img.shields.io/badge/Maintenance%20Level-Actively%20Maintained-green.svg)](https://gist.github.com/cheerfulstoic/d107229326a01ff0f333a1d3476e068d) 3 | [![Discord](https://img.shields.io/discord/1017782904509710366)](https://discord.gg/2vqUzSpt6N) 4 | 5 | This project is a Discord bot that can provide solutions to 6 | [leetcode](https://leetcode.com/) problems in 7 | up to 13 programming languages. The bot is designed to help programmers prepare 8 | for coding interviews by providing quick and easy access to solutions in multiple 9 | languages. To use the bot, simply send a message containing the LeetCode problem 10 | number and the desired programming language. The bot will respond with the solution. 11 | The bot is built using the [Discord.py](https://github.com/Rapptz/discord.py) framework. 12 | This project is open-source and contributions are welcome! 13 | 14 | The bot is Currently active on the NeetCode server, which has a community of over 30,000 developers, and also available for invite to other Discord servers. 15 | 16 | ## Servers 17 | Leetcode bot is currently active on over 25 servers including: 18 | - [Neetcode](https://discord.gg/ddjKRXPqtk) 19 | - [Code & Coffee](https://www.codeandcoffee.chat/) 20 | - [abe's server](https://discord.gg/Bv8XkBSEHP) 21 | 22 | 23 | ## Features 24 | - Provides solutions to LeetCode problems in multiple programming languages 25 | - Easy to use commands for requesting solutions 26 | 27 | ## Usage 28 | To request a solution to a LeetCode problem, use the following command in a Discord channel where the bot is active: 29 | 30 | `/leetcode ` 31 | 32 | For example, to request a solution to LeetCode problem #1 in Python, you would use the following command: 33 | 34 | `/leetcode 1 python` 35 | 36 | ## Invite to your server 37 | You can invite the bot to your own Discord server using the following link: 38 | 39 | [Invite me](https://discord.com/oauth2/authorize?client_id=1052787378718253106&scope=bot+applications.commands&permissions=0) 40 | 41 | ## Technologies and tools 42 | - [Discord.py](https://github.com/Rapptz/discord.py) 43 | - Python 44 | 45 | ## See it in action 46 | 47 | [demo video.webm](https://user-images.githubusercontent.com/82916197/208010250-54f21d02-8774-4953-aa93-92a8bfd0f31d.webm) 48 | -------------------------------------------------------------------------------- /cogs/devtools.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import typing 3 | 4 | import discord 5 | from discord import app_commands 6 | from discord.ext import commands 7 | from discord.ext.commands import Context 8 | 9 | _logger = logging.getLogger(__name__) 10 | 11 | 12 | class DevTools(commands.Cog): 13 | def __init__(self, bot: commands.Bot) -> None: 14 | self.bot = bot 15 | 16 | @commands.command() 17 | @commands.guild_only() 18 | @commands.is_owner() 19 | async def sync( 20 | self, 21 | ctx: commands.Context, 22 | guilds: commands.Greedy[discord.Object], 23 | spec: typing.Optional[typing.Literal["~", "*", "^"]] = None, 24 | ) -> None: 25 | """Syncs command tree. 26 | Parameters 27 | ----------- 28 | guilds: list[int] 29 | The guilds to sync to 30 | spec: str 31 | The spec to sync. 32 | ~ -> Current Guild 33 | * -> Globals to current guild 34 | ^ -> Clear globals copied to current guild. 35 | """ 36 | if not guilds: 37 | if spec == "~": 38 | synced = await ctx.bot.tree.sync(guild=ctx.guild) 39 | elif spec == "*": 40 | ctx.bot.tree.copy_global_to(guild=ctx.guild) 41 | synced = await ctx.bot.tree.sync(guild=ctx.guild) 42 | elif spec == "^": 43 | ctx.bot.tree.clear_commands(guild=ctx.guild) 44 | await ctx.bot.tree.sync(guild=ctx.guild) 45 | synced = [] 46 | else: 47 | synced = await ctx.bot.tree.sync() 48 | await ctx.send( 49 | f"Synced {len(synced)} commands {'globally' if spec is None else 'to the current guild.'}" 50 | ) 51 | return 52 | ret = 0 53 | for guild in guilds: 54 | try: 55 | await ctx.bot.tree.sync(guild=guild) 56 | except discord.HTTPException: 57 | pass 58 | else: 59 | ret += 1 60 | await ctx.send(f"Synced the tree to {ret}/{len(guilds)}.") 61 | 62 | @commands.command(aliases=['invite']) 63 | async def join(self, ctx: Context): 64 | """Posts my invite to allow you to invite me""" 65 | perms = discord.Permissions.none() 66 | await ctx.send(f'<{discord.utils.oauth_url(self.bot.client_id, permissions=perms)}>') 67 | 68 | 69 | 70 | async def setup(bot): 71 | _logger.info("Loading DevTools cog") 72 | await bot.add_cog(DevTools(bot)) 73 | 74 | 75 | async def teardown(_): 76 | _logger.info("Extension: Unloading DevTools") 77 | -------------------------------------------------------------------------------- /TERMS_OF_SERVICE.md: -------------------------------------------------------------------------------- 1 | # Terms of Service 2 | 3 | Last updated: February 11, 2025 4 | 5 | ## Agreement to Terms 6 | By using the Leetcode Bot ("the Bot"), you agree to these Terms of Service. If you disagree with any part of these terms, you do not have permission to use the Bot. 7 | 8 | ## Description of Service 9 | The Leetcode Bot is a Discord bot that provides: 10 | - Solutions to Leetcode problems in multiple programming languages 11 | - Access to the Neetcode solutions repository 12 | - Programming language support through Discord commands 13 | 14 | ## Usage Requirements 15 | To use the Bot, you must: 16 | - Be a member of a Discord server where the Bot is installed 17 | - Follow Discord's Terms of Service and Community Guidelines 18 | - Use the Bot only for its intended purpose 19 | - Not attempt to abuse, exploit, or circumvent the Bot's limitations 20 | 21 | ## Acceptable Use 22 | You agree not to: 23 | - Use the Bot to violate any laws or regulations 24 | - Attempt to access, tamper with, or use non-public areas of the Bot 25 | - Probe, scan, or test the vulnerability of the Bot 26 | - Spam commands or intentionally overload the Bot 27 | - Share solutions in violation of Leetcode's terms of service 28 | 29 | ## Intellectual Property 30 | - The Bot's code is open source under the MIT License 31 | - Leetcode solutions are provided through the Neetcode repository 32 | - Users are responsible for adhering to Leetcode's terms when using solutions 33 | 34 | ## Disclaimer of Warranty 35 | The Bot is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, either express or implied, including but not limited to: 36 | - Accuracy of solutions 37 | - Availability of the service 38 | - Reliability of the service 39 | 40 | ## Limitation of Liability 41 | We shall not be liable for any indirect, incidental, special, consequential, or punitive damages resulting from: 42 | - Use or inability to use the Bot 43 | - Any solutions provided by the Bot 44 | - Any changes to the service 45 | 46 | ## Service Modifications 47 | We reserve the right to: 48 | - Modify or discontinue the Bot temporarily or permanently 49 | - Change these Terms of Service at any time 50 | - Limit Bot usage or features as needed 51 | 52 | ## Third-Party Services 53 | The Bot interacts with third-party services including: 54 | - Discord 55 | - Leetcode 56 | - Neetcode GitHub repository 57 | Users are subject to the respective terms and policies of these services. 58 | 59 | ## Termination 60 | We reserve the right to: 61 | - Terminate or suspend access to the Bot without prior notice 62 | - Remove the Bot from any Discord server 63 | - Block users who violate these terms 64 | 65 | ## Contact Information 66 | For questions about these Terms: 67 | - Visit our GitHub repository: https://github.com/abe-101/abe-101-leetcode-bot 68 | - Join our Discord support server: https://discord.gg/2vqUzSpt6N 69 | 70 | ## Open Source 71 | This bot is open source under the MIT License. You can view, fork, and contribute to the code on GitHub. 72 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from logging.handlers import RotatingFileHandler 4 | 5 | import discord 6 | from discord.ext import commands 7 | from dotenv import load_dotenv 8 | 9 | 10 | # Setup basic logging 11 | 12 | load_dotenv() 13 | 14 | DISCORD_TOKEN = os.getenv("DISCORD_TOKEN") 15 | 16 | 17 | class Bot(commands.Bot): 18 | def __init__(self): 19 | intents = discord.Intents.default() 20 | intents.message_content = True 21 | intents.members = True 22 | self.client_id = None 23 | 24 | super().__init__( 25 | command_prefix=commands.when_mentioned_or("?"), 26 | intents=intents, 27 | activity=discord.Game(name="💻"), 28 | ) 29 | 30 | async def on_ready(self): 31 | self.logger.info(f"Logged in as {self.user} (ID: {self.user.id})") 32 | self.logger.info("------") 33 | self.client_id = self.user.id 34 | 35 | async def setup_hook(self) -> None: 36 | # Load cogs 37 | for file in os.listdir(f"./cogs"): 38 | if file.endswith(".py"): 39 | extension = file[:-3] 40 | try: 41 | await bot.load_extension(f"cogs.{extension}") 42 | self.logger.info(f"Loaded extension '{extension}'") 43 | except Exception as e: 44 | self.logger.exception(f"Failed to load extension {extension}") 45 | 46 | 47 | class LoggingFormatter(logging.Formatter): 48 | # Colors 49 | black = "\x1b[30m" 50 | red = "\x1b[31m" 51 | green = "\x1b[32m" 52 | yellow = "\x1b[33m" 53 | blue = "\x1b[34m" 54 | gray = "\x1b[38m" 55 | # Styles 56 | reset = "\x1b[0m" 57 | bold = "\x1b[1m" 58 | 59 | COLORS = { 60 | logging.DEBUG: gray + bold, 61 | logging.INFO: blue + bold, 62 | logging.WARNING: yellow + bold, 63 | logging.ERROR: red, 64 | logging.CRITICAL: red + bold, 65 | } 66 | 67 | def format(self, record): 68 | log_color = self.COLORS[record.levelno] 69 | format = "(black){asctime}(reset) (levelcolor){levelname:<8}(reset) (green){name}(reset) {message}" 70 | format = format.replace("(black)", self.black + self.bold) 71 | format = format.replace("(reset)", self.reset) 72 | format = format.replace("(levelcolor)", log_color) 73 | format = format.replace("(green)", self.green + self.bold) 74 | formatter = logging.Formatter(format, "%Y-%m-%d %H:%M:%S", style="{") 75 | return formatter.format(record) 76 | 77 | 78 | logger = logging.getLogger("discord_bot") 79 | logger.setLevel(logging.INFO) 80 | 81 | # Console handler 82 | console_handler = logging.StreamHandler() 83 | console_handler.setFormatter(LoggingFormatter()) 84 | ## File handler 85 | file_handler = RotatingFileHandler( 86 | filename="discord.log", 87 | encoding="utf-8", 88 | mode="a", 89 | maxBytes=1024 * 1024, 90 | backupCount=5, 91 | ) 92 | file_handler_formatter = logging.Formatter( 93 | "[{asctime}] [{levelname:<8}] {name}: {message}", "%Y-%m-%d %H:%M:%S", style="{" 94 | ) 95 | file_handler.setFormatter(file_handler_formatter) 96 | 97 | 98 | # Add the handlers 99 | logger.addHandler(console_handler) 100 | logger.addHandler(file_handler) 101 | 102 | bot = Bot() 103 | bot.logger = logger 104 | 105 | bot.run(DISCORD_TOKEN) 106 | 107 | -------------------------------------------------------------------------------- /cogs/neetcode.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | from typing import List 3 | import datetime 4 | from zoneinfo import ZoneInfo 5 | 6 | import discord 7 | import git 8 | from discord import app_commands 9 | from discord.ext import commands, tasks 10 | from git.repo.base import Repo 11 | 12 | 13 | 14 | class Neetcode(commands.Cog): 15 | def __init__(self, bot: commands.Bot) -> None: 16 | self.bot = bot 17 | self.logger = self.bot.logger 18 | self.pull_repo.start() 19 | self.daily_report.start() # Start the daily report loop 20 | self.bot_spam_channels = [ 21 | 1053845551315173397, # bot-spam -> abes-server 22 | 1053874909014675576, # bot-playground -> neetcode 23 | 24 | ] 25 | 26 | self.command_usage_stats = { 27 | "pulls": 0, 28 | "leetcode_invoked": 0, 29 | } 30 | 31 | @tasks.loop(time=datetime.time(hour=0, minute=0, tzinfo=ZoneInfo("America/New_York"))) 32 | async def daily_report(self): 33 | # Log the daily report 34 | self.logger.info("Daily Report:") 35 | self.logger.info(f"Number of repo pulls: {self.command_usage_stats['pulls']}") 36 | self.logger.info(f"Number of leetcode command invocations: {self.command_usage_stats['leetcode_invoked']}") 37 | 38 | @tasks.loop(time=datetime.time(hour=22, minute=54, tzinfo=ZoneInfo("America/New_York"))) 39 | async def pull_repo(self): 40 | o = self.repo.remotes.origin 41 | o.pull() 42 | self.logger.info("pulled repo on timer") 43 | self.command_usage_stats["pulls"] += 1 # Increment pull count 44 | 45 | 46 | async def cog_load(self) -> None: 47 | self.neetcode = pathlib.Path("leetcode") 48 | self.neetcode.mkdir(exist_ok=True) 49 | try: 50 | self.repo = Repo.clone_from( 51 | "https://github.com/neetcode-gh/leetcode.git", self.neetcode 52 | ) 53 | self.logger.info("cloned repo") 54 | self.repo = Repo(self.neetcode) 55 | except git.exc.GitCommandError: 56 | self.repo = Repo(self.neetcode) 57 | o = self.repo.remotes.origin 58 | o.pull() 59 | self.logger.info("pulled repo") 60 | 61 | self.languages = [ 62 | x.name 63 | for x in self.neetcode.iterdir() 64 | if x.is_dir() and not x.name.startswith(".") 65 | ] 66 | 67 | @app_commands.command() 68 | @app_commands.describe( 69 | number="the number leetcode problem you want a soluiton for", 70 | language="the coding language", 71 | ) 72 | async def leetcode( 73 | self, interaction: discord.Interaction, number: int, language: str 74 | ): 75 | self.command_usage_stats["leetcode_invoked"] += 1 76 | # add leading zeros to match file names 77 | number = "{:04d}".format(number) 78 | """Returns the leetcode solution""" 79 | files = list(self.neetcode.glob(language + "/" + str(number) + "-*")) 80 | if language not in self.languages or len(files) == 0: 81 | await interaction.response.send_message( 82 | f"there are no solutions for leetcode problem #{number} in {language}", 83 | ephemeral=True 84 | ) 85 | self.logger.info(f"{interaction.user} asked for problom #{number} in {language} but none exist") 86 | return 87 | 88 | self.logger.info(f"{interaction.user} asked for problom #{number} in {language}") 89 | with open(files[0]) as f: 90 | code = f.read() 91 | if interaction.channel_id in self.bot_spam_channels or interaction.channel.name.lower() == "leetcode": 92 | problem_name = pathlib.Path(files[0].stem).name.replace('-', ' ') 93 | await interaction.response.send_message(f"Problem #{problem_name} ({language})\n```{language}\n{code}\n```") 94 | else: 95 | await interaction.response.send_message(f"```{language}\n{code}\n```", ephemeral=True) 96 | 97 | @leetcode.autocomplete("language") 98 | async def leetcode_autocomplete( 99 | self, 100 | interaction: discord.Interaction, 101 | current: str, 102 | ) -> List[app_commands.Choice[str]]: 103 | return [ 104 | app_commands.Choice(name=language, value=language) 105 | for language in self.languages 106 | if current.lower() in language.lower() 107 | ] 108 | 109 | @commands.command(hidden=True) 110 | @commands.is_owner() 111 | async def stats(self, ctx): 112 | """Reports the usage stats of the bot.""" 113 | stats_message = "Command Usage Stats:\n" 114 | stats_message += f"Number of repo pulls: {self.command_usage_stats['pulls']}\n" 115 | stats_message += f"Number of leetcode command invocations: {self.command_usage_stats['leetcode_invoked']}\n" 116 | 117 | await ctx.send(stats_message) 118 | 119 | 120 | 121 | async def setup(bot: commands.Bot): 122 | await bot.add_cog(Neetcode(bot)) 123 | --------------------------------------------------------------------------------