Skip to content

Instantly share code, notes, and snippets.

@agret
Last active January 9, 2024 04:26
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agret/1dffa44adec2b8838f966e2f42438e6c to your computer and use it in GitHub Desktop.
Save agret/1dffa44adec2b8838f966e2f42438e6c to your computer and use it in GitHub Desktop.
optional icon0 downloading, added way to provide a list of DLC you have the exdata for (owned_dlc.txt), added option to skip exdata size checking (rarely useful)
$current_dir = Split-Path $MyInvocation.MyCommand.Path
# $download_region = "AU"
$download_region = "US"
$entitle_path = "$current_dir\fake_dlc_temp"
$out_path = "$current_dir\fake_dlc_pkg"
$check_dlc_sizes = $true # Set to false if you want to skip checking the exdata download size (not recommended but could be useful for testing with some specific titles)
$download_icon0 = $false # Set to true if you want the PKGs to contain their ICON0.PNG (This lets you get an icon for the content in XMB)
$use_owned_dlc_txt = $false
$owned_dlc = @("")
if ((Test-Path $out_path) -eq 0) { New-Item -ItemType Directory -Path $out_path > $null }
if ((Test-Path $entitle_path) -eq 0) { New-Item -ItemType Directory -Path $entitle_path > $null }
if ((Test-Path "$entitle_path\sce_sys") -eq 0) { New-Item -ItemType Directory -Path "$entitle_path\sce_sys" > $null }
if (Test-Path "$current_dir\owned_dlc.txt") { # We have a list of DLC that we own so let's let it into the script
$use_owned_dlc_txt = $true
foreach ($owned_dlc_id in Get-Content .\owned_dlc.txt) {
$owned_dlc += $owned_dlc_id
}
$owned_dlc = $owned_dlc | sort -Unique # Sort the list and remove duplicates for faster enumeration
}
$i = 0
function CleanupDLCFiles {
if (Test-Path "$entitle_path\param_template.sfx") { Remove-Item -Path "$entitle_path\param_template.sfx" -Force }
if (Test-Path "$entitle_path\fake_dlc_project.gp4") { Remove-Item -Path "$entitle_path\fake_dlc_project.gp4" -Force }
if (Test-Path "$entitle_path\sce_sys\icon0.png") { Remove-Item -Path "$entitle_path\sce_sys\icon0.png" -Force }
if (Test-Path "$entitle_path\sce_sys\param.sfo") { Remove-Item -Path "$entitle_path\sce_sys\param.sfo" -Force }
}
function ConvertImage {
$path = "$entitle_path\temp.jpg" # path to file to convert
if (Test-Path $path)
{
#Load required assemblies and get object reference
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$convertfile = New-Object System.Drawing.Bitmap ($path)
$newfilname = ($path -replace '([^.]).jpg','$1') + ".png"
$convertfile.Save($newfilname,"png")
$convertfile.Dispose()
# $file.Fullname
}
else
{
Write-Host "Path not found."
}
};
foreach ($content_id in Get-Content .\download_list.txt) {
$i++
CleanupDLCFiles # Cleanup any leftovers in case the script exited uncleanly or to avoid conflicts with the previous file in the loop
if (($content_id).length -eq 36 -and (Test-Path "$out_path\$content_id-A0000-V0100.pkg") -eq 0)
{
$download_url = "https://store.playstation.com/store/api/chihiro/00_09_000/container/$download_region/en/19/" + $content_id
$build_info = Invoke-RestMethod -Uri $download_url
$icon0_jpg = "https://store.playstation.com/store/api/chihiro/00_09_000/container/$download_region/en/19/$content_id/1520727265000/image?w=512&h=512&bg_color=000000&opacity=100&_version=00_09_000"
if ($download_icon0 -eq $true) { Invoke-WebRequest -Uri $icon0_jpg -OutFile "$entitle_path\temp.jpg" }
if (Test-Path "$entitle_path\temp.jpg") { ConvertImage } # If our download succeeds let's convert it to a PNG
if (Test-Path "$entitle_path\temp.png") {
Copy-Item -Path "$entitle_path\temp.png" -Destination "$entitle_path\sce_sys\icon0.png" -Force
Remove-Item -Path "$entitle_path\temp.png" -Force
}
if (Test-Path "$entitle_path\temp.jpg") { Remove-Item -Path "$entitle_path\temp.jpg" -Force }
$dlc_name = $build_info.Name
$dlc_activator = $true
foreach ($check1 in $build_info.default_sku.entitlements) { # Loop each entitlement granted by the content
if ($check1.id -eq $content_id -and ($check1.Name).length -gt 1 -and $dlc_name -ne $check1.Name) { # The entitlement matches the content, We should prefer the content name rather than the "friendly" store name if it's available
Write-Host "[INFO] " $dlc_name "->" $check1.Name
$dlc_name = $check1.Name # default_sku.entitlements[""0""].id -- default_sku.entitlements[""0""].name
}
if ($check_dlc_sizes -eq $true) { # Let's check the metadata to make sure the content is actually an activator and not something that requires exdata
foreach ($check2 in $check1.packages) { # If the entitlement grants packages we must enumerate them
if ($check2.size -gt 0) { # If the content requires a download size it is not a valid activator DLC and requires exdata :(
if ($use_owned_dlc_txt -eq $true -and $check1.id -ne $content_id -and $owned_dlc -contains $check1.id) # However, if we already own the DLC inside the package then the package itself may add extra content (i.e. a season pass exclusive unlock)
{
Write-Host "[INFO] Package " $dlc_name "contains " $check1.Name "which we already own =)"
} else {
Write-Host "[ERR]" $dlc_name "needs EXDATA" $check1.id "(packages)" -BackgroundColor black -ForegroundColor red
$dlc_activator = $false
}
}
}
foreach ($check2 in $check1.drms) { # If the entitlement grants DRMs we must enumerate them
if ($check2.id -eq $content_id) { # If the DRM ID is the same as our content we might be in trouble
if ($check2.size -gt 0) {
Write-Host "[ERR]" $dlc_name "needs EXDATA" $check2.id "(packages)" -BackgroundColor black -ForegroundColor red
$dlc_activator = $false } # If the content ID matches and requires a download size it is not a valid activator DLC and requires exdata :(
}
}
}
}
if ($dlc_name -lt 2) # Item name is less than 2 characters so i'd say that's invalid, revert to item ID
{
Write-Host "[ERROR] Could not find the name for $dlc_name, revert to using content ID"
$dlc_name = $content_id
}
$dlc_name = $dlc_name -replace "&","and" # The PKG generator seems to have issues with content that contains the & symbol, most entitlement names convert it but i've seen it escaped on the console as & before haha
if ($dlc_activator -eq $true) {
$title_id = ($content_id).Substring(7,9)
$timestamp = Get-Date -UFormat "%Y-%m-%d %H:%M:%S"
$sfx_output = "<?xml version=`"1.0`" encoding=`"utf-8`" standalone=`"yes`"?>`r`n<paramsfo>`r`n <param key=`"ATTRIBUTE`">0</param>`r`n <param key=`"CATEGORY`">ac</param>`r`n <param key=`"CONTENT_ID`">" + $content_id + "</param>`r`n <param key=`"FORMAT`">obs</param>`r`n <param key=`"TITLE`">" + $dlc_name + "</param>`r`n <param key=`"TITLE_ID`">" + $title_id + "</param>`r`n <param key=`"VERSION`">01.00</param>`r`n</paramsfo>)"
if ((Test-Path $entitle_path"\sce_sys\icon0.png") -eq 0) { # If we don't have icon0 use the top one, otherwise use bottom one which includes icon0.png
$gp4_output = "<?xml version=`"1.0`" encoding=`"utf-8`" standalone=`"yes`"?>`r`n<psproject fmt=`"gp4`" version=`"1000`">`r`n <volume>`r`n <volume_type>pkg_ps4_ac_nodata</volume_type>`r`n <volume_id>PS4VOLUME</volume_id>`r`n <volume_ts>" + $timestamp + "</volume_ts>`r`n <package content_id=`"" + $content_id + "`" passcode=`"00000000000000000000000000000000`"/>`r`n </volume>`r`n <files img_no=`"0`">`r`n <file targ_path=`"sce_sys/param.sfo`" orig_path=`"" + $entitle_path + "\sce_sys\param.sfo`"/>`r`n </files>`r`n <rootdir>`r`n <dir targ_name=`"sce_sys`"/>`r`n </rootdir>`r`n</psproject>"
} else {
$gp4_output = "<?xml version=`"1.0`" encoding=`"utf-8`" standalone=`"yes`"?>`r`n<psproject fmt=`"gp4`" version=`"1000`">`r`n <volume>`r`n <volume_type>pkg_ps4_ac_nodata</volume_type>`r`n <volume_id>PS4VOLUME</volume_id>`r`n <volume_ts>" + $timestamp + "</volume_ts>`r`n <package content_id=`"" + $content_id + "`" passcode=`"00000000000000000000000000000000`"/>`r`n </volume>`r`n <files img_no=`"0`">`r`n <file targ_path=`"sce_sys/param.sfo`" orig_path=`"" + $entitle_path + "\sce_sys\param.sfo`"/>`r`n <file targ_path=`"sce_sys/icon0.png`" orig_path=`"" + $entitle_path + "\sce_sys\icon0.png`"/>`r`n </files>`r`n <rootdir>`r`n <dir targ_name=`"sce_sys`"/>`r`n </rootdir>`r`n</psproject>"
}
New-Item -Force -Path $entitle_path"\param_template.sfx" -Value $sfx_output -Type file > $null
New-Item -Force -Path $entitle_path"\fake_dlc_project.gp4" -Value $gp4_output -Type file > $null
Start-Process -WindowStyle hidden -FilePath ".\orbis-pub-cmd.exe" -Wait -ArgumentList "sfo_create","$entitle_path\param_template.sfx","$entitle_path\sce_sys\param.sfo"
Start-Process -WindowStyle hidden -FilePath ".\orbis-pub-cmd.exe" -Wait -ArgumentList "img_create","$entitle_path\fake_dlc_project.gp4","$out_path\$content_id-A0000-V0100.pkg"
if ((Test-Path "$out_path\$content_id-A0000-V0100.pkg") -eq 1) {
Write-Host $i.ToString("00000") $content_id "`t" $dlc_name -BackgroundColor black -ForegroundColor green
} else {
Write-Host $i.ToString("00000") $content_id "`t" $dlc_name "`t ERROR OCCURED GENERATING PKG" -BackgroundColor black -ForegroundColor red
}
} else {
Write-Host $i.ToString("00000") $content_id "`t" $dlc_name "`t CONTENT NEEDS EXDATA" -BackgroundColor black -ForegroundColor red
}
} else {
if (($content_id).length -eq 36) {
Write-Host $i.ToString("00000") $content_id "`t PKG HAS ALREADY BEEN GENERATED" -BackgroundColor black -ForegroundColor blue
} else {
Write-Host $i.ToString("00000") $content_id "`t`t INVALID CONTENT ID (must be 36 characters exactly)" -BackgroundColor black -ForegroundColor red
}
}
}
Remove-Item $entitle_path -Force -Recurse
Write-Host "Fake DLC generation complete, press any key to exit."
$HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null
$HOST.UI.RawUI.Flushinputbuffer()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment