# Converts videos to HEVC for given path: # https://github.com/rigaya/NVEnc/releases #----------------------------------------------------------------------- # Edit the $videoPath variable to point to your video-files folder: $videoPath = 'M:\1_movies\_main.movies\' #$videoPath = 'M:\2_serien\_main.series\' #----------------------------------------------------------------------- # HEVC profiles: main, main10, main444 $profile = 'main10' $forceReviewAll = $false # If set to $true all failed conversions are reviewed even those that are obviously corrupt. $NVEncoder = "$PSScriptRoot\encoder\NVEncC64.exe" $fileTester = "$PSScriptRoot\mediainfo.exe" $reviewPlayer = "C:\Program Files\VideoLAN\VLC\vlc.exe" ############################################################################################################# # Testing and conversion preparations # ############################################################################################################# if(!(Test-Path $NVEncoder -PathType leaf)) { Write-Host "NVEncC64.exe not found, please check path in `"$NVEncoder`"." -ForegroundColor Yellow Read-Host -Prompt "Press Enter to exit" exit } # Get video list from provided path: $videos = Get-ChildItem -LiteralPath $videoPath -Name -Recurse -Include ('*.mp4', '*.mkv') #('*.avi', '*.mp4', '*.mkv') - avi currently doesn't work. # Instantiating used variables: $videoID = 1 $convertedVideos = 0 $notConvertedVideos = 0 $failedVideos = 0 # Square brackets are used as wildcards in Powershell. # To recognize this as normal text, the LogWite function uses the -LiteralPath parameter instead of the -Path parameter. $logFolderName = $((Get-Date).tostring("dd-MM-yyyy") + ' - [run started at ' + (Get-Date).tostring("HH-mm") + ']') $count = $videos.Count if($videos.Count -lt 1) { Write-Host "No videos found in: $videoPath" -ForegroundColor Red Read-Host -Prompt "Press Enter to exit" exit } # Log write function: Function LogWrite { Param ([string]$logstring) Add-content -LiteralPath $Logfile -value $logstring } # Create new log directory: New-Item -itemType Directory -Path $PSScriptRoot\logs\ -Name $logFolderName > $null # Calculates the total size of the given directory in GB: Write-Host "Inizialization in progress.." $folderSizeInGB = "{0:N2} GB" -f ((Get-ChildItem $videoPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1GB) Clear-Host # Clears the upper message from the window ############################################################################################################# # END - Testing and conversion preparations ############################################################################################################# # Main conversion process # ############################################################################################################# Write-Host "Found $count videos with a total size of $folderSizeInGB - starting converter.." -ForegroundColor Cyan Write-Host Write-Host Write-Host "------------------------------------------------------------------------------------------------" foreach($video in $videos) { # Check filename for '-HVEC' string and skip filetester if true to make it run faster with lots of files already converted if(! $video -match "-HVEC") { $video = $video.Replace("`"", "") $inputFile = $videoPath + $video # Get and check File info for codec, if it's already HEVC: - JSON query: (['media']['track'][1]['Format']) $fileDetails = cmd /c $fileTester $inputFile --Output=JSON | ConvertFrom-Json $codec = $fileDetails.media.track[1].Format #echo $codec } else {} $codec = 'HVEC' } # If not already HEVC, convert video using NVEncC64: if($codec -ne "HEVC") { # Configure new file naming: if ($video -match "264") { $outputFile = $videoPath + $video.Replace("264", "265") } else { $outputFile = $videoPath + $video.Insert(($video.Length - 4), '-HEVC') } Write-Host "Analyzing video ($videoID of $count), starting convertion of number: $($convertedVideos + 1) please wait.." -ForegroundColor Magenta Write-Host "$video `nto:`n$outputFile" -ForegroundColor White Write-Host # If the Subtitles should not be copied, delete the "--sub-copy 1,2" argument. $arguments = "--input `"$inputFile`" --codec hevc --audio-copy 1,2,3,4,5,6 --sub-copy 1,2,3,4,5,6 --profile $profile --output `"$outputFile`"" Start-Process $NVEncoder -ArgumentList $arguments -WindowStyle Minimized $processName = 'NVEncC64' Start-Sleep -Seconds 8 # Sets to use 3 cores (always set to one less core that your CPU has) # 2 Cores = 3, 3 Cores = 7, 4 cores = 15, 5 cores = 31, 6 cores = 63 # Code to calculate for your CPU: # $noOfCores = Get-WmiObject Win32_Processor | Measure-Object NumberOfLogicalProcessors -Sum # $noOfCores.Sum = $noOfCores.Sum - 1 # [math]::Pow(2,$($noOfCores).Sum) - 1 # $process = Get-Process $processName; $process.ProcessorAffinity=7 Start-Sleep -Seconds 8 # Sets priorty to High # Values: High, AboveNormal, Normal, BelowNormal, Low $process = Get-Process -Id $process.Id $process.PriorityClass = 'High' # Waits for process to complete $processID = (Get-Process $processName).id Wait-Process -Id $processID if(Test-Path -LiteralPath $outputFile) # Specifies a path to be tested. Unlike Path, the value of the LiteralPath parameter is used exactly as it is typed. #No characters are interpreted as wildcard characters. { Write-Host "CONVERSION DONE! FILE: `"$outputFile`" FOUND" -ForegroundColor Yellow Start-Sleep -Seconds 4 # Check if File is valid; the duration of video must be the same! (['media']['track'][0]['Duration']): $fileDetails_new = cmd /c $fileTester $outputFile --Output=JSON | ConvertFrom-Json # This code gets the duration and splits it in two parts, only the part before the "." is needed: $StreamSize_old,$notused = $($fileDetails.media.track[0].Duration).split('.') $StreamSize_new,$notused = $($fileDetails_new.media.track[0].Duration).split('.') Write-Host Write-Host "Old Duration was: $StreamSize_old `nnew Duration is: $StreamSize_new" -ForegroundColor White Write-Host if ($StreamSize_new -eq $StreamSize_old) { # Delete old video File! Write-Host "Conversion Successful! - Deleting old file.." Write-Host Write-Host "------------------------------------------------------------------------------------------------" Remove-Item -LiteralPath $inputFile $convertedVideos = $convertedVideos + 1 $Logfile = "$PSScriptRoot\logs\$logFolderName\successfully_converted.log" LogWrite "$outputFile" } else { if (($StreamSize_new -eq $($StreamSize_old - 1)) -or ($($StreamSize_new - 1) -eq $StreamSize_old)) { # Newly converted file does not match exactly the old duration! Write-Host "Conversion Done! - But streamsize is not exactly the same. - Please review!" Write-Host Write-Host "------------------------------------------------------------------------------------------------" $review = $true $convertedVideos = $convertedVideos + 1 $Logfile = "$PSScriptRoot\logs\$logFolderName\review_needed.log" LogWrite "$inputFile,$outputFile" } else { if ($forceReviewAll) { # Mark probably corrupted file for review Write-Host "Conversion Failed! - Marked for review! because it is desired." Write-Host Write-Host "------------------------------------------------------------------------------------------------" $review = $true $convertedVideos = $convertedVideos + 1 $Logfile = "$PSScriptRoot\logs\$logFolderName\review_needed.log" LogWrite "$inputFile,$outputFile" } else { # Delete obviously corrupt File! Write-Host "Conversion Failded! - Deleting new converted file.." -ForegroundColor Red Write-Host Write-Host "------------------------------------------------------------------------------------------------" Remove-Item -LiteralPath $outputFile $failedVideos = $failedVideos + 1 $notConvertedVideos = $notConvertedVideos + 1 $Logfile = "$PSScriptRoot\logs\$logFolderName\error_during_conversion.log" LogWrite "$inputFile,$StreamSize_new,$StreamSize_old," } } } } } else { # Alert if video doesn't need conversion: Write-Host "Analyzing video ($videoID of $count) - skip" -ForegroundColor Magenta Write-Host "$video is already in correct format!" -ForegroundColor Green Write-Host Write-Host "------------------------------------------------------------------------------------------------" # Increments not converted video counter: $notConvertedVideos = $notConvertedVideos + 1 $Logfile = "$PSScriptRoot\logs\$logFolderName\skipped_files.log" LogWrite "$inputFile" } # Increments video counter: $videoID = $videoID + 1 $outputFile = "" # Resets the variable to nothing, that in case of an error the old file is not affected. } ############################################################################################################# # END - Main conversion process ############################################################################################################# # Evaluation part of the conversion script # ############################################################################################################# if ($review) { Write-Host "There are some files to review.. Starting reviewing first file." Write-Host $review_count = 1 foreach($review_pair in Get-Content -LiteralPath "$PSScriptRoot\logs\$logFolderName\review_needed.log") { $oldFile,$newFile = $review_pair.split(',') Write-Host "Playing $review_count converted file: $newFile" Write-Host # Starting VLC Player with the file to review Start-Process $reviewPlayer -ArgumentList `"$newFile`" Start-Sleep -Seconds 6 # Wait until player is closed. $processID = (Get-Process "vlc").id Wait-Process -Id $processID $msg = 'Do you want to keep the newly converted file and delete the old? (N for deleting NEW-file) [Y/N]' do { $response = Read-Host -Prompt $msg } until (($response -eq 'n') -or ($response -eq 'y')) if ($response -eq 'y') { Write-Host "delete old file, keep newly converted.." $to_delete = $oldFile } else { Write-Host "delete newly converted, keep old file" $to_delete = $newFile $failedVideos = $failedVideos + 1 $convertedVideos = $convertedVideos - 1 } Write-Host "DELETED: $to_delete" -ForegroundColor Red #Remove-Item -LiteralPath $to_delete Write-Host "------------------------------------------------------------------------------------------------" Start-Sleep -Seconds 2 } } Write-Host "Final calculations are in progress.." $folderSizeInGB2 = "{0:N2} GB" -f ((Get-ChildItem $videoPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1GB) if($notConvertedVideos -eq 0) { Write-Host "Finished converted $convertedVideos out of $count videos." -ForegroundColor Green } else { if($failedVideos -eq 0) { Write-Host "Finished converted $convertedVideos out of $count videos. - $notConvertedVideos where not converted because of already correct codec!" -ForegroundColor Green } else { Write-Host "Finished converted $convertedVideos out of $count videos. - $notConvertedVideos where not converted because error or already correct codec!!" -ForegroundColor Green Write-Host "$failedVideos have failed!" -ForegroundColor Red } } Write-Host "Directory size before conversion: $folderSizeInGB" Write-Host "Directory size after conversion: $folderSizeInGB2" Read-Host -Prompt "Press Enter to exit" ############################################################################################################# # END - conversion script