Skip to content

Instantly share code, notes, and snippets.

@hornc
Forked from Hans5958/rb-cachebuster.py
Last active August 26, 2025 23:47
Show Gist options
  • Save hornc/cf56aefe92a0186ede77fd102eb8fc36 to your computer and use it in GitHub Desktop.
Save hornc/cf56aefe92a0186ede77fd102eb8fc36 to your computer and use it in GitHub Desktop.
Roblox Cache Buster: Simple script to convert Roblox cache files in `%appdata%\Local\Roblox\rbx-storage` folder to normal, openable files (if valid). Run the script inside `%appdata%\Local\Roblox\rbx-storage` normally in Windows OR ~/.var/app/org.vinegarhq.Sober/cache/sober/http for Sober under Linux. Now tested in Linux and original Windows wit…
from genericpath import isfile
import puremagic, io, os
os.makedirs('cachebuster', exist_ok=True)
# Tries to identify rbx file not identifiable by puremagic:
def rbx_format(data):
head = data.read(20)
if head.startswith(b'version'):
# https://devforum.roblox.com/t/roblox-filemesh-format-specification/326114
return 'mesh'
elif head.startswith(b'\xabKTX 11'):
# b'\xabKTX is a texture, https://registry.khronos.org/KTX/specs/1.0/ktxspec.v1.html
return 'ktx'
elif head.startswith(b'<roblox xmlns'):
return 'xml'
# b'<roblox! is an animation?
# roblox-assettypeid files: https://create.roblox.com/docs/reference/engine/enums/AssetType
return
files = []
for file_name in os.listdir('.'):
if not os.path.isfile(file_name):
if len(file_name) == 2:
files += [os.path.join(file_name, f) for f in os.listdir(file_name)]
else:
files.append(file_name)
for file_name in files:
print(file_name)
if not os.path.isfile(file_name):
continue
new_file_headers = b""
new_file_content = None
with open(file_name, mode='rb') as file:
if file.read(4) != b"RBXH":
continue
print()
# Seeking to HTTP request
file.read(4)
d = int.from_bytes(file.read(4), byteorder='little')
print(d)
url = file.read(d)
print(url)
sep = file.read(1)
assert sep == b'\x00'
file.read(4) # not sure what this is?
header_length = int.from_bytes(file.read(4), 'little')
unk = file.read(12)
#print("Header length:", header_length)
# READ 03 00 00 00
mark = int.from_bytes(file.read(4), 'little')
assert mark == 3
if header_length:
header = file.read(header_length)
print("Header:", header)
# print("READ CONTENT")
new_file_content = io.BytesIO(file.read())
# print(puremagic.magic_stream(file))
# print(new_file.read(16))
new_file_name = None
file_name = os.path.basename(file_name)
puremagic_result = None
try:
puremagic_result = puremagic.magic_stream(new_file_content)
# print(puremagic_result[0].extension)
new_file_name = os.path.join("cachebuster", file_name + puremagic_result[0].extension)
ftype = puremagic_result[0].name
except:
new_file_name = os.path.join("cachebuster", file_name)
new_file_content.seek(0)
if not new_file_content.read(1):
print(file_name + ": No content")
continue
if not puremagic_result:
new_file_content.seek(0)
rbx_result = rbx_format(new_file_content)
if rbx_result:
new_file_name = os.path.join("cachebuster", file_name + "." + rbx_result)
ftype = rbx_result
else:
print(file_name + ": OK, unknown")
new_file_content.seek(0)
print('FILE:', new_file_content.read(22))
continue
new_file_content.seek(0)
with open(new_file_name, 'wb') as new_file:
new_file.write(new_file_content.read())
print(file_name + ": OK, " + ftype)
@SpacePiracy112
Copy link

@hornc thank you, I would like to note that this script has significantly less occurrences where it exits upon encountering a problematic file type, compared to the original (while that one still worked)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment