jerrrycans commited on
Commit
2b58625
·
verified ·
1 Parent(s): c35ff57

Create ccc.py

Browse files
Files changed (1) hide show
  1. ccc.py +705 -0
ccc.py ADDED
@@ -0,0 +1,705 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import discord
3
+ from discord.ext import commands
4
+ import asyncio
5
+ import json
6
+ import re
7
+ from collections import defaultdict
8
+ from collections import deque
9
+ from datetime import datetime, timedelta
10
+ import pytz
11
+ import os
12
+
13
+ TOKEN = os.environ['TOKEN']
14
+ CHANNEL_ID = 1298830206387228682
15
+ MONITORED_ITEMS_CHANNEL_ID = 1307752080139878500
16
+ AUTHORIZED_USER_ID = 1219416244806094883
17
+
18
+ PETS_API = 'https://petsapi.deno.dev/'
19
+ EXISTS_API = 'https://existsapi.deno.dev/'
20
+ RAP_API = 'https://rapapi.deno.dev/'
21
+
22
+ last_rap_values = {
23
+ "Crystal Key": None,
24
+ "Huge Shiba": None,
25
+ "Huge Dragon": None,
26
+ "Huge Inferno Cat": None,
27
+ "Autumn God Potion": None
28
+ }
29
+
30
+ LIMITED_PETS = {
31
+ "Huge Shiba": 15000,
32
+ "Huge Dragon": 7500,
33
+ "Huge Nightmare Corgi": 15000,
34
+ "Huge Jelly Axolotl": 5000
35
+ }
36
+
37
+ JELLY_LEAVE_TIMES = {
38
+ "Huge Pilgrim Turkey": datetime.strptime('2024-12-06 12:00:00', '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.timezone('US/Eastern')),
39
+ "Acorn": datetime.strptime('2024-12-06 12:00:00', '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.timezone('US/Eastern'))
40
+ }
41
+
42
+ intents = discord.Intents.default()
43
+ intents.message_content = True
44
+ bot = commands.Bot(command_prefix='!', intents=intents)
45
+
46
+ pet_images = {}
47
+ pet_difficulties = {}
48
+ pet_raps = {}
49
+ pet_changes = {}
50
+ recent_notifications = defaultdict(lambda: deque(maxlen=5))
51
+
52
+ async def fetch_exists_data():
53
+ try:
54
+ response = requests.get('https://biggamesexists.deno.dev')
55
+ if response.status_code == 200:
56
+ return response.json().get('data', [])
57
+ except Exception as e:
58
+ print(f"Error fetching exists data: {e}")
59
+ return []
60
+
61
+ def format_number(number):
62
+ if not isinstance(number, (int, float)):
63
+ return str(number)
64
+
65
+ abs_number = abs(number)
66
+ if abs_number < 1000:
67
+ return str(number)
68
+ elif abs_number < 1000000:
69
+ return f"{number/1000:.1f}k"
70
+ elif abs_number < 1000000000:
71
+ return f"{number/1000000:.1f}m"
72
+ elif abs_number < 1000000000000:
73
+ return f"{number/1000000000:.1f}b"
74
+ else:
75
+ return f"{number/1000000000000:.1f}t"
76
+
77
+ async def fetch_pet_collection_data(pet_name):
78
+ try:
79
+ response = requests.get('https://collectionpet.deno.dev')
80
+ if response.status_code == 200:
81
+ data = response.json().get('data', [])
82
+ for pet in data:
83
+ if pet.get('configName', '').lower() == pet_name.lower():
84
+ return pet
85
+ except Exception as e:
86
+ print(f"Error fetching pet collection data: {e}")
87
+ return None
88
+
89
+ async def fetch_pet_exists_data(pet_name):
90
+ try:
91
+ response = requests.get('https://biggamesexists.deno.dev')
92
+ if response.status_code == 200:
93
+ data = response.json().get('data', [])
94
+ variants = {
95
+ 'Normal': 0,
96
+ 'Golden': 0,
97
+ 'Rainbow': 0,
98
+ 'Shiny': 0,
99
+ 'Shiny Golden': 0,
100
+ 'Shiny Rainbow': 0
101
+ }
102
+
103
+ for pet_data in data:
104
+ config_data = pet_data.get('configData', {})
105
+ value = pet_data.get('value', 0)
106
+
107
+ pet_id = config_data.get('id', '')
108
+ is_shiny = config_data.get('sh', False)
109
+ pt_value = config_data.get('pt', 0)
110
+
111
+ if pet_id.lower() == pet_name.lower():
112
+ if is_shiny and pt_value == 1:
113
+ variants['Shiny Golden'] = max(variants['Shiny Golden'], value)
114
+ elif is_shiny and pt_value == 2:
115
+ variants['Shiny Rainbow'] = max(variants['Shiny Rainbow'], value)
116
+ elif is_shiny:
117
+ variants['Shiny'] = max(variants['Shiny'], value)
118
+ elif pt_value == 1:
119
+ variants['Golden'] = max(variants['Golden'], value)
120
+ elif pt_value == 2:
121
+ variants['Rainbow'] = max(variants['Rainbow'], value)
122
+ else:
123
+ variants['Normal'] = max(variants['Normal'], value)
124
+
125
+ return variants
126
+ except Exception as e:
127
+ print(f"Error fetching exists data: {e}")
128
+ return None
129
+
130
+ @bot.command(name='petdata')
131
+ async def pet_data(ctx, *, pet_name):
132
+ collection_data = await fetch_pet_collection_data(pet_name)
133
+
134
+ exists_data = await fetch_pet_exists_data(pet_name)
135
+
136
+ if not collection_data or not exists_data:
137
+ await ctx.send("Pet does not exist!")
138
+ return
139
+
140
+ embed = discord.Embed(
141
+ title=collection_data.get('configName', 'Unknown Pet'),
142
+ color=int('11ff00', 16)
143
+ )
144
+
145
+ config_data = collection_data.get('configData', {})
146
+
147
+ description = f"**Index Description:** {config_data.get('indexDesc', 'N/A')}\n"
148
+ description += f"**Obtainable in Index:** {config_data.get('indexObtainable', 'N/A')}"
149
+ embed.description = description
150
+
151
+ total_exists = sum(exists_data.values())
152
+
153
+ exists_text = "\n".join([
154
+ f"{variant}: **{count:,}**"
155
+ for variant, count in exists_data.items() if count > 0
156
+ ])
157
+ exists_text += f"\n\n**Total Exist: {total_exists:,}**"
158
+
159
+ embed.add_field(name="**Pet Exists:**", value=exists_text, inline=False)
160
+
161
+ thumbnail_url = config_data.get('thumbnail')
162
+ if thumbnail_url:
163
+ if thumbnail_url.startswith('rbxassetid://'):
164
+ asset_id = re.search(r'\d+', thumbnail_url.replace('rbxassetid://', '')).group(0)
165
+ thumbnail_url = f"https://rbxgleaks.pythonanywhere.com/asset/{asset_id}"
166
+
167
+ embed.set_image(url=thumbnail_url)
168
+
169
+ await ctx.send(embed=embed)
170
+
171
+ @bot.command(name='commonhuges')
172
+ async def common_huge_pets(ctx, count: int = 10):
173
+ if ctx.author.id != AUTHORIZED_USER_ID:
174
+ await ctx.send("You are not authorized to use this command.")
175
+ return
176
+
177
+ count = max(1, min(count, 25))
178
+
179
+ exists_data = await fetch_exists_data()
180
+ if not exists_data:
181
+ await ctx.send("Could not retrieve pet data. Please try again later.")
182
+ return
183
+
184
+ huge_pet_counts = defaultdict(int)
185
+
186
+ for pet in exists_data:
187
+ config_data = pet.get('configData', {})
188
+ value = pet.get('value', 0)
189
+
190
+ if config_data.get('id', '').startswith('Huge'):
191
+ pet_name = config_data.get('id', 'Unknown')
192
+
193
+ is_shiny = config_data.get('sh', False)
194
+ pt_value = config_data.get('pt', 0)
195
+
196
+ if is_shiny and pt_value == 1:
197
+ variant_key = f"Shiny Golden {pet_name}"
198
+ elif is_shiny and pt_value == 2:
199
+ variant_key = f"Shiny Rainbow {pet_name}"
200
+ elif is_shiny:
201
+ variant_key = f"Shiny {pet_name}"
202
+ elif pt_value == 1:
203
+ variant_key = f"Golden {pet_name}"
204
+ elif pt_value == 2:
205
+ variant_key = f"Rainbow {pet_name}"
206
+ else:
207
+ variant_key = f"Normal {pet_name}"
208
+
209
+ huge_pet_counts[variant_key] = max(huge_pet_counts[variant_key], value)
210
+
211
+ sorted_huge_pets = sorted(huge_pet_counts.items(), key=lambda x: x[1], reverse=True)
212
+
213
+ embed = discord.Embed(title=f"Top {count} Most Common Huge Pets", color=discord.Color.blue())
214
+
215
+ if sorted_huge_pets:
216
+ for i, (pet_name, count_value) in enumerate(sorted_huge_pets[:count], 1):
217
+ embed.add_field(
218
+ name=f"{i}. {pet_name}",
219
+ value=f"Exists: **{format_number(count_value)}**",
220
+ inline=False
221
+ )
222
+ else:
223
+ embed.description = "No huge pets found in the data."
224
+
225
+ await ctx.send(embed=embed)
226
+
227
+ @bot.command(name='commontitanics')
228
+ async def common_titanic_pets(ctx, count: int = 10):
229
+ if ctx.author.id != AUTHORIZED_USER_ID:
230
+ await ctx.send("You are not authorized to use this command.")
231
+ return
232
+
233
+ count = max(1, min(count, 25))
234
+
235
+ exists_data = await fetch_exists_data()
236
+ if not exists_data:
237
+ await ctx.send("Could not retrieve pet data. Please try again later.")
238
+ return
239
+
240
+ huge_pet_counts = defaultdict(int)
241
+
242
+ for pet in exists_data:
243
+ config_data = pet.get('configData', {})
244
+ value = pet.get('value', 0)
245
+
246
+ if config_data.get('id', '').startswith('Titanic'):
247
+ pet_name = config_data.get('id', 'Unknown')
248
+
249
+ is_shiny = config_data.get('sh', False)
250
+ pt_value = config_data.get('pt', 0)
251
+
252
+ if is_shiny and pt_value == 1:
253
+ variant_key = f"Shiny Golden {pet_name}"
254
+ elif is_shiny and pt_value == 2:
255
+ variant_key = f"Shiny Rainbow {pet_name}"
256
+ elif is_shiny:
257
+ variant_key = f"Shiny {pet_name}"
258
+ elif pt_value == 1:
259
+ variant_key = f"Golden {pet_name}"
260
+ elif pt_value == 2:
261
+ variant_key = f"Rainbow {pet_name}"
262
+ else:
263
+ variant_key = f"Normal {pet_name}"
264
+
265
+ huge_pet_counts[variant_key] = max(huge_pet_counts[variant_key], value)
266
+
267
+ sorted_huge_pets = sorted(huge_pet_counts.items(), key=lambda x: x[1], reverse=True)
268
+
269
+ embed = discord.Embed(title=f"Top {count} Most Common Titanic Pets", color=discord.Color.blue())
270
+
271
+ if sorted_huge_pets:
272
+ for i, (pet_name, count_value) in enumerate(sorted_huge_pets[:count], 1):
273
+ embed.add_field(
274
+ name=f"{i}. {pet_name}",
275
+ value=f"Exists: **{format_number(count_value)}**",
276
+ inline=False
277
+ )
278
+ else:
279
+ embed.description = "No titanic pets found in the data."
280
+
281
+ await ctx.send(embed=embed)
282
+
283
+ @bot.command(name='leastcommonhuges')
284
+ async def least_common_huge_pets(ctx, count: int = 10):
285
+ if ctx.author.id != AUTHORIZED_USER_ID:
286
+ await ctx.send("You are not authorized to use this command.")
287
+ return
288
+
289
+ count = max(1, min(count, 25))
290
+
291
+ exists_data = await fetch_exists_data()
292
+ if not exists_data:
293
+ await ctx.send("Could not retrieve pet data. Please try again later.")
294
+ return
295
+
296
+ huge_pet_counts = defaultdict(int)
297
+
298
+ for pet in exists_data:
299
+ config_data = pet.get('configData', {})
300
+ value = pet.get('value', 0)
301
+
302
+ if config_data.get('id', '').startswith('Huge'):
303
+ pet_name = config_data.get('id', 'Unknown')
304
+
305
+ is_shiny = config_data.get('sh', False)
306
+ pt_value = config_data.get('pt', 0)
307
+
308
+ if is_shiny and pt_value == 1:
309
+ variant_key = f"Shiny Golden {pet_name}"
310
+ elif is_shiny and pt_value == 2:
311
+ variant_key = f"Shiny Rainbow {pet_name}"
312
+ elif is_shiny:
313
+ variant_key = f"Shiny {pet_name}"
314
+ elif pt_value == 1:
315
+ variant_key = f"Golden {pet_name}"
316
+ elif pt_value == 2:
317
+ variant_key = f"Rainbow {pet_name}"
318
+ else:
319
+ variant_key = f"Normal {pet_name}"
320
+
321
+ huge_pet_counts[variant_key] = max(huge_pet_counts[variant_key], value)
322
+
323
+ sorted_huge_pets = sorted(huge_pet_counts.items(), key=lambda x: x[1])
324
+
325
+ embed = discord.Embed(title=f"Top {count} Least Common Huge Pets", color=discord.Color.dark_red())
326
+
327
+ if sorted_huge_pets:
328
+ for i, (pet_name, count_value) in enumerate(sorted_huge_pets[:count], 1):
329
+ embed.add_field(
330
+ name=f"{i}. {pet_name}",
331
+ value=f"Exists: **{format_number(count_value)}**",
332
+ inline=False
333
+ )
334
+ else:
335
+ embed.description = "No huge pets found in the data."
336
+
337
+ await ctx.send(embed=embed)
338
+
339
+ @bot.command(name='leastcommontitanics')
340
+ async def least_common_titanic_pets(ctx, count: int = 10):
341
+ if ctx.author.id != AUTHORIZED_USER_ID:
342
+ await ctx.send("You are not authorized to use this command.")
343
+ return
344
+
345
+ count = max(1, min(count, 25))
346
+
347
+ exists_data = await fetch_exists_data()
348
+ if not exists_data:
349
+ await ctx.send("Could not retrieve pet data. Please try again later.")
350
+ return
351
+
352
+ titanic_pet_counts = defaultdict(int)
353
+
354
+ for pet in exists_data:
355
+ config_data = pet.get('configData', {})
356
+ value = pet.get('value', 0)
357
+
358
+ if config_data.get('id', '').startswith('Titanic'):
359
+ pet_name = config_data.get('id', 'Unknown')
360
+
361
+ is_shiny = config_data.get('sh', False)
362
+ pt_value = config_data.get('pt', 0)
363
+
364
+ if is_shiny and pt_value == 1:
365
+ variant_key = f"Shiny Golden {pet_name}"
366
+ elif is_shiny and pt_value == 2:
367
+ variant_key = f"Shiny Rainbow {pet_name}"
368
+ elif is_shiny:
369
+ variant_key = f"Shiny {pet_name}"
370
+ elif pt_value == 1:
371
+ variant_key = f"Golden {pet_name}"
372
+ elif pt_value == 2:
373
+ variant_key = f"Rainbow {pet_name}"
374
+ else:
375
+ variant_key = f"Normal {pet_name}"
376
+
377
+ titanic_pet_counts[variant_key] = max(titanic_pet_counts[variant_key], value)
378
+
379
+ sorted_titanic_pets = sorted(titanic_pet_counts.items(), key=lambda x: x[1])
380
+
381
+ embed = discord.Embed(title=f"Top {count} Least Common Titanic Pets", color=discord.Color.dark_red())
382
+
383
+ if sorted_titanic_pets:
384
+ for i, (pet_name, count_value) in enumerate(sorted_titanic_pets[:count], 1):
385
+ embed.add_field(
386
+ name=f"{i}. {pet_name}",
387
+ value=f"Exists: **{format_number(count_value)}**",
388
+ inline=False
389
+ )
390
+ else:
391
+ embed.description = "No titanic pets found in the data."
392
+
393
+ await ctx.send(embed=embed)
394
+
395
+ def calculate_jelly_prediction(pet_name, current_value, hourly_rate):
396
+ if pet_name not in JELLY_LEAVE_TIMES:
397
+ return None
398
+
399
+ current_time = datetime.now(pytz.timezone('US/Eastern'))
400
+ leave_time = JELLY_LEAVE_TIMES[pet_name]
401
+
402
+ if current_time >= leave_time:
403
+ return None
404
+
405
+ time_diff = leave_time - current_time
406
+ hours_remaining = time_diff.total_seconds() / 3600
407
+ predicted_increase = hourly_rate * hours_remaining
408
+ predicted_final = current_value + predicted_increase
409
+
410
+ return {
411
+ 'predicted_value': int(predicted_final),
412
+ 'hours_remaining': round(hours_remaining, 1)
413
+ }
414
+
415
+ def calculate_time_until_limited(pet_name, current_value, hourly_rate):
416
+ if pet_name not in LIMITED_PETS or hourly_rate <= 0:
417
+ return None
418
+
419
+ limit = LIMITED_PETS[pet_name]
420
+ remaining = limit - current_value
421
+
422
+ if remaining <= 0:
423
+ return "Already Limited!"
424
+
425
+ hours = remaining / hourly_rate
426
+ if hours < 0:
427
+ return "Error calculating time"
428
+
429
+ days = hours // 24
430
+ remaining_hours = hours % 24
431
+
432
+ if days > 0:
433
+ return f"~{int(days)}d {int(remaining_hours)}h"
434
+ else:
435
+ return f"~{int(remaining_hours)}h"
436
+
437
+ async def send_rap_change_notification(channel, item_name, previous_rap, current_rap):
438
+ percent_change = ((current_rap - previous_rap) / previous_rap) * 100
439
+
440
+ if current_rap > previous_rap:
441
+ message = f"🚀 {item_name} RAP ROSE BY {percent_change:.2f}%!\n" + \
442
+ f"Previous RAP: {previous_rap:,}\n" + \
443
+ f"Current RAP: {current_rap:,}"
444
+ await channel.send(message)
445
+ else:
446
+ message = f"📉 {item_name} RAP DROPPED BY {abs(percent_change):.2f}%!\n" + \
447
+ f"Previous RAP: {previous_rap:,}\n" + \
448
+ f"Current RAP: {current_rap:,}"
449
+ await channel.send(message)
450
+
451
+ async def update_rap_values():
452
+ try:
453
+ response = requests.get(RAP_API)
454
+ if response.status_code == 200:
455
+ data = response.json()
456
+ if data['status'] == 'ok':
457
+ pet_raps.clear()
458
+
459
+ monitored_channel = bot.get_channel(MONITORED_ITEMS_CHANNEL_ID)
460
+ if monitored_channel:
461
+ for pet_data in data['data']:
462
+ config_data = pet_data['configData']
463
+ pet_id = config_data['id']
464
+ value = pet_data['value']
465
+ is_shiny = config_data.get('sh', False)
466
+
467
+ monitored_key = f"Shiny {pet_id}" if is_shiny else pet_id
468
+
469
+ if monitored_key in last_rap_values:
470
+ current_rap = value
471
+ previous_rap = last_rap_values[monitored_key]
472
+
473
+ if previous_rap is not None and current_rap != previous_rap:
474
+ await send_rap_change_notification(monitored_channel, monitored_key, previous_rap, current_rap)
475
+
476
+ last_rap_values[monitored_key] = current_rap
477
+
478
+ if is_shiny:
479
+ pet_raps[f"Shiny {pet_id}"] = value
480
+ else:
481
+ pet_raps[pet_id] = value
482
+
483
+ print(f"Updated RAP values for {len(data['data'])} pets and items")
484
+ except Exception as e:
485
+ print(f"Error fetching RAP values: {e}")
486
+
487
+ def calculate_hourly_rate(pet_name):
488
+ if pet_name not in pet_changes:
489
+ return 0
490
+
491
+ changes = pet_changes[pet_name]
492
+ if not changes:
493
+ return 0
494
+
495
+ current_time = datetime.now()
496
+ one_hour_ago = current_time - timedelta(hours=1)
497
+
498
+ recent_changes = [change for change in changes if change['timestamp'] > one_hour_ago]
499
+
500
+ if not recent_changes:
501
+ return 0
502
+
503
+ if len(recent_changes) >= 2:
504
+ earliest_value = recent_changes[0]['value']
505
+ latest_value = recent_changes[-1]['value']
506
+ return latest_value - earliest_value
507
+
508
+ return 1
509
+
510
+ async def get_huge_secret_pets():
511
+ try:
512
+ response = requests.get(PETS_API)
513
+ if response.status_code == 200:
514
+ data = response.json()
515
+ if data['status'] == 'ok':
516
+ huge_secret_pets = []
517
+
518
+ for pet in data['data']:
519
+ config_data = pet['configData']
520
+ if config_data.get('huge') or config_data.get('secret'):
521
+ pet_name = config_data['name']
522
+ huge_secret_pets.append(pet_name)
523
+ huge_secret_pets.append(f"Shiny {pet_name}")
524
+
525
+ difficulty = config_data.get('difficulty', 'Unknown')
526
+ pet_difficulties[pet_name] = difficulty
527
+ pet_difficulties[f"Shiny {pet_name}"] = difficulty * 100
528
+
529
+ if 'thumbnail' in config_data:
530
+ pet_images[pet_name] = config_data['thumbnail']
531
+ pet_images[f"Shiny {pet_name}"] = config_data['thumbnail']
532
+ print(f"Stored image URL for {pet_name}: {config_data['thumbnail']}")
533
+
534
+ for pet_name in huge_secret_pets:
535
+ if pet_name not in pet_changes:
536
+ pet_changes[pet_name] = deque(maxlen=100)
537
+
538
+ print(f"Found {len(huge_secret_pets)} pets to track (including shiny versions)")
539
+ return huge_secret_pets
540
+ except Exception as e:
541
+ print(f"Error fetching pets list: {e}")
542
+ return []
543
+
544
+ async def send_embed_message(channel, pet_name, previous_value, current_value, is_change=False):
545
+ notification_key = f"{pet_name}_{previous_value}_{current_value}"
546
+
547
+ if notification_key in recent_notifications.get(pet_name, []):
548
+ print(f"Skipping duplicate notification for {pet_name}")
549
+ return
550
+
551
+ if pet_name not in recent_notifications:
552
+ recent_notifications[pet_name] = []
553
+ recent_notifications[pet_name].append(notification_key)
554
+
555
+ pet_image_url = pet_images.get(pet_name, None)
556
+ difficulty = pet_difficulties.get(pet_name, "Unknown")
557
+ rap_value = pet_raps.get(pet_name, "No RAP")
558
+ hourly_rate = calculate_hourly_rate(pet_name)
559
+
560
+ difficulty_display = format_number(difficulty) if isinstance(difficulty, (int, float)) else difficulty
561
+ rap_display = format_number(rap_value) if isinstance(rap_value, (int, float)) else rap_value
562
+ current_display = f"{current_value:,}" if isinstance(current_value, (int, float)) else current_value
563
+ previous_display = format_number(previous_value) if isinstance(previous_value, (int, float)) else previous_value
564
+ hourly_rate_display = format_number(hourly_rate) if isinstance(hourly_rate, (int, float)) else hourly_rate
565
+
566
+ is_shiny = pet_name.startswith("Shiny ")
567
+ base_name = pet_name.replace("Shiny ", "") if is_shiny else pet_name
568
+
569
+ time_until_limited = None
570
+ if base_name in LIMITED_PETS:
571
+ time_until_limited = calculate_time_until_limited(base_name, current_value, hourly_rate)
572
+
573
+ jelly_prediction = None
574
+ if base_name in JELLY_LEAVE_TIMES:
575
+ jelly_prediction = calculate_jelly_prediction(base_name, current_value, hourly_rate)
576
+
577
+ value_change = current_value - previous_value if previous_value is not None else current_value
578
+
579
+ if is_shiny:
580
+ title = f"✨ {f'A **SHINY** {base_name} was' if value_change == 1 else f'{value_change} **SHINY** {base_name}s were'} rolled! ✨"
581
+ embed_color = discord.Color.from_rgb(255, 255, 255)
582
+ else:
583
+ title = f"🎲 {f'A {pet_name}' if value_change == 1 else f'{value_change} {pet_name}s'} were rolled! 🎲"
584
+ embed_color = discord.Color.blue() if not is_change else discord.Color.orange()
585
+
586
+ description = f"{pet_name} exists: **{current_display}**\n" \
587
+ f"Difficulty: **1 in {difficulty_display}**\n" \
588
+ f"RAP Value: **{rap_display}**\n" \
589
+ f"Hourly Rate: **{hourly_rate_display}/h**"
590
+
591
+ if time_until_limited is not None:
592
+ description += f"\nTime Remaining Until Limited: **{time_until_limited}**"
593
+
594
+ if base_name in LIMITED_PETS:
595
+ limit = LIMITED_PETS[base_name]
596
+ remaining = limit - current_value
597
+ if remaining > 0:
598
+ description += f"\nQuantity Remaining: **{remaining:,}**"
599
+
600
+ if jelly_prediction is not None:
601
+ description += f"\nEstimated Final Count: **{jelly_prediction['predicted_value']:,}**"
602
+ description += f"\nGoing Limited In: **{jelly_prediction['hours_remaining']}h**"
603
+
604
+ embed = discord.Embed(
605
+ title=title,
606
+ description=description,
607
+ color=embed_color
608
+ )
609
+
610
+ if pet_image_url:
611
+ if isinstance(pet_image_url, str):
612
+ if pet_image_url.startswith('rbxassetid://'):
613
+ asset_id = re.search(r'^\d+', pet_image_url.replace('rbxassetid://', '')).group(0)
614
+ pet_image_url = f"https://rbxgleaks.pythonanywhere.com/asset/{asset_id}"
615
+
616
+ print(f"Using image URL for {pet_name}: {pet_image_url}")
617
+ embed.set_thumbnail(url=pet_image_url)
618
+
619
+ try:
620
+ await channel.send(embed=embed)
621
+ except discord.HTTPException as e:
622
+ print(f"Failed to send embed for {pet_name}: {e}")
623
+ await channel.send(f"🎲 {'A' if value_change == 1 else value_change} {pet_name} was rolled! Exists: {current_display} (Previous: {previous_display})")
624
+
625
+ async def petdata(tracked_pets):
626
+ try:
627
+ response = requests.get(EXISTS_API)
628
+ if response.status_code == 200:
629
+ data = response.json()
630
+ if data['status'] == 'ok':
631
+ pet_values = {pet: 0 for pet in tracked_pets}
632
+
633
+ for pet in data['data']:
634
+ pet_id = pet['configData']['id']
635
+ is_shiny = pet['configData'].get('sh', False)
636
+ value = pet['value']
637
+
638
+ pet_name = f"Shiny {pet_id}" if is_shiny else pet_id
639
+ if pet_name in pet_values:
640
+ print(f"Found pet: {pet_name} with exist count {value}")
641
+ pet_values[pet_name] = value
642
+
643
+ return pet_values
644
+ print(f"Error code: {response.status_code}")
645
+ except Exception as e:
646
+ print(f"Error: {e}")
647
+ return None
648
+
649
+ async def main_loop():
650
+ channel = bot.get_channel(CHANNEL_ID)
651
+ if channel is None:
652
+ print("Invalid channel ID. Please check your channel ID.")
653
+ return
654
+
655
+ tracked_pets = await get_huge_secret_pets()
656
+ if not tracked_pets:
657
+ print("No pets fetched, retrying in 60 seconds...")
658
+ await asyncio.sleep(60)
659
+ return
660
+
661
+ lastknown = {pet: None for pet in tracked_pets}
662
+ print(f"Initially tracking {len(tracked_pets)} pets")
663
+
664
+ while True:
665
+ try:
666
+
667
+ if not tracked_pets:
668
+ tracked_pets = await get_huge_secret_pets() or []
669
+ lastknown.update({pet: None for pet in tracked_pets if pet not in lastknown})
670
+
671
+ await update_rap_values()
672
+
673
+ vvalues = await petdata(tracked_pets)
674
+ if vvalues is not None:
675
+ for pet, value in vvalues.items():
676
+ if lastknown[pet] is None:
677
+ print(f"Initial value for {pet}: {value}")
678
+ elif value != lastknown[pet]:
679
+ pet_changes[pet].append({
680
+ 'timestamp': datetime.now(),
681
+ 'value': value,
682
+ 'previous': lastknown[pet]
683
+ })
684
+ await send_embed_message(channel, pet, lastknown[pet], value, is_change=True)
685
+ lastknown[pet] = value
686
+ else:
687
+ print("Broken check")
688
+
689
+ new_pets = await get_huge_secret_pets() or []
690
+ if new_pets and set(new_pets) != set(tracked_pets):
691
+ print("Pet list updated!")
692
+ tracked_pets = new_pets
693
+ lastknown.update({pet: None for pet in tracked_pets if pet not in lastknown})
694
+
695
+ await asyncio.sleep(60)
696
+
697
+ except Exception as e:
698
+ print(f"Error in main loop: {e}")
699
+ await asyncio.sleep(60)
700
+
701
+ @bot.event
702
+ async def on_ready():
703
+ print(f'Logged in as {bot.user.name}')
704
+ bot.loop.create_task(main_loop())
705
+ bot.run(TOKEN)