Files
1-800/checker/commands.py
T
2026-06-28 11:30:57 -05:00

2002 lines
88 KiB
Python

import os
from PIL import Image, ImageDraw, ImageFont, ImageOps
import json
import user
import colorsys
import logging
import math
import urllib.request
from datetime import datetime
from io import BytesIO
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
from utils import mask_email, mask_account_id, bool_to_emoji, country_to_flag
from user import RiftUser
from cosmetic import FortniteCosmetic
from epic_auth import EpicUser, EpicEndpoints, EpicGenerator, LockerData
def escape_markdown(text):
"""
Escapes special characters for markdown formatting
@note: sometimes external connections shows error due to these, so we handle it that way
"""
escape_chars = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!']
for char in escape_chars:
text = text.replace(char, f"\\{char}")
return text
class FortniteCache:
def __init__(self):
self.cache = {}
self.cache_dir = "cache"
if not os.path.exists(self.cache_dir):
os.makedirs(self.cache_dir)
self.load_cache_from_directory()
def load_cache_from_directory(self):
for filename in os.listdir(self.cache_dir):
if filename.endswith(".png"):
id = os.path.splitext(filename)[0]
file_path = os.path.join(self.cache_dir, filename)
try:
image = Image.open(file_path).convert('RGBA')
self.cache[id] = image
except Exception as e:
continue
def get_cosmetic_icon_from_cache(self, url, id):
if not url:
print(f"Error: No URL provided for ID: {id}")
return None
cache_path = os.path.join(self.cache_dir, f"{id}.png")
if id in self.cache:
return self.cache[id]
if os.path.exists(cache_path):
# getting the icon from filesystem
try:
image = Image.open(cache_path).convert('RGBA')
self.cache[id] = image
return image
except Exception as e:
print(f"Error loading {cache_path}: {e}")
try:
# downloading the icon from url
with urllib.request.urlopen(url) as response:
image_data = response.read()
image = Image.open(BytesIO(image_data)).convert('RGBA')
try:
image.save(cache_path)
except Exception as e:
print(f"Error saving {cache_path}: {e}")
self.cache[id] = image
return image
except Exception as e:
print(f"Error downloading image from {url}: {e}")
return None
# global members
fortnite_cache = FortniteCache()
available_styles = [
{"ID": 0, "name": "Rift", "image": "img/styles/rift.png"},
{"ID": 1, "name": "Easy", "image": "img/styles/easy.png"},
{"ID": 2, "name": "Raika", "image": "img/styles/raika.png"},
{"ID": 3, "name": "kayy", "image": "img/styles/kayy.png"},
{"ID": 4, "name": "Storm", "image": "img/styles/storm.png"}
]
avaliable_badges = [
{"name": "Alpha Tester 1", "data": "alpha_tester_1_badge", "data2": "alpha_tester_1_badge_active", "image": "badges/icon/alpha1.png"},
{"name": "Alpha Tester 2", "data": "alpha_tester_2_badge", "data2": "alpha_tester_2_badge_active", "image": "badges/icon/alpha2.png"},
{"name": "Alpha Tester 3", "data": "alpha_tester_3_badge", "data2": "alpha_tester_3_badge_active", "image": "badges/icon/alpha3.png"},
{"name": "Epic Games", "data": "epic_badge", "data2": "epic_badge_active", "image": "badges/icon/epic.png"}
]
locker_categories = ['AthenaCharacter', 'AthenaBackpack', 'AthenaPickaxe', 'AthenaDance', 'AthenaGlider', 'AthenaPopular', 'AthenaExclusive']
# global members
def draw_gradient_text(gradient_type, draw, position, text, font, fill=(255, 255, 255)):
"""
Draw text with a rainbow gradient at a given position.
:param gradient_type: The gradient we use to render the text as.
:param draw: ImageDraw object to draw on.
:param position: Tuple (x, y) of the position where the text starts.
:param text: Text to draw.
:param font: Font object to use for the text.
:param fill: the color in RGB in base to draw
"""
num_colors = len(text)
if gradient_type == 0:
# white text(no gradient)
gradient_colors = [(255, 255, 255)] * num_colors
elif gradient_type == 1:
# rainbow gradient
gradient_colors = [
tuple(int(c * 255) for c in colorsys.hsv_to_rgb(i / num_colors, 1, 1))
for i in range(num_colors)
]
elif gradient_type == 2:
# golden gradient
gradient_colors = [
tuple(int(c * 255) for c in colorsys.hsv_to_rgb(0.13, 0.5 + (i / num_colors) * 0.5, 0.8 + (i / num_colors) * 0.2))
for i in range(num_colors)
]
elif gradient_type == 3:
# silver gradient
gradient_colors = [
tuple(int(c * 255) for c in colorsys.hsv_to_rgb(0, 0 + (i / num_colors) * 0.2, 0.6 + (i / num_colors) * 0.4))
for i in range(num_colors)
]
x, y = position
for i, char in enumerate(text):
color = gradient_colors[i]
char_width = font.getbbox(char)[2]
draw.text((x, y), char, font=font, fill=color)
x += char_width
def render_rift_style(header:str, user_data: json, arr: list[str], nametosave:str) -> None:
# calculating cosmetics per row
cosmetic_per_row = 6
total_cosmetics = len(arr)
num_rows = math.ceil(total_cosmetics / cosmetic_per_row)
if total_cosmetics > 30:
num_rows = int(math.sqrt(total_cosmetics))
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
while cosmetic_per_row * num_rows < total_cosmetics:
num_rows += 1
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
# setup for our image, thumbnails
padding = 30
thumbnail_width = 128
thumbnail_height = 128
image_width = int(cosmetic_per_row * thumbnail_width)
image_height = int(thumbnail_height + 5 + thumbnail_width * num_rows + 180)
font_path = 'styles/rift/font.ttf'
font_size = 16
font = ImageFont.truetype(font_path, font_size)
image = Image.new('RGB', (image_width, image_height), (0, 0, 0))
# custom background
custom_background_path = f"users/backgrounds/{user_data['ID']}.png"
if os.path.isfile(custom_background_path):
custom_background = Image.open(custom_background_path).resize((image_width, image_height), Image.Resampling.BILINEAR)
image.paste(custom_background, (0, 0))
current_row = 0
current_column = 0
sortarray = ['mythic', 'legendary', 'dark', 'slurp', 'starwars', 'marvel', 'lava', 'frozen', 'gaminglegends', 'shadow', 'icon', 'dc', 'epic', 'rare', 'uncommon', 'common']
arr.sort(key=lambda x: sortarray.index(x.rarity_value))
# had some issues with exclusives rendering in wrong order, so i'm sorting them
try:
with open('exclusive.txt', 'r', encoding='utf-8') as f:
exclusive_cosmetics = [i.strip() for i in f.readlines()]
with open('most_wanted.txt', 'r', encoding='utf-8') as f:
popular_cosmetics = [i.strip() for i in f.readlines()]
except FileNotFoundError:
print("Error: 'exclusive.txt' or 'most_wanted.txt' not found.")
exclusive_cosmetics = []
popular_cosmetics = []
mythic_items = [item for item in arr if item.rarity_value == 'mythic']
other_items = [item for item in arr if item.rarity_value != 'mythic']
mythic_items.sort(
key=lambda x: exclusive_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in exclusive_cosmetics else float('inf')
)
if header == "Popular":
other_items.sort(
key=lambda x: popular_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in popular_cosmetics else float('inf')
)
arr = mythic_items + other_items
draw = ImageDraw.Draw(image)
# top
icon_logo = Image.open(f'cosmetic_icons/{header}.png')
icon_logo.thumbnail((thumbnail_width, thumbnail_height))
image.paste(icon_logo, (5, 0), mask=icon_logo)
draw.text((thumbnail_width + 12, 14), '{}'.format(len(arr)), font=ImageFont.truetype(font_path, 70), fill=(0, 0, 0)) # shadow
draw.text((thumbnail_width + 12, 82), '{}'.format(header), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((thumbnail_width + 8, 10), '{}'.format(len(arr)), font=ImageFont.truetype(font_path, 70), fill=(255, 255, 255))
draw.text((thumbnail_width + 8, 78), '{}'.format(header), font=ImageFont.truetype(font_path, 40), fill=(200, 200, 200))
special_items = {
"CID_029_Athena_Commando_F_Halloween": "cache/pink_ghoul.png",
"CID_030_Athena_Commando_M_Halloween": "cache/purple_skull.png",
"CID_116_Athena_Commando_M_CarbideBlack": "cache/omega_max.png",
"CID_694_Athena_Commando_M_CatBurglar": "cache/gold_midas.png",
"CID_693_Athena_Commando_M_BuffCat": "cache/gold_cat.png",
"CID_691_Athena_Commando_F_TNTina": "cache/gold_tntina.png",
"CID_690_Athena_Commando_F_Photographer": "cache/gold_skye.png",
"CID_701_Athena_Commando_M_BananaAgent": "cache/gold_peely.png",
"CID_315_Athena_Commando_M_TeriyakiFish": "cache/worldcup_fish.png",
"CID_971_Athena_Commando_M_Jupiter_S0Z6M": "cache/black_masterchief.png",
"CID_028_Athena_Commando_F": "cache/og_rene.png",
"CID_017_Athena_Commando_M": "cache/og_aat.png"
}
for cosmetic in arr:
special_icon = False
is_banner = cosmetic.is_banner
photo = None
if cosmetic.rarity_value.lower() == "mythic" and cosmetic.cosmetic_id in special_items:
special_icon = True
icon_path = special_items[cosmetic.cosmetic_id]
if os.path.exists(icon_path):
try:
photo = Image.open(icon_path)
except Exception as e:
special_icon = False
else:
special_icon = False
else:
photo = fortnite_cache.get_cosmetic_icon_from_cache(cosmetic.small_icon, cosmetic.cosmetic_id)
if is_banner:
scaled_width = int(photo.width * 1.5)
scaled_height = int(photo.height * 1.5)
photo = photo.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
x_offset = 32
y_offset = 10
new_img = Image.open(f'styles/rift/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA')
new_img.paste(photo, (x_offset, y_offset), mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
else:
new_img = Image.open(f'styles/rift/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA').resize(photo.size)
new_img.paste(photo, mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
# black box for cosmetic name
box = Image.new('RGBA', (128, 28), (0, 0, 0, 100))
photo.paste(box, (0, new_img.size[1] - 28), mask=box)
if header != "Exclusives" and cosmetic.cosmetic_id in popular_cosmetics:
star_image = Image.open('cosmetic_icons/WantedStar.png').resize((128, 128), Image.BILINEAR)
photo.paste(star_image, (0, 0), star_image.convert("RGBA"))
x = thumbnail_width * current_column
y = thumbnail_width + thumbnail_height * current_row
image.paste(photo, (x, y))
name = cosmetic.name.upper()
max_text_width = thumbnail_width - 10
max_text_height = 20
# fixed font size
font_size = 16
offset = 9
while True:
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
name_height = bbox[3] - bbox[1]
if name_width > max_text_width or name_height > max_text_height:
font_size -= 1
offset += 0.5
else:
break
# cosmetic name
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
draw.text((x + (thumbnail_width - name_width) // 2, y + (thumbnail_height - padding + offset)), name, font=font, fill=(255, 255, 255))
# make the cosmetics show ordered in rows(cosmetic_per_row is hardcoded)
current_column += 1
if current_column >= cosmetic_per_row:
current_row += 1
current_column = 0
# footer
current_date = datetime.now().strftime('%B %d, %Y')
# custom logo
custom_logo_path = f"users/logos/{user_data['ID']}.png"
if os.path.isfile(custom_logo_path):
custom_logo = Image.open(custom_logo_path).resize((150, 150), Image.Resampling.BILINEAR)
image.paste(custom_logo, (10, image_height - 165), mask=custom_logo)
else:
# original logo if not found
logo = Image.open('img/logo.png').resize((150, 150), Image.Resampling.BILINEAR)
image.paste(logo, (10, image_height - 165), mask=logo)
draw.text((174, image_height - 40 * 3 - 24), '{}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((170, image_height - 40 * 3 - 28), '{}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
draw.text((174, image_height - 40 * 2 - 24), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw_gradient_text(user_data['gradient_type'], draw, (170, image_height - 40 * 2 - 28), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40))
# badges
font_size = 40
font = ImageFont.truetype(font_path, font_size)
username_width = font.getbbox(f"@{user_data['username']}")[2]
offset_badge = 170 + username_width + 8
if user_data['epic_badge_active'] == True and user_data['epic_badge'] == True:
# epic games badge(special people only)
alpha_badge = Image.open('badges/epic.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_3_badge_active'] == True and user_data['alpha_tester_3_badge'] == True:
# alpha tester 3 badge
alpha_badge = Image.open('badges/alpha3.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_2_badge_active'] == True and user_data['alpha_tester_2_badge'] == True:
# alpha tester 2 badge
alpha_badge = Image.open('badges/alpha2.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_1_badge_active'] == True and user_data['alpha_tester_1_badge'] == True:
# alpha tester 1 badge
alpha_badge = Image.open('badges/alpha1.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
draw.text((174, image_height - 61), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((170, image_height - 65), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
image.save(nametosave)
def render_easy_style(header:str, user_data: json, arr: list[str], nametosave:str) -> None:
# calculating cosmetics per row
cosmetic_per_row = 6
total_cosmetics = len(arr)
num_rows = math.ceil(total_cosmetics / cosmetic_per_row)
if total_cosmetics > 30:
num_rows = int(math.sqrt(total_cosmetics))
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
while cosmetic_per_row * num_rows < total_cosmetics:
num_rows += 1
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
# setup for our image, thumbnails
padding_height = 10
padding_width = 50
thumbnail_width = 128
thumbnail_height = 128
image_width = int(cosmetic_per_row * thumbnail_width + padding_width * 2)
image_height = int(padding_width + (padding_height + thumbnail_width) * num_rows + padding_width * 2)
font_path = 'styles/easy/font.ttf'
font_size = 16
font = ImageFont.truetype(font_path, font_size)
image = Image.new('RGB', (image_width, image_height), (58, 58, 58))
current_row = 0
current_column = 0
sortarray = ['mythic', 'legendary', 'dark', 'slurp', 'starwars', 'marvel', 'lava', 'frozen', 'gaminglegends', 'shadow', 'icon', 'dc', 'epic', 'rare', 'uncommon', 'common']
arr.sort(key=lambda x: sortarray.index(x.rarity_value))
# had some issues with exclusives rendering in wrong order, so i'm sorting them
try:
with open('exclusive.txt', 'r', encoding='utf-8') as f:
exclusive_cosmetics = [i.strip() for i in f.readlines()]
with open('most_wanted.txt', 'r', encoding='utf-8') as f:
popular_cosmetics = [i.strip() for i in f.readlines()]
except FileNotFoundError:
print("Error: 'exclusive.txt' or 'most_wanted.txt' not found.")
exclusive_cosmetics = []
popular_cosmetics = []
mythic_items = [item for item in arr if item.rarity_value == 'mythic']
other_items = [item for item in arr if item.rarity_value != 'mythic']
mythic_items.sort(
key=lambda x: exclusive_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in exclusive_cosmetics else float('inf')
)
if header == "Popular":
other_items.sort(
key=lambda x: popular_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in popular_cosmetics else float('inf')
)
arr = mythic_items + other_items
draw = ImageDraw.Draw(image)
# cosmetics count
cosmetics = '{} count: {}'.format(header, len(arr))
max_text_width = image_width - 20
max_text_height = 40
min_font_size = 10
font_size = 40
while True:
bbox = draw.textbbox((0, 0), cosmetics, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
if text_width > max_text_width or font_size > image_height - 2:
font_size -= 1
if font_size < min_font_size:
font_size = min_font_size
break
font = ImageFont.truetype(font_path, font_size)
else:
break
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), cosmetics, font=font)
text_width = bbox[2] - bbox[0]
text_x = (image_width - text_width) // 2
draw.text((text_x, 9), cosmetics, font=font, fill=(255, 255, 255))
special_items = {
"CID_029_Athena_Commando_F_Halloween": "cache/pink_ghoul.png",
"CID_030_Athena_Commando_M_Halloween": "cache/purple_skull_old.png",
"CID_116_Athena_Commando_M_CarbideBlack": "cache/omega_max.png",
"CID_694_Athena_Commando_M_CatBurglar": "cache/gold_midas.png",
"CID_693_Athena_Commando_M_BuffCat": "cache/gold_cat.png",
"CID_691_Athena_Commando_F_TNTina": "cache/gold_tntina.png",
"CID_690_Athena_Commando_F_Photographer": "cache/gold_skye.png",
"CID_701_Athena_Commando_M_BananaAgent": "cache/gold_peely.png",
"CID_315_Athena_Commando_M_TeriyakiFish": "cache/worldcup_fish.png",
"CID_971_Athena_Commando_M_Jupiter_S0Z6M": "cache/black_masterchief.png",
"CID_028_Athena_Commando_F": "cache/og_rene.png",
"CID_017_Athena_Commando_M": "cache/og_aat.png"
}
for cosmetic in arr:
special_icon = False
is_banner = cosmetic.is_banner
photo = None
if cosmetic.rarity_value.lower() == "mythic" and cosmetic.cosmetic_id in special_items:
special_icon = True
icon_path = special_items[cosmetic.cosmetic_id]
if os.path.exists(icon_path):
try:
photo = Image.open(icon_path)
except Exception as e:
special_icon = False
else:
special_icon = False
else:
photo = fortnite_cache.get_cosmetic_icon_from_cache(cosmetic.small_icon, cosmetic.cosmetic_id)
if is_banner:
scaled_width = int(photo.width * 1.5)
scaled_height = int(photo.height * 1.5)
photo = photo.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
x_offset = 32
y_offset = 10
new_img = Image.open(f'styles/easy/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA')
new_img.paste(photo, (x_offset, y_offset), mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
else:
new_img = Image.open(f'styles/easy/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA').resize(photo.size)
new_img.paste(photo, mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
# black box for cosmetic name
box = Image.new('RGBA', (128, 20), (0, 0, 0, 75))
photo.paste(box, (0, new_img.size[1] - 40), mask=box)
border = Image.open(f'styles/easy/border/{cosmetic.rarity_value.lower()}.png').convert('RGBA').resize(photo.size)
photo.paste(border, mask=border)
x = padding_width + thumbnail_width * current_column
y = padding_width + (thumbnail_height + padding_height) * current_row
image.paste(photo, (x, y))
name = cosmetic.name
max_text_width = thumbnail_width - 10
max_text_height = 20
offset_y = 38
font_size = 18
while True:
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
name_height = bbox[3] - bbox[1]
if name_width > max_text_width or name_height > max_text_height:
font_size -= 1
offset_y -= 0.5
else:
break
# cosmetic name
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
draw.text((x + (thumbnail_width - name_width) // 2, y + (thumbnail_height - offset_y)), name, font=font, fill=(255, 255, 255))
# make the cosmetics show ordered in rows(cosmetic_per_row is hardcoded)
current_column += 1
if current_column >= cosmetic_per_row:
current_row += 1
current_column = 0
# footer
current_date = datetime.now().strftime('%d/%m/%Y')
footer = 'Submitted by @{} on {}'.format(user_data['username'], current_date)
max_text_width = image_width - 20
max_text_height = 40
min_font_size = 15
font_size = 40
while True:
bbox = draw.textbbox((0, 0), footer, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
if text_width > max_text_width or font_size > image_height - 2:
font_size -= 1
if font_size < min_font_size:
font_size = min_font_size
break
font = ImageFont.truetype(font_path, font_size)
else:
break
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), footer, font=font)
text_width = bbox[2] - bbox[0]
text_x = (image_width - text_width) // 2
text_y = image_height - font_size - 52
draw.text((text_x, text_y), footer, font=font, fill=(255, 255, 255))
# bot advertisment
footer2 = 't.me/RiftCheckerBot'
max_text_width = image_width - 20
max_text_height = 40
min_font_size = 15
font_size = 40
while True:
bbox = draw.textbbox((0, 0), footer2, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
if text_width > max_text_width or font_size > image_height - 2:
font_size -= 1
if font_size < min_font_size:
font_size = min_font_size
break
font = ImageFont.truetype(font_path, font_size)
else:
break
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), footer2, font=font)
text_width = bbox[2] - bbox[0]
text_x = (image_width - text_width) // 2
text_y = image_height - font_size - 8
draw.text((text_x, text_y), footer2, font=font, fill=(255, 255, 255))
image.save(nametosave)
def render_raika_style(header:str, user_data: json, arr: list[str], nametosave:str) -> None:
# calculating cosmetics per row
cosmetic_per_row = 6
total_cosmetics = len(arr)
num_rows = math.ceil(total_cosmetics / cosmetic_per_row)
if total_cosmetics > 30:
num_rows = int(math.sqrt(total_cosmetics))
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
while cosmetic_per_row * num_rows < total_cosmetics:
num_rows += 1
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
# setup for our image, thumbnails
padding = 30
thumbnail_width = 128
thumbnail_height = 128
image_width = int(cosmetic_per_row * thumbnail_width)
image_height = int(thumbnail_height + 5 + thumbnail_width * num_rows + 180)
font_path = 'styles/raika/font.ttf'
font_size = 16
font = ImageFont.truetype(font_path, font_size)
image = Image.new('RGB', (image_width, image_height), (0, 0, 0))
# custom background
custom_background_path = f"users/backgrounds/{user_data['ID']}.png"
if os.path.isfile(custom_background_path):
custom_background = Image.open(custom_background_path).resize((image_width, image_height), Image.Resampling.BILINEAR)
image.paste(custom_background, (0, 0))
current_row = 0
current_column = 0
sortarray = ['mythic', 'legendary', 'dark', 'slurp', 'starwars', 'marvel', 'lava', 'frozen', 'gaminglegends', 'shadow', 'icon', 'dc', 'epic', 'rare', 'uncommon', 'common']
arr.sort(key=lambda x: sortarray.index(x.rarity_value))
# had some issues with exclusives rendering in wrong order, so i'm sorting them
try:
with open('exclusive.txt', 'r', encoding='utf-8') as f:
exclusive_cosmetics = [i.strip() for i in f.readlines()]
with open('most_wanted.txt', 'r', encoding='utf-8') as f:
popular_cosmetics = [i.strip() for i in f.readlines()]
except FileNotFoundError:
print("Error: 'exclusive.txt' or 'most_wanted.txt' not found.")
exclusive_cosmetics = []
popular_cosmetics = []
mythic_items = [item for item in arr if item.rarity_value == 'mythic']
other_items = [item for item in arr if item.rarity_value != 'mythic']
mythic_items.sort(
key=lambda x: exclusive_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in exclusive_cosmetics else float('inf')
)
if header == "Popular":
other_items.sort(
key=lambda x: popular_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in popular_cosmetics else float('inf')
)
arr = mythic_items + other_items
draw = ImageDraw.Draw(image)
# top
icon_logo = Image.open(f'cosmetic_icons/{header}.png')
icon_logo.thumbnail((thumbnail_width, thumbnail_height))
image.paste(icon_logo, (5, 0), mask=icon_logo)
draw.text((thumbnail_width + 12, 14), '{}'.format(len(arr)), font=ImageFont.truetype(font_path, 70), fill=(0, 0, 0)) # shadow
draw.text((thumbnail_width + 12, 82), '{}'.format(header), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((thumbnail_width + 8, 10), '{}'.format(len(arr)), font=ImageFont.truetype(font_path, 70), fill=(255, 255, 255))
draw.text((thumbnail_width + 8, 78), '{}'.format(header), font=ImageFont.truetype(font_path, 40), fill=(200, 200, 200))
special_items = {
"CID_029_Athena_Commando_F_Halloween": "cache/pink_ghoul.png",
"CID_030_Athena_Commando_M_Halloween": "cache/purple_skull_old.png",
"CID_116_Athena_Commando_M_CarbideBlack": "cache/omega_max.png",
"CID_694_Athena_Commando_M_CatBurglar": "cache/gold_midas.png",
"CID_693_Athena_Commando_M_BuffCat": "cache/gold_cat.png",
"CID_691_Athena_Commando_F_TNTina": "cache/gold_tntina.png",
"CID_690_Athena_Commando_F_Photographer": "cache/gold_skye.png",
"CID_701_Athena_Commando_M_BananaAgent": "cache/gold_peely.png",
"CID_315_Athena_Commando_M_TeriyakiFish": "cache/worldcup_fish.png",
"CID_971_Athena_Commando_M_Jupiter_S0Z6M": "cache/black_masterchief.png",
"CID_028_Athena_Commando_F": "cache/og_rene.png",
"CID_017_Athena_Commando_M": "cache/og_aat.png"
}
for cosmetic in arr:
special_icon = False
is_banner = cosmetic.is_banner
photo = None
if cosmetic.rarity_value.lower() == "mythic" and cosmetic.cosmetic_id in special_items:
special_icon = True
icon_path = special_items[cosmetic.cosmetic_id]
if os.path.exists(icon_path):
try:
photo = Image.open(icon_path)
except Exception as e:
special_icon = False
else:
special_icon = False
else:
photo = fortnite_cache.get_cosmetic_icon_from_cache(cosmetic.small_icon, cosmetic.cosmetic_id)
if is_banner:
scaled_width = int(photo.width * 1.5)
scaled_height = int(photo.height * 1.5)
photo = photo.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
x_offset = 32
y_offset = 10
new_img = Image.open(f'styles/raika/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA')
new_img.paste(photo, (x_offset, y_offset), mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
else:
new_img = Image.open(f'styles/raika/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA').resize(photo.size)
new_img.paste(photo, mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
# black box for cosmetic name
box = Image.new('RGBA', (128, 28), (0, 0, 0, 100))
photo.paste(box, (0, new_img.size[1] - 28), mask=box)
if header != "Exclusives" and cosmetic.cosmetic_id in popular_cosmetics:
star_image = Image.open('cosmetic_icons/WantedStar.png').resize((128, 128), Image.BILINEAR)
photo.paste(star_image, (0, 0), star_image.convert("RGBA"))
x = thumbnail_width * current_column
y = thumbnail_width + thumbnail_height * current_row
image.paste(photo, (x, y))
name = cosmetic.name.upper()
max_text_width = thumbnail_width - 10
max_text_height = 20
# fixed font size
font_size = 16
offset = 6
while True:
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
name_height = bbox[3] - bbox[1]
if name_width > max_text_width or name_height > max_text_height:
font_size -= 1
offset += 0.5
else:
break
# cosmetic name
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
draw.text((x + (thumbnail_width - name_width) // 2, y + (thumbnail_height - padding + offset)), name, font=font, fill=(255, 255, 255))
# make the cosmetics show ordered in rows(cosmetic_per_row is hardcoded)
current_column += 1
if current_column >= cosmetic_per_row:
current_row += 1
current_column = 0
# footer
current_date = datetime.now().strftime('%B %d, %Y')
# custom logo
custom_logo_path = f"users/logos/{user_data['ID']}.png"
if os.path.isfile(custom_logo_path):
custom_logo = Image.open(custom_logo_path).resize((150, 150), Image.Resampling.BILINEAR)
image.paste(custom_logo, (10, image_height - 165), mask=custom_logo)
else:
# original logo if not found
logo = Image.open('img/logo.png').resize((150, 150), Image.Resampling.BILINEAR)
image.paste(logo, (10, image_height - 165), mask=logo)
draw.text((174, image_height - 40 * 3 - 24), '{}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((170, image_height - 40 * 3 - 28), '{}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
draw.text((174, image_height - 40 * 2 - 24), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw_gradient_text(user_data['gradient_type'], draw, (170, image_height - 40 * 2 - 28), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40))
# badges
font_size = 40
font = ImageFont.truetype(font_path, font_size)
username_width = font.getbbox(f"@{user_data['username']}")[2]
offset_badge = 170 + username_width + 8
if user_data['epic_badge_active'] == True and user_data['epic_badge'] == True:
# epic games badge(special people only)
alpha_badge = Image.open('badges/epic.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_3_badge_active'] == True and user_data['alpha_tester_3_badge'] == True:
# alpha tester 3 badge
alpha_badge = Image.open('badges/alpha3.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_2_badge_active'] == True and user_data['alpha_tester_2_badge'] == True:
# alpha tester 2 badge
alpha_badge = Image.open('badges/alpha2.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_1_badge_active'] == True and user_data['alpha_tester_1_badge'] == True:
# alpha tester 1 badge
alpha_badge = Image.open('badges/alpha1.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
draw.text((174, image_height - 61), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((170, image_height - 65), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
image.save(nametosave)
def render_kayy_style(header:str, user_data: json, arr: list[str], nametosave:str) -> None:
# calculating cosmetics per row
cosmetic_per_row = 6
total_cosmetics = len(arr)
num_rows = math.ceil(total_cosmetics / cosmetic_per_row)
if total_cosmetics > 30:
num_rows = int(math.sqrt(total_cosmetics))
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
while cosmetic_per_row * num_rows < total_cosmetics:
num_rows += 1
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
# setup for our image, thumbnails
padding = 30
thumbnail_width = 128
thumbnail_height = 128
image_width = int(cosmetic_per_row * thumbnail_width)
image_height = int(thumbnail_width * num_rows + 180)
font_path = 'styles/kayy/font.ttf'
font_size = 16
font = ImageFont.truetype(font_path, font_size)
image = Image.new('RGB', (image_width, image_height), (0, 0, 0))
# custom background
custom_background_path = f"users/backgrounds/{user_data['ID']}.png"
if os.path.isfile(custom_background_path):
custom_background = Image.open(custom_background_path).resize((image_width, image_height), Image.Resampling.BILINEAR)
image.paste(custom_background, (0, 0))
current_row = 0
current_column = 0
sortarray = ['mythic', 'legendary', 'dark', 'slurp', 'starwars', 'marvel', 'lava', 'frozen', 'gaminglegends', 'shadow', 'icon', 'dc', 'epic', 'rare', 'uncommon', 'common']
arr.sort(key=lambda x: sortarray.index(x.rarity_value))
# had some issues with exclusives rendering in wrong order, so i'm sorting them
try:
with open('exclusive.txt', 'r', encoding='utf-8') as f:
exclusive_cosmetics = [i.strip() for i in f.readlines()]
with open('most_wanted.txt', 'r', encoding='utf-8') as f:
popular_cosmetics = [i.strip() for i in f.readlines()]
except FileNotFoundError:
print("Error: 'exclusive.txt' or 'most_wanted.txt' not found.")
exclusive_cosmetics = []
popular_cosmetics = []
mythic_items = [item for item in arr if item.rarity_value == 'mythic']
other_items = [item for item in arr if item.rarity_value != 'mythic']
mythic_items.sort(
key=lambda x: exclusive_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in exclusive_cosmetics else float('inf')
)
if header == "Popular":
other_items.sort(
key=lambda x: popular_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in popular_cosmetics else float('inf')
)
arr = mythic_items + other_items
draw = ImageDraw.Draw(image)
special_items = {
"CID_029_Athena_Commando_F_Halloween": "cache/pink_ghoul.png",
"CID_030_Athena_Commando_M_Halloween": "cache/purple_skull_old.png",
"CID_116_Athena_Commando_M_CarbideBlack": "cache/omega_max.png",
"CID_694_Athena_Commando_M_CatBurglar": "cache/gold_midas.png",
"CID_693_Athena_Commando_M_BuffCat": "cache/gold_cat.png",
"CID_691_Athena_Commando_F_TNTina": "cache/gold_tntina.png",
"CID_690_Athena_Commando_F_Photographer": "cache/gold_skye.png",
"CID_701_Athena_Commando_M_BananaAgent": "cache/gold_peely.png",
"CID_315_Athena_Commando_M_TeriyakiFish": "cache/worldcup_fish.png",
"CID_971_Athena_Commando_M_Jupiter_S0Z6M": "cache/black_masterchief.png",
"CID_028_Athena_Commando_F": "cache/og_rene.png",
"CID_017_Athena_Commando_M": "cache/og_aat.png"
}
for cosmetic in arr:
special_icon = False
is_banner = cosmetic.is_banner
photo = None
if cosmetic.rarity_value.lower() == "mythic" and cosmetic.cosmetic_id in special_items:
special_icon = True
icon_path = special_items[cosmetic.cosmetic_id]
if os.path.exists(icon_path):
try:
photo = Image.open(icon_path)
except Exception as e:
special_icon = False
else:
special_icon = False
else:
photo = fortnite_cache.get_cosmetic_icon_from_cache(cosmetic.small_icon, cosmetic.cosmetic_id)
if is_banner:
scaled_width = int(photo.width * 1.5)
scaled_height = int(photo.height * 1.5)
photo = photo.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
x_offset = 32
y_offset = 10
new_img = Image.open(f'styles/kayy/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA')
new_img.paste(photo, (x_offset, y_offset), mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
else:
new_img = Image.open(f'styles/kayy/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA').resize(photo.size)
new_img.paste(photo, mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
# black box for cosmetic name
box = Image.new('RGBA', (128, 28), (0, 0, 0, 100))
photo.paste(box, (0, new_img.size[1] - 28), mask=box)
if header != "Exclusives" and cosmetic.cosmetic_id in popular_cosmetics:
star_image = Image.open('cosmetic_icons/WantedStar.png').resize((128, 128), Image.BILINEAR)
photo.paste(star_image, (0, 0), star_image.convert("RGBA"))
x = thumbnail_width * current_column
y = thumbnail_height * current_row
image.paste(photo, (x, y))
name = cosmetic.name.upper()
max_text_width = thumbnail_width - 10
max_text_height = 20
# fixed font size
font_size = 16
offset = 9
while True:
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
name_height = bbox[3] - bbox[1]
if name_width > max_text_width or name_height > max_text_height:
font_size -= 1
offset += 0.5
else:
break
# cosmetic name
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
draw.text((x + (thumbnail_width - name_width) // 2, y + (thumbnail_height - padding + offset)), name, font=font, fill=(255, 255, 255))
# make the cosmetics show ordered in rows(cosmetic_per_row is hardcoded)
current_column += 1
if current_column >= cosmetic_per_row:
current_row += 1
current_column = 0
# footer
current_date = datetime.now().strftime('%d/%m/%Y')
# custom logo
custom_logo_path = f"users/logos/{user_data['ID']}.png"
if os.path.isfile(custom_logo_path):
custom_logo = Image.open(custom_logo_path).resize((150, 150), Image.Resampling.BILINEAR)
image.paste(custom_logo, (10, image_height - 165), mask=custom_logo)
else:
# original logo if not found
logo = Image.open('img/logo.png').resize((150, 150), Image.Resampling.BILINEAR)
image.paste(logo, (10, image_height - 165), mask=logo)
draw.text((174, image_height - 40 * 3 - 24), 'Objects Total: {}'.format(len(arr)), font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255)) # shadow
draw.text((170, image_height - 40 * 3 - 28), 'Objects Total: {}'.format(len(arr)), font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
draw.text((174, image_height - 40 * 2 - 24), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255)) # shadow
draw_gradient_text(user_data['gradient_type'], draw, (170, image_height - 40 * 2 - 28), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40))
# badges
font_size = 40
font = ImageFont.truetype(font_path, font_size)
username_width = font.getbbox(f"@{user_data['username']}")[2]
offset_badge = 170 + username_width + 8
if user_data['epic_badge_active'] == True and user_data['epic_badge'] == True:
# epic games badge(special people only)
alpha_badge = Image.open('badges/epic.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_3_badge_active'] == True and user_data['alpha_tester_3_badge'] == True:
# alpha tester 3 badge
alpha_badge = Image.open('badges/alpha3.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_2_badge_active'] == True and user_data['alpha_tester_2_badge'] == True:
# alpha tester 2 badge
alpha_badge = Image.open('badges/alpha2.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_1_badge_active'] == True and user_data['alpha_tester_1_badge'] == True:
# alpha tester 1 badge
alpha_badge = Image.open('badges/alpha1.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
draw.text((offset_badge + 10, image_height - 40 * 2 - 26), '| {}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((offset_badge + 8, image_height - 40 * 2 - 28), '| {}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
draw.text((174, image_height - 61), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((170, image_height - 65), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
image.save(nametosave)
def render_storm_style(header:str, user_data: json, arr: list[str], nametosave:str) -> None:
# calculating cosmetics per row
cosmetic_per_row = 6
total_cosmetics = len(arr)
num_rows = math.ceil(total_cosmetics / cosmetic_per_row)
if total_cosmetics > 30:
num_rows = int(math.sqrt(total_cosmetics))
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
while cosmetic_per_row * num_rows < total_cosmetics:
num_rows += 1
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
# setup for our image, thumbnails
padding = 30
thumbnail_width = 128
thumbnail_height = 128
image_width = int(cosmetic_per_row * thumbnail_width)
image_height = int(thumbnail_width * num_rows + 180)
font_path = 'styles/storm/font.ttf'
font_size = 16
font = ImageFont.truetype(font_path, font_size)
image = Image.new('RGB', (image_width, image_height), (0, 0, 0))
# custom background
custom_background_path = f"users/backgrounds/{user_data['ID']}.png"
if os.path.isfile(custom_background_path):
custom_background = Image.open(custom_background_path).resize((image_width, image_height), Image.Resampling.BILINEAR)
image.paste(custom_background, (0, 0))
current_row = 0
current_column = 0
sortarray = ['mythic', 'legendary', 'dark', 'slurp', 'starwars', 'marvel', 'lava', 'frozen', 'gaminglegends', 'shadow', 'icon', 'dc', 'epic', 'rare', 'uncommon', 'common']
arr.sort(key=lambda x: sortarray.index(x.rarity_value))
# had some issues with exclusives rendering in wrong order, so i'm sorting them
try:
with open('exclusive.txt', 'r', encoding='utf-8') as f:
exclusive_cosmetics = [i.strip() for i in f.readlines()]
with open('most_wanted.txt', 'r', encoding='utf-8') as f:
popular_cosmetics = [i.strip() for i in f.readlines()]
except FileNotFoundError:
print("Error: 'exclusive.txt' or 'most_wanted.txt' not found.")
exclusive_cosmetics = []
popular_cosmetics = []
mythic_items = [item for item in arr if item.rarity_value == 'mythic']
other_items = [item for item in arr if item.rarity_value != 'mythic']
mythic_items.sort(
key=lambda x: exclusive_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in exclusive_cosmetics else float('inf')
)
if header == "Popular":
other_items.sort(
key=lambda x: popular_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in popular_cosmetics else float('inf')
)
arr = mythic_items + other_items
draw = ImageDraw.Draw(image)
special_items = {
"CID_029_Athena_Commando_F_Halloween": "cache/pink_ghoul.png",
"CID_030_Athena_Commando_M_Halloween": "cache/purple_skull_old.png",
"CID_116_Athena_Commando_M_CarbideBlack": "cache/omega_max.png",
"CID_694_Athena_Commando_M_CatBurglar": "cache/gold_midas.png",
"CID_693_Athena_Commando_M_BuffCat": "cache/gold_cat.png",
"CID_691_Athena_Commando_F_TNTina": "cache/gold_tntina.png",
"CID_690_Athena_Commando_F_Photographer": "cache/gold_skye.png",
"CID_701_Athena_Commando_M_BananaAgent": "cache/gold_peely.png",
"CID_315_Athena_Commando_M_TeriyakiFish": "cache/worldcup_fish.png",
"CID_971_Athena_Commando_M_Jupiter_S0Z6M": "cache/black_masterchief.png",
"CID_028_Athena_Commando_F": "cache/og_rene.png",
"CID_017_Athena_Commando_M": "cache/og_aat.png"
}
for cosmetic in arr:
special_icon = False
is_banner = cosmetic.is_banner
photo = None
if cosmetic.rarity_value.lower() == "mythic" and cosmetic.cosmetic_id in special_items:
special_icon = True
icon_path = special_items[cosmetic.cosmetic_id]
if os.path.exists(icon_path):
try:
photo = Image.open(icon_path)
except Exception as e:
special_icon = False
else:
special_icon = False
else:
photo = fortnite_cache.get_cosmetic_icon_from_cache(cosmetic.small_icon, cosmetic.cosmetic_id)
if is_banner:
scaled_width = int(photo.width * 1.5)
scaled_height = int(photo.height * 1.5)
photo = photo.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
x_offset = 32
y_offset = 10
new_img = Image.open(f'styles/storm/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA')
new_img.paste(photo, (x_offset, y_offset), mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
else:
new_img = Image.open(f'styles/storm/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA').resize(photo.size)
new_img.paste(photo, mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
# black box for cosmetic name
box = Image.new('RGBA', (128, 28), (0, 0, 0, 100))
photo.paste(box, (0, new_img.size[1] - 28), mask=box)
if header != "Exclusives" and cosmetic.cosmetic_id in popular_cosmetics:
star_image = Image.open('cosmetic_icons/WantedStar.png').resize((128, 128), Image.BILINEAR)
photo.paste(star_image, (0, 0), star_image.convert("RGBA"))
x = thumbnail_width * current_column
y = thumbnail_height * current_row
image.paste(photo, (x, y))
name = cosmetic.name.upper()
max_text_width = thumbnail_width - 10
max_text_height = 20
# fixed font size
font_size = 16
offset = 9
while True:
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
name_height = bbox[3] - bbox[1]
if name_width > max_text_width or name_height > max_text_height:
font_size -= 1
offset += 0.5
else:
break
# cosmetic name
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
draw.text((x + (thumbnail_width - name_width) // 2, y + (thumbnail_height - padding + offset)), name, font=font, fill=(255, 255, 255))
# make the cosmetics show ordered in rows(cosmetic_per_row is hardcoded)
current_column += 1
if current_column >= cosmetic_per_row:
current_row += 1
current_column = 0
# footer
current_date = datetime.now().strftime('%d %B %Y')
# custom logo
custom_logo_path = f"users/logos/{user_data['ID']}.png"
if os.path.isfile(custom_logo_path):
custom_logo = Image.open(custom_logo_path).resize((150, 150), Image.Resampling.BILINEAR)
image.paste(custom_logo, (10, image_height - 165), mask=custom_logo)
else:
# original logo if not found
logo = Image.open('img/logo.png').resize((150, 150), Image.Resampling.BILINEAR)
image.paste(logo, (10, image_height - 165), mask=logo)
draw.text((174, image_height - 40 * 3 - 24), '{}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((170, image_height - 40 * 3 - 28), '{}'.format(current_date), font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
draw.text((174, image_height - 40 * 2 - 24), 'Submitted by ', font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw_gradient_text(0, draw, (170, image_height - 40 * 2 - 28), 'Submitted by ', font=ImageFont.truetype(font_path, 40))
# badges
font_size = 40
font = ImageFont.truetype(font_path, font_size)
submit_width = font.getbbox(f"Submitted by")[2]
offset_submit = 170 + submit_width + 8
username_width = font.getbbox(f"Submitted by @{user_data['username']}")[2]
offset_badge = 170 + username_width + 8
if user_data['epic_badge_active'] == True and user_data['epic_badge'] == True:
# epic games badge(special people only)
alpha_badge = Image.open('badges/epic.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_3_badge_active'] == True and user_data['alpha_tester_3_badge'] == True:
# alpha tester 3 badge
alpha_badge = Image.open('badges/alpha3.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_2_badge_active'] == True and user_data['alpha_tester_2_badge'] == True:
# alpha tester 2 badge
alpha_badge = Image.open('badges/alpha2.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
if user_data['alpha_tester_1_badge_active'] == True and user_data['alpha_tester_1_badge'] == True:
# alpha tester 1 badge
alpha_badge = Image.open('badges/alpha1.png').resize((40, 40), Image.BILINEAR)
image.paste(alpha_badge, (offset_badge, image_height - 40 * 2 - 28), alpha_badge.convert("RGBA"))
offset_badge += 45
draw.text((offset_submit + 2, image_height - 40 * 2 - 26), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw_gradient_text(user_data['gradient_type'], draw, (offset_submit, image_height - 40 * 2 - 28), '@{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 40))
draw.text((174, image_height - 61), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((170, image_height - 65), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 40), fill=(255, 255, 255))
image.save(nametosave)
def render_aqua_style(header:str, user_data: json, arr: list[str], nametosave:str) -> None:
# calculating cosmetics per row
cosmetic_per_row = 6
total_cosmetics = len(arr)
num_rows = math.ceil(total_cosmetics / cosmetic_per_row)
if total_cosmetics > 30:
num_rows = int(math.sqrt(total_cosmetics))
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
while cosmetic_per_row * num_rows < total_cosmetics:
num_rows += 1
cosmetic_per_row = math.ceil(total_cosmetics / num_rows)
# setup for our image, thumbnails
padding = 30
padding_height = 2
thumbnail_width = 128
thumbnail_height = 128
image_width = int(cosmetic_per_row * thumbnail_width)
image_height = int(thumbnail_height + 5 + (num_rows * (padding_height + thumbnail_height)) + 140)
font_path = 'styles/aqua/font.ttf'
font_size = 16
font = ImageFont.truetype(font_path, font_size)
image = Image.new('RGB', (image_width, image_height), (0, 0, 0))
current_row = 0
current_column = 0
sortarray = ['mythic', 'legendary', 'dark', 'slurp', 'starwars', 'marvel', 'lava', 'frozen', 'gaminglegends', 'shadow', 'icon', 'dc', 'epic', 'rare', 'uncommon', 'common']
arr.sort(key=lambda x: sortarray.index(x.rarity_value))
# had some issues with exclusives rendering in wrong order, so i'm sorting them
try:
with open('exclusive.txt', 'r', encoding='utf-8') as f:
exclusive_cosmetics = [i.strip() for i in f.readlines()]
with open('most_wanted.txt', 'r', encoding='utf-8') as f:
popular_cosmetics = [i.strip() for i in f.readlines()]
except FileNotFoundError:
print("Error: 'exclusive.txt' or 'most_wanted.txt' not found.")
exclusive_cosmetics = []
popular_cosmetics = []
mythic_items = [item for item in arr if item.rarity_value == 'mythic']
other_items = [item for item in arr if item.rarity_value != 'mythic']
mythic_items.sort(
key=lambda x: exclusive_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in exclusive_cosmetics else float('inf')
)
if header == "Popular":
other_items.sort(
key=lambda x: popular_cosmetics.index(x.cosmetic_id)
if x.cosmetic_id in popular_cosmetics else float('inf')
)
arr = mythic_items + other_items
draw = ImageDraw.Draw(image)
# top
icon_logo = Image.open(f'cosmetic_icons/{header}.png').resize((128, 128), Image.Resampling.BILINEAR)
icon_logo.thumbnail((thumbnail_width, thumbnail_height))
image.paste(icon_logo, (10, 5), mask=icon_logo)
draw.text((162, 30), '{}'.format(len(arr)), font=ImageFont.truetype(font_path, 70), fill=(0, 0, 0)) # shadow
draw.text((166, 87), '{}'.format(header), font=ImageFont.truetype(font_path, 40), fill=(0, 0, 0)) # shadow
draw.text((162, 26), '{}'.format(len(arr)), font=ImageFont.truetype(font_path, 70), fill=(255, 255, 255))
draw.text((166, 83), '{}'.format(header), font=ImageFont.truetype(font_path, 40), fill=(167, 167, 167))
special_items = {
"CID_029_Athena_Commando_F_Halloween": "cache/pink_ghoul.png",
"CID_030_Athena_Commando_M_Halloween": "cache/purple_skull_old.png",
"CID_116_Athena_Commando_M_CarbideBlack": "cache/omega_max.png",
"CID_694_Athena_Commando_M_CatBurglar": "cache/gold_midas.png",
"CID_693_Athena_Commando_M_BuffCat": "cache/gold_cat.png",
"CID_691_Athena_Commando_F_TNTina": "cache/gold_tntina.png",
"CID_690_Athena_Commando_F_Photographer": "cache/gold_skye.png",
"CID_701_Athena_Commando_M_BananaAgent": "cache/gold_peely.png",
"CID_315_Athena_Commando_M_TeriyakiFish": "cache/worldcup_fish.png",
"CID_971_Athena_Commando_M_Jupiter_S0Z6M": "cache/black_masterchief.png",
"CID_028_Athena_Commando_F": "cache/og_rene.png",
"CID_017_Athena_Commando_M": "cache/og_aat.png"
}
for cosmetic in arr:
special_icon = False
is_banner = cosmetic.is_banner
photo = None
if cosmetic.rarity_value.lower() == "mythic" and cosmetic.cosmetic_id in special_items:
special_icon = True
icon_path = special_items[cosmetic.cosmetic_id]
if os.path.exists(icon_path):
try:
photo = Image.open(icon_path)
except Exception as e:
special_icon = False
else:
special_icon = False
else:
photo = fortnite_cache.get_cosmetic_icon_from_cache(cosmetic.small_icon, cosmetic.cosmetic_id)
if is_banner:
scaled_width = int(photo.width * 1.5)
scaled_height = int(photo.height * 1.5)
photo = photo.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
x_offset = 32
y_offset = 10
new_img = Image.open(f'styles/aqua/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA')
new_img.paste(photo, (x_offset, y_offset), mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
else:
new_img = Image.open(f'styles/aqua/rarity/{cosmetic.rarity_value.lower()}.png').convert('RGBA').resize(photo.size)
new_img.paste(photo, mask=photo)
photo = new_img
photo.thumbnail((thumbnail_width, thumbnail_height))
# black box for cosmetic name
box = Image.new('RGBA', (128, 27), (0, 0, 0, 100))
photo.paste(box, (0, new_img.size[1] - 27), mask=box)
if header != "Exclusives" and cosmetic.cosmetic_id in popular_cosmetics:
star_image = Image.open('cosmetic_icons/WantedStar.png').resize((128, 128), Image.BILINEAR)
photo.paste(star_image, (0, 0), star_image.convert("RGBA"))
x = thumbnail_width * current_column
y = thumbnail_width + (thumbnail_height + padding_height) * current_row
image.paste(photo, (x, y))
name = cosmetic.name.upper()
max_text_width = thumbnail_width - 10
max_text_height = 20
# fixed font size
font_size = 16
offset = 6
while True:
font = ImageFont.truetype(font_path, font_size)
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
name_height = bbox[3] - bbox[1]
if name_width > max_text_width or name_height > max_text_height:
font_size -= 1
offset += 0.5
else:
break
# cosmetic name
bbox = draw.textbbox((0, 0), name, font=font)
name_width = bbox[2] - bbox[0]
draw.text((x + (thumbnail_width - name_width) // 2, y + (thumbnail_height - padding + offset)), name, font=font, fill=(255, 255, 255))
# make the cosmetics show ordered in rows(cosmetic_per_row is hardcoded)
current_column += 1
if current_column >= cosmetic_per_row:
current_row += 1
current_column = 0
# footer
current_date = datetime.now().strftime('%d %B %Y')
# custom logo
custom_logo_path = f"users/logos/{user_data['ID']}.png"
if os.path.isfile(custom_logo_path):
custom_logo = Image.open(custom_logo_path).resize((125, 125), Image.Resampling.BILINEAR)
image.paste(custom_logo, (25, image_height - 140), mask=custom_logo)
else:
# original logo if not found
logo = Image.open('img/logo.png').resize((125, 125), Image.Resampling.BILINEAR)
image.paste(logo, (25, image_height - 140), mask=logo)
draw.text((179, image_height - 114), '{}'.format(current_date), font=ImageFont.truetype(font_path, 30), fill=(0, 0, 0)) # shadow
draw.text((175, image_height - 118), '{}'.format(current_date), font=ImageFont.truetype(font_path, 30), fill=(255, 255, 255))
draw.text((179, image_height - 84), 'Submitted By: @{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 30), fill=(0, 0, 0)) # shadow
draw.text((175, image_height - 88), 'Submitted By: @{}'.format(user_data['username']), font=ImageFont.truetype(font_path, 30), fill=(255, 255, 255))
draw.text((179, image_height - 31), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 20), fill=(0, 0, 0)) # shadow
draw.text((175, image_height - 55), "t.me/RiftCheckerBot", font=ImageFont.truetype(font_path, 20), fill=(255, 255, 255))
image.save(nametosave)
def command_start(bot, message):
if message.chat.type != "private":
return
user = RiftUser(message.from_user.id, message.from_user.username)
user_data = user.register()
if not user_data:
bot.reply_to(message, "You have already used this command, you don't have to use it anymore!")
return
bot.reply_to(message, f'''
What is Rift Checker Bot?
> Rift checker is provably safe open-sourced telegram fortnite skin checker bot, it visualises your locker into an image and sends it back to you, aswell it does display info about your account.
Why should we use Rift and not other skincheckers?
> Unlike majority of skincheckers, we make NO profit from our service, the bot is entirely hosted by choice, as well unlike Raika we DO NOT store your account information anywhere, for security reasons all account credentials are private and inaccessible.
How do i know you're not stealing our accounts?
> Rift checker is open-sourced bot, if you don't believe that it's safe, you could check the source code yourself to make sure that rift is completely safe!
> Rift Checker's Official Github Repository: https://github.com/Debugtopia/RiftCheckerBot
> Yes, you could use rift's source code to create your own bot aswell! just make to credit @xhexago for his work :)
> Other open sourced projects by @xhexago:
- GrowBase(Growtopia Private Server - Game Server source code): https://github.com/Debugtopia/GrowBase
Who are the developers of Rift Checker Bot?
> Rift is a single-handedly developed by @xhexago and nobody else.
Commands:
/start - register to rift checker
/help - displays info about the bot, it's commands.
/login - skincheck your epic games fortnite account.
/style - choose your style based on your need, we support multiple skincheck styles.
/badges - toggle your achieved badges on your skincheck.
/stats - shows statistics of how many accounts have u checked with our bot or the badges you have enabled.
''')
markup = InlineKeyboardMarkup([
[InlineKeyboardButton("🔗 Source Code", url="https://github.com/Debugtopia/RiftCheckerBot")],
[InlineKeyboardButton("🔗 Stock Channel", url="https://t.me/riftstock"),
InlineKeyboardButton("🔗 News Channel", url="https://t.me/RiftCheckerNews")]
])
bot.send_message(
chat_id=message.chat.id,
text=(
"Welcome to Rift Checker Bot!\n"
"Developed by @xhexago\n"
"Interested in purchasing Fortnite accounts?\n"
"- @riftstock\n\n"
"Rift Checker Bot's News channel:\n"
"- @riftcheckernews"
),
reply_markup=markup,
parse_mode="Markdown"
)
def command_help(bot, message):
bot.reply_to(message, f'''
What is Rift Checker Bot?
> Rift checker is provably safe open-sourced telegram fortnite skin checker bot, it visualises your locker into an image and sends it back to you, aswell it does display info about your account.
Why should we use Rift and not other skincheckers?
> Unlike majority of skincheckers, we make NO profit from our service, the bot is entirely hosted by choice, as well unlike Raika we DO NOT store your account information anywhere, for security reasons all account credentials are private and inaccessible.
How do i know you're not stealing our accounts?
> Rift checker is open-sourced bot, if you don't believe that it's safe, you could check the source code yourself to make sure that rift is completely safe!
> Rift Checker's Official Github Repository: https://github.com/Debugtopia/RiftCheckerBot
> Yes, you could use rift's source code to create your own bot aswell! just make to credit @xhexago for his work :)
> Other open sourced projects by @xhexago:
- GrowBase(Growtopia Private Server - Game Server source code): https://github.com/Debugtopia/GrowBase
Who are the developers of Rift Checker Bot?
> Rift is a single-handedly developed by @xhexago and nobody else.
Commands:
/start - register to rift checker
/help - displays info about the bot, it's commands.
/login - skincheck your epic games fortnite account.
/style - choose your style based on your need, we support multiple skincheck styles.
/badges - toggle your achieved badges on your skincheck.
/stats - shows statistics of how many accounts have u checked with our bot or the badges you have enabled.
''')
markup = InlineKeyboardMarkup([
[InlineKeyboardButton("🔗 Source Code", url="https://github.com/Debugtopia/RiftCheckerBot")],
[InlineKeyboardButton("🔗 Stock Channel", url="https://t.me/riftstock"),
InlineKeyboardButton("🔗 News Channel", url="https://t.me/RiftCheckerNews")]
])
bot.send_message(
chat_id=message.chat.id,
text=(
"Welcome to Rift Checker Bot!\n"
"Developed by @xhexago\n"
"Interested in purchasing Fortnite accounts?\n"
"- @riftstock\n\n"
"Rift Checker Bot's News channel:\n"
"- @riftcheckernews"
),
reply_markup=markup,
parse_mode="Markdown"
)
async def command_login(bot, message):
if message.chat.type != "private":
return
user = RiftUser(message.from_user.id, message.from_user.username)
user_data = user.load_data()
if user_data == {}:
bot.reply_to(message, "You haven't setup your user yet, please use /start before skinchecking!")
return
msg = bot.reply_to(message, "⏳ Creating authorization login link...")
epic_generator = EpicGenerator()
await epic_generator.start()
device_data = await epic_generator.create_device_code()
epic_games_auth_link = f"https://www.epicgames.com/activate?userCode={device_data['user_code']}"
# login link message(embed link button)
markup = InlineKeyboardMarkup()
button = InlineKeyboardButton("🔗 Login", url=epic_games_auth_link)
markup.add(button)
bot.edit_message_text(
chat_id=msg.chat.id,
message_id=msg.message_id,
text=f"Open [this link](<{epic_games_auth_link}>) to log in to your account.",
reply_markup=markup,
parse_mode="Markdown")
epic_user = await epic_generator.wait_for_device_code_completion(bot, message, code=device_data['device_code'])
if not epic_user:
# something went wrong so we can't check the account
await epic_generator.kill()
return
account_data = await epic_generator.get_account_metadata(epic_user)
accountID = account_data.get('id', "INVALID_ACCOUNT_ID")
if (accountID == "INVALID_ACCOUNT_ID"):
bot.edit_message_text(chat_id=msg.chat.id, message_id=msg.message_id, text="Invalid account(banned or fortnite has not been launched).")
return
bot.delete_message(msg.chat.id, msg.message_id)
msg = bot.send_message(message.chat.id, f'✅ Logged in account {account_data.get("displayName", "HIDDEN_ID_ACCOUNT")}')
# account information
account_public_data = await epic_generator.get_public_account_info(epic_user)
bot.send_message(message.chat.id,f'''
━━━━━━━━━━━
Account Information
━━━━━━━━━━━
#️⃣ Account ID: {mask_account_id(accountID)}
📧 Email: {mask_email(account_data.get('email', ''))}
🧑‍🦱 Display Name: {account_data.get('displayName', 'DeletedUser')}
📛 Full Name: {account_data.get('name', '')} {account_data.get('lastName', '')}
🌐 Country: {account_data.get('country', 'US')} {country_to_flag(account_data.get('country', 'US'))}
🔐 Email Verified: {bool_to_emoji(account_data.get('emailVerified', False))}
🔒 Mandatory 2FA Security: {bool_to_emoji(account_data.get('tfaEnabled', False))}
''')
# external connections
connected_accounts = 0
connected_accounts_message = f"""
━━━━━━━━━━━
Connected Account
━━━━━━━━━━━\n"""
external_auths = account_public_data.get('externalAuths', [])
for auth in external_auths:
auth_type = auth.get('type', '?').lower()
display_name = auth.get('externalDisplayName', '?')
external_id = auth.get('externalAuthId', '?')
date_added = auth.get('dateAdded', '?')
if date_added != '?':
parsed_date = datetime.strptime(date_added, "%Y-%m-%dT%H:%M:%S.%fZ")
date_added = parsed_date.strftime("%d/%m/%Y")
connected_accounts += 1
connected_accounts_message += f"""
Connection Type: {escape_markdown(auth_type.upper())}
External Display Name: {escape_markdown(display_name)}
Date of Connection: {escape_markdown(date_added)}
"""
if connected_accounts == 0:
connected_accounts_message += "No connected accounts."
markup = InlineKeyboardMarkup()
button = InlineKeyboardButton("🔗 Remove Restrictions", url='https://www.epicgames.com/help/en/wizards/w4')
markup.add(button)
bot.send_message(
chat_id=msg.chat.id,
text=connected_accounts_message,
reply_markup=markup,
parse_mode="Markdown")
# purchases infos
vbucks_categories = [
"Currency:MtxPurchased",
"Currency:MtxEarned",
"Currency:MtxGiveaway",
"Currency:MtxPurchaseBonus"
]
total_vbucks = 0
refunds_used = 0
refund_credits = 0
receipts = []
vbucks_purchase_history = {
"1000": 0,
"2800": 0,
"5000": 0,
"7500": 0,
"13500": 0
}
gift_received = 0
gift_sent = 0
pending_gifts_amount = 0
common_profile_data = await epic_generator.get_common_profile(epic_user)
for item_id, item_data in common_profile_data.get("profileChanges", [{}])[0].get("profile", {}).get("items", {}).items():
if item_data.get("templateId") in vbucks_categories:
# getting vbucks
total_vbucks += item_data.get("quantity", 0)
for profileChange in common_profile_data.get("profileChanges", []):
attributes = profileChange["profile"]["stats"]["attributes"]
mtx_purchases = attributes.get("mtx_purchase_history", {})
if mtx_purchases:
refunds_used = mtx_purchases.get("refundsUsed", 0)
refund_credits = mtx_purchases.get("refundCredits", 0)
iap = attributes.get("in_app_purchases", {})
if iap:
receipts = iap.get("receipts", [])
purchases = iap.get("fulfillmentCounts", {})
if purchases:
# vbucks purchases packs amount
vbucks_purchase_history["1000"] = purchases.get("FN_1000_POINTS", 0)
vbucks_purchase_history["2800"] = purchases.get("FN_2800_POINTS", 0)
vbucks_purchase_history["5000"] = purchases.get("FN_5000_POINTS", 0)
vbucks_purchase_history["7500"] = purchases.get("FN_7500_POINTS", 0)
vbucks_purchase_history["13500"] = purchases.get("FN_13500_POINTS", 0)
gift_history = attributes.get("gift_history", {})
if gift_history:
# pending gifts count
gifts_pending = gift_history.get("gifts", [])
pending_gifts_amount = len(gifts_pending)
# gifts sent & received count
gift_sent = gift_history.get("num_sent", 0)
gift_received = gift_history.get("num_received", 0)
total_vbucks_bought = 1000 * vbucks_purchase_history["1000"] + 2800 * vbucks_purchase_history["2800"] + 5000 * vbucks_purchase_history["5000"] + 7500 * vbucks_purchase_history["7500"] + 13500 * vbucks_purchase_history["13500"]
bot.send_message(message.chat.id,f'''
━━━━━━━━━━━
Purchases Information
━━━━━━━━━━━
💰 VBucks: {total_vbucks}
🎟 Refunds Used: {refunds_used}
🎟 Refund Tickets: {refund_credits}
━━━━━━━━━━━
Vbucks Purchases
━━━━━━━━━━━
#️⃣ Receipts: {len(receipts)}
💰 1000 Vbucks Packs: {vbucks_purchase_history["1000"]}
💰 2800 Vbucks Packs: {vbucks_purchase_history["2800"]}
💰 5000 Vbucks Packs: {vbucks_purchase_history["5000"]}
💰 7500 Vbucks Packs: {vbucks_purchase_history["7500"]}
💰 13500 Vbucks Packs: {vbucks_purchase_history["13500"]}
💰 Total Vbucks Purchased: {total_vbucks_bought}
━━━━━━━━━━━
Gifts Information
━━━━━━━━━━━
🎁 Pending Gifts: {pending_gifts_amount}
🎁 Gifts Sent: {gift_sent}
🎁 Gifts Received: {gift_received}
''')
# season history
seasons_msg = await epic_generator.get_seasons_message(epic_user)
bot.send_message(message.chat.id, seasons_msg)
# locker data
locker_data = await epic_generator.get_locker_data(epic_user)
# activity info
bot.send_message(message.chat.id,f'''
━━━━━━━━━━━
Activity Information
━━━━━━━━━━━
👪 Parental Control: {bool_to_emoji(account_data.get('minorVerified', False))}
🕘 Last Match: {locker_data.last_match}
🤯 Headless: {bool_to_emoji(account_data.get("headless", False))}
✏️ Display Name Changes: {account_data.get("numberOfDisplayNameChanges", 0)}
✏️ Display Name Changeable: {bool_to_emoji(account_data.get("canUpdateDisplayName", False))}
#️⃣ Hashed email: {bool_to_emoji(account_data.get("hasHashedEmail", False))}
''')
bot.send_message(message.chat.id,f'''
━━━━━━━━━━━
Locker Information
━━━━━━━━━━━
🧍‍♂️ Outfits: {len(locker_data.cosmetic_array.get('AthenaCharacter', []))}
🎒 Backpacks: {len(locker_data.cosmetic_array.get('AthenaBackpack', []))}
⛏️ Pickaxes: {len(locker_data.cosmetic_array.get('AthenaPickaxe', []))}
🕺 Emotes: {len(locker_data.cosmetic_array.get('AthenaDance', []))}
✈️ Gliders: {len(locker_data.cosmetic_array.get('AthenaGlider', []))}
⭐ Most Wanted Cosmetics: {len(locker_data.cosmetic_array.get('AthenaPopular', []))}
🌟 Exclusives: {len(locker_data.cosmetic_array.get('AthenaExclusive', []))}
''')
homebase_data = await epic_generator.get_homebase_profile(epic_user)
stats = homebase_data.get("profileChanges", [{}])[0].get("profile", {}).get("stats", {}).get("attributes", {})
if stats:
stw_level = 1
research_offence = 1
research_fortitude = 1
research_resistance = 1
research_tech = 1
collection_book_level = 1
stw_claimed = False
legacy_research_points = 0
matches_played = 0
stats = homebase_data.get("profileChanges", [{}])[0].get("profile", {}).get("stats", {}).get("attributes", {})
if stats:
stw_level = stats.get("level", 1)
research_offence = stats.get("research_levels", {}).get("offence", 1)
research_fortitude = stats.get("research_levels", {}).get("fortitude", 1)
research_resistance = stats.get("research_levels", {}).get("resistance", 1)
research_tech = stats.get("research_levels", {}).get("technology", 1)
collection_book_level = stats.get("collection_book", {}).get("maxBookXpLevelAchieved", 1)
stw_claimed = stats.get("mfa_reward_claimed", False)
legacy_research_points = stats.get("legacy_research_points_spent", 0)
matches_played = stats.get("matches_played", 0)
bot.send_message(message.chat.id,f'''
━━━━━━━━━━━
Homebase Information
━━━━━━━━━━━
#️⃣ Level: {stw_level}
🎒 Collection Book Level: {collection_book_level}
🎁 Claimed Rewards: {bool_to_emoji(stw_claimed)}
Research:
⭐ Total spent points: {legacy_research_points}
⛏️ Offence: {research_offence}
⚔️ Fortitude: {research_fortitude}
🪖 Resistance: {research_resistance}
🔧 Tech: {research_tech}
Activity:
🎟 Matches Played: {matches_played}
''')
# saved data path
# note: it only saves the rendered images for locker, data that DOES NOT contain private or login information!!!
save_path = f"accounts/{accountID}"
if not os.path.exists(save_path):
os.mkdir(save_path)
for category in locker_categories:
if category not in locker_data.cosmetic_array or len(locker_data.cosmetic_array[category]) < 1:
continue
header = 'Outfits'
if category == 'AthenaBackpack':
header = 'Backblings'
elif category == 'AthenaPickaxe':
header = 'Pickaxes'
elif category == 'AthenaDance':
header = 'Emotes'
elif category == 'AthenaGlider':
header = 'Gliders'
elif category == 'AthenaExclusive':
header = 'Exclusives'
elif category == 'AthenaPopular':
header = 'Popular'
if user_data['style'] == 0: # rift style
render_rift_style(header, user_data, locker_data.cosmetic_array[category], f'{save_path}/{category}.png')
elif user_data['style'] == 1: # easy style
render_easy_style(header, user_data, locker_data.cosmetic_array[category], f'{save_path}/{category}.png')
elif user_data['style'] == 2: # raika style
render_raika_style(header, user_data, locker_data.cosmetic_array[category], f'{save_path}/{category}.png')
elif user_data['style'] == 3: # kayy style
render_kayy_style(header, user_data, locker_data.cosmetic_array[category], f'{save_path}/{category}.png')
elif user_data['style'] == 4: # storm style
render_storm_style(header, user_data, locker_data.cosmetic_array[category], f'{save_path}/{category}.png')
elif user_data['style'] == 5: # aqua style
render_aqua_style(header, user_data, locker_data.cosmetic_array[category], f'{save_path}/{category}.png')
with open(f'{save_path}/{category}.png', 'rb') as photo_file:
file_size = os.path.getsize(f'{save_path}/{category}.png')
if file_size > 10 * 1024 * 1024: # 10 MBs
print("File too large for photo, sending as a document.")
bot.send_document(msg.chat.id, photo_file)
else:
bot.send_photo(msg.chat.id, photo_file)
skins = len(locker_data.cosmetic_array['AthenaCharacter'])
excl = locker_data.cosmetic_array['AthenaExclusive']
cosmetic_list = ''
desc = ''
cosmetics_listed = 0
for cosmetic in excl:
cosmetic_list += cosmetic.name + " + "
cosmetics_listed += 1
if cosmetics_listed >= 10:
break
cosmetic_list = cosmetic_list.rstrip(" + ")
desc = f'{skins} + {cosmetic_list} + {total_vbucks}VB'
bot.send_message(message.chat.id,f'{desc}')
await epic_generator.kill()
# button-embed message
markup = InlineKeyboardMarkup([
[InlineKeyboardButton("🔗 Source Code", url="https://github.com/Debugtopia/RiftCheckerBot")],
[InlineKeyboardButton("🔗 Rift Stock", url="https://t.me/riftstock"),
InlineKeyboardButton("🔗 News Channel", url="https://t.me/RiftCheckerNews")]
])
bot.send_message(
chat_id=message.chat.id,
text=(
"Thanks for using Rift Checker Bot!\n"
"Developed by @xhexago\n"
"Interested in purchasing Fortnite accounts?\n"
"- @riftstock\n\n"
"Rift Checker Bot's News channel:\n"
"- @riftcheckernews"
),
reply_markup=markup,
parse_mode="Markdown"
)
async def command_style(bot, message):
if message.chat.type != "private":
return
user = RiftUser(message.from_user.id, message.from_user.username)
user_data = user.load_data()
if not user_data:
bot.reply_to(message, "You haven't setup your user yet, please use /start before skinchecking!")
return
current_style_index = user_data['style']
send_style_message(bot, message.chat.id, current_style_index)
async def command_badges(bot, message):
if message.chat.type != "private":
return
user = RiftUser(message.from_user.id, message.from_user.username)
user_data = user.load_data()
if not user_data:
bot.reply_to(message, "You haven't setup your user yet, please use /start before skinchecking!")
return
badges_unlocked = 0
for badge in avaliable_badges:
if user_data[badge['data']] == True:
badges_unlocked += 1
if badges_unlocked < 1:
msg = bot.reply_to(message, "You don't have any badges unlocked.")
return
current_badge_index = 0
send_badges_message(bot, message.chat.id, current_badge_index, user_data)
async def command_stats(bot, message):
if message.chat.type != "private":
return
user = RiftUser(message.from_user.id, message.from_user.username)
user_data = user.load_data()
if not user_data:
bot.reply_to(message, "You haven't setup your user yet, please use /start before skinchecking!")
return
style = 'rift'
if user_data['style'] == 0:
style = 'rift'
elif user_data['style'] == 1:
style = 'easy'
elif user_data['style'] == 2:
style = 'raika'
elif user_data['style'] == 3:
style = 'kayy'
elif user_data['style'] == 4:
style = 'storm'
elif user_data['style'] == 5:
style = 'aqua'
else:
style = 'unknown style'
msg = bot.reply_to(message, f'''
Stats for user {message.from_user.username}(#{user_data['ID']}):
Checked accounts: {user_data['accounts_checked']}
Style: {style}
Badges:
Alpha Tester 1 Badge: {bool_to_emoji(user_data['alpha_tester_1_badge'])}
> Badge Enabled: {bool_to_emoji(user_data['alpha_tester_1_badge_active'])}
Alpha Tester 2 Badge: {bool_to_emoji(user_data['alpha_tester_2_badge'])}
> Badge Enabled: {bool_to_emoji(user_data['alpha_tester_2_badge_active'])}
Alpha Tester 3 Badge: {bool_to_emoji(user_data['alpha_tester_3_badge'])}
> Badge Enabled: {bool_to_emoji(user_data['alpha_tester_3_badge_active'])}
Epic Games Badge: {bool_to_emoji(user_data['epic_badge'])}
> Badge Enabled: {bool_to_emoji(user_data['epic_badge_active'])}
100 Checks Badge: {bool_to_emoji(user_data['newbie_badge'])}
> Badge Enabled: {bool_to_emoji(user_data['newbie_badge_active'])}
200 Checks Badge: {bool_to_emoji(user_data['advanced_badge'])}
> Badge Enabled: {bool_to_emoji(user_data['advanced_badge_active'])}
''')
def send_style_message(bot, chat_id, style_index):
style = available_styles[style_index]
markup = InlineKeyboardMarkup()
if style_index > 0:
markup.add(InlineKeyboardButton("◀️", callback_data=f"style_{style_index - 1}"))
if style_index < len(available_styles) - 1:
markup.add(InlineKeyboardButton("▶️", callback_data=f"style_{style_index + 1}"))
markup.add(InlineKeyboardButton("✅ Select This Style", callback_data=f"select_{style_index}"))
with open(style['image'], 'rb') as img_file:
img = Image.open(style['image']).convert("RGBA")
bot.send_photo(
chat_id,
img,
caption=f"{style['name']}",
reply_markup=markup,
parse_mode="Markdown"
)
def send_badges_message(bot, chat_id, badge_index, user_data):
unlocked_badges = [
(i, badge)
for i, badge in enumerate(avaliable_badges)
if user_data.get(badge['data'], False)
]
if not unlocked_badges:
bot.send_message(chat_id, "You don't have any badges unlocked.")
return
badge_index = min(max(0, badge_index), len(unlocked_badges) - 1)
actual_index, badge = unlocked_badges[badge_index]
badge_status = user_data.get(badge['data2'], False)
toggle_text = "✅ Enabled" if badge_status else "❌ Disabled"
markup = InlineKeyboardMarkup()
if badge_index > 0:
markup.add(InlineKeyboardButton("◀️", callback_data=f"badge_{badge_index - 1}"))
if badge_index < len(unlocked_badges) - 1:
markup.add(InlineKeyboardButton("▶️", callback_data=f"badge_{badge_index + 1}"))
markup.add(InlineKeyboardButton(toggle_text, callback_data=f"toggle_{actual_index}"))
try:
with open(badge['image'], 'rb') as img:
bot.send_photo(
chat_id,
img,
caption=f"{badge['name']}",
reply_markup=markup,
parse_mode="Markdown"
)
except FileNotFoundError:
bot.send_message(chat_id, f"Image for badge {badge['name']} not found.")