Skip to content

Instantly share code, notes, and snippets.

@khaosx
Last active June 5, 2021 22:26
Show Gist options
  • Save khaosx/32774efa7ce110d0be9a908faf86f12c to your computer and use it in GitHub Desktop.
Save khaosx/32774efa7ce110d0be9a908faf86f12c to your computer and use it in GitHub Desktop.
Convert media using Don Melton's Other Video Transcoding
########################################################
# hw-convert-media
##################################################-kan-#
<#
.Synopsis
This script will create batch files to convert media using Don Melton's Other Video Transcoding project.
.DESCRIPTION
This script examines all .mkv files located in a specified directory to determine appropriate transcoding options based around Don Melton's Other Video Transcoding project(see links).
Once examined, .cmd files will be generated for each file for later processing.
.EXAMPLE
hw-convert-media.ps1 -mode [mode]
Sets the script options based on what kind of output is desired.
hw-convert-media.ps1 -help
Displays help for script options.
.NOTES
Author : Copyright 2020 - K. Austin Newman
Version : 2.5.0
Date : 06/05/2021
.INPUTS
Inputs to this script file
- mode [default,hevc,testing,testsuite,customdir]
.OUTPUTS
Creates a cmd file with same name as input file.
.LINK
https://github.com/donmelton/other_video_transcoding
#>
# Define arguments
Param(
[Parameter( Mandatory = $false )]
[ValidateSet( "default","qsv","testing","testsuite","customdir" )]
[string]$mode
)
# Define user vars
$dirWorkflowRoot = "workflows"
$dirWorkflowName = "transcoding"
$optionSet = $mode
# Define Functions
function findDriveLetterForVolume {
param ($volumeName)
try {
$drvData = get-volume -FileSystemLabel "$volumeName" -ErrorAction Stop
$script:strRootVol = $drvData.DriveLetter
}
catch {
Write-warning "Volume $volumeName not available"
exit 1
}
}
function buildAndVerifyWorkingDirectories {
$script:dirWorkFlow = "$strRootVol`:\$dirWorkflowRoot\$dirWorkflowName"
if ( $mode -ne "testsuite" ) {
$script:dirReady = "$dirWorkFlow\ready"
}
else {
$script:dirReady = "C:\Users\kris\Documents\test-suite"
}
if ( $mode -ne "testsuite" ) {
$script:dirOutbox = "$dirWorkFlow\outbox"
}
else {
$script:dirOutbox = "$dirTesting"
}
$script:dirManual = "$dirWorkFlow\manual"
$script:dirLogs = "$dirWorkFlow\encodingLogs"
$script:dirArchive = "$dirOutbox\archive"
$script:dirQueue = "$dirWorkFlow\queue"
$script:dirTesting = "$dirWorkFlow\testing"
$script:dirOverrides = "$dirWorkFlow\overrides"
if ( $mode -ne "testing" -AND $mode -ne "testsuite" ) {
$script:engine = "other-transcode"
}
else {
$script:engine = "beta-other-transcode"
}
$aPaths = $dirWorkFlow,$dirReady,$dirOutbox,$dirManual,$dirLogs,$dirArchive,$dirQueue,$dirTesting,$dirOverrides
foreach ( $dir in $aPaths ) {
If (!( Test-Path "$dir" )) {
New-Item -ItemType Directory -Force -Path $dir -ErrorAction SilentlyContinue
}
}
}
function verifyAllToolRequirements {
$aTools = "ruby","beta-other-transcode","ffmpeg","mpv","ffprobe","remux","mkvmerge","jq","mkvpropedit","filebot"
foreach ( $tool in $aTools ) {
if ( $null -eq ( Get-Command "$tool" -ErrorAction SilentlyContinue )) {
Write-warning -Message "Executable not in path: $tool"
$strExit = $true
}
if ( $strExit -eq $true ) {
Write-warning "Exiting due to previous errors"
exit 1
}
}
}
Function Get-Folder($initialDirectory="") {
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")|Out-Null
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.Description = "Select a folder"
$foldername.rootfolder = "MyComputer"
$foldername.SelectedPath = $initialDirectory
if($foldername.ShowDialog() -eq "OK")
{
$folder += $foldername.SelectedPath
}
return $folder
}
# Begin Processing
## Define immutable vars
$dirStartingLoc = Get-Location
$strTVRegEx = "([sS]([0-9]{2,}|[X]{2,})[eE]([0-9]{2,}|[Y]{2,}))"
## Verify all paths and tools
findDriveLetterForVolume "data"
buildAndVerifyWorkingDirectories
verifyAllToolRequirements
### Define variables
#### Defaults
switch ( $optionset ) {
qsv {
$strVidOpts = "--decode all --qsv-device 1 --qsv"
$strAudOpts = "--all-eac3 --keep-ac3-stereo --add-audio all --pass-dts"
$strTargets = "--target 2160p=16000 --target 1080p=8000 --target 720p=4000 --target 480p=2000"
$strSafeOpts = "--max-muxing-queue-size 1024"
}
default {
$strVidOpts = "--hevc --nvenc-recommended --8-bit-vc1"
$strAudOpts = "--aac-only --add-audio all"
$strTargets = "" #"--target 2160p=8000 --target 1080p=4000 --target 720p=2000 --target 480p=1000"
$strSafeOpts = "--max-muxing-queue-size 1024"
}
testing {
$strVidOpts = "--hevc --nvenc-recommended --8-bit-vc1"
$strAudOpts = "--aac-only --add-audio all"
$strTargets = ""
$strSafeOpts = "--max-muxing-queue-size 1024"
}
testsuite {
$strVidOpts = "--hevc --nvenc-recommended --8-bit-vc1"
$strAudOpts = "--aac-only --add-audio all"
$strTargets = ""
$strSafeOpts = "--max-muxing-queue-size 1024"
}
customdir {
$strVidOpts = "--hevc --nvenc-recommended --8-bit-vc1"
$strAudOpts = "--aac-only --add-audio all"
$strTargets = "" #"--target 2160p=8000 --target 1080p=4000 --target 720p=2000 --target 480p=1000"
$strSafeOpts = "--max-muxing-queue-size 1024"
}
}
## Process all MKV files
if ( $optionSet = "customdir" ) {
$dirReady = Get-Folder
}
$fArray = Get-ChildItem -recurse $dirReady -include *.mkv -File
foreach ($element in $fArray){
Write-Output "Processing $element"
$strTheFile = $element.ToString()
$strFilename = (Get-Item $strTheFile).Basename
$strExtension = (Get-Item $strTheFile).Extension
### Run ffprobe against result
$strMI = ffprobe -i "$strTheFile" -show_format -show_streams -show_data -v quiet -print_format json=compact=1 -v quiet
### Check for overrides file and apply
$strOverrides = ""
if ( Test-Path "$dirOverrides\$strFilename.txt" ) {
$strOverrides = Get-Content $dirOverrides\$strFilename.txt
}
### if TV episode, set significantly lower bitrates
If ($strTheFile -match $strTVRegEx){
$strOverrides = "$strOverrides --nvenc-cq 28"
}
### Set Subtitle Options - Soft add all eng subtitles, find forced and mark in file
$strSubOpts = ""
$strSubInfo = ffprobe -i "$strTheFile" -select_streams s -show_streams -print_format json=compact=1 -v quiet
$intSubCount = 0
$subtrack = "$strSubInfo" | jq -r '.streams[] | .disposition | .forced'
ForEach ( $element in $subtrack ){
$strLanguage = "$strSubInfo" | jq -r ".streams[$intSubCount] | .tags | .language"
$intSubCount++
if ( "$element" -eq "1" -And "$strLanguage" -eq "eng" ){
$strSubOpts = "$strSubOpts --add-subtitle $intSubCount=forced"
}
elseif ( "$strLanguage" -eq "eng" ){
$strSubOpts = "$strSubOpts --add-subtitle $intSubCount"
}
}
$stroptionsLine = "$strVidOpts $strTargets $strAudOpts $strSafeOpts $strSubOpts $strOverrides"
### Write command file
$outfile = Join-Path -Path "$dirQueue" -ChildPath "$strFilename.cmd"
if ( Test-Path $outfile ) {
write-warning "$outfile already exists - Skipping"
continue
}
New-Item -Path "$dirQueue" -Name "$strFilename.cmd" -Force -ItemType "file"
out-file $outfile -Append -encoding OEM -inputObject "@ECHO Off"
out-file $outfile -Append -encoding OEM -inputObject "$strRootVol`:"
out-file $outfile -Append -encoding OEM -inputObject "cd ""$dirOutbox"""
out-file $outfile -Append -encoding OEM -inputObject "call $engine $stroptionsLine ""$strTheFile"""
if ( $mode -ne "testing" -AND $mode -ne "testsuite" ) {
out-file $outfile -Append -encoding OEM -inputObject "move ""$strTheFile"" ""$dirArchive"""
out-file $outfile -Append -encoding OEM -inputObject "move ""$dirOutbox\$strFilename.mkv.log"" ""$dirLogs"""
If ($strTheFile -match $strTVRegEx){
out-file $outfile -Append -encoding OEM -inputObject "filebot -rename ""$dirOutbox\$strFilename.mkv"" --db TheTVDB --format "".\{n} - {s00e00} - {t}"" -non-strict"
} else {
out-file $outfile -Append -encoding OEM -inputObject "filebot -rename ""$dirOutbox\$strFilename.mkv"" --db TheMovieDB --format c:\bin\movies_final.groovy -non-strict"
}
}
out-file $outfile -Append -encoding OEM -inputObject "DEL ""%~f0"""
}
Write-Output "No files remain to be processed. Exiting..."
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment