CCCPaste

Batch Video Cutter & Encoder - Kontextmen...

# Dieses Skript komprimiert alle markierten .mp4-Dateien über das Kontextmenü per FFmpeg mit einem wählbaren CRF-Wert als H.265 oder AV1. Der ursprüngliche Zeitstempel (Änderungsdatum) der Datei wird im Nachhinein neu gesetzt, und die Ausgabedateien erhalten angepasste Namen (_crfXX.mp4 bzw. mit AV1 _AV1_crfXX.mp4). Bei Videos, die von einer DJI Action Kamera oder der DJI Mimo App stammen, wird automatisch das Datum aus dem Dateinamen verwendet, unabhängig von dem Änderungsdatum. Zusätzlich wird die Zeitzone aus der Abfrage berücksichtigt.

# Pfade in install_menu.reg anpassen, wo video_compress.ps1 liegt
# "ffmpeg-release-essentials.zip" hier herunterladen, entpacken und aus dem Ordner "bin" die ffmpeg.exe und ffprobe.exe in das Verzeichnis $ToolDir kopieren: https://www.gyan.dev/ffmpeg/builds/
# "exiftool-XXX.zip" hier herunterladen, entpacken, in das Verzeichnis $ToolDir kopieren und die .exe-Datei umbenennen in "exiftool.exe": https://exiftool.org/
:: Version 1.0.1-pub - 14.01.2026

$ToolDir = "X:\PFAD\ZU\assets"

param (
	[string]$FilePath,
	[int]$CRF = 25,
	[string]$Codec = "HEVC"
)

$FFmpeg = Join-Path $ToolDir "ffmpeg.exe"
$FFprobe = Join-Path $ToolDir "ffprobe.exe"
$ExifTool = Join-Path $ToolDir "exiftool.exe"

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Helper für ExifTool (verhindert Null-Reference)
function Get-ExifTag {
	param([string]$Tag, [string]$Path)
	$val = & $ExifTool -s3 -api "QuickTimeUTC" $Tag $Path | Out-String
	return $val.Trim()
}

# --- 1. Datei-Check ---
$File = Get-Item -LiteralPath $FilePath
$BaseName = $File.BaseName

# Suffix und Codec-Einstellungen festlegen
if ($Codec -eq "AV1") {
	$Suffix = "_AV1_crf$CRF"
	# CPU-Used Logik für AV1
	if ($CRF -le 20) { $CpuUsed = 2 }
	elseif ($CRF -le 28) { $CpuUsed = 4 }
	elseif ($CRF -le 35) { $CpuUsed = 6 }
	else { $CpuUsed = 8 }
	$VArgs = "-c:v libaom-av1 -crf $CRF -cpu-used $CpuUsed -pix_fmt yuv420p"
} else {
	$Suffix = "_crf$CRF"
	$VArgs = "-c:v libx265 -crf $CRF -preset slow -pix_fmt yuv420p -tag:v hvc1"
}

$OutFile = Join-Path $File.DirectoryName "$($BaseName)$($Suffix).mp4"

# Prüfung: Bereits verarbeitetes Video
if ($File.BaseName -match "(_crf\d+|_AV1_crf\d+)$") {
	[System.Windows.Forms.MessageBox]::Show("Ignoriert: $($File.Name) ist bereits ein verarbeitetes Video.", "Info")
	exit
}

# Prüfung: Existiert die Zieldatei bereits?
if (Test-Path -LiteralPath $OutFile) {
	[System.Windows.Forms.MessageBox]::Show("Ignoriert: Die Datei existiert bereits:`n$($OutFile)", "Info")
	exit
}

# Prüfung: Gültiges Video
$Duration = & $FFprobe -v error -select_streams v:0 -show_entries format=duration -of default=nokey=1:noprint_wrappers=1 "$FilePath" | Out-String
if ([string]::IsNullOrWhiteSpace($Duration)) {
	[System.Windows.Forms.MessageBox]::Show("Fehler: $($File.Name) ist keine gültige Videodatei.", "Fehler")
	exit
}

