Last active
March 28, 2018 00:09
-
-
Save tostka/40e75779978c308883ec89aedf9fb485 to your computer and use it in GitHub Desktop.
convert-ToMp3.ps1 - Movie to Mp3 conversion wrapper script for ffmpeg or VLC player.
This file contains 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
# convert-ToMp3.ps1 | |
<# This gist is TRIMMED to ust the core pieces #> | |
#*================v FUNCTIONS v================ | |
#*----------------v Function convert-ToMp3 v------ | |
function convert-ToMp3 { | |
<# TRIMMED #> | |
[CmdletBinding()] | |
PARAM ( | |
[parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$True,HelpMessage="File(s) to be transcoded")] | |
$InputObject, | |
[parameter(HelpMessage="Bitrate for transcoded output (defaults to 320k)")] | |
[int]$bitrate=320, | |
[parameter(HelpMessage="Samplerate for transcoded output (defaults to 44100)")] | |
[int]$samplerate=44100, | |
[Parameter(Mandatory=$false,HelpMessage="Specify Site to analyze [-Encoder (FFMPEG|VLC]")] | |
[ValidateSet("FFMPEG","VLC")] | |
[string]$encoder="VLC", | |
[Parameter(HelpMessage='ShowProgress [$switch]')] | |
[switch] $showProgress, | |
[Parameter(HelpMessage='Debugging Flag [$switch]')] | |
[switch] $showDebug, | |
[Parameter(HelpMessage='Whatif Flag [$switch]')] | |
[switch] $whatIf | |
) ; # PARAM-E | |
BEGIN { | |
$rgxInputExts="(?i:^\.(MPEG|MP3|AVI|ASF|WMV|WMA|MP4|MOV|3GP|OGG|OGM|MKV|WEBM|WAV|DTS|AAC|AC3|A52|FLAC|FLV|MXF|MIDI|SMF)$)" ; | |
$outputExtension = ".mp3" ; | |
$audio_codec="mp3" ; | |
#"mpga" | |
$channels = 2 ; | |
$mux="dummy" ; # for mp3 audio-only extracts, use the dummy mux | |
#"mpeg1" | |
$progInterval= 500 ; # write-progress interval in ms | |
$iProcd= 0 ; | |
$continue = $true ; | |
$programFiles = ${env:ProgramFiles(x86)}; | |
if($programFiles -eq $null) { $programFiles = $env:ProgramFiles; } ; | |
switch($encoder){ | |
"VLC" {$processName = $programFiles + "\VideoLAN\VLC\vlc.exe" ; } | |
"FFMPEG" {$processName = "C:\apps\ffmpeg\bin\ffmpeg.exe" } | |
} ; | |
if(!(test-path -path $processName)){throw "MISSING/INVALID $($encoder) install path!:$($processName)"} ; | |
write-verbose -verbose:$true "$((get-date).ToString("HH:mm:ss")):=== v PROCESSING STARTED v ===" ; | |
$progParam=@{ | |
CurrentOperation ="Beginning"; | |
Status="Preparing Processing..."; | |
PercentComplete = 0; | |
} ; | |
} # BEG-E ; | |
PROCESS { | |
$ttl = ($InputObject | measure).count ; | |
$iProcd=0 ; $swp = [System.Diagnostics.Stopwatch]::StartNew() ; | |
# foreach, to accommodate arrays passed in | |
foreach($inputFile in $InputObject) { | |
$continue = $true ; | |
try { | |
if($inputfile.GetType().fullname -ne "System.IO.DirectoryInfo"){ | |
switch ($inputfile.GetType().fullname){ | |
"System.IO.FileInfo" { | |
if($tf=Get-childitem -path $inputFile.fullname -ea Stop) { | |
} else { | |
write-host -ForegroundColor red "Unable to read infile: $($inputFile.fullname)" ; | |
throw "MISSING/INVALID inputfile:$($inputFile.fullname)" | |
} ; | |
} ; | |
"System.String" { | |
# if it's a string, it's not going to have a fullname prop - it's a full path string | |
if($tf=Get-childitem -path $inputFile) { | |
} else { | |
write-host -ForegroundColor red "Unable to read infile: $($inputFile.fullname)" ; | |
throw "MISSING/INVALID inputfile:$($inputFile.fullname)" | |
} ; | |
}; | |
default { | |
write-host -ForegroundColor red "Unable to read infile: $($inputFile.fullname)" ; | |
"inputfile.GetType().fullname:$($inputfile.GetType().fullname)" ; | |
throw "UNRECOGNIZED TYPE OBJECT inputfile:$($inputFile.fullname). ABORTING!" ; | |
} ; | |
} ; | |
if($tf.extension -notmatch $rgxInputExts ) {throw "UNSUPPORTED INPUTFILE TYPE:$($inpuptFile)"} ; | |
$outputFileName=(join-path -path $tf.Directory -ChildPath "$($tf.BaseName)$($outputExtension)") ; | |
# Generate a unique filename with a specific extension (non-tmp, leverages the GUID-generating call): | |
$tempout=(join-path -path $tf.Directory -ChildPath "$([guid]::NewGuid().tostring())$($outputExtension)").replace("\","\\") ; | |
$inputFileName=$tf.FullName.replace("\","\\") ; | |
if($showDebug) {write-verbose -verbose:$true "`$outputFileName:$outputFileName`n`$tempout:$($tempout)" } ; | |
switch($encoder){ | |
"VLC" { | |
# build args where we can see whats going on | |
# 1st spec dummy/non-GUI pass, and input filename $($inputFileName) | |
$processArgs = "-I dummy -v `"$($inputFileName)`"" ; | |
if($whatif){ | |
write-verbose -verbose:$true "-whatif detected, test-transcoding only the first 30secs" ; | |
$processArgs+=" --stop-time=30" ; | |
} ; | |
# build output transcode settings | |
$processArgs+= " :sout=#transcode{" ; | |
$processArgs+= "vcodec=none,acodec=$($audio_codec),ab=$($bitrate),channels=$($channels),samplerate=$($samplerate)" ; | |
$processArgs+= "acodec=$($audio_codec),ab=$($bitrate),channels=$($channels),samplerate=$($samplerate)" ; | |
# end output transcode settings | |
$processArgs+="}" ; | |
# add the output file specs & mux | |
$processArgs+=":standard{access=`"file`",mux=$($mux),dst=`"$($tempout)`"}" | |
# tell it to exit on completion | |
$processArgs+=" vlc://quit" ; | |
} | |
"FFMPEG" { | |
$processArgs = "-i `"$($inputFileName)`"" ; | |
# $bitrate=320 | |
$processArgs+= " -ab $($bitrate * 1000)" ; | |
# $samplerate=44100 | |
$processArgs+= " -ar $($samplerate)" ; | |
$processArgs+= " -f mp3" ; | |
$processArgs+= " `"$($tempout)`"" ; | |
} | |
} ; | |
if($showDebug){ | |
write-verbose -verbose:$true "`$processName:$($processName | out-string)" ; | |
write-verbose -verbose:$true "`$processArgs:$($processArgs | out-string)" ; | |
} ; | |
# launch command | |
# capture and echo back errors from robocopy.exe | |
$soutf= [System.IO.Path]::GetTempFileName() ; | |
$serrf= [System.IO.Path]::GetTempFileName() ; | |
"Cmd:$($processName) $($processArgs)" ; | |
$process = Start-Process -FilePath $processName -ArgumentList $processArgs -NoNewWindow -PassThru -Wait -RedirectStandardOutput $soutf -RedirectStandardError $serrf ; | |
switch($process.ExitCode){ | |
0 { | |
"ExitCode 0 returned (No Errors, File converted)" | |
# ren $tempout => $outputFileName | |
if($rf=get-childitem -path $tempout ){ | |
# renames fail if there's an existing fn clash -> ren the clash, -ea 0 to suppress notfound errors | |
if($cf=get-childitem -path ($outputFileName | split-path -Leaf) -ea 0 ){ | |
Rename-Item -path $rf.fullname -NewName "$($cf.BaseName)-$((get-date).tostring('yyyyMMdd-HHmmtt'))$($cf.Extension)" ; | |
} else { | |
Rename-Item -path $rf.fullname -NewName $($outputFileName | split-path -Leaf) | |
}; | |
} else { | |
throw "No matching temporary output file found: $($tmpout)" ; | |
} ; | |
} ; | |
1 {"ExitCode 1 returned (fatal error)"} ; | |
default {write-host "ERROR during VLC Transcoding: Non-0/1 ExitCode returned $($process.ExitCode)" ; write-host "`a" ;} ; | |
} ; | |
if((get-childitem $soutf).length){ | |
if($ShowDebug){(gc $soutf) | out-string ;} ; | |
remove-item $soutf ; | |
} ; | |
if((get-childitem $serrf).length){ | |
if($ShowDebug){(gc $serrf) | out-string ;} ; | |
remove-item $serrf ; | |
} ; | |
$iProcd++ ; | |
[int]$pct = ($iProcd/$ttl)*100 ; | |
} else { | |
# code leak to throw out directories | |
# System.IO.DirectoryInfo | |
"(Skipping $($inputfile) -- Directory)" ; | |
} ; | |
} catch { | |
# BOILERPLATE ERROR-TRAP | |
<# TRIMMED #> | |
write-output "$((get-date).ToString("HH:mm:ss") ): Error Details: $($_)" ; | |
Continue ; | |
# Exit; here if you want processing to die and not continue on next for-pass | |
} # try/cat-E ; | |
} # # loop-E ; | |
} # PROC-E ; | |
END { | |
write-verbose -verbose:$true "$((get-date).ToString("HH:mm:ss")):$($iProcd) conversions processed" ; | |
write-verbose -verbose:$true "$((get-date).ToString("HH:mm:ss")):=== ^ PROCESSING COMPLETE ^ ===" ; | |
} # END-E | |
} #*----------------^ END Function convert-ToMp3 ^-------- | |
#*================^ END FUNCTIONS ^================ | |
#*================v SUB MAIN v================ | |
<# TRIMMED #> | |
$error.clear() ; | |
TRY { | |
$useTempDir=$false ; | |
if ($InputObjec -is [system.array]){ | |
$oPath = (split-path -Path $InputObject.fullname -Parent)[0] ; | |
} else { | |
$opath = (split-path -Path $InputObject.fullname -Parent) ; | |
} | |
if( $oPath -match "(\,|')"){ | |
# also need to detect ''s in the path | |
write-host "$((get-date).ToString('HH:mm:ss')):Banned Char detected in input path (causes VLC path-misparses)`nusing temp directory for all processing."; | |
#exit; | |
$useTempDir=$true ; | |
} | |
[array]$opfiles =@() ; [array]$renfiles =@() ; | |
foreach ($i in $InputObject){ | |
if ($i.mode.substring(0,1) -ne "d") { | |
if($i.name -match "(\[|\])"){ | |
$name = $i.name.replace("[","_").replace("]","_") ; | |
$npath=(join-path -path $i.Directory -childpath "$($name)") ; | |
$spath=$i.fullname ; | |
write-host -foregroundcolor green "Square-brackets in file name: Renaming to $($name): " ; | |
if($showDebug){"`$spath:$($spath)`nto `$npath:$($npath)`n"; } ; | |
[System.IO.File]::Move($spath, $npath ) ; | |
$renfiles+=$spath ; | |
$opfiles+=$npath ; | |
} else { | |
$opfiles+= $i.fullname ; | |
} ; | |
} else { | |
write-host -foregroundcolor green "Skipping dir object: $($i.name)" ; | |
} ; | |
} # loop-E | |
if($host.version.major -ge 3){ | |
$fSplat=[ordered]@{ | |
Dummy = $null ; | |
} ; | |
} else { | |
$fSplat = New-Object Collections.Specialized.OrderedDictionary ; | |
} ; | |
If($fSplat.Contains("Dummy")){$fSplat.remove("Dummy")} ; | |
# Populate the $fSplat with fields, post creation | |
if($useTempDir){ | |
# capture pwd | |
$sdir=get-location ; | |
push-location ; | |
$TempDir = [System.Guid]::NewGuid().ToString() | |
# create temporary folder (this creates it as a sub of the pwd, unless you pre set-location) | |
set-location ([System.IO.Path]::GetTempPath()) ; | |
$bout=New-Item -Type Directory -Name $TempDir ; # create the tmpdir in the profle temp path (C:\Users\MyAccount\AppData\Local\Temp\) | |
Set-Location $TempDir | |
write-host "Processing conversion in temp dir:$((get-location).path)" ; | |
copy-item $opfiles -Destination (get-location) ; | |
get-childitem | %{ | |
if($_){ | |
$fSplat.Add("InputObject",$($_)) ; | |
} else {throw "INVALID/MISSING -InputObject!. ABORTING!" }; | |
} ; | |
} else { | |
# if squarebracket ren'd, we can't use inputobj | |
if($renfiles){ | |
$fSplat.Add("InputObject",$($opfiles)) | |
} elseif($InputObject){$fSplat.Add("InputObject",$($InputObject))} | |
else {throw "INVALID/MISSING -InputObject!. ABORTING!" }; | |
} | |
if($bitrate){$fSplat.Add("bitrate",$($bitrate))} ; | |
if($samplerate){$fSplat.Add("samplerate",$($samplerate))} ; | |
if($showDebug){$fSplat.Add("showDebug",$($showDebug))} ; | |
if($whatif){$fSplat.Add("whatif",$($whatif))} ; | |
if($showProgress){$fSplat.Add("showProgress",$($showProgress))} ; | |
# 8:21 PM 5/3/2017 | |
if($encoder){$fSplat.Add("encoder",$($encoder))} ; | |
} CATCH { | |
Write-Error "$(get-date -format "HH:mm:ss"): Failed processing $($_.Exception.ItemName). `nError Message: $($_.Exception.Message)`nError Details: $($_)" ; | |
if($sDir){set-location $sDir} ; # return to $sdir | |
Exit #Opts: STOP(debug)|EXIT(close)|Continue(move on in loop cycle) | |
} # try/catch-E ; | |
if($showDebug){write-host -foregroundcolor green "Conv Params`$fsplat:$($fsplat | out-string)" ; } | |
$bRet=convert-ToMp3 @fSplat ; | |
Try { | |
# if we cached, need to move the mp3 back to original dir, and remove all else | |
if($useTempDir){ | |
write-host -foregroundcolor green "$((get-date).ToString('HH:mm:ss')):Cleaning up temp cache directory..." ; | |
Move-Item -path .\*.mp3 -Destination $oPath ; | |
Remove-Item *.* -Force ; # Remove everything we put in our temporary folder | |
Set-Location .. # go one level up | |
Remove-Item $TempDir # And delete our temporary folder | |
set-location $sDir ; # return to $sdir | |
} ; | |
# if renamed need to restore the name | |
if($fRename -eq $true){ | |
rename-item -path (join-path -path (get-location) -childpath $ftempname) -newname $origname ; | |
} | |
} CATCH { | |
Write-Error "$(get-date -format "HH:mm:ss"): Failed processing $($_.Exception.ItemName). `nError Message: $($_.Exception.Message)`nError Details: $($_)" ; | |
if($sDir){set-location $sDir} ; # return to $sdir | |
Exit #Opts: STOP(debug)|EXIT(close)|Continue(move on in loop cycle) | |
} # try/catch-E ; | |
<# TRIMMED #> | |
#*================^ END SUB MAIN ^================ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment