import os import requests import discord from discord.ext import commands import asyncio import re from datetime import datetime, timedelta from collections import defaultdict from aiohttp import web # Create web app app = web.Application() async def hello(request): return web.Response(text="Hello World") app.router.add_get('/', hello) TOKEN = os.environ.get('token') # Discord bot setup intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) CHANNEL_ID = 1298830206387228682 PETS_API = 'https://petsapi.deno.dev/' EXISTS_API = 'https://existsapi.deno.dev/' RAP_API = 'https://rapapi.deno.dev/' pet_images = {} pet_difficulties = {} pet_raps = {} hourly_hatches = defaultdict(list) async def update_rap_values(): try: response = requests.get(RAP_API) if response.status_code == 200: data = response.json() if data['status'] == 'ok': pet_raps.clear() for pet_data in data['data']: config_data = pet_data['configData'] pet_id = config_data['id'] value = pet_data['value'] is_shiny = config_data.get('sh', False) if is_shiny: pet_raps[f"Shiny {pet_id}"] = value else: pet_raps[pet_id] = value print(f"Updated RAP values for {len(data['data'])} pets") except Exception as e: print(f"Error fetching RAP values: {e}") async def get_huge_secret_pets(): try: response = requests.get(PETS_API) if response.status_code == 200: data = response.json() if data['status'] == 'ok': huge_secret_pets = [] for pet in data['data']: config_data = pet['configData'] if config_data.get('huge') or config_data.get('secret'): pet_name = config_data['name'] huge_secret_pets.append(pet_name) huge_secret_pets.append(f"Shiny {pet_name}") difficulty = config_data.get('difficulty', 'Unknown') pet_difficulties[pet_name] = difficulty pet_difficulties[f"Shiny {pet_name}"] = difficulty * 100 if 'thumbnail' in config_data: pet_images[pet_name] = config_data['thumbnail'] pet_images[f"Shiny {pet_name}"] = config_data['thumbnail'] print(f"Found {len(huge_secret_pets)} pets to track (including shiny versions)") return huge_secret_pets except Exception as e: print(f"Error fetching pets list: {e}") return [] async def send_embed_message(channel, pet_name, previous_value, current_value, is_change=False): if is_change and current_value > previous_value: hatches = current_value - previous_value for _ in range(hatches): hourly_hatches[pet_name].append(datetime.now()) pet_image_url = pet_images.get(pet_name, None) difficulty = pet_difficulties.get(pet_name, "Unknown") rap_value = pet_raps.get(pet_name, "No RAP") if isinstance(rap_value, (int, float)): rap_display = f"{rap_value:,}" else: rap_display = rap_value if isinstance(difficulty, (int, float)): difficulty_display = f"{difficulty:,}" else: difficulty_display = difficulty if isinstance(current_value, (int, float)): current_display = f"{current_value:,}" else: current_display = current_value if isinstance(previous_value, (int, float)): previous_display = f"{previous_value:,}" else: previous_display = previous_value embed = discord.Embed( title=f"🎲 A {pet_name} was rolled! 🎲", description=f"{pet_name} exists: **{current_display}**\nDifficulty: **1 in {difficulty_display}**\nRAP Value: **{rap_display}**", color=discord.Color.blue() if not is_change else discord.Color.orange(), ) if pet_image_url: if isinstance(pet_image_url, str): if pet_image_url.startswith('rbxassetid://'): asset_id = pet_image_url.replace('rbxassetid://', '') asset_id = re.search(r'^\d+', asset_id).group(0) pet_image_url = f"https://rbxgleaks.pythonanywhere.com/asset/{asset_id}" print(f"Using image URL for {pet_name}: {pet_image_url}") embed.set_thumbnail(url=pet_image_url) try: await channel.send(embed=embed) except discord.HTTPException as e: print(f"Failed to send embed for {pet_name}: {e}") await channel.send(f"🎲 A {pet_name} was rolled! Exists: {current_display} (Previous: {previous_display})") async def petdata(tracked_pets): try: response = requests.get(EXISTS_API) if response.status_code == 200: data = response.json() if data['status'] == 'ok': pet_values = {pet: 0 for pet in tracked_pets} for pet in data['data']: pet_id = pet['configData']['id'] is_shiny = pet['configData'].get('sh', False) value = pet['value'] pet_name = f"Shiny {pet_id}" if is_shiny else pet_id if pet_name in pet_values: print(f"Found pet: {pet_name} with exist count {value}") pet_values[pet_name] = value return pet_values print(f"Error code: {response.status_code}") except Exception as e: print(f"Error: {e}") return None async def main_loop(): channel = bot.get_channel(CHANNEL_ID) if channel is None: print("Invalid channel ID. Please check your channel ID.") return tracked_pets = await get_huge_secret_pets() lastknown = {pet: None for pet in tracked_pets} print(f"Initially tracking {len(tracked_pets)} pets") while True: cleanup_old_hatches() if not tracked_pets: tracked_pets = await get_huge_secret_pets() lastknown.update({pet: None for pet in tracked_pets if pet not in lastknown}) await update_rap_values() vvalues = await petdata(tracked_pets) if vvalues is not None: for pet, value in vvalues.items(): if lastknown[pet] is None: print(f"Initial value for {pet}: {value}") elif value != lastknown[pet]: await send_embed_message(channel, pet, lastknown[pet], value, is_change=True) lastknown[pet] = value else: print("Broken check") if len(tracked_pets) > 0: new_pets = await get_huge_secret_pets() if set(new_pets) != set(tracked_pets): print("Pet list updated!") tracked_pets = new_pets lastknown.update({pet: None for pet in tracked_pets if pet not in lastknown}) await asyncio.sleep(60) def cleanup_old_hatches(): one_hour_ago = datetime.now() - timedelta(hours=1) for pet in hourly_hatches: hourly_hatches[pet] = [timestamp for timestamp in hourly_hatches[pet] if timestamp > one_hour_ago] @bot.command(name='lasthour') async def last_hour_stats(ctx): cleanup_old_hatches() if not hourly_hatches: await ctx.send("No pets have been hatched in the last hour.") return total_hatches = sum(len(hatches) for hatches in hourly_hatches.values()) embed = discord.Embed( title="🕒 Last Hour Hatch Statistics 🕒", description=f"Total hatches in the last hour: **{total_hatches}**", color=discord.Color.green() ) sorted_pets = sorted( hourly_hatches.items(), key=lambda x: len(x[1]), reverse=True ) for pet_name, hatches in sorted_pets: if hatches: count = len(hatches) difficulty = pet_difficulties.get(pet_name, "Unknown") rap_value = pet_raps.get(pet_name, "No RAP") if isinstance(rap_value, (int, float)): rap_display = f"{rap_value:,}" else: rap_display = rap_value if isinstance(difficulty, (int, float)): difficulty_display = f"{difficulty:,}" else: difficulty_display = difficulty embed.add_field( name=pet_name, value=f"Hatches: **{count}**\nDifficulty: 1 in {difficulty_display}\nRAP: {rap_display}", inline=True ) embed.set_footer(text=f"Last updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") await ctx.send(embed=embed) @bot.event async def on_ready(): print(f'Logged in as {bot.user.name}') bot.loop.create_task(main_loop()) runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, '0.0.0.0', 7860) await site.start() print(f"Web server started on port 7860") def run_bot(): bot.run(TOKEN) if __name__ == "__main__": run_bot()