# --- 2. GUI Setup ---
$Form = New-Object System.Windows.Forms.Form
$Form.Text = "Video Encoder - 1.1.0 @nurjns"
$Form.Size = New-Object System.Drawing.Size(450, 160)
$Form.StartPosition = "CenterScreen"
$Form.FormBorderStyle = "FixedDialog"
$Form.MaximizeBox = $false
$Form.TopMost = $true

$Label = New-Object System.Windows.Forms.Label
$Label.Location = New-Object System.Drawing.Point(15, 20)
$Label.Size = New-Object System.Drawing.Size(400, 40)
$Label.Text = "Analysiere Metadaten..."

$ProgressBar = New-Object System.Windows.Forms.ProgressBar
$ProgressBar.Location = New-Object System.Drawing.Point(15, 70)
$ProgressBar.Size = New-Object System.Drawing.Size(400, 23)
$ProgressBar.Style = "Marquee"

$Form.Controls.AddRange(@($Label, $ProgressBar))

# --- 3. Metadaten-Logik ---
$Offset = Get-ExifTag "-OffsetTimeOriginal" "$FilePath"
if ([string]::IsNullOrWhiteSpace($Offset)) { $Offset = Get-ExifTag "-OffsetTime" "$FilePath" }
if ([string]::IsNullOrWhiteSpace($Offset)) {
	$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById("W. Europe Standard Time")
	$Offset = if ($TZ.IsDaylightSavingTime((Get-Date))) { "+02:00" } else { "+01:00" }
}

$Timestamp = ""
if ($BaseName -match "^DJI_(\d{14})_") {
	$dt = $Matches[1]
	$Timestamp = "$($dt.Substring(0,4)):$($dt.Substring(4,2)):$($dt.Substring(6,2)) $($dt.Substring(8,2)):$($dt.Substring(10,2)):$($dt.Substring(12,2))"
} elseif ($BaseName -match "dji_mimo_(\d{8})_(\d{6})") {
	$d = $Matches[1]; $t = $Matches[2]
	$Timestamp = "$($d.Substring(0,4)):$($d.Substring(4,2)):$($d.Substring(6,2)) $($t.Substring(0,2)):$($t.Substring(2,2)):$($t.Substring(4,2))"
} else {
	$Timestamp = Get-ExifTag "-CreateDate" "$FilePath"
	if ([string]::IsNullOrWhiteSpace($Timestamp) -or $Timestamp -eq "0000:00:00 00:00:00") {
		$Timestamp = $File.LastWriteTime.ToString("yyyy:MM:dd HH:mm:ss")
	}
}

# --- 4. Prozess-Start ---
$Form.Add_Shown({
	$Label.Text = "Encoding läuft ($Codec)...`nCRF: $CRF | Offset: $Offset"
	
	$CommonArgs = "-y -i `"$FilePath`" $VArgs -movflags +faststart -c:a aac -b:a 160k `"$OutFile`""
	$Process = Start-Process -FilePath $FFmpeg -ArgumentList $CommonArgs -NoNewWindow -PassThru -Wait
	
	if ($Process.ExitCode -eq 0) {
		$Label.Text = "Schreibe Metadaten..."
		& $ExifTool -overwrite_original "-DateTimeOriginal=$Timestamp$Offset" "-OffsetTimeOriginal=$Offset" "-FileModifyDate=$Timestamp" "$OutFile"
		$Label.Text = 'Kodierung erfolgreich!'
		[console]::Beep(500,200)
		Start-Sleep -Seconds 2
	} else {
		[System.Windows.Forms.MessageBox]::Show("Fehler beim Encoding!", "Fehler")
		[console]::Beep(200,200)
	}
	$Form.Close()
})

$Form.ShowDialog()