-
-
Save TheRadziu/b7321fdf2672197d14b87eeb2a5bd919 to your computer and use it in GitHub Desktop.
Easy Fake DLC / DLC without Extra Data Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Easy Fake DLC / DLC without Extra Data Generator | |
## Version 2.1.0 (24.07.20) | |
## NOW UPDATED TO USE OPEN SOURCED PKGTOOL.EXE (from LibOrbisPkg) AND WITH PSS URL SUPPORT | |
## Written in python 3.5 by TheRadziu | |
import os, os.path | |
import sys | |
import json | |
import urllib.request | |
import errno | |
import shutil | |
import datetime | |
current_dir = os.path.dirname(os.path.abspath(__file__)) | |
gen_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | |
contentid = "EP0002-CUSA00000_00-0000000000000000" | |
name = "NO DLC NAME" | |
titleid = "CUSA00000" | |
def mkdir_p(path): | |
try: | |
os.makedirs(path) | |
except OSError as exc: | |
if exc.errno == errno.EEXIST and os.path.isdir(path): | |
pass | |
else: raise | |
def safe_open_w(path): | |
mkdir_p(os.path.dirname(path)) | |
return open(path, 'w') | |
def parse_store_url(url): | |
url = url.replace("https://", "") | |
urls = url.split("/") | |
contentid = urls[3] | |
chihiro_url = 'https://store.playstation.com/store/api/chihiro/00_09_000/container/'+urls[1][-2:]+'/'+urls[1][:2]+'/999/'+urls[3]+'/' | |
chihiro_response = urllib.request.urlopen(chihiro_url) | |
chihiro_json = json.loads(chihiro_response.read().decode('utf-8')) | |
if chihiro_json['skus'][0]['entitlements'][0]['packageType'] != 'PS4AL': | |
print('!!!!!!!! WARNING !!!!!!!!\nPackage seems to be DLC WITH EXTRA DATA or a BUNDLE. Created fpkg is most likely to be unusable.\n!!!!!!!! WARNING !!!!!!!!') | |
if yes_no_prompt("Do you wish to continue anyway?") == False: | |
print('Aborting!') | |
sys.exit(2) | |
print('----------------------------------------') | |
contentid = chihiro_json['id'] | |
name = chihiro_json['name'] | |
urllib.request.urlretrieve(chihiro_json['images'][len(chihiro_json['images'])-1]['url'], "fake_dlc_temp/sce_sys/icon0.png") | |
return name, contentid | |
if not os.path.exists('PkgTool.exe') or not os.path.exists('LibOrbisPkg.dll'): | |
print("File or files \'PkgTool.exe.exe\', \'LibOrbisPkg.dll'\ are missing from current directory!!") | |
sys.exit(2) | |
def yes_no_prompt(question, default="yes"): | |
valid = {"yes": True, "y": True, "ye": True, | |
"no": False, "n": False} | |
if default is None: | |
prompt = " [y/n] " | |
elif default == "yes": | |
prompt = " [Y/n] " | |
elif default == "no": | |
prompt = " [y/N] " | |
else: | |
raise ValueError("invalid default answer: '%s'" % default) | |
while True: | |
print(question + prompt) | |
choice = input('Choice: ').lower() | |
if default is not None and choice == '': | |
return valid[default] | |
elif choice in valid: | |
return valid[choice] | |
else: | |
print('Please respond with \'yes\' or \'no\'\n(or \'y\' or \'n\').') | |
## Precreate some directories if needed | |
mkdir_p(os.path.dirname('fake_dlc_temp/sce_sys/')) | |
if os.path.isdir("fake_dlc_pkg"): | |
pass | |
else: | |
os.mkdir('fake_dlc_pkg') | |
## decide if from url or not: | |
if len(sys.argv) > 1 and "https://store.playstation.com" in sys.argv[1]: | |
print("!! STORE URL PARSING MODE !!\n") | |
res = parse_store_url(sys.argv[1]) | |
name = res[0] | |
contentid = res[1] | |
else: | |
try: | |
contentid = sys.argv[1] | |
name = sys.argv[2] | |
urllib.request.urlretrieve("https://i.imgur.com/JeaTFEX.png", "fake_dlc_temp/sce_sys/icon0.png") | |
print("!! LOCAL METADATA MODE !!\n") | |
if len(contentid) != 36: | |
print("DLC CID IS TOO LONG OR TOO SHORT, IT HAS TO BE 36 CHARACTERS LONG, FOR EXAMPLE 'UP9000-CUSA00900_00-SPEXPANSIONDLC03'") | |
shutil.rmtree('fake_dlc_temp') | |
sys.exit(2) | |
except: | |
print("Usage for local metadata mode: {} {} {}\n".format(sys.argv[0], 'DLC_CID', '\"DLC_NAME\"')) | |
print("Usage for store url parsing mode: {} {}".format(sys.argv[0], 'https://store.playstation.com/pl-pl/product/EP0002-CUSA07399_00-CRASHNSANELEVEL2')) | |
shutil.rmtree('fake_dlc_temp') | |
sys.exit(2) | |
GP4_template = """<?xml version="1.0"?> | |
<psproject xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" fmt="gp4" version="1000"> | |
<volume> | |
<volume_type>pkg_ps4_ac_data</volume_type> | |
<volume_ts>%s</volume_ts> | |
<package content_id="%s" passcode="00000000000000000000000000000000" entitlement_key="00000000000000000000000000000000" /> | |
</volume> | |
<files img_no="0"> | |
<file targ_path="sce_sys/icon0.png" orig_path="sce_sys\icon0.png" /> | |
<file targ_path="sce_sys/param.sfo" orig_path="sce_sys\param.sfo" /> | |
</files> | |
<rootdir> | |
<dir targ_name="sce_sys" /> | |
</rootdir> | |
</psproject>""" % (gen_time, contentid) | |
## save template as a project file | |
x = safe_open_w('fake_dlc_temp/fake_dlc_project.gp4') | |
x.write(GP4_template) | |
x.close() | |
## make and populate param.sfo | |
print('SFO:') | |
os.system('PkgTool.exe sfo_new fake_dlc_temp\sce_sys\param.sfo') | |
os.system('PkgTool.exe sfo_setentry --value 0x00000000 --type integer --maxsize 4 fake_dlc_temp\sce_sys\param.sfo ATTRIBUTE') | |
os.system('PkgTool.exe sfo_setentry --value ac --type utf8 --maxsize 4 fake_dlc_temp\sce_sys\param.sfo CATEGORY') | |
os.system('PkgTool.exe sfo_setentry --value ' + contentid + ' --type utf8 --maxsize 48 fake_dlc_temp\sce_sys\param.sfo CONTENT_ID') | |
os.system('PkgTool.exe sfo_setentry --value obs --type utf8 --maxsize 4 fake_dlc_temp\sce_sys\param.sfo FORMAT') | |
os.system('PkgTool.exe sfo_setentry --value \"' + name + '\" --type utf8 --maxsize 128 fake_dlc_temp\sce_sys\param.sfo TITLE') | |
os.system('PkgTool.exe sfo_setentry --value ' + contentid[7:16] + ' --type utf8 --maxsize 12 fake_dlc_temp\sce_sys\param.sfo TITLE_ID') | |
os.system('PkgTool.exe sfo_setentry --value 01.00 --type utf8 --maxsize 8 fake_dlc_temp\sce_sys\param.sfo VERSION') | |
print('----------------------------------------') | |
## build fpkg out of generated PG4 project file | |
os.system('PkgTool.exe pkg_build fake_dlc_temp\\fake_dlc_project.gp4 fake_dlc_pkg') | |
## be a good boy and clean up after | |
shutil.rmtree('fake_dlc_temp') | |
print('----------------------------------------') | |
print('Everything is finished, quitting :)') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for creating this, it's a huge time saver having it done with those magic command lines :)
I ported it to PowerShell and made it automatically get the DLC name from PSN server and also check the entitlements to make sure it's a DLC without exdata, you just put a list of content IDs into download_list.txt in the same folder and it will automatically create the PKGs with correct naming. (Right click it and hit Run With Powershell)
https://gist.github.com/agret/1dffa44adec2b8838f966e2f42438e6c