3DS-RPC/api/love3.py
Deltaion Lee 76fe06218b Remove some credits after reconsideration
If you are questioning my reasoning, just search up @Cruel 's full name on Google.
2023-05-31 20:57:44 -05:00

102 lines
2.8 KiB
Python

# Created by Deltaion Lee (MCMi460) on Github
# Grab icons and title information from IDBE database
# A solid afternoon was spent. :D
# Thank you to 3DBrew's IDBE page (https://www.3dbrew.org/wiki/IDBE)
from Cryptodome.Cipher import AES
import Cryptodome.Cipher.AES
from binascii import hexlify, unhexlify
import requests, io, math, json, os
from PIL import Image
def getTitleData(titleID:hex):
data = requests.get('https://idbe-ctr.cdn.nintendo.net/icondata/10/%s.idbe' % titleID.zfill(16), verify = False).content
IV = unhexlify('A46987AE47D82BB4FA8ABC0450285FA4')
K0 = unhexlify('4AB9A40E146975A84BB1B4F3ECEFC47B')
K1 = unhexlify('90A0BB1E0E864AE87D13A6A03D28C9B8')
K2 = unhexlify('FFBB57C14E98EC6975B384FCF40786B5')
K3 = unhexlify('80923799B41F36A6A75FB8B48C95F66F')
AES_KEYS = [K0, K1, K2, K3]
key = AES_KEYS[data[1]]
decipher = AES.new(key,AES.MODE_CBC,IV)
return decipher.decrypt(data[2:])
def getTitleInfo(titleID:hex):
titleID = str(titleID)
try:
int(titleID, 16) # Errors if not HEX
except:
return None
if isinstance(titleID, str):
titleID = hex(int(titleID)).replace('0x', '')
titleID = titleID.zfill(16).upper()
if os.path.isfile('cache/homebrew' + titleID + '.txt'):
return None
if os.path.isfile('cache/' + titleID + '.txt') and os.path.isfile('cache/' + titleID + '.png'):
with open('cache/' + titleID + '.txt', 'r') as file:
return json.loads(file.read())
try:
data = getTitleData(titleID)
except:
with open('cache/homebrew' + titleID + '.txt', 'w') as file:
file.write('')
return None
for i in range(3):
offset = 0x50 + i * 0x200
n = data[offset:offset+0x200]
short = n[0x00:0x00+0x80].decode('utf-16').replace('\x00', '')
long = n[0x80:0x80+0x100].decode('utf-16').replace('\x00', '')
publisher = n[0x180:0x180+0x80].decode('utf-16').replace('\x00', '')
if short:
break
ret = {
'short': short,
'long': long,
'publisher': publisher,
'imageID': titleID,
}
with open('cache/' + titleID + '.txt', 'w') as file:
file.write(json.dumps(ret))
icon_data = data[0x24D0:0x24D0+0x1200] # 48x48 icon data
# Taken from Repo3DS (https://github.com/Repo3DS/shop-cache/blob/master/TitleInfo.py)
(w, h) = (48, 48)
tiled_icon = Image.frombuffer('RGB', (w, h), icon_data, 'raw', 'BGR;16')
# Untile the image
tile_order = [0,1,8,9,2,3,10,11,16,17,24,25,18,19,26,27,4,5,12,13,6,7,14,15,20,21,28,29,22,23,30,31,32,33,40,41,34,35,42,43,48,49,56,57,50,51,58,59,36,37,44,45,38,39,46,47,52,53,60,61,54,55,62,63]
icon = Image.new('RGB', (w, h))
pos = 0
for y in range(0, h, 8):
for x in range(0, w, 8):
for k in range(8 * 8):
xoff = tile_order[k] % 8
yoff = int((tile_order[k] - xoff) / 8)
posx = pos % w
posy = math.floor(pos / w)
pos += 1
pixel = tiled_icon.getpixel((posx, posy))
icon.putpixel((x + xoff, y + yoff), pixel)
icon.save('cache/' + titleID + '.png', 'PNG')
return ret