-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVideoFileResizer.ps1
More file actions
249 lines (228 loc) · 11.2 KB
/
VideoFileResizer.ps1
File metadata and controls
249 lines (228 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
Param(
$TvShowDir = "C:\Temp\Shows",
$MovieDir = "C:\Temp\Movies",
$TvShowSize = 1GB,
$MovieSize = 2GB,
$Format = "mp4",
$Program = "ffmpeg", #ffmpeg or HandBrake
$Logging = "Console" #Console,PerFile,SingleLog Console drops all info to console window, perfile creates a new log for each file, singlefile will create a new file for each day.
)
# Specify directory for HandBrake and ffmpeg
$HandBrakeDir = "C:\Users\$env:USERNAME\Downloads\HandBrakeCLI-1.3.2-win-x86_64"
$ffmpegBinDir = "C:\Users\$env:USERNAME\Downloads\ffmpeg\bin"
# Set the conversion string we want to use for both programs
if($Program -eq "HandBrake"){
# HandBrake options, add or remove if you don't like them. Full list: https://handbrake.fr/docs/en/latest/cli/command-line-reference.html
$Executable = "HandBrakeCLI.exe" #Program executalbe file name.
$ExecutableDir = $HandBrakeDir
$HandBrakeOptions = @()
$HandBrakeOptions += "-f" #Format flag
$HandBrakeOptions += $Format #Format value (MKV or MP4 specified earlier)
$HandBrakeOptions += "-a" #Audio channel flag
$HandBrakeOptions += "1,2,3,4,5,6,7,8,9,10" #Audio channels to scan
$HandBrakeOptions += "-e" #Output video codec flag
$HandBrakeOptions += "x264" #Output using x264
$HandBrakeOptions += "--encoder-preset" #Encode speed preset flag
$HandBrakeOptions += "slow" #Encode speed preset
$HandBrakeOptions += "--encoder-profile" #Encode quality preset flag
$HandBrakeOptions += "high" #Encode quality preset
$HandBrakeOptions += "--encoder-level" #Profile version to use for encoding flag
$HandBrakeOptions += "4.1" #Encode profile value
$HandBrakeOptions += "-q" #CFR flag
$HandBrakeOptions += "27" #CFR value (Higher is less quality)
$HandBrakeOptions += "-E" #Audio codec flag
$HandBrakeOptions += "aac" #Specify AAC to use as the audio codec
$HandBrakeOptions += "--audio-copy-mask" #Permitted audio codecs for copying flag
$HandBrakeOptions += "aac" #Set only AAC as allowed for copying
$HandBrakeOptions += "--verbose=1" #Logging level
$HandBrakeOptions += "--decomb" #Deinterlace video flag
$HandBrakeOptions += "--loose-anamorphic" #Try and keep source aspect ratio
$HandBrakeOptions += "--modulus" #Modulus flag
$HandBrakeOptions += "2" #Modulus value
}
if($Program -eq "ffmpeg"){
$Executable = "ffmpeg.exe" #Program executalbe file name.
$ExecutableDir = $ffmpegBinDir
# ffmpeg options, add or remove if you don'y like them. Full list: https://ffmpeg.org/ffmpeg.html#Options
$ffmpegOptions = @()
#$ffmpegOptions += "-map_metadata" #Map metadata flag
#$ffmpegOptions += "-1" #Clear all file meta data
$ffmpegOptions += "-c:v" #Video codec flag
$ffmpegOptions += "libx264" #Specify x264 as the codec
$ffmpegOptions += "-preset" #Preset flag
$ffmpegOptions += "fast" #Use fast preset
$ffmpegOptions += "-crf" #CRF flag
$ffmpegOptions += "27" #CRF value (Higher is less quality)
$ffmpegOptions += "-c:a" #Audio codec flag
$ffmpegOptions += "aac" #Specify aac for audio codec
$ffmpegOptions += "-hide_banner" #Hide top banner on each encode
}
# Validate we are on powershell 5.1 or higher
$Version = "$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)"
if($Version -lt 5.1){
Write-Host "Powershell version is $Version please upgrade to 5.1 from here: https://www.microsoft.com/en-us/download/details.aspx?id=54616 Quitting" -ForegroundColor Red
Read-Host "Press Enter to exit..."
exit
}
# Create Variable for storing the current directory
if (!$WorkingDir){
$WorkingDir = (Resolve-Path .\).Path
}
# Check to see if the exacuteable exists
if(-not(Test-Path("$ExecutableDir\$exacuteable"))){
Write-Host "$exacuteable not found in $ExecutableDir Please make sure that $program is installed. Quitting" -ForegroundColor Red
Read-Host "Press Enter to exit..."
exit
}
# Check to see if $MovieDir exists
if(-not(Test-Path("$MovieDir"))){
Write-Host "Movie directory: $MovieDir not found. Please make sure the path is correct. Quitting" -ForegroundColor Red
Read-Host "Press Enter to exit..."
exit
}
# Check to see if $TvShowDir exists
if(-not(Test-Path("$TvShowDir"))){
Write-Host "Tv Show directory: $TvShowDir not found. Please make sure the path is correct. Quitting" -ForegroundColor Red
Read-Host "Press Enter to exit..."
exit
}
# Output that we are finding file
Write-Host "Finding Movie files over $($MovieSize/1GB)GB in $MovieDir and Episodes over $($TvShowSize/1GB)GB in $TvShowDir be patient..." -ForegroundColor Gray
# Set variables so we can get number of files while scanning
$b = 0
$i = 0
# Get all items in both folders that are greater than the specified size and sort them largest to smallest
$LargeTVEpisodes = Get-ChildItem -Path $TvShowDir -Recurse -File | Where-Object {$_.Length -gt $TvShowSize} | ForEach-Object {$b++; If ($b -eq 1){Write-Host -NoNewLine "`rFound $b file so far..."} Else{Write-Host -NoNewLine "`rFound $b files so far..." -foregroundcolor green};$_}
$LargeMovies = Get-ChildItem -Path $MovieDir -Recurse -File | Where-Object {$_.Length -gt $MovieSize} | ForEach-Object {$b++; If ($b -eq 1){Write-Host -NoNewLine "`rFound $b file so far..."} Else{Write-Host -NoNewLine "`rFound $b files so far..." -foregroundcolor green};$_}
$LargeFiles = $LargeTVEpisodes + $LargeMovies | Sort-Object Length -Descending
# If no large files are found then write that out
If($LargeFiles -eq $null){
Write-Host "No Movies over $($MovieSize/1GB)GB in $MovieDir and no Episodes over $($TvShowSize/1GB)GB in $TvShowDir found. Exiting"
exit
}
# Get total file count so we can display progress
$num = $LargeFiles | measure
$fileCount = $num.count
# Create the Conversion Completed Spreadsheet if it does not exist
$ConversionCSV = "$WorkingDir\ConversionsCompleted.csv"
If(-not(Test-Path $ConversionCSV)){
$headers = "File Name", "Completed Date"
$psObject = New-Object psobject
foreach($header in $headers){
Add-Member -InputObject $psobject -MemberType noteproperty -Name $header -Value ""
}
$psObject | Export-Csv $ConversionCSV -NoTypeInformation
$ConversionCSV = Resolve-Path -Path $ConversionCSV
}
#Create Hash table to check against before starting conversions. This will prevent converting items that have already been converted (This spreadsheet updates automatically)
$CompletedTable = Import-Csv -Path $ConversionCSV
$HashTable=@{}
foreach($file in $CompletedTable){
$HashTable[$file."File Name"]=$file."Completed Date"
}
# Convert the file using -NEW at the end
foreach($File in $LargeFiles){
# Incriment $i so we can update progress
$i++;
# Build the name of the file as we want it to be after the conversion and rename
$FinalName = "$($File.Directory)\$($File.BaseName).$Format"
# Check the Hash table we created from the Conversions Completed spreadsheet. If it exists skip that file
if(-not($HashTable.ContainsKey("$FinalName"))){
# File name + "-NEW.$Format" we want it to be an $FileFormat file and we don't want to overwrite the file we are reading from if it is already a .$FileFormat
$OutputFile = "$($File.Directory)\$($File.BaseName)-NEW.$Format"
# Check that the Output file does not already exist, if it does delete it so the new conversions works as intended.
if(Test-Path $OutputFile){
Remove-Item $OutputFile -Force
}
# Change the CPU priorety of $Executable to below Normal in 10 seconds so that the conversion has started
Start-Job -ScriptBlock {
Start-Sleep -s 10
$p = Get-Process -Name $Executable
$p.PriorityClass = [System.Diagnostics.ProcessPriorityClass]::BelowNormal
} | Out-Null
#region Logging
if($Logging -ne "Console") {
# Create the Logs directory if it does not exist
$LogFileDir = "$WorkingDir\Logs"
if(!(Test-Path($LogFileDir))){
New-Item -ItemType Directory -Force -Path $LogFileDir | Out-Null
}
}
If($Logging -eq "PerFile"){
# Build Log file name
$LogFileName = $File.BaseName -replace '[[\]]',''
$LogPath = "$LogFileDir\$LogFileName.txt"
if($Program -eq "ffmpeg"){
$ffmpegOptions += "-nostats" #Specify not to send stats to the log file (Logs will get huge without this but you can comment out for testing)
}
}
If($Logging -eq "SingleLog"){
# Get date info
$Date = Get-Date
if(!(Test-Path -path "$LogFileDir\$($Date.Year)\$($Date.Month)\$($Date.Day)")){
New-Item -path "$LogFileDir\$($Date.Year)\$($Date.Month)\$($Date.Day)" -type Directory | Out-Null
}
# Build Log file name
$LogFileName = "Conversions"
$LogPath = "$LogFileDir\$($Date.Year)\$($Date.Month)\$($Date.Day)\$LogFileName.txt"
if($Program -eq "ffmpeg"){
$ffmpegOptions += "-nostats" #Specify not to send stats to the log file (Logs will get huge without this but you can comment out for testing)
}
}
#endregion
# Input file
$InputFile = $File.FullName
# Write that we are starting the conversion
$progress = ($i / $fileCount) * 100
$progress = [Math]::Round($progress,2)
Write-Host "File $i of $fileCount - Total queue $progress%"
$StartingFileSize = $File.Length/1GB
Write-Host "Starting conversion on $InputFile it is $([math]::Round($StartingFileSize,2))GB in size before conversion" -ForegroundColor Cyan
if($Program -eq "HandBrake"){
if($Logging -eq "Console"){
& $HandBrakeDir\HandBrakeCLI.exe -i "$InputFile" -o "$OutputFile" $HandBrakeOptions
}
else{
& $HandBrakeDir\HandBrakeCLI.exe -i "$InputFile" -o "$OutputFile" $HandBrakeOptions 2> $LogPath
}
}
if($Program -eq "ffmpeg"){
if($Logging -eq "Console"){
& $ffmpegBinDir\ffmpeg.exe -i "$InputFile" $ffmpegOptions "$OutputFile"
}
else{
& $ffmpegBinDir\ffmpeg.exe -i "$InputFile" $ffmpegOptions "$OutputFile" 2> $LogPath
}
}
# Check to make sure that the output file actuall exists so that if there was a conversion error we don't delete the original
if($Error.Count -eq 0){
if(Test-Path $OutputFile){
Remove-Item $InputFile -Force
Rename-Item $OutputFile $FinalName
Write-Host "Finished converting $FinalName" -ForegroundColor Green
$EndingFile = Get-Item $FinalName | Select-Object Length
$EndingFileSize = $EndingFile.Length/1GB
Write-Host "Ending file size is $([math]::Round($EndingFileSize,2))GB so, space saved is $([math]::Round($StartingFileSize-$EndingFileSize,2))GB" -ForegroundColor Green
# Add the completed file to the completed csv file so we don't convert it again later
$csvFileName = "$FinalName"
$csvCompletedDate = Get-Date -UFormat "%x - %I:%M %p"
$hash = @{
"File Name" = $csvFileName
"Completed Date" = $csvCompletedDate
}
$newRow = New-Object PsObject -Property $hash
Export-Csv $ConversionCSV -inputobject $newrow -append -Force
}
}
# If file not found write that the conversion failed.
elseif ((!(Test-Path $OutputFile)) -Or ($Error.Count -gt 0)){
$Error.Clear()
Write-Host "Failed to convert $InputFile" -ForegroundColor Red
}
}
# If file exists in Conversions Completed Spreadsheet write that we are skipping the file because it was already converted
elseif($HashTable.ContainsKey("$FinalName")){
$CompletedTime = $HashTable.Item("$Finalname")
Write-Host "Skipping $FinalName because it was already converted on $CompletedTime." -ForegroundColor DarkGreen
}
}