Last active
October 1, 2023 17:33
-
-
Save revoice1/73e2972f00d1fe3ee3f24216437013ac to your computer and use it in GitHub Desktop.
Convert_z7_cue_to_CHD.ps1
This file contains hidden or 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
#Requires -Version 5.1 | |
[cmdletbinding()] | |
param( | |
[string]$SourcePath = "", # Path to 7z zipped disc images to be converted | |
[string]$DestinationPath = "", # Path where you would like the CHD's to go. One folder per game. | |
[string]$WorkingPath = "", # Path where files will be extracting temporarily for CHD creation, use fast disk if possible. Will be created in the running path if undefined | |
[string]$CHDMANPath = "", # Path to the CHDMAN executable, will be downloaded if this isn't defined or isn't correct | |
[switch]$CleanWorkingPath = $false, # Switch to automatically clean (delete contents) the working path dir if it is non-empty | |
[switch]$DisableMultithreading = $false, # Option to disable multithreading logic, for low thread systems or if you don't want CHD conversion to take most of your CPU % | |
[switch]$WritePlaylistFiles = $false # Write m3u files in the destination dir, for all CHDs present (not just new ones) | |
) | |
<# | |
This code can be run in a script editor by manually editing the parameters above or as a script, defining the parameters as switches | |
Example 1 - Covert a folder of 7z compressed bin/cue or iso/cue cd images to CHD and copy to the destination folder | |
PS> .\Convert_z7_cue_to_CHD.ps1 -SourcePath "C:\Path\..\Sega Mega CD & Sega CD" -DestinationPath "C:\Other Path\..\Sega CD" | |
Example 2 - Include verbose output and generate m3u files for multi-disc games | |
PS> .\Convert_z7_cue_to_CHD.ps1 -SourcePath "..\Sega Mega CD & Sega CD" -DestinationPath "..\Sega CD" -Verbose -WritePlaylistFiles | |
Example 3 - Don't convert anything, just create playlist files in a dir with CHD's already present | |
PS> .\Convert_z7_cue_to_CHD.ps1 -SourcePath "" -DestinationPath "..\Sega CD" -WritePlaylistFiles | |
#> | |
$Stopwatch = [system.diagnostics.stopwatch]::StartNew() # Start a stopwatch for runtime calc | |
# If CHDMAN path isn't defined or the path doesn't exist, download CHDMAN | |
if ((!$CHDMANPath) -or !(Test-Path $CHDMANPath)) { | |
if (Test-Path .\CHDMAN\chdman.exe) { | |
$CHDMANPath = ".\CHDMAN\chdman.exe" | |
} | |
else { | |
Write-Verbose "chdman.exe not found, downloading from archive.org to $((Get-Location).Path)\CHDMAN\chdman.exe" | |
Invoke-WebRequest https://archive.org/download/chdman/CHDMAN.zip -OutFile .\CHDMAN.zip | |
Expand-Archive .\CHDMAN.zip .\ | |
Remove-Item .\CHDMAN.zip | |
$CHDMANPath = ".\CHDMAN\chdman.exe" | |
} | |
} | |
# create working path directory if it doesn't exist or is undefined | |
if ((!$WorkingPath) -or !(Test-Path $WorkingPath)) { | |
if (Test-Path .\_temp_extract_dir) { | |
$WorkingPath = ".\_temp_extract_dir" | |
Write-Verbose "Working dir set: $WorkingPath" | |
} | |
else { | |
Write-Warning "Working path not defined or non-existent, creating directory .\_temp_extract_dir " | |
$WorkingDirCreate = New-Item -ItemType Directory -Path .\_temp_extract_dir | |
$WorkingPath = ".\_temp_extract_dir" | |
Write-Verbose "Working dir created: $($WorkingDirCreate.FullName)" | |
} | |
} | |
# If the 7Zip4Powershell module isn't installed, attempt to install it | |
if (!(Get-Module 7Zip4Powershell -ListAvailable)) { | |
Write-Verbose "Attempting to install 7zip powershell module" | |
try { | |
Install-Module 7Zip4Powershell -Confirm:$false -Scope CurrentUser -Force | |
} | |
catch { | |
Write-Error "Failed to detect or install the 7Zip4Powershell module. Please manually install the module or try running the script with administrator rights. $_" | |
} | |
} | |
# If the working path doesn't exist attempt to create it | |
if (!(Test-Path $WorkingPath)) { New-Item -ItemType Directory $WorkingPath | Out-Null } | |
# If the working path is not empty, throw a warning | |
# Or delete the contents if the CleanWorkingPath switch is used | |
elseif (Test-Path -Path $WorkingPath\*) { | |
if ($CleanWorkingPath) { | |
Remove-Item -Recurse $WorkingPath\* | |
} | |
else { | |
return Write-Warning "Working path not empty, this can cause unintended issues. Please use an empty folder.`n`t Or use the `"-CleanWorkingPath`" switch to have the contents of `"$($WorkingPath)`" automatically deleted" | |
} | |
} | |
if ($DisableMultithreading) { | |
$NumProcessors = 0 # If multithreading is disabled, set to 0 to use the default CHDMAN logic | |
} | |
else { | |
# Get the num of logical processors to use for CHDMAN | |
# Subtract one from total just to allow for some breathing room | |
$NumProcessors = (Get-CimInstance -ClassName 'Win32_Processor' -Verbose:$false).NumberOfLogicalProcessors - 1 | |
Write-Verbose "$NumProcessors processors will be used for CHDMAN" | |
} | |
# Locate all the 7z files in the source path | |
$7zDiscs = Get-ChildItem $SourcePath -Recurse -Include *.7z | |
# Counts for reporting | |
$CHDCreateCount = 0 | |
$CHDSkipCount = 0 | |
# For each 7z file found in the source path... | |
foreach ($7zDisc in $7zDiscs) { | |
$FolderName = $7zDisc.name -replace "\.7z$", "" -replace "(\s+)?.?disc.\d.?", "" | |
$DestinationSubfolder = "$DestinationPath\$FolderName" | |
if (!(Test-Path $DestinationSubfolder)) { | |
New-Item -ItemType Directory -Path $DestinationSubfolder | Out-Null | |
} | |
# Generate a list of cue files in the 7z file | |
$ZippedCues = Get-7Zip $7zDisc.FullName | Where-Object { $_.FileName -match "\.cue$" } | |
$Skip7z = $true # Default to skipping unless we find an unconverted cue" | |
# For each cue in the 7z, check if a CHD already exists in the destination path | |
# If there are any cue files that don't already had CHD files, proceed to extraction | |
# If all cue files in the 7z already have CHD files present, skip the 7z | |
foreach ($ZippedCue in $ZippedCues) { | |
if ($Skip7z) { | |
$ZippedCueName = Split-Path $ZippedCue.FileName -Leaf | |
$DestinationCHD = "$($DestinationSubfolder)\$($ZippedCueName -replace "\.cue$",".chd")" | |
if (!(Test-Path -LiteralPath $DestinationCHD)) { | |
$Skip7z = $false # Don't skip the 7z as we need to create some CHD's | |
} | |
else { | |
Write-Verbose "Destination CHD already exists for $($ZippedCue.FileName)" | |
} | |
} | |
} | |
if ($Skip7z) { | |
$CHDSkipCount += $ZippedCues.count | |
continue | |
} | |
# Extract the 7z file to the working path if an existing CHD isn't found | |
Expand-7Zip -ArchiveFileName $7zDisc.FullName -TargetPath $WorkingPath | |
# Locate cue file(s) that were extracted from the 7z file | |
$CueFiles = Get-ChildItem $WorkingPath -Recurse -Include "*.cue" | |
# For each cue file found... | |
foreach ($CueFile in $CueFiles) { | |
# Check if a CHD file exists in the destination path with the same name as the cue file | |
# This will likely catch multi-disc games that have already been converted | |
$DestinationCHD = "$($DestinationSubfolder)\$($CueFile.name -replace "\.cue$",".chd")" | |
if (Test-Path -LiteralPath $DestinationCHD) { | |
Write-Verbose "Destination CHD already exists for $($CueFile.name)" | |
$CHDSkipCount++ | |
continue | |
} | |
# Converto the cue file to a chd file | |
&$CHDMANPath createcd -i $CueFile.fullname -o $DestinationCHD -np $NumProcessors | |
$CHDCreateCount++ | |
} | |
# Clean up the extracted files in the working path | |
Remove-Item -Recurse $WorkingPath\* | |
} | |
# Generate report object | |
$Report = [PSCustomObject]@{ | |
"CHD Files Created" = $CHDCreateCount | |
"CHD Files Skipped" = $CHDSkipCount | |
} | |
# If CreatePlayListFiles was set | |
if ($WritePlaylistFiles) { | |
$PlaylistWriteCount = 0 # Count for reporting | |
# Get a list of multi-disc games | |
$Files = Get-ChildItem -Recurse $DestinationPath -Include "*.chd" | Where-Object { $_.name -match "disc.\d" } | |
# Group them and filter out false positives | |
$Groups = $Files | Group-Object -Property { $_.name -replace "(\s+)?.?disc.\d.?", "" } | Where-Object { $_.count -gt 1 } | |
Write-Verbose "$($Groups.count) multi-disc games found" | |
# For each multi-disc game found... | |
foreach ($Group in $Groups) { | |
$Extension = $Group.group[0].Extension # Isolate the extension to replace | |
$m3uName = $group.name -replace "$Extension$", ".m3u" # Replace the extension with m3u for the target filename | |
$m3uDir = Split-Path $Group.group[0].FullName -Parent | |
$m3uPath = "$m3uDir\$m3uName" # The absolute path of the m3u file | |
Write-Verbose "Writing m3u for $($Group.count) disc game: $m3uName" | |
$Group.group.name | Out-File -LiteralPath $m3uPath # Write the m3u file | |
$PlaylistWriteCount++ | |
} | |
# Add count to report | |
$Report | Add-Member "Playlist Files Written" $PlaylistWriteCount | |
} | |
# Add runtime to report | |
$Report | Add-Member "Elapsed Runtime" ([string]$Stopwatch.Elapsed) | |
# Write the report output | |
Write-Output "" | |
return "--- Script Result ---$($Report | Format-List | Out-String)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is actually running now on 250 PSX roms and seems to be doing a perfect job, thank you!