├── LICENSE
├── README.md
├── config.json
├── data.json
├── image
├── banner.png
└── slotbotthumbnail.png
├── main.py
├── pingcount.json
└── requirements.txt
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Riza
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Slot Bot
3 |
🙌 Discord bot designed to streamline slot management in your server
4 |
Click the thumbnail below to watch the tutorial on setting it up!
5 |
6 |
7 |
8 |
9 |
10 | ---
11 |
12 | ---
13 |
14 | ## Table of Contents
15 |
16 | - [Features](#features)
17 | - [Installation](#installation)
18 | - [Usage](#usage)
19 | - [Contributing](##contributing)
20 | - [Support](#support)
21 |
22 |
23 | ---
24 |
25 |
26 | ## Features
27 |
28 | - Create slots with specified durations and categories
29 | - Renew slots with updated durations
30 | - Hold slots temporarily
31 | - Unhold slots when ready
32 | - Add and remove users from slots
33 | - Set slot rules and guidelines
34 | - Receive notifications for slot activities
35 |
36 | ## Usage
37 |
38 | To use the bot, follow these steps:
39 |
40 | 1. **Create a Slot:** Use the `,create` command to create a new slot. Example: `,create @user 1 d category1 4 Slot`.
41 |
42 | 2. **Add Users:** Use the `,add` command to add users to a slot. Example: `,add @user`.
43 |
44 | 3. **Renew a Slot:** Use the `,renew` command to renew a slot with updated duration. Example: `,renew @user #channel 1 m/d his Slot`.
45 |
46 | 4. **Hold a Slot:** Use the `,hold` command to temporarily hold a slot.
47 |
48 | 5. **Unhold a Slot:** Use the `,unhold` command to unhold a slot.
49 |
50 | 6. **Remove Users:** Use the `,remove` command to remove users from a slot. Example: `,remove @user`.
51 |
52 | 7. **Ping Notification:** Use the `,ping` command to receive a notification in the slot channel. You can use `,ping everyone` or `,ping @here` to mention everyone or here respectively. Example: `,ping`.
53 |
54 | 8. **Nuke Command:** Use the `,nuke` command to delete all messages in the slot channel if you have owner permissions. Example: `,nuke`.
55 |
56 |
57 |
58 |
59 |
60 | > [!note]
61 | > The Discord bot needs to have admin permissions and be positioned at the top of the role hierarchy, above the `buyers` in order to create a slot
62 |
63 |
64 |
65 |
66 | ## Installation
67 |
68 | To install the bot, follow these steps:
69 |
70 | 1. Clone the repository: `git clone https://github.com/codewithriza/SlotBot.git`
71 | 2. Install dependencies: `pip install -r requirements.txt`
72 | 3. Set up your configuration: Create a `config.json` file with your bot token, category ID, staff ID, etc. Make sure to keep your bot token private and secure.
73 | 4. Replace token and other guild id, channel id, 2 category id in `main.py`
74 | 5. Run the bot: `python3 main.py`
75 |
76 | > [!IMPORTANT]
77 | > Ensure that your bot token is kept private and setup in config.json along with category id staff id etc create separate category for 1 and 2 and read through the code to understand
78 |
79 | ## Contributing
80 |
81 | Contributions are welcome! If you have any ideas or improvements, feel free to open an issue or submit a pull request.(or) update us in [](https://discord.gg/JdyvFVgsTN)
82 |
83 | ## Support
84 |
85 | If you find this project useful, please consider giving it a star on GitHub! 🌟
86 |
87 | ---
88 |
89 | [](https://discord.com/users/887532157747212370)
90 | [](https://twitter.com/pyriza)
91 | [](https://www.youtube.com/watch?v=JYJ2N_ebS_w)
92 |
93 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "staffrole": 123,
3 | "premiumeroleid": 123,
4 | "guildid": 123,
5 | "categoryid": 123
6 | }
7 |
--------------------------------------------------------------------------------
/data.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/image/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithriza/SlotBot/34ce29951d7c2350d476b518d02c194b2a386d29/image/banner.png
--------------------------------------------------------------------------------
/image/slotbotthumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithriza/SlotBot/34ce29951d7c2350d476b518d02c194b2a386d29/image/slotbotthumbnail.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | # Slot Bot - A Discord bot for managing slots
2 | # Made by Riza (https://github.com/codewithriza/SlotBot)
3 | # Contact for help - https://discord.com/users/887532157747212370
4 | # Create an issue in this repo for support: https://github.com/codewithriza/SlotBot/issues
5 |
6 | import discord
7 | from discord.ext import commands , tasks
8 | import datetime
9 | import json
10 | import os
11 | from colorama import Fore
12 |
13 | bot = commands.Bot(
14 | command_prefix=",",
15 | intents=discord.Intents.all(),
16 | status=discord.Status.dnd,
17 | activity=discord.Activity(
18 | type=discord.ActivityType.watching, name="Riza"
19 | ),
20 | guild = discord.Object(id=1229389945626693714) # Change it with your guild id right click on your server and copy the server id and paste it instead of 1229389945626693714
21 | )
22 | bot.remove_command("help")
23 |
24 |
25 | @bot.event
26 | async def on_ready():
27 | print("\033[94m" + """
28 |
29 | ███████╗██╗███████╗░█████╗░
30 | ██╔══██╗██║╚════██║██╔══██╗
31 | ██████╔╝██║░░███╔═╝███████║
32 | ██╔══██╗██║██╔══╝░░██╔══██║
33 | ██║░░██║██║███████╗██║░░██║
34 | ╚═╝░░╚═╝╚═╝╚══════╝╚═╝░░╚═╝
35 |
36 | """ + "\033[0m" + "Made By @codewithriza")
37 | print("Bot is ready!")
38 | with open("config.json", "r") as file:
39 | hmm = json.load(file)
40 |
41 | rid = hmm["premiumeroleid"]
42 | cid = hmm["categoryid"]
43 | staff = hmm["staffrole"]
44 | print(rid)
45 | @tasks.loop(hours=1)
46 | async def expire():
47 | try:
48 | with open("data.json", "r") as file:
49 | data = json.load(file)
50 | except FileNotFoundError:
51 | data = []
52 |
53 | nowtime = datetime.datetime.now()
54 | nt = nowtime.strftime("%Y%m%d")
55 | remove = []
56 |
57 | for xd in data:
58 | for item in xd:
59 | slottime = item["endtime"]
60 | st = datetime.datetime.fromtimestamp(int(slottime))
61 | print(st.strftime("%Y%m%d"))
62 | finalse = st.strftime("%Y%m%d")
63 | print(f"Slot end {finalse}")
64 | print(f"now time {nt}")
65 | print(nt >= finalse)
66 |
67 | if nt >= finalse:
68 |
69 | with open("data.json", "w") as file:
70 | json.dump(data, file, indent=4)
71 |
72 | channel = bot.get_channel(item["channelid"])
73 | guild = bot.get_guild(int(hmm["guildid"]))
74 | member = guild.get_member(item["userid"])
75 | await bot.tree.sync()
76 |
77 | @bot.command()
78 | async def help(ctx):
79 | embed = discord.Embed(description="**,create** - Use To Create Slot `,create @user 7 d 2 category1 slotname`\n**,add** - Use To Add User In Slot`,add @usermention`\n**,remove** - Use To Remove User In SLot\n**,renew** - Use To Renew Slot\n**,hold\n**,**unhold**\n**,nuke\n**/ping @everyone/@here",color=0x8A2BE2)
80 | embed.set_thumbnail(url=ctx.guild.icon)
81 | embed.set_author(name="Slot Bot Help Menu")
82 | await ctx.send(embed=embed,delete_after=30)
83 |
84 |
85 | def get_slot_owner(channel_id):
86 | try:
87 | with open("pingcount.json", "r") as file:
88 | data = json.load(file)
89 | except FileNotFoundError:
90 | data = []
91 |
92 | for entry in data:
93 | if entry.get('channelid') == channel_id:
94 | return entry.get('userid')
95 |
96 | return None
97 |
98 |
99 | @bot.command()
100 | async def delete(ctx):
101 | if discord.utils.get(ctx.guild.roles, id=1229402537648455700) in ctx.author.roles:
102 | try:
103 | await ctx.channel.delete()
104 | await ctx.send("Channel deleted successfully.")
105 | except discord.Forbidden:
106 | await ctx.send("I do not have permission to delete this channel.")
107 | else:
108 | await ctx.send("You do not have the necessary role to use this command.")
109 |
110 |
111 | @bot.command()
112 | @commands.has_role(int(staff))
113 | async def hold(ctx):
114 | channel = ctx.channel
115 | await channel.set_permissions(ctx.guild.default_role, send_messages=False)
116 |
117 | # Find the slot owner
118 | user_id = get_slot_owner(channel.id)
119 |
120 | if user_id is None:
121 | await ctx.reply("Could not find slot owner")
122 | return
123 |
124 | # Create the embed
125 | embed = discord.Embed(title="SLOT ON HOLD",
126 | description=f"A report is open against <@{user_id}>\nDo not start a deal with them until the slot is open",
127 | color=0x8A2BE2)
128 | embed.set_thumbnail(url="https://www.iconsdb.com/icons/preview/white/warning-xxl.png")
129 | embed.set_footer(text=f"{ctx.author.display_name} has held the slot")
130 |
131 | # Send the embed
132 | await channel.send(embed=embed)
133 |
134 |
135 |
136 |
137 | @bot.command()
138 | @commands.has_role(int(staff))
139 | async def unhold(ctx):
140 | channel = ctx.channel
141 | await channel.set_permissions(ctx.guild.default_role, send_messages=True)
142 |
143 | # Create the embed
144 | embed = discord.Embed(title="UNHELD SLOT",
145 | description="Slot has been unheld and the case has been solved.",
146 | color=0x8A2BE2)
147 | embed.set_footer(text=f"Slot unheld by {ctx.author.display_name}")
148 | embed.set_thumbnail(url="https://wallpapers-clan.com/wp-content/uploads/2022/10/rick-sanchez-pfp-26.jpg")
149 |
150 | # Send the embed
151 | await channel.send(embed=embed)
152 |
153 |
154 |
155 | @bot.command()
156 | @commands.has_role(int(staff))
157 | async def add(ctx, member: discord.Member):
158 | role = ctx.guild.get_role(1229474713345069199)
159 | await member.add_roles(role)
160 | await ctx.send(f"Added role {role.name} to {member.display_name}")
161 | @bot.command()
162 | @commands.has_role(int(staff))
163 | async def renew(ctx, member: discord.Member = None, channel: discord.TextChannel = None, yoyo: str = None, cx: str = None):
164 | if member is None:
165 | await ctx.reply("Member Not Found")
166 | return
167 |
168 | if channel is None:
169 | await ctx.reply("Channel Not Found")
170 | return
171 |
172 | if yoyo is None or cx is None:
173 | await ctx.reply("Use valid Format: ,renew @user #channel 1 m/d his Slot")
174 | return
175 |
176 | yoyo_value = None
177 | try:
178 | yoyo_value = int(yoyo[:-1]) if yoyo.endswith(('m', 'd')) else None
179 | except ValueError:
180 | pass
181 |
182 | if yoyo_value is None:
183 | await ctx.reply("Use valid Format: ,renew @user #channel 1 m/d his Slot")
184 | return
185 |
186 | if cx.lower() == "d":
187 | yoyo_value = (yoyo_value * 24 * 60 * 60) + datetime.datetime.now().timestamp()
188 | elif cx.lower() == "m":
189 | yoyo_value = (yoyo_value * 30 * 24 * 60 * 60) + datetime.datetime.now().timestamp()
190 | else:
191 | await ctx.reply("Use valid Format: ,renew @user #channel 1 m/d his Slot")
192 | return
193 |
194 | await channel.set_permissions(member,view_channel=True,send_messages=True,mention_everyone=True)
195 | role = discord.utils.get(ctx.guild.roles, id=int(rid))
196 | await member.add_roles(role)
197 | print("renew")
198 | async for message in channel.history(limit=1000):
199 | await message.delete()
200 | dataz = {
201 | "endtime": yoyo,
202 | "userid": member.id,
203 | "channelid": channel.id
204 | },
205 | try:
206 | with open("data.json", "r") as file:
207 | data = json.load(file)
208 | except FileNotFoundError:
209 | data = []
210 | data.append(dataz)
211 | with open("data.json", "w") as file:
212 | json.dump(data, file,indent=4)
213 |
214 | embed = discord.Embed(description="""We don't offer any refunds.
215 | You can't sell or share your slot.
216 | If you promote any server your slot will be revoked.
217 | If you scam your slot will get Revoked and you will get banned.
218 | We can put your slot on hold at any time.
219 | If you do not save the transcript of the ticket when you bought it if you or our server will get Termed you will not get your slot back.
220 | We recommend to use MM, if the slot user denies MM, we have the right to revoke your slot.
221 | You are not allowed to advertise your server invite or telegram invite.
222 | ping reset | every 24 hours
223 | positions are never fixed
224 | If we see that your slot is inactive and is hardly used, we have the right to revoke your slot without a refund.
225 | we can change the rules whenever we want without further notice
226 | overpinging will lead in an instant slot revoke without any refund
227 | Inactivity For More Than 2 Days Will Result In Removal Of Slot (YOU WILL BE WARNED FIRST)""",color=0x8A2BE2)
228 |
229 | embed.set_author(name="Slot Rules")
230 | embed.set_thumbnail(url=f"{ctx.guild.icon}")
231 |
232 | await channel.send(embed=embed)
233 | embed = discord.Embed(description=f'**Slot Owner:** {member.mention}\n**End:** ',color=0x8A2BE2)
234 | embed.set_footer(text=ctx.guild.name)
235 | embed.set_author(name=member)
236 | await channel.send(embed=embed)
237 | await ctx.reply(f"successfully renew Slot {channel.mention}")
238 |
239 |
240 | @bot.command()
241 | @commands.has_role(int(staff))
242 | async def remove(ctx, member: discord.Member):
243 | role = ctx.guild.get_role(1229474713345069199)
244 | if role in member.roles:
245 | await member.remove_roles(role)
246 | await ctx.send(f"Removed role {role.name} from {member.display_name}")
247 | else:
248 | await ctx.send(f"{member.display_name} doesn't have the role {role.name}")
249 |
250 |
251 | @bot.command()
252 | @commands.has_role(int(staff))
253 | async def revoke(ctx,member: discord.Member=None, channel: discord.TextChannel = None):
254 |
255 | rr = []
256 |
257 | with open("./data.json","r") as rr:
258 | rr = json.load(rr)
259 |
260 | ftf = False
261 |
262 | for x in rr:
263 | for xx in x:
264 | if (xx["channelid"] == channel.id):
265 | ftf = True
266 |
267 | if (ftf == False):
268 | await ctx.send("Slot Not In DataBase")
269 | return
270 |
271 | if (member == False):
272 | await ctx.reply("Member Not Found")
273 |
274 | if (channel == False):
275 | await ctx.reply("Channel Not Found")
276 |
277 | await channel.set_permissions(member, send_messages=True,mention_everyone=False)
278 | await ctx.reply("successfully removed")
279 | @bot.command()
280 | @commands.has_role(int(staff))
281 | async def create(ctx, member: discord.Member = None, yoyo: int = None, cx=None, ping_count: int = 0, category: str = "category1", *, x=None):
282 | if member is None:
283 | await ctx.reply("User Not Found")
284 | return
285 |
286 | if yoyo is None:
287 | await ctx.reply("Use valid Format: ,create @user 1 d his Slot")
288 | return
289 |
290 | if cx is None:
291 | await ctx.reply("Use valid Format: ,create @user 1 d his Slot")
292 | return
293 |
294 | if category.lower() not in ['category1', 'category2']:
295 | await ctx.reply("Invalid category. Please choose either 'category1' or 'category2'.")
296 | return
297 |
298 | # Determine the category ID based on the user's choice
299 | if category.lower() == 'category1':
300 | category_id = 1229474371588849745 # Category 1 ID
301 | else:
302 | category_id = 1229474415734034472 # Category 2 ID
303 |
304 | if x is None:
305 | x = member.display_name
306 |
307 | overwrites = {
308 | ctx.guild.default_role: discord.PermissionOverwrite(view_channel=True, send_messages=False, mention_everyone=False),
309 | member: discord.PermissionOverwrite(view_channel=True, send_messages=True, mention_everyone=True)
310 | }
311 |
312 |
313 | category = discord.utils.get(ctx.guild.categories, id=category_id)
314 |
315 | a = await ctx.guild.create_text_channel(x, category=category, overwrites=overwrites)
316 |
317 | await a.set_permissions(ctx.guild.default_role, send_messages=False)
318 | role = discord.utils.get(ctx.author.guild.roles, id=int(rid))
319 | await member.add_roles(role)
320 | embed = discord.Embed(title=" SLOT RULES", color=0x8A2BE2)
321 | rules = """
322 | 1. We don't offer any refunds.
323 | 2. You can't sell or share your slot.
324 | 3. If you promote any server your slot will be revoked.
325 | 4. If you scam your slot will get revoked and you will get banned.
326 | 5. We can put your slot on hold at any time.
327 | 6. If you do not save the transcript of the ticket when you bought it if you or our server will get termed you will not get your slot back.
328 | 7. We recommend using MM, if the slot user denies MM, we have the right to revoke your slot.
329 | 8. You are not allowed to advertise your server invite or telegram invite.
330 | 9. Ping reset: every 24 hours.
331 | 10. Positions are never fixed.
332 | 11. If we see that your slot is inactive and is hardly used, we have the right to revoke your slot without a refund.
333 | 12. We can change the rules whenever we want without further notice.
334 | 13. Overpinging will lead to an instant slot revoke without any refund.
335 | 14. Inactivity for more than 2 days will result in the removal of the slot (you will be warned first).
336 | """
337 | embed.add_field(name="Rules", value=rules, inline=False)
338 | embed.set_image(url="https://media.discordapp.net/attachments/1229389946226475122/1229475051817140379/Rick-and-Morty-sunglasses.jpg?ex=662fd0de&is=661d5bde&hm=3f5f6515b54ba7d626e2a1eccfb7a89a2a7061fd6b96d203e6143c0a500138ab&=&format=webp&width=932&height=700")
339 | await a.send(embed=embed)
340 |
341 | if cx.lower() == "d":
342 | yoyo = (yoyo * 24 * 60 * 60) + datetime.datetime.now().timestamp()
343 | elif cx.lower() == "m":
344 | yoyo = (yoyo * 30 * 24 * 60 * 60) + datetime.datetime.now().timestamp()
345 | else:
346 | await ctx.reply("Use valid Format: ,create @user 1 m 4")
347 |
348 | embed = discord.Embed(description=f'**Slot Owner:** {member.mention}\n**End:** \n**Ping Count:** {ping_count}', color=0x8A2BE2)
349 | embed.set_footer(text=ctx.guild.name)
350 | embed.set_author(name=member)
351 | await a.send(embed=embed)
352 | await ctx.reply(f"successfully Create Slot {a.mention}")
353 |
354 | dataz = {
355 | "endtime": yoyo,
356 | "userid": member.id,
357 | "channelid": a.id,
358 | "ping_count": ping_count # Store the initial ping count
359 | }
360 |
361 | try:
362 | with open("pingcount.json", "r") as file:
363 | data = json.load(file)
364 | except FileNotFoundError:
365 | data = []
366 |
367 | data.append(dataz)
368 |
369 | with open("pingcount.json", "w") as file:
370 | json.dump(data, file, indent=4)
371 |
372 |
373 | @bot.command()
374 | async def ping(ctx, mention: str = None):
375 | try:
376 | with open("pingcount.json", "r") as file:
377 | data = json.load(file)
378 | except FileNotFoundError:
379 | data = []
380 |
381 | for i, user_data in enumerate(data):
382 | if user_data["userid"] == ctx.author.id:
383 | # Check if the user is the owner of the channel
384 | if ctx.channel.id == user_data["channelid"]:
385 | # Check if the user has any ping counts left
386 | if user_data["ping_count"] > 0:
387 | # Decrement the ping count
388 | data[i]["ping_count"] -= 1
389 | with open("pingcount.json", "w") as file:
390 | json.dump(data, file, indent=4)
391 |
392 | # Determine the mention based on user input
393 | mention_str = ""
394 | if mention == "@here":
395 | mention_str = "@here"
396 | elif mention == "@everyone":
397 | mention_str = "@everyone"
398 |
399 | # Send the appropriate mention
400 | here_message = await ctx.send(mention_str)
401 |
402 | # Send a message in an embed format
403 | embed = discord.Embed(
404 | title="Ping Detected",
405 | description=f"{ctx.author.mention} pinged {mention_str} in their slot! You have {data[i]['ping_count']} ping{'s' if data[i]['ping_count'] != 1 else ''} left.\n\n**Use <#1220914365193257010>**",
406 | color=0xFFFF00
407 | )
408 | await ctx.send(embed=embed)
409 |
410 | # Wait for 5 seconds
411 | await asyncio.sleep(5)
412 |
413 | # Delete the mention message
414 | await here_message.delete()
415 | return
416 |
417 | else:
418 | await ctx.send("You have used all your pings.")
419 | return
420 | else:
421 | await ctx.send("You can only use the ping command in your slot channel.")
422 | return
423 | await ctx.send("You don't have any slots. Create a slot to get pings.")
424 |
425 | @bot.command()
426 | async def nuke(ctx):
427 | # Check if the user has the specified role
428 | role = ctx.guild.get_role(1229474713345069199)
429 | if role and role in ctx.author.roles:
430 | # Define a predicate to filter messages
431 | def is_not_bot_embed_message(message):
432 | return message.author != bot.user or not message.embeds
433 |
434 | # Delete all messages except bot embed messages
435 | await ctx.channel.purge(limit=None, check=is_not_bot_embed_message)
436 |
437 | # Build the embed
438 | embed = discord.Embed(
439 | title="Nuke",
440 | description=f"Successfully nuked {ctx.channel.mention}",
441 | color=discord.Color.red()
442 | )
443 | embed.set_image(url="https://media.discordapp.net/attachments/1229481737348976740/1229496580319739924/latest.png?ex=662fe4eb&is=661d6feb&hm=01571fce0db9e7b8a0b6c9f8146197c8fed98aaa99991bf51da563f3cd16e31c&=&format=webp&quality=lossless&width=846&height=874")
444 |
445 | # Send the embed
446 | await ctx.send(embed=embed)
447 | else:
448 | await ctx.send("You do not have permission to use this command.")
449 |
450 | bot.run(" paste your bot token from https://discord.com/developers/applications ")
451 |
--------------------------------------------------------------------------------
/pingcount.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | discord.py==1.7.3
2 | colorama==0.4.4
3 |
--------------------------------------------------------------------------------