I've noticed that when MakeMKV starts up it will automatically scans the disc to show the list of titles.
Can the same be enabled when MakeMKV is already running and a new disc is inserted?
It's already detecting the new drive and presents the huge button, I'm asking for that button to press itself.
Not sure if this is a feature request or it's already possible.
[Request] Automatic title scanning
Re: [Request] Automatic title scanning
It does? Not that I've seen.I've noticed that when MakeMKV starts up it will automatically scans the disc to show the list of titles.
Starting MakeMKV with a disk inserted, the disk gets scanned enough to display its information in the Info window, but I still have to click the Open button to get the directory read.
If no disk is inserted when it is started, inserting a disk takes me to the same screen, and I have to click the Open button to get the directory.
MakeMKV Frequently Asked Questions
FAQ about BETA and PERMANENT keys.
How to aid in finding the answer to your problem: Activating Debug Logging
FAQ about BETA and PERMANENT keys.
How to aid in finding the answer to your problem: Activating Debug Logging
Re: [Request] Automatic title scanning
One more vote for this. It would speed up ripping disks for me.
When I pop a disk in, I typically get involved with something else and fail to notice when the disk is loaded. The app just sits there, waiting for me to click the Open button.
At the very least, if there could be a reminder, like when initial loading is complete, it would help a bit.
When I pop a disk in, I typically get involved with something else and fail to notice when the disk is loaded. The app just sits there, waiting for me to click the Open button.
At the very least, if there could be a reminder, like when initial loading is complete, it would help a bit.
Re: [Request] Automatic title scanning
Any update on this? It would be great if MakeMKV could auto-scan and go straight to the title selection automatically.
In the meantime, I put together a PowerShell script as a workaround. It relies on forcing window focus and sending keystrokes, so it might be a bit clunky/unstable, but it gets the job done for now.
In the meantime, I put together a PowerShell script as a workaround. It relies on forcing window focus and sending keystrokes, so it might be a bit clunky/unstable, but it gets the job done for now.
Code: Select all
# MakeMKV_Opener_Ejector.ps1
# Author: Gemini + Claude Sonnet 4.6 Thinking
# Version: 1.0.5
# Combined Auto-Open-Disc and Auto-Eject Monitor
param(
[string]$DriveLetter = "D",
[string]$MakeMKVPath = "C:\Program Files (x86)\MakeMKV\makemkv.exe",
[string]$LogFile = "$env:USERPROFILE\MakeMKV_log.txt",
[int]$PollSeconds = 3,
[int]$MaxScanAttempts = 5,
[int]$ScanConfirmTimeoutSeconds = 8
)
if ($DriveLetter -match '([A-Za-z])') {
$CleanDrive = $matches[1].ToUpper()
} else {
$CleanDrive = "D"
}
$root = "${CleanDrive}:\"
$hasRunForLabel = $null
$TempLog = "$env:TEMP\MakeMKV_master_shadow_$PID.txt"
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class WinAPI {
[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")] public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();
[DllImport("user32.dll")] public static extern bool BlockInput(bool fBlockIt);
}
"@
function Force-Focus([IntPtr]$hWnd) {
if ($hWnd -eq [IntPtr]::Zero) { return $false }
[WinAPI]::ShowWindowAsync($hWnd, 9) | Out-Null
[WinAPI]::SetForegroundWindow($hWnd) | Out-Null
$remoteThreadId = [WinAPI]::GetWindowThreadProcessId($hWnd, [IntPtr]::Zero)
$currentThreadId = [WinAPI]::GetCurrentThreadId()
if ($remoteThreadId -ne $currentThreadId) {
[WinAPI]::AttachThreadInput($currentThreadId, $remoteThreadId, $true) | Out-Null
[WinAPI]::SetForegroundWindow($hWnd) | Out-Null
[WinAPI]::AttachThreadInput($currentThreadId, $remoteThreadId, $false) | Out-Null
}
return $true
}
function Send-OpenDiscMacro($proc) {
Add-Type -AssemblyName System.Windows.Forms
if (-not (Force-Focus $proc.MainWindowHandle)) { return $false }
try {
[WinAPI]::BlockInput($true) | Out-Null
Start-Sleep -Milliseconds 300
[System.Windows.Forms.SendKeys]::SendWait("%(f)")
Start-Sleep -Milliseconds 400
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")
Start-Sleep -Milliseconds 100
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")
Start-Sleep -Milliseconds 100
[System.Windows.Forms.SendKeys]::SendWait("{RIGHT}")
Start-Sleep -Milliseconds 300
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
return $true
} finally {
[WinAPI]::BlockInput($false) | Out-Null
}
}
function Wait-ForReadySignal($baselineLines, $timeoutSeconds, $SourceLog, $ShadowLog) {
$readyPattern = 'SDF id v'
$deadline = (Get-Date).AddSeconds($timeoutSeconds)
$bl = $baselineLines
while ((Get-Date) -lt $deadline) {
Copy-Item -LiteralPath $SourceLog -Destination $ShadowLog -Force -ErrorAction SilentlyContinue
if (Test-Path $ShadowLog) {
$allLines = @(Get-Content $ShadowLog -Encoding UTF8 -ErrorAction SilentlyContinue)
if ($allLines.Count -lt $bl) { $bl = 0 }
$newLines = $allLines | Select-Object -Skip $bl
if ($newLines | Where-Object { $_ -match $readyPattern }) {
return $true
}
}
Start-Sleep -Milliseconds 500
}
return $false
}
function Wait-ForLogLine($baselineLines, $timeoutSeconds, $SourceLog, $ShadowLog) {
$successPattern = 'Using direct disc access mode|Launching.*mmgplsrv64\.exe|Title #\d+ was added'
$deadline = (Get-Date).AddSeconds($timeoutSeconds)
$bl = $baselineLines
while ((Get-Date) -lt $deadline) {
if (Test-Path $SourceLog) {
Copy-Item -LiteralPath $SourceLog -Destination $ShadowLog -Force -ErrorAction SilentlyContinue
if (Test-Path $ShadowLog) {
$allLines = @(Get-Content $ShadowLog -Encoding UTF8 -ErrorAction SilentlyContinue)
if ($allLines.Count -lt $bl) {
$bl = 0
}
$newLines = $allLines | Select-Object -Skip $bl
if ($newLines | Where-Object { $_ -match $successPattern }) {
return $true
}
}
}
Start-Sleep -Milliseconds 500
}
return $false
}
Write-Host "=== MakeMKV Opener & Ejector Monitor ===" -ForegroundColor Cyan
Write-Host "Watching drive $CleanDrive for new discs and rip completions..." -ForegroundColor Gray
$lastSize = 0
$seenLines = 0
if (Test-Path $LogFile) {
Copy-Item -LiteralPath $LogFile -Destination $TempLog -Force -ErrorAction SilentlyContinue
if (Test-Path $TempLog) {
$lastSize = (Get-Item $TempLog).Length
$seenLines = @(Get-Content $TempLog -Encoding UTF8 -ErrorAction SilentlyContinue).Count
}
}
try {
while ($true) {
try {
$di = New-Object System.IO.DriveInfo($root)
# --- 1. SCAN LOGIC ---
if ($di.IsReady) {
$label = $di.VolumeLabel
if (-not $label) { $label = "__NO_LABEL__" }
if ($hasRunForLabel -ne $label) {
Write-Host "`n$(Get-Date -Format 'HH:mm:ss') -> New disc detected: $label" -ForegroundColor Green
$hasRunForLabel = $label
$proc = Get-Process makemkv -ErrorAction SilentlyContinue |
Where-Object { $_.MainWindowHandle -ne 0 } |
Select-Object -First 1
if (-not $proc) {
Write-Host "Launching MakeMKV..." -ForegroundColor DarkGray
Start-Process -FilePath $MakeMKVPath -WindowStyle Normal
$waited = 0
while ($waited -lt 15) {
Start-Sleep -Seconds 1
$waited++
$proc = Get-Process makemkv -ErrorAction SilentlyContinue |
Where-Object { $_.MainWindowHandle -ne 0 } |
Select-Object -First 1
if ($proc) { break }
}
}
if ($proc) {
$baselineLines = 0
if (Test-Path $LogFile) {
Copy-Item -LiteralPath $LogFile -Destination $TempLog -Force -ErrorAction SilentlyContinue
if (Test-Path $TempLog) {
$baselineLines = @(Get-Content $TempLog -Encoding UTF8 -ErrorAction SilentlyContinue).Count
}
}
Write-Host "Waiting for MakeMKV ready signal (SDF id)..." -ForegroundColor DarkGray
if (-not (Wait-ForReadySignal $baselineLines 60 $LogFile $TempLog)) {
Write-Host "MakeMKV did not become ready in time." -ForegroundColor Red
} else {
Write-Host "MakeMKV ready. Sending Open Disc macro..." -ForegroundColor DarkGray
$scanConfirmed = $false
for ($attempt = 1; $attempt -le $MaxScanAttempts; $attempt++) {
Write-Host "Sending scan command (attempt $attempt)..." -ForegroundColor DarkGray
Send-OpenDiscMacro $proc | Out-Null
Write-Host "Waiting for scan confirmation in log (${ScanConfirmTimeoutSeconds}s)..." -ForegroundColor DarkGray
if (Wait-ForLogLine $baselineLines $ScanConfirmTimeoutSeconds $LogFile $TempLog) {
Write-Host "Scan confirmed!" -ForegroundColor Green
$scanConfirmed = $true
break
} else {
Write-Host "Not confirmed yet, retrying..." -ForegroundColor Yellow
}
}
if (-not $scanConfirmed) {
Write-Host "Scan could not be confirmed after $MaxScanAttempts attempts." -ForegroundColor Red
}
}
} else {
Write-Host "MakeMKV did not start in time." -ForegroundColor Red
}
if (Test-Path $LogFile) {
Copy-Item -LiteralPath $LogFile -Destination $TempLog -Force -ErrorAction SilentlyContinue
if (Test-Path $TempLog) {
$lastSize = (Get-Item $TempLog).Length
$seenLines = @(Get-Content $TempLog -Encoding UTF8 -ErrorAction SilentlyContinue).Count
}
}
continue
}
} else {
if ($null -ne $hasRunForLabel) {
Write-Host "$(Get-Date -Format 'HH:mm:ss') -> Disc removed." -ForegroundColor DarkGray
}
$hasRunForLabel = $null
}
# --- 2. EJECT LOGIC ---
if (Test-Path $LogFile) {
Copy-Item -LiteralPath $LogFile -Destination $TempLog -Force -ErrorAction SilentlyContinue
if (Test-Path $TempLog) {
$currentSize = (Get-Item $TempLog).Length
if ($currentSize -gt $lastSize) {
$allLines = @(Get-Content $TempLog -Encoding UTF8 -ErrorAction SilentlyContinue)
if ($allLines.Count -lt $seenLines) {
$seenLines = 0
}
$newLines = $allLines | Select-Object -Skip $seenLines
$seenLines = $allLines.Count
$lastSize = $currentSize
foreach ($line in $newLines) {
if ($line -match 'Copy complete\. (\d+) titles? saved') {
$titleCount = [int]$matches[1]
if ($titleCount -eq 0) { continue }
Write-Host "`n>>> RIP COMPLETE! ($titleCount titles saved) <<<" -ForegroundColor Green
Write-Host "Closing MakeMKV popup..." -ForegroundColor Cyan
$proc = Get-Process makemkv -ErrorAction SilentlyContinue |
Where-Object { $_.MainWindowHandle -ne 0 } |
Select-Object -First 1
if ($proc) {
Add-Type -AssemblyName System.Windows.Forms
$popupClosed = $false
$attempt = 0
while (-not $popupClosed -and $attempt -lt 3) {
$attempt++
Start-Sleep -Seconds 3
try {
[WinAPI]::BlockInput($true) | Out-Null
[WinAPI]::ShowWindowAsync($proc.MainWindowHandle, 9) | Out-Null
[WinAPI]::SetForegroundWindow($proc.MainWindowHandle) | Out-Null
Start-Sleep -Milliseconds 600
[System.Windows.Forms.SendKeys]::SendWait(" ")
Start-Sleep -Milliseconds 200
[System.Windows.Forms.SendKeys]::SendWait("{ESC}")
Start-Sleep -Milliseconds 200
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Write-Host "Popup keystrokes sent (attempt $attempt)." -ForegroundColor Green
$popupClosed = $true
} finally {
[WinAPI]::BlockInput($false) | Out-Null
}
}
} else {
Write-Host "MakeMKV GUI process not found." -ForegroundColor Yellow
}
if ($titleCount -eq 1) {
Write-Host "Single title saved. Ejecting drive..." -ForegroundColor Green
$ejected = $false
try {
$wmp = New-Object -ComObject WMPlayer.OCX.7
$cdroms = $wmp.cdromCollection
for ($i = 0; $i -lt $cdroms.Count; $i++) {
if ($cdroms.Item($i).DriveSpecifier -match "^$CleanDrive") {
$cdroms.Item($i).Eject()
$ejected = $true
break
}
}
if (-not $ejected) { throw "Not in WMP" }
} catch {
try {
$shell = New-Object -ComObject Shell.Application
$shell.Namespace(17).ParseName("$CleanDrive`:").InvokeVerb("Eject")
} catch {
if ($proc) {
Write-Host "COM Eject failed, using Menu fallback..." -ForegroundColor Yellow
try {
[WinAPI]::BlockInput($true) | Out-Null
[WinAPI]::ShowWindowAsync($proc.MainWindowHandle, 9) | Out-Null
[WinAPI]::SetForegroundWindow($proc.MainWindowHandle) | Out-Null
Start-Sleep -Milliseconds 300
[System.Windows.Forms.SendKeys]::SendWait("%(f)")
Start-Sleep -Milliseconds 200
[System.Windows.Forms.SendKeys]::SendWait("e")
} finally {
[WinAPI]::BlockInput($false) | Out-Null
}
}
}
}
} else {
Write-Host "Multiple titles ($titleCount) saved. TV Series Mode: Eject SKIPPED." -ForegroundColor Magenta
}
Write-Host "Playing completion sound..." -ForegroundColor Yellow
for ($i = 1; $i -le 4; $i++) {
[System.Console]::Beep(750, 500)
Start-Sleep -Milliseconds 500
}
$wavPaths = @(
"C:\Program Files (x86)\Elaborate Bytes\CloneDVD2\sounds\success.wav",
"C:\Program Files (x86)\DVD Decrypter\Sounds\Success.wav",
"C:\Program Files (x86)\ImgBurn\Sounds\Success.wav",
"C:\Windows\Media\tada.wav"
)
foreach ($wav in $wavPaths) {
if (Test-Path $wav) {
try {
$player = New-Object System.Media.SoundPlayer
$player.SoundLocation = $wav
$player.PlaySync()
break
} catch { }
}
}
Write-Host "Waiting for the next disc..." -ForegroundColor Cyan
break
}
}
}
}
}
} catch { }
Start-Sleep -Seconds $PollSeconds
}
} finally {
Remove-Item $TempLog -Force -ErrorAction SilentlyContinue
}