diff --git a/TorrentScript.ps1 b/TorrentScript.ps1
index e82a863..100365f 100644
--- a/TorrentScript.ps1
+++ b/TorrentScript.ps1
@@ -1,22 +1,35 @@
param(
- [Parameter(mandatory = $false)]
- [string] $DownloadPath,
- [Parameter(mandatory = $false)]
- [string] $DownloadLabel,
- [Parameter(mandatory = $false)]
- [string] $TorrentHash,
- [Parameter(Mandatory = $false)]
- [switch] $NoCleanUp
+ [Parameter(
+ mandatory = $false
+ )]
+ [string] $DownloadPath,
+
+ [Parameter(
+ mandatory = $false
+ )]
+ [string] $DownloadLabel,
+
+ [Parameter(
+ mandatory = $false
+ )]
+ [string] $TorrentHash,
+
+ [Parameter(
+ Mandatory = $false
+ )]
+ [switch] $NoCleanUp
)
# User Variables
-try {
- $configPath = Join-Path $PSScriptRoot "config.json"
+try
+{
+ $configPath = Join-Path $PSScriptRoot 'config.json'
$Config = Get-Content $configPath -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop
}
-catch {
- Write-Host "Exception:" $_.Exception.Message -ForegroundColor Red
- Write-Host "Invalid config.json file" -ForegroundColor Red
+catch
+{
+ Write-Host 'Exception:' $_.Exception.Message -ForegroundColor Red
+ Write-Host 'Invalid config.json file' -ForegroundColor Red
exit 1
}
@@ -75,929 +88,36 @@ $omdbAPI = $Config.OpenSub.omdbAPI
$WantedLanguages = $Config.WantedLanguages
$SubtitleNamesToRemove = $Config.SubtitleNamesToRemove
-# Functions
-Function Get-Input {
- param(
- [Parameter(Mandatory = $true)]
- [string] $Message,
- [Parameter(Mandatory = $false)]
- [switch] $Required
- )
- if ($Required) {
- While ( ($Null -eq $Variable) -or ($Variable -eq '') ) {
- $Variable = Read-Host -Prompt "$Message"
- $Variable = $Variable.Trim()
- }
- }
- else {
- $Variable = Read-Host -Prompt "$Message"
- $Variable = $Variable.Trim()
- }
- Return $Variable
-}
-
-function New-Mutex {
- <#
- .SYNOPSIS
- Create a Mutex
- .DESCRIPTION
- This function attempts to get a lock to a mutex with a given name. If a lock
- cannot be obtained this function waits until it can.
-
- Using mutexes, multiple scripts/processes can coordinate exclusive access
- to a particular work product. One script can create the mutex then go about
- doing whatever work is needed, then release the mutex at the end. All other
- scripts will wait until the mutex is released before they too perform work
- that only one at a time should be doing.
-
- This function outputs a PSObject with the following NoteProperties:
-
- Name
- Mutex
-
- Use this object in a followup call to Remove-Mutex once done.
- .PARAMETER MutexName
- The name of the mutex to create.
- .INPUTS
- None. You cannot pipe objects to this function.
- .OUTPUTS
- PSObject
- #Requires -Version 2.0
- #>
- [CmdletBinding()][OutputType([PSObject])]
- Param ([Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$MutexName)
- $MutexWasCreated = $false
- $Mutex = $Null
- Write-Host "Waiting to acquire lock [$MutexName]..." -ForegroundColor DarkGray
- [void][System.Reflection.Assembly]::LoadWithPartialName('System.Threading')
- try {
- $Mutex = [System.Threading.Mutex]::OpenExisting($MutexName)
- }
- catch {
- $Mutex = New-Object System.Threading.Mutex($true, $MutexName, [ref]$MutexWasCreated)
- }
- try {
- if (!$MutexWasCreated) {
- $Mutex.WaitOne() | Out-Null
- }
- }
- catch {
- }
- Write-Host "Lock [$MutexName] acquired. Executing..." -ForegroundColor DarkGray
- Write-Output ([PSCustomObject]@{ Name = $MutexName; Mutex = $Mutex })
-} # New-Mutex
-
-function Remove-Mutex {
- <#
- .SYNOPSIS
- Removes a previously created Mutex
- .DESCRIPTION
- This function attempts to release a lock on a mutex created by an earlier call
- to New-Mutex.
- .PARAMETER MutexObject
- The PSObject object as output by the New-Mutex function.
- .INPUTS
- None. You cannot pipe objects to this function.
- .OUTPUTS
- None.
- #Requires -Version 2.0
- #>
- [CmdletBinding()]
- Param ([Parameter(Mandatory)][ValidateNotNull()][PSObject]$MutexObject)
- # $MutexObject | fl * | Out-String | Write-Host
- Write-Host "Releasing lock [$($MutexObject.Name)]..." -ForegroundColor DarkGray
- try {
- [void]$MutexObject.Mutex.ReleaseMutex()
- }
- catch {
- }
-} # Remove-Mutex
-
-# Robocopy function
-function Start-RoboCopy {
- <#
- .SYNOPSIS
- RoboCopy wrapper
- .DESCRIPTION
- Wrapper for RoboCopy since it it way faster to copy that way
- .PARAMETER Source
- Source path
- .PARAMETER Destination
- Destination path
- .PARAMETER File
- File patern to copy *.* or name.ext
- This allows for folder or single filecopy
- .EXAMPLE
- Start-RoboCopy -Source 'C:\Temp\Source' -Destination 'C:\Temp\Destination -File '*.*'
- Start-RoboCopy -Source 'C:\Temp\Source' -Destination 'C:\Temp\Destination -File 'file.ext'
- #>
- param (
- [Parameter(Mandatory = $true)]
- [string] $Source,
- [Parameter(Mandatory = $true)]
- [string] $Destination,
- [Parameter(Mandatory = $true)]
- [string] $File
- )
-
- if ($File -ne '*.*') {
- $options = @("/R:1", "/W:1", "/J", "/NP", "/NP", "/NJH", "/NFL", "/NDL", "/MT8")
- }
- elseif ($File -eq '*.*') {
- $options = @("/R:1", "/W:1", "/E", "/J", "/NP", "/NJH", "/NFL", "/NDL", "/MT8")
- }
-
- $cmdArgs = @("`"$Source`"", "`"$Destination`"", "`"$File`"", $options)
-
- #executing unrar command
- Write-HTMLLog -Column1 "Starting:" -Column2 "Copy files"
- #executing Robocopy command
- $Output = robocopy @cmdArgs
-
- foreach ($line in $Output) {
- switch -Regex ($line) {
- #Dir metrics
- '^\s+Dirs\s:\s*' {
- #Example: Dirs : 35 0 0 0 0 0
- $dirs = $_.Replace('Dirs :', '').Trim()
- #Now remove the white space between the values.'
- $dirs = $dirs -split '\s+'
-
- #Assign the appropriate column to values.
- $TotalDirs = $dirs[0]
- $CopiedDirs = $dirs[1]
- $FailedDirs = $dirs[4]
- }
- #File metrics
- '^\s+Files\s:\s[^*]' {
- #Example: Files : 8318 0 8318 0 0 0
- $files = $_.Replace('Files :', '').Trim()
- #Now remove the white space between the values.'
- $files = $files -split '\s+'
-
- #Assign the appropriate column to values.
- $TotalFiles = $files[0]
- $CopiedFiles = $files[1]
- $FailedFiles = $files[4]
- }
- #Byte metrics
- '^\s+Bytes\s:\s*' {
- #Example: Bytes : 1.607 g 0 1.607 g 0 0 0
- $bytes = $_.Replace('Bytes :', '').Trim()
- #Now remove the white space between the values.'
- $bytes = $bytes -split '\s+'
-
- #The raw text from the log file contains a k,m,or g after the non zero numers.
- #This will be used as a multiplier to determin the size in MB.
- $counter = 0
- $tempByteArray = 0, 0, 0, 0, 0, 0
- $tempByteArrayCounter = 0
- foreach ($column in $bytes) {
- if ($column -eq 'k') {
- $tempByteArray[$tempByteArrayCounter - 1] = "{0:N2}" -f ([single]($bytes[$counter - 1]) / 1024)
- $counter += 1
- }
- elseif ($column -eq 'm') {
- $tempByteArray[$tempByteArrayCounter - 1] = "{0:N2}" -f $bytes[$counter - 1]
- $counter += 1
- }
- elseif ($column -eq 'g') {
- $tempByteArray[$tempByteArrayCounter - 1] = "{0:N2}" -f ([single]($bytes[$counter - 1]) * 1024)
- $counter += 1
- }
- else {
- $tempByteArray[$tempByteArrayCounter] = $column
- $counter += 1
- $tempByteArrayCounter += 1
- }
- }
- #Assign the appropriate column to values.
- $TotalMBytes = $tempByteArray[0]
- $CopiedMBytes = $tempByteArray[1]
- $FailedMBytes = $tempByteArray[4]
- #array columns 2,3, and 5 are available, but not being used currently.
- }
- #Speed metrics
- '^\s+Speed\s:.*sec.$' {
- #Example: Speed : 120.816 MegaBytes/min.
- $speed = $_.Replace('Speed :', '').Trim()
- $speed = $speed.Replace('Bytes/sec.', '').Trim()
- #Assign the appropriate column to values.
- $speed = $speed / 1048576
- $SpeedMBSec = [math]::Round($speed, 2)
- }
- }
- }
-
- if ($FailedDirs -gt 0 -or $FailedFiles -gt 0) {
- Write-HTMLLog -Column1 "Dirs" -Column2 "$TotalDirs Total" -ColorBg "Error"
- Write-HTMLLog -Column1 "Dirs" -Column2 "$FailedDirs Failed" -ColorBg "Error"
- Write-HTMLLog -Column1 "Files:" -Column2 "$TotalFiles Total" -ColorBg "Error"
- Write-HTMLLog -Column1 "Files:" -Column2 "$FailedFiles Failed" -ColorBg "Error"
- Write-HTMLLog -Column1 "Size:" -Column2 "$TotalMBytes MB Total" -ColorBg "Error"
- Write-HTMLLog -Column1 "Size:" -Column2 "$FailedMBytes MB Failed" -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Copy Error: $DownloadLabel - $DownloadName"
- }
- else {
- Write-HTMLLog -Column1 "Dirs:" -Column2 "$CopiedDirs Copied"
- Write-HTMLLog -Column1 "Files:" -Column2 "$CopiedFiles Copied"
- Write-HTMLLog -Column1 "Size:" -Column2 "$CopiedMBytes MB"
- Write-HTMLLog -Column1 "Throughput:" -Column2 "$SpeedMBSec MB/s"
- Write-HTMLLog -Column1 "Result:" -Column2 "Successful" -ColorBg "Success"
- }
-}
-
-# Function to unrar
-function Start-UnRar {
- <#
- .SYNOPSIS
- Unrar file
- .DESCRIPTION
- Takes rar file and unrar them to target
- .PARAMETER UnRarSourcePath
- Path of rar file to extract
- .PARAMETER UnRarTargetPath
- Destination folder path
- .EXAMPLE
- Start-UnRar -UnRarSourcePath 'C:\Temp\Source\file.rar' -UnRarTargetPath 'C:\Temp\Destination'
- #>
- Param(
- [Parameter(Mandatory = $true)]
- $UnRarSourcePath,
- [Parameter(Mandatory = $true)]
- $UnRarTargetPath
- )
-
- $RarFile = Split-Path -Path $UnRarSourcePath -Leaf
-
- #executing unrar command
- Write-HTMLLog -Column1 "File:" -Column2 "$RarFile"
- $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
- $StartInfo.FileName = $WinRarPath
- $StartInfo.RedirectStandardError = $true
- $StartInfo.RedirectStandardOutput = $true
- $StartInfo.UseShellExecute = $false
- $StartInfo.Arguments = @("x", "`"$UnRarSourcePath`"", "`"$UnRarTargetPath`"", "-y", "-idq")
- $Process = New-Object System.Diagnostics.Process
- $Process.StartInfo = $StartInfo
- $Process.Start() | Out-Null
- # $stdout = $Process.StandardOutput.ReadToEnd()
- $stderr = $Process.StandardError.ReadToEnd()
- # Write-Host "stdout: $stdout"
- # Write-Host "stderr: $stderr"
- $Process.WaitForExit()
- if ($Process.ExitCode -gt 0) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "Error:" -Column2 $stderr -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Unrar Error: $DownloadLabel - $DownloadName"
- }
- else {
- Write-HTMLLog -Column1 "Result:" -Column2 "Successful" -ColorBg "Success"
- }
-}
-
-function Start-MKV-Subtitle-Strip {
- <#
- .SYNOPSIS
- Extract wanted SRT subtitles from MKVs in root folder and remux MKVs to strip out unwanted subtitle languages
- .DESCRIPTION
- Searches for all MKV files in root folder and extracts the SRT that are defined in $WantedLanguages
- Remux any MKV that has subtitles of unwanted languages or Track_name in $SubtitleNamesToRemove.
- Rename srt subtitle files based on $LanguageCodes
- .PARAMETER Source
- Defines the root folder to start the search for MKV files
- .EXAMPLE
- Start-MKV-Subtitle-Strip 'C:\Temp\Source'
- .OUTPUTS
- SRT files of the desired languages
- file.en.srt
- file.2.en.srt
- file.nl.srt
- file.de.srt
- MKV files without the unwanted subtitles
- file.mkv
- #>
- param (
- [Parameter(Mandatory = $true)]
- [string] $Source
- )
- $episodes = @()
- $SubsExtracted = $false
- $TotalSubsToExtract = 0
- $TotalSubsToRemove = 0
-
- Write-HTMLLog -Column1 "*** Extract srt files from MKV ***" -Header
- Get-ChildItem -LiteralPath $Source -Recurse -Filter "*.mkv" | ForEach-Object {
- Get-ChildItem -LiteralPath $_.FullName | ForEach-Object {
- $fileName = $_.BaseName
- $filePath = $_.FullName
- $fileRoot = $_.Directory
-
- # Start the json export with MKVMerge on the available tracks
- $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
- $StartInfo.FileName = $MKVMergePath
- $StartInfo.RedirectStandardError = $true
- $StartInfo.RedirectStandardOutput = $true
- $StartInfo.UseShellExecute = $false
- $StartInfo.Arguments = @("-J", "`"$filePath`"")
- $Process = New-Object System.Diagnostics.Process
- $Process.StartInfo = $StartInfo
- $Process.Start() | Out-Null
- $stdout = $Process.StandardOutput.ReadToEnd()
- # $stderr = $Process.StandardError.ReadToEnd()
- # Write-Host "stdout: $stdout"
- # Write-Host "stderr: $stderr"
- $Process.WaitForExit()
- if ($Process.ExitCode -eq 2) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvmerge:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- }
- elseif ($Process.ExitCode -eq 1) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvmerge:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Warning" -ColorBg "Error"
- }
- elseif ($Process.ExitCode -eq 0) {
- $fileMetadata = $stdout | ConvertFrom-Json
- }
- else {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvmerge:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Warning" -ColorBg "Error"
- }
-
- $file = @{
- FileName = $fileName
- FilePath = $filePath
- FileRoot = $fileRoot
- FileTracks = $fileMetadata.tracks
- FileAttachments = $fileMetadata.attachments
- }
-
- $episodes += New-Object PSObject -Property $file
- }
- }
-
- # Exctract wanted SRT subtitles
- $episodes | ForEach-Object {
- $episode = $_
- $SubIDsToExtract = @()
- $SubIDsToRemove = @()
- $SubsToExtract = @()
- $SubNamesToKeep = @()
-
- $episode.FileTracks | ForEach-Object {
- $FileTrack = $_
- if ($FileTrack.id) {
- # Check if subtitle is srt
- if ($FileTrack.type -eq "subtitles" -and $FileTrack.codec -eq "SubRip/SRT") {
-
- # Check to see if track_name is part of $SubtitleNamesToRemove list
- if ($null -ne ($SubtitleNamesToRemove | Where-Object { $FileTrack.properties.track_name -match $_ })) {
- $SubIDsToRemove += $FileTrack.id
- }
- # Check is subtitle is in $WantedLanguages list
- elseif ($FileTrack.properties.language -in $WantedLanguages) {
-
- # Handle multiple subtitles of same language, if exist append ID to file
- if ("$($episode.FileName).$($FileTrack.properties.language).srt" -in $SubNamesToKeep) {
- $prefix = "$($FileTrack.id).$($FileTrack.properties.language)"
- }
- else {
- $prefix = "$($FileTrack.properties.language)"
- }
-
- # Add Subtitle name and ID to be extracted
- $SubsToExtract += "`"$($FileTrack.id):$($episode.FileRoot)\$($episode.FileName).$($prefix).srt`""
-
- # Keep track of subtitle file names that will be extracted to handle possible duplicates
- $SubNamesToKeep += "$($episode.FileName).$($prefix).srt"
-
- # Add subtitle ID to for MKV remux
- $SubIDsToExtract += $FileTrack.id
- }
- else {
- $SubIDsToRemove += $FileTrack.id
- }
- }
- }
- }
-
- # Count all subtitles to keep and remove of logging
- $TotalSubsToExtract = $TotalSubsToExtract + $SubIDsToExtract.count
- $TotalSubsToRemove = $TotalSubsToRemove + $SubIDsToRemove.count
-
- # Extract the wanted subtitle languages
- if ($SubIDsToExtract.count -gt 0) {
- $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
- $StartInfo.FileName = $MKVExtractPath
- $StartInfo.RedirectStandardError = $true
- $StartInfo.RedirectStandardOutput = $true
- $StartInfo.UseShellExecute = $false
- $StartInfo.Arguments = @("`"$($episode.FilePath)`"", "tracks", "$SubsToExtract")
- $Process = New-Object System.Diagnostics.Process
- $Process.StartInfo = $StartInfo
- $Process.Start() | Out-Null
- $stdout = $Process.StandardOutput.ReadToEnd()
- # $stderr = $Process.StandardError.ReadToEnd()
- # Write-Host "stdout: $stdout"
- # Write-Host "stderr: $stderr"
- $Process.WaitForExit()
- if ($Process.ExitCode -eq 2) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvextract:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- }
- elseif ($Process.ExitCode -eq 1) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvextract:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Warning" -ColorBg "Error"
- }
- elseif ($Process.ExitCode -eq 0) {
- $SubsExtracted = $true
- # Write-HTMLLog -Column1 "Extracted:" -Column2 "$($SubsToExtract.count) Subtitles"
- }
- else {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvextract:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Unknown" -ColorBg "Error"
- }
- }
-
- # Remux and strip out all unwanted subtitle languages
- if ($SubIDsToRemove.Count -gt 0) {
- $TmpFileName = $Episode.FileName + ".tmp"
- $TmpMkvPath = Join-Path $episode.FileRoot $TmpFileName
- $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
- $StartInfo.FileName = $MKVMergePath
- $StartInfo.RedirectStandardError = $true
- $StartInfo.RedirectStandardOutput = $true
- $StartInfo.UseShellExecute = $false
- $StartInfo.Arguments = @("-o `"$TmpMkvPath`"", "-s !$($SubIDsToRemove -join ",")", "`"$($episode.FilePath)`"")
- $Process = New-Object System.Diagnostics.Process
- $Process.StartInfo = $StartInfo
- $Process.Start() | Out-Null
- $stdout = $Process.StandardOutput.ReadToEnd()
- # $stderr = $Process.StandardError.ReadToEnd()
- # Write-Host "stdout: $stdout"
- # Write-Host "stderr: $stderr"
- $Process.WaitForExit()
- if ($Process.ExitCode -eq 2) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvmerge:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- }
- elseif ($Process.ExitCode -eq 1) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvmerge:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Warning" -ColorBg "Error"
- }
- elseif ($Process.ExitCode -eq 0) {
- # Overwrite original mkv after successful remux
- Move-Item -Path $TmpMkvPath -Destination $($episode.FilePath) -Force
- # Write-HTMLLog -Column1 "Removed:" -Column2 "$($SubIDsToRemove.Count) unwanted subtitle languages"
- }
- else {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "mkvmerge:" -Column2 $stdout -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Warning" -ColorBg "Error"
- }
- }
- }
-
- # Rename extracted subs to correct 2 county code based on $LanguageCodes
- if ($SubsExtracted) {
- $SrtFiles = Get-ChildItem -LiteralPath $Source -Recurse -Filter "*.srt"
- foreach ($srt in $SrtFiles) {
- $FileDirectory = $srt.Directory
- $FilePath = $srt.FullName
- $FileName = $srt.Name
- foreach ($LanguageCode in $Config.LanguageCodes) {
- $FileNameNew = $FileName.Replace(".$($LanguageCode.alpha3).", ".$($LanguageCode.alpha2).")
- $ReplacementWasMade = $FileName -cne $FileNameNew
- if ($ReplacementWasMade) {
- $Destination = Join-Path -Path $FileDirectory -ChildPath $FileNameNew
- Move-Item -Path $FilePath -Destination $Destination -Force
- break
- }
- }
- }
- if ($TotalSubsToExtract -gt 0) {
- Write-HTMLLog -Column1 "Subtitles:" -Column2 "$TotalSubsToExtract Extracted"
- }
- if ($TotalSubsToRemove -gt 0) {
- Write-HTMLLog -Column1 "Subtitles:" -Column2 "$TotalSubsToRemove Removed"
- }
- Write-HTMLLog -Column1 "Result:" -Column2 "Successful" -ColorBg "Success"
- }
- else {
- Write-HTMLLog -Column1 "Result:" -Column2 "No SRT subs found in MKV"
- }
-}
-
-# Function to Clean up subtitles
-function Start-SubEdit {
- param (
- [Parameter(Mandatory = $true)]
- $Source,
- [Parameter(Mandatory = $true)]
- $Files
- )
- Write-HTMLLog -Column1 "*** Clean up Subtitles ***" -Header
- $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
- $StartInfo.FileName = $SubtitleEditPath
- $StartInfo.RedirectStandardError = $true
- $StartInfo.RedirectStandardOutput = $true
- $StartInfo.UseShellExecute = $false
- $StartInfo.Arguments = @("/convert", "$Files", "subrip", "/inputfolder`:`"$Source`"", "/overwrite", "/fixcommonerrors", "/removetextforhi", "/fixcommonerrors", "/fixcommonerrors")
- $Process = New-Object System.Diagnostics.Process
- $Process.StartInfo = $StartInfo
- $Process.Start() | Out-Null
- $stdout = $Process.StandardOutput.ReadToEnd()
- $stderr = $Process.StandardError.ReadToEnd()
- $Process.WaitForExit()
- if ($Process.ExitCode -gt 1) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "Error:" -Column2 $stderr -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "SubEdit Error: $DownloadLabel - $DownloadName"
- }
- else {
- Write-HTMLLog -Column1 "Result:" -Column2 "Successful" -ColorBg "Success"
- }
-}
-
-function Start-Subliminal {
- param (
- [Parameter(Mandatory = $true)]
- $Source
- )
- Write-HTMLLog -Column1 "*** Download missing Subtitles ***" -Header
- $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
- $StartInfo.FileName = $SubliminalPath
- $StartInfo.RedirectStandardError = $true
- $StartInfo.RedirectStandardOutput = $true
- $StartInfo.UseShellExecute = $false
- $StartInfo.Arguments = @("--opensubtitles", $OpenSubUser, $OpenSubPass, "--omdb $omdbAPI", "download", "-r omdb", "-p opensubtitles", "-l eng", "-l nld", "`"$Source`"")
- $Process = New-Object System.Diagnostics.Process
- $Process.StartInfo = $StartInfo
- $Process.Start() | Out-Null
- $stdout = $Process.StandardOutput.ReadToEnd()
- $stderr = $Process.StandardError.ReadToEnd()
- $Process.WaitForExit()
- # Write-Host $stdout
- # Write-Host $stderr
- if ($stdout -match '(\d+)(?=\s*video collected)') {
- $VideoCollected = $Matches.0
- }
- if ($stdout -match '(\d+)(?=\s*video ignored)') {
- $VideoIgnored = $Matches.0
- }
- if ($stdout -match '(\d+)(?=\s*error)') {
- $VideoError = $Matches.0
- }
- if ($stdout -match '(\d+)(?=\s*subtitle)') {
- $SubsDownloaded = $Matches.0
- }
- if ($stdout -match 'Some providers have been discarded due to unexpected errors') {
- $SubliminalExitCode = 1
- }
- if ($SubliminalExitCode -gt 0) {
- Write-HTMLLog -Column1 "Exit Code:" -Column2 $($Process.ExitCode) -ColorBg "Error"
- Write-HTMLLog -Column1 "Error:" -Column2 $stderr -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- }
- else {
- if ($SubsDownloaded -gt 0) {
- # Write-HTMLLog -Column1 "Downloaded:" -Column2 "$SubsDownloaded Subtitles"
- Write-HTMLLog -Column1 "Collected:" -Column2 "$VideoCollected Videos"
- Write-HTMLLog -Column1 "Ignored:" -Column2 "$VideoIgnored Videos"
- Write-HTMLLog -Column1 "Error:" -Column2 "$VideoError Videos"
- Write-HTMLLog -Column1 "Downloaded:" -Column2 "$SubsDownloaded Subtitles"
- Write-HTMLLog -Column1 "Result:" -Column2 "Successful" -ColorBg "Success"
- }
- else {
- Write-HTMLLog -Column1 "Result:" -Column2 "No subs downloaded with Subliminal"
- }
- }
-}
-
-# Fuction to Process Medusa
-function Import-Medusa {
- param (
- [Parameter(Mandatory = $true)]
- $Source
- )
-
- $body = @{
- 'proc_dir' = $Source
- 'resource' = ''
- 'process_method' = 'move'
- 'force' = $true
- 'is_priority' = $false
- 'delete_on' = $false
- 'failed' = $false
- 'proc_type' = 'manual'
- 'ignore_subs' = $false
- } | ConvertTo-Json
-
- $headers = @{
- 'X-Api-Key' = $MedusaApiKey
- }
- Write-HTMLLog -Column1 "*** Medusa Import ***" -Header
- try {
- $response = Invoke-RestMethod -Uri "http://$MedusaHost`:$MedusaPort/api/v2/postprocess" -Method Post -Body $Body -Headers $headers
- }
- catch {
- Write-HTMLLog -Column1 "Exception:" -Column2 $_.Exception.Message -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
- }
- if ($response.status -eq "success") {
- $timeout = New-TimeSpan -Minutes $MedusaTimeOutMinutes
- $endTime = (Get-Date).Add($timeout)
- do {
- try {
- $status = Invoke-RestMethod -Uri "http://$MedusaHost`:$MedusaPort/api/v2/postprocess/$($response.queueItem.identifier)" -Method Get -Headers $headers
- }
- catch {
- Write-HTMLLog -Column1 "Exception:" -Column2 $_.Exception.Message -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
- }
- Start-Sleep 1
- }
- until ($status.success -or ((Get-Date) -gt $endTime))
- if ($status.success) {
- $ValuesToFind = 'Processing failed', 'aborting post-processing'
- $MatchPattern = ($ValuesToFind | ForEach-Object { [regex]::Escape($_) }) -join '|'
- if ($status.output -match $MatchPattern) {
- $ValuesToFind = 'Retrieving episode object for', 'Current quality', 'New quality', 'Old size', 'New size', 'Processing failed', 'aborting post-processing'
- $MatchPattern = ($ValuesToFind | ForEach-Object { [regex]::Escape($_) }) -join '|'
- foreach ($line in $status.output ) {
- if ($line -match $MatchPattern) {
- Write-HTMLLog -Column1 "Medusa:" -Column2 $line -ColorBg "Error"
- }
- }
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
- }
- else {
- Write-HTMLLog -Column1 "Result:" -Column2 "Successful" -ColorBg "Success"
- }
- }
- else {
- Write-HTMLLog -Column1 "Medusa:" -Column2 $status.success -ColorBg "Error"
- Write-HTMLLog -Column1 "Medusa:" -Column2 "Import Timeout: ($MedusaTimeOutMinutes) minutes" -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
- }
+# Get function definition files.
+$Functions = @( Get-ChildItem -Path $PSScriptRoot\functions\*.ps1 -ErrorAction SilentlyContinue )
+# Dot source the files
+ForEach ($import in @($Functions))
+{
+ Try
+ {
+ # Lightweight alternative to dotsourcing a function script
+ . ([ScriptBlock]::Create([System.Io.File]::ReadAllText($import)))
}
- else {
- Write-HTMLLog -Column1 "Medusa:" -Column2 $response.status -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
+ Catch
+ {
+ Write-Error -Message "Failed to import function $($import.fullname): $_"
}
}
-# Function to Process Radarr
-function Import-Radarr {
- param (
- [Parameter(Mandatory = $true)]
- $Source
- )
-
- $body = @{
- 'name' = 'DownloadedMoviesScan'
- 'downloadClientId' = $TorrentHash
- 'importMode' = 'Move'
- 'path' = $Source
- } | ConvertTo-Json
-
- $headers = @{
- 'X-Api-Key' = $RadarrApiKey
- }
- Write-HTMLLog -Column1 "*** Radarr Import ***" -Header
- try {
- $response = Invoke-RestMethod -Uri "http://$RadarrHost`:$RadarrPort/api/v3/command" -Method Post -Body $Body -Headers $headers
- }
- catch {
- Write-HTMLLog -Column1 "Exception:" -Column2 $_.Exception.Message -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
- }
- if ($response.status -eq "queued" -or $response.status -eq "started" -or $response.status -eq "completed") {
- $timeout = New-TimeSpan -Minutes $RadarrTimeOutMinutes
- $endTime = (Get-Date).Add($timeout)
- do {
- try {
- $status = Invoke-RestMethod -Uri "http://$RadarrHost`:$RadarrPort/api/v3/command/$($response.id)" -Method Get -Headers $headers
- }
- catch {
- Write-HTMLLog -Column1 "Exception:" -Column2 $_.Exception.Message -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
- }
- Start-Sleep 1
- }
- until ($status.status -ne "started" -or ((Get-Date) -gt $endTime) )
- if ($status.status -eq "completed") {
- if ($status.duration -gt "00:00:05.0000000") {
- Write-HTMLLog -Column1 "Result:" -Column2 "Successful" -ColorBg "Success"
- }
- else {
- Write-HTMLLog -Column1 "Radarr:" -Column2 "Completed but failed" -ColorBg "Error"
- Write-HTMLLog -Column1 "Radarr:" -Column2 "Radarr has no failed handling see: https://github.com/Radarr/Radarr/issues/5539" -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
- }
- }
- if ($status.status -eq "failed") {
- Write-HTMLLog -Column1 "Radarr:" -Column2 $status.status -ColorBg "Error"
- Write-HTMLLog -Column1 "Radarr:" -Column2 $status.exception -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
- }
- if ((Get-Date) -gt $endTime) {
- Write-HTMLLog -Column1 "Radarr:" -Column2 $status.status -ColorBg "Error"
- Write-HTMLLog -Column1 "Radarr:" -Column2 "Import Timeout: ($RadarrTimeOutMinutes) minutes" -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
- }
- }
- else {
- Write-HTMLLog -Column1 "Radarr:" -Column2 $response.status -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
- }
-}
-
-# Function to close the log and send out mail
-function Send-Mail {
- param (
- [Parameter(Mandatory = $true)]
- $MailSubject
- )
- # Close log file
- # Add-Content -LiteralPath $LogFilePath -Value ''
-
- $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
- $StartInfo.FileName = $MailSendPath
- $StartInfo.RedirectStandardError = $true
- $StartInfo.RedirectStandardOutput = $true
- $StartInfo.UseShellExecute = $false
- $StartInfo.Arguments = @("-smtp $SMTPserver", "-port $SMTPport", "-domain $SMTPserver", "-t $MailTo", "-f $MailFrom", "-fname `"$MailFromName`"", "-sub `"$MailSubject`"", "body", "-file `"$LogFilePath`"", "-mime-type `"text/html`"", "-ssl", "auth -user $SMTPuser -pass $SMTPpass")
- $Process = New-Object System.Diagnostics.Process
- $Process.StartInfo = $StartInfo
- $Process.Start() | Out-Null
- # $stdout = $Process.StandardOutput.ReadToEnd()
- # $stderr = $Process.StandardError.ReadToEnd()
- # Write-Host "stdout: $stdout"
- # Write-Host "stderr: $stderr"
- $Process.WaitForExit()
- # Write-Host "exit code: " + $p.ExitCode
- # return $stdout
-}
-
-Function Write-HTMLLog {
- Param(
- [Parameter(Mandatory = $true)]
- [string] $Column1,
- [Parameter(Mandatory = $false)]
- [string] $Column2,
- [Parameter(Mandatory = $false)]
- [switch] $Header,
- [Parameter(Mandatory = $false)]
- [ValidateSet("Success", "Error")]
- [string] $ColorBg
- )
-
- $global:Log += "
"
- if ($Header) {
- $global:Log += "$Column1 | "
- }
- else {
- if ($ColorBg -eq "") {
- $global:Log += "$Column1 | "
- $global:Log += "$Column2 | "
- $global:Log += "
"
- }
- elseif ($ColorBg -eq "Success") {
- $global:Log += "$Column1 | "
- $global:Log += "$Column2 | "
- $global:Log += ""
- }
- elseif ($ColorBg -eq "Error") {
- $global:Log += "$Column1 | "
- $global:Log += "$Column2 | "
- $global:Log += ""
- }
- }
- Write-Output "$Column1 $Column2"
-
-}
-
-function Format-Table {
- param (
- [Parameter(Mandatory = $false)]
- [switch] $Start
- )
- if ($Start) {
- $global:Log = @()
- $global:Log += ""
- $global:Log += ""
- $global:Log += ""
- $global:Log += ""
- }
- else {
- $global:Log += ""
- $global:Log += "
"
- }
-}
-
-function Write-Log {
- param (
- [Parameter(Mandatory = $true)]
- [string] $LogFile
- )
- Set-Content -Path $LogFile -Value $global:Log
-
-}
-
-# Fuction to clean up process folder
-function CleanProcessPath {
-
- if ($NoCleanUp) {
- Write-HTMLLog -Column1 "Cleanup" -Column2 "NoCleanUp switch was given at command line, leaving files"
- }
- else {
- try {
- If (Test-Path -LiteralPath $ProcessPathFull) {
- Remove-Item -Force -Recurse -LiteralPath $ProcessPathFull
- }
- }
- catch {
- Write-HTMLLog -Column1 "Exception:" -Column2 $_.Exception.Message -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
- }
- }
-}
-
-
-# Fuction to stop the script and send out the mail
-function Stop-Script {
- Param(
- [Parameter(Mandatory = $true)]
- [string] $ExitReason
- )
- # Stop the Stopwatch
- $StopWatch.Stop()
-
- Write-HTMLLog -Column1 "*** Script Exection time ***" -Header
- Write-HTMLLog -Column1 "Time Taken:" -Column2 $($StopWatch.Elapsed.ToString('mm\:ss'))
-
- Format-Table
- Write-Log -LogFile $LogFilePath
- Send-Mail -MailSubject $ExitReason
- # Clean up the Mutex
-
- Remove-Mutex -MutexObject $ScriptMutex
- Exit
-}
-
-function Test-Variable-Path {
- param (
- [Parameter(Mandatory = $true)]
- [string] $Path,
- [Parameter(Mandatory = $true)]
- [string] $Name
- )
- if (!(Test-Path -LiteralPath $Path)) {
- Write-Host "Cannot find: $Path" -ForegroundColor Red
- Write-Host "As defined in variable: $Name" -ForegroundColor Red
- Write-Host "Will now exit!" -ForegroundColor Red
- Exit 1
- }
-}
-
# Test additional programs
-Test-Variable-Path -Path $WinRarPath -Name "WinRarPath"
-Test-Variable-Path -Path $MKVMergePath -Name "MKVMergePath"
-Test-Variable-Path -Path $MKVExtractPath -Name "MKVExtractPath"
-Test-Variable-Path -Path $SubtitleEditPath -Name "SubtitleEditPath"
-Test-Variable-Path -Path $SubliminalPath -Name "SubliminalPath"
-Test-Variable-Path -Path $MailSendPath -Name "MailSendPath"
+Test-Variable-Path -Path $WinRarPath -Name 'WinRarPath'
+Test-Variable-Path -Path $MKVMergePath -Name 'MKVMergePath'
+Test-Variable-Path -Path $MKVExtractPath -Name 'MKVExtractPath'
+Test-Variable-Path -Path $SubtitleEditPath -Name 'SubtitleEditPath'
+Test-Variable-Path -Path $SubliminalPath -Name 'SubliminalPath'
+Test-Variable-Path -Path $MailSendPath -Name 'MailSendPath'
# Get input if no parameters defined
# Build the download Location, this is the Download Root Path added with the Download name
-if ( ($Null -eq $DownloadPath) -or ($DownloadPath -eq '') ) {
- $DownloadPath = Get-Input -Message "Download Name" -Required
+if ( ($Null -eq $DownloadPath) -or ($DownloadPath -eq '') )
+{
+ $DownloadPath = Get-Input -Message 'Download Name' -Required
$DownloadPath = Join-Path -Path $DownloadRootPath -ChildPath $DownloadPath
}
@@ -1005,26 +125,30 @@ if ( ($Null -eq $DownloadPath) -or ($DownloadPath -eq '') ) {
$DownloadName = Split-Path -Path $DownloadPath -Leaf
# Download Label
-if ( ($Null -eq $DownloadLabel) -or ($DownloadLabel -eq '') ) {
- $DownloadLabel = Get-Input -Message "Download Label"
+if ( ($Null -eq $DownloadLabel) -or ($DownloadLabel -eq '') )
+{
+ $DownloadLabel = Get-Input -Message 'Download Label'
}
# Torrent Hash (only needed for Radarr)
-if ( ($Null -eq $TorrentHash) -or ($TorrentHash -eq '') ) {
- $TorrentHash = Get-Input -Message "Torrent Hash"
+if ( ($Null -eq $TorrentHash) -or ($TorrentHash -eq '') )
+{
+ $TorrentHash = Get-Input -Message 'Torrent Hash'
}
# Uppercase TorrentHash
$TorrentHash = $TorrentHash.ToUpper()
# Handle NoProcess Torrent Label
-if ($DownloadLabel -eq "NoProcess") {
- Write-Host "Do nothing"
+if ($DownloadLabel -eq 'NoProcess')
+{
+ Write-Host 'Do nothing'
Exit
}
# Handle empty Torrent Label
-if ($DownloadLabel -eq "") {
- $DownloadLabel = "NoLabel"
+if ($DownloadLabel -eq '')
+{
+ $DownloadLabel = 'NoLabel'
}
# Create Log file
@@ -1033,17 +157,19 @@ $LogFilePath = Join-Path -Path $LogArchivePath -ChildPath "$LogFileDateFormat-$D
# Log Header
Format-Table -Start
-Write-HTMLLog -Column1 "*** Information ***" -Header
-Write-HTMLLog -Column1 "Start:" -Column2 "$(Get-Date -Format "yyyy-MM-dd") at $(Get-Date -Format "HH:mm:ss")"
-Write-HTMLLog -Column1 "Label:" -Column2 $DownloadLabel
-Write-HTMLLog -Column1 "Name:" -Column2 $DownloadName
-Write-HTMLLog -Column1 "Hash:" -Column2 $TorrentHash
+Write-HTMLLog -Column1 '*** Information ***' -Header
+Write-HTMLLog -Column1 'Start:' -Column2 "$(Get-Date -Format 'yyyy-MM-dd') at $(Get-Date -Format 'HH:mm:ss')"
+Write-HTMLLog -Column1 'Label:' -Column2 $DownloadLabel
+Write-HTMLLog -Column1 'Name:' -Column2 $DownloadName
+Write-HTMLLog -Column1 'Hash:' -Column2 $TorrentHash
# Test File Paths
-If (!(Test-Path -LiteralPath $ProcessPath)) {
+If (!(Test-Path -LiteralPath $ProcessPath))
+{
New-Item -ItemType Directory -Force -Path $ProcessPath | Out-Null
}
-If (!(Test-Path -LiteralPath $LogArchivePath)) {
+If (!(Test-Path -LiteralPath $LogArchivePath))
+{
New-Item -ItemType Directory -Force -Path $LogArchivePath | Out-Null
}
@@ -1054,10 +180,11 @@ $ScriptMutex = New-Mutex -MutexName 'DownloadScript'
$StopWatch = [system.diagnostics.stopwatch]::startNew()
# Check paths from Parameters
-If (!(Test-Path -LiteralPath $DownloadPath)) {
+If (!(Test-Path -LiteralPath $DownloadPath))
+{
Write-Host "$DownloadPath - Not valid location"
- Write-HTMLLog -Column1 "Path:" -Column2 "$DownloadPath - Not valid location" -ColorBg "Error"
- Write-HTMLLog -Column1 "Result:" -Column2 "Failed" -ColorBg "Error"
+ Write-HTMLLog -Column1 'Path:' -Column2 "$DownloadPath - Not valid location" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
Stop-Script -ExitReason "Path Error: $DownloadLabel - $DownloadName"
}
@@ -1066,60 +193,80 @@ $SingleFile = (Get-Item -LiteralPath $DownloadPath) -is [System.IO.FileInfo]
$Folder = (Get-Item -LiteralPath $DownloadPath) -is [System.IO.DirectoryInfo]
# Set Source and Destination paths and get Rar paths
-if ($Folder) {
+if ($Folder)
+{
$ProcessPathFull = Join-Path -Path $ProcessPath -ChildPath $DownloadLabel | Join-Path -ChildPath $DownloadName
- $RarFilePaths = (Get-ChildItem -LiteralPath $DownloadPath -Recurse -Filter "*.rar").FullName
+ $RarFilePaths = (Get-ChildItem -LiteralPath $DownloadPath -Recurse -Filter '*.rar').FullName
}
-elseif ($SingleFile) {
+elseif ($SingleFile)
+{
$ProcessPathFull = Join-Path -Path $ProcessPath -ChildPath $DownloadLabel | Join-Path -ChildPath $DownloadName.Substring(0, $DownloadName.LastIndexOf('.'))
$DownloadRootPath = Split-Path -Path $DownloadPath
- if ([IO.Path]::GetExtension($DownloadPath) -eq '.rar') {
+ if ([IO.Path]::GetExtension($DownloadPath) -eq '.rar')
+ {
$RarFilePaths = (Get-Item -LiteralPath $DownloadPath).FullName
}
}
# Find rar files
$RarCount = $RarFilePaths.Count
-if ($RarCount -gt 0) {
+if ($RarCount -gt 0)
+{
$RarFile = $true
}
-else {
+else
+{
$RarFile = $false
}
# Check is destination folder exists otherwise create it
-If (!(Test-Path -LiteralPath $ProcessPathFull)) {
+If (!(Test-Path -LiteralPath $ProcessPathFull))
+{
New-Item -ItemType Directory -Force -Path $ProcessPathFull | Out-Null
}
-if ($RarFile) {
- Write-HTMLLog -Column1 "*** Unrar Download ***" -Header
- Write-HTMLLog -Column1 "Starting:" -Column2 "Unpacking files"
- foreach ($Rar in $RarFilePaths) {
+if ($RarFile)
+{
+ Write-HTMLLog -Column1 '*** Unrar Download ***' -Header
+ Write-HTMLLog -Column1 'Starting:' -Column2 'Unpacking files'
+ $TotalSize = (Get-ChildItem -LiteralPath $DownloadPath -Recurse | Measure-Object -Property Length -sum).Sum
+ $UnRarStopWatch = [system.diagnostics.stopwatch]::startNew()
+ foreach ($Rar in $RarFilePaths)
+ {
Start-UnRar -UnRarSourcePath $Rar -UnRarTargetPath $ProcessPathFull
- }
+ }
+ # Stop the Stopwatch
+ $UnRarStopWatch.Stop()
+ Write-HTMLLog -Column1 'Size:' -Column2 (Format-Size -SizeInBytes $TotalSize)
+ Write-HTMLLog -Column1 'Throughput:' -Column2 "$(Format-Size -SizeInBytes ($TotalSize/$UnRarStopWatch.Elapsed.TotalSeconds))/s"
}
-elseif (-not $RarFile -and $SingleFile) {
- Write-HTMLLog -Column1 "*** Single File ***" -Header
+elseif (-not $RarFile -and $SingleFile)
+{
+ Write-HTMLLog -Column1 '*** Single File ***' -Header
Start-RoboCopy -Source $DownloadRootPath -Destination $ProcessPathFull -File $DownloadName
}
-elseif (-not $RarFile -and $Folder) {
- Write-HTMLLog -Column1 "*** Folder ***" -Header
+elseif (-not $RarFile -and $Folder)
+{
+ Write-HTMLLog -Column1 '*** Folder ***' -Header
Start-RoboCopy -Source $DownloadPath -Destination $ProcessPathFull -File '*.*'
}
# Starting Post Processing for Movies and TV Shows
-if ($DownloadLabel -eq $TVLabel) {
- $MKVFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter "*.mkv"
+if ($DownloadLabel -eq $TVLabel)
+{
+ $MKVFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter '*.mkv'
$MKVCount = $MKVFiles.Count
- if ($MKVCount -gt 0) {
+ if ($MKVCount -gt 0)
+ {
$MKVFile = $true
}
- else {
+ else
+ {
$MKVFile = $false
}
- if ($MKVFile) {
+ if ($MKVFile)
+ {
# Download any missing subs
Start-Subliminal -Source $ProcessPathFull
@@ -1127,43 +274,52 @@ if ($DownloadLabel -eq $TVLabel) {
Start-MKV-Subtitle-Strip $ProcessPathFull
# Clean up Subs
- Start-SubEdit -File "*.srt" -Source $ProcessPathFull
+ Start-SubEdit -File '*.srt' -Source $ProcessPathFull
- Write-HTMLLog -Column1 "*** MKV Files ***" -Header
- foreach ($Mkv in $MKVFiles) {
- Write-HTMLLog -Column1 " " -Column2 $Mkv.name
+ Write-HTMLLog -Column1 '*** MKV Files ***' -Header
+ foreach ($Mkv in $MKVFiles)
+ {
+ Write-HTMLLog -Column1 ' ' -Column2 $Mkv.name
}
- $SrtFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter "*.srt"
- if ($SrtFiles.Count -gt 0) {
- Write-HTMLLog -Column1 "*** Subtitle Files ***" -Header
- foreach ($Srt in $SrtFiles) {
- Write-HTMLLog -Column1 " " -Column2 $srt.name
+ $SrtFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter '*.srt'
+ if ($SrtFiles.Count -gt 0)
+ {
+ Write-HTMLLog -Column1 '*** Subtitle Files ***' -Header
+ foreach ($Srt in $SrtFiles)
+ {
+ Write-HTMLLog -Column1 ' ' -Column2 $srt.name
}
}
}
- else {
- Write-HTMLLog -Column1 "*** Files ***" -Header
- $Files = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter "*.*"
- foreach ($File in $Files) {
- Write-HTMLLog -Column1 "File:" -Column2 $File.name
+ else
+ {
+ Write-HTMLLog -Column1 '*** Files ***' -Header
+ $Files = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter '*.*'
+ foreach ($File in $Files)
+ {
+ Write-HTMLLog -Column1 'File:' -Column2 $File.name
}
}
# Call Medusa to Post Process
Import-Medusa -Source $ProcessPathFull
- CleanProcessPath
+ CleanProcessPath -Path $ProcessPathFull -NoCleanUp $NoCleanUp
Stop-Script -ExitReason "$DownloadLabel - $DownloadName"
}
-elseif ($DownloadLabel -eq $MovieLabel) {
- $MKVFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter "*.mkv"
+elseif ($DownloadLabel -eq $MovieLabel)
+{
+ $MKVFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter '*.mkv'
$MKVCount = $MKVFiles.Count
- if ($MKVCount -gt 0) {
+ if ($MKVCount -gt 0)
+ {
$MKVFile = $true
}
- else {
+ else
+ {
$MKVFile = $false
}
- if ($MKVFile) {
+ if ($MKVFile)
+ {
# Download any missing subs
Start-Subliminal -Source $ProcessPathFull
@@ -1171,36 +327,41 @@ elseif ($DownloadLabel -eq $MovieLabel) {
Start-MKV-Subtitle-Strip $ProcessPathFull
# Clean up Subs
- Start-SubEdit -File "*.srt" -Source $ProcessPathFull
+ Start-SubEdit -File '*.srt' -Source $ProcessPathFull
- Write-HTMLLog -Column1 "*** MKV Files ***" -Header
- foreach ($Mkv in $MKVFiles) {
- Write-HTMLLog -Column1 " " -Column2 $Mkv.name
+ Write-HTMLLog -Column1 '*** MKV Files ***' -Header
+ foreach ($Mkv in $MKVFiles)
+ {
+ Write-HTMLLog -Column1 ' ' -Column2 $Mkv.name
}
- Write-HTMLLog -Column1 "*** Subtitle Files ***" -Header
- $SrtFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter "*.srt"
- foreach ($Srt in $SrtFiles) {
- Write-HTMLLog -Column1 " " -Column2 $srt.name
+ Write-HTMLLog -Column1 '*** Subtitle Files ***' -Header
+ $SrtFiles = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter '*.srt'
+ foreach ($Srt in $SrtFiles)
+ {
+ Write-HTMLLog -Column1 ' ' -Column2 $srt.name
}
}
- else {
- Write-HTMLLog -Column1 "*** Files ***" -Header
- $Files = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter "*.*"
- foreach ($File in $Files) {
- Write-HTMLLog -Column1 "File:" -Column2 $File.name
+ else
+ {
+ Write-HTMLLog -Column1 '*** Files ***' -Header
+ $Files = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter '*.*'
+ foreach ($File in $Files)
+ {
+ Write-HTMLLog -Column1 'File:' -Column2 $File.name
}
}
# Call Radarr to Post Process
Import-Radarr -Source $ProcessPathFull
- CleanProcessPath
+ CleanProcessPath -Path $ProcessPathFull -NoCleanUp $NoCleanUp
Stop-Script -ExitReason "$DownloadLabel - $DownloadName"
}
# Reached the end of script
-Write-HTMLLog -Column1 "*** Post Process General Download ***" -Header
-$Files = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter "*.*"
-foreach ($File in $Files) {
- Write-HTMLLog -Column1 "File:" -Column2 $File.name
+Write-HTMLLog -Column1 '*** Post Process General Download ***' -Header
+$Files = Get-ChildItem -LiteralPath $ProcessPathFull -Recurse -Filter '*.*'
+foreach ($File in $Files)
+{
+ Write-HTMLLog -Column1 'File:' -Column2 $File.name
}
Stop-Script -ExitReason "$DownloadLabel - $DownloadName"
\ No newline at end of file
diff --git a/functions/CleanProcessPath.ps1 b/functions/CleanProcessPath.ps1
new file mode 100644
index 0000000..dff4c6d
--- /dev/null
+++ b/functions/CleanProcessPath.ps1
@@ -0,0 +1,54 @@
+function CleanProcessPath
+{
+ param (
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Path,
+
+ [Parameter(
+ Mandatory = $false
+ )]
+ [bool] $NoCleanUp
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+
+ if ($NoCleanUp)
+ {
+ Write-HTMLLog -Column1 'Cleanup' -Column2 'NoCleanUp switch was given at command line, leaving files'
+ }
+ else
+ {
+ try
+ {
+ If (Test-Path -LiteralPath $ProcessPathFull)
+ {
+ Remove-Item -Force -Recurse -LiteralPath $ProcessPathFull
+ }
+ }
+ catch
+ {
+ Write-HTMLLog -Column1 'Exception:' -Column2 $_.Exception.Message -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ }
+ }
+}
\ No newline at end of file
diff --git a/functions/Format-Size.ps1 b/functions/Format-Size.ps1
new file mode 100644
index 0000000..d07eb29
--- /dev/null
+++ b/functions/Format-Size.ps1
@@ -0,0 +1,58 @@
+function Format-Size()
+{
+ <#
+ .SYNOPSIS
+ Takes bytes and converts it to KB.MB,GB,TB,PB
+
+ .DESCRIPTION
+ Takes bytes and converts it to KB.MB,GB,TB,PB
+
+ .PARAMETER SizeInBytes
+ Input bytes
+
+ .EXAMPLE
+ Format-Size -SizeInBytes 864132
+ 843,88 KB
+
+ Format-Size -SizeInBytes 8641320
+ 8,24 MB
+
+ .NOTES
+ General notes
+ #>
+ [CmdletBinding()]
+ param(
+ [Parameter(
+ Mandatory = $true,
+ ValueFromPipeline = $true
+ )]
+ [double] $SizeInBytes
+ )
+ switch ([math]::Max($SizeInBytes, 0))
+ {
+ { $_ -ge 1PB }
+ {
+ '{0:N2} PB' -f ($SizeInBytes / 1PB); break
+ }
+ { $_ -ge 1TB }
+ {
+ '{0:N2} TB' -f ($SizeInBytes / 1TB); break
+ }
+ { $_ -ge 1GB }
+ {
+ '{0:N2} GB' -f ($SizeInBytes / 1GB); break
+ }
+ { $_ -ge 1MB }
+ {
+ '{0:N2} MB' -f ($SizeInBytes / 1MB); break
+ }
+ { $_ -ge 1KB }
+ {
+ '{0:N2} KB' -f ($SizeInBytes / 1KB); break
+ }
+ default
+ {
+ "$SizeInBytes Bytes"
+ }
+ }
+}
\ No newline at end of file
diff --git a/functions/Get-Input.ps1 b/functions/Get-Input.ps1
new file mode 100644
index 0000000..663f4dd
--- /dev/null
+++ b/functions/Get-Input.ps1
@@ -0,0 +1,50 @@
+Function Get-Input
+{
+ <#
+ .SYNOPSIS
+ Get input from user
+
+ .DESCRIPTION
+ Stop the script and get input from user and answer will be returned
+
+ .PARAMETER Message
+ The question to show to the user
+
+ .PARAMETER Required
+ If provided will force an answer to be given
+
+ .EXAMPLE
+ $UserName = Get-Input -Message "What is your name" -Required
+ $UserAge = Get-Input -Message "What is your age"
+
+ .NOTES
+ General notes
+ #>
+ [CmdletBinding()]
+ param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Message,
+
+ [Parameter(
+ Mandatory = $false
+ )]
+ [switch] $Required
+
+ )
+ if ($Required)
+ {
+ While ( ($Null -eq $Variable) -or ($Variable -eq '') )
+ {
+ $Variable = Read-Host -Prompt "$Message"
+ $Variable = $Variable.Trim()
+ }
+ }
+ else
+ {
+ $Variable = Read-Host -Prompt "$Message"
+ $Variable = $Variable.Trim()
+ }
+ Return $Variable
+}
\ No newline at end of file
diff --git a/functions/Import-Medusa.ps1 b/functions/Import-Medusa.ps1
new file mode 100644
index 0000000..da4a93b
--- /dev/null
+++ b/functions/Import-Medusa.ps1
@@ -0,0 +1,127 @@
+
+function Import-Medusa
+{
+ <#
+ .SYNOPSIS
+ Start import in Medusa
+
+ .DESCRIPTION
+ Start import to Medusa with timeout and error handeling
+
+ .PARAMETER Source
+ Path to episode to import
+
+ .EXAMPLE
+ Import-Medusa -Source 'C:\Temp\Episode'
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(Mandatory = $true)]
+ $Source
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog', 'Stop-Script'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+
+ $body = @{
+ 'proc_dir' = $Source
+ 'resource' = ''
+ 'process_method' = 'move'
+ 'force' = $true
+ 'is_priority' = $false
+ 'delete_on' = $false
+ 'failed' = $false
+ 'proc_type' = 'manual'
+ 'ignore_subs' = $false
+ } | ConvertTo-Json
+
+ $headers = @{
+ 'X-Api-Key' = $MedusaApiKey
+ }
+ Write-HTMLLog -Column1 '*** Medusa Import ***' -Header
+ try
+ {
+ $response = Invoke-RestMethod -Uri "http://$MedusaHost`:$MedusaPort/api/v2/postprocess" -Method Post -Body $Body -Headers $headers
+ }
+ catch
+ {
+ Write-HTMLLog -Column1 'Exception:' -Column2 $_.Exception.Message -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
+ }
+ if ($response.status -eq 'success')
+ {
+ $timeout = New-TimeSpan -Minutes $MedusaTimeOutMinutes
+ $endTime = (Get-Date).Add($timeout)
+ do
+ {
+ try
+ {
+ $status = Invoke-RestMethod -Uri "http://$MedusaHost`:$MedusaPort/api/v2/postprocess/$($response.queueItem.identifier)" -Method Get -Headers $headers
+ }
+ catch
+ {
+ Write-HTMLLog -Column1 'Exception:' -Column2 $_.Exception.Message -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
+ }
+ Start-Sleep 1
+ }
+ until ($status.success -or ((Get-Date) -gt $endTime))
+ if ($status.success)
+ {
+ $ValuesToFind = 'Processing failed', 'aborting post-processing', 'Unable to figure out what folder to process'
+ $MatchPattern = ($ValuesToFind | ForEach-Object { [regex]::Escape($_) }) -join '|'
+ if ($status.output -match $MatchPattern)
+ {
+ $ValuesToFind = 'Retrieving episode object for', 'Current quality', 'New quality', 'Old size', 'New size', 'Processing failed', 'aborting post-processing', 'Unable to figure out what folder to process'
+ $MatchPattern = ($ValuesToFind | ForEach-Object { [regex]::Escape($_) }) -join '|'
+ foreach ($line in $status.output )
+ {
+ if ($line -match $MatchPattern)
+ {
+ Write-HTMLLog -Column1 'Medusa:' -Column2 $line -ColorBg 'Error'
+ }
+ }
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+ }
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Medusa:' -Column2 $status.success -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Medusa:' -Column2 "Import Timeout: ($MedusaTimeOutMinutes) minutes" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
+ }
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Medusa:' -Column2 $response.status -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Medusa Error: $DownloadLabel - $DownloadName"
+ }
+}
\ No newline at end of file
diff --git a/functions/Import-Radarr.ps1 b/functions/Import-Radarr.ps1
new file mode 100644
index 0000000..82b1890
--- /dev/null
+++ b/functions/Import-Radarr.ps1
@@ -0,0 +1,122 @@
+function Import-Radarr
+{
+ <#
+ .SYNOPSIS
+ Start Radarr movie import
+
+ .DESCRIPTION
+ STart the Radarr movie import with error handling
+
+ .PARAMETER Source
+ Path to movie to import
+
+ .EXAMPLE
+ Import-Radarr -Source 'C:\Temp\Movie'
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Source
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog', 'Stop-Script'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+
+ $body = @{
+ 'name' = 'DownloadedMoviesScan'
+ 'downloadClientId' = $TorrentHash
+ 'importMode' = 'Move'
+ 'path' = $Source
+ } | ConvertTo-Json
+
+ $headers = @{
+ 'X-Api-Key' = $RadarrApiKey
+ 'Content-Type' = 'application/json'
+ }
+ Write-HTMLLog -Column1 '*** Radarr Import ***' -Header
+ try
+ {
+ $response = Invoke-RestMethod -Uri "http://$RadarrHost`:$RadarrPort/api/v3/command" -Method Post -Body $Body -Headers $headers
+ }
+ catch
+ {
+ Write-HTMLLog -Column1 'Exception:' -Column2 $_.Exception.Message -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
+ }
+ if ($response.status -eq 'queued' -or $response.status -eq 'started' -or $response.status -eq 'completed')
+ {
+ $timeout = New-TimeSpan -Minutes $RadarrTimeOutMinutes
+ $endTime = (Get-Date).Add($timeout)
+ do
+ {
+ try
+ {
+ $status = Invoke-RestMethod -Uri "http://$RadarrHost`:$RadarrPort/api/v3/command/$($response.id)" -Method Get -Headers $headers
+ }
+ catch
+ {
+ Write-HTMLLog -Column1 'Exception:' -Column2 $_.Exception.Message -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
+ }
+ Start-Sleep 1
+ }
+ until ($status.status -ne 'started' -or ((Get-Date) -gt $endTime) )
+ if ($status.status -eq 'completed')
+ {
+ if ($status.duration -gt '00:00:02.0000000')
+ {
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Radarr:' -Column2 'Completed but failed' -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Radarr:' -Column2 'Radarr has no failed handling see: https://github.com/Radarr/Radarr/issues/5539' -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
+ }
+ }
+ if ($status.status -eq 'failed')
+ {
+ Write-HTMLLog -Column1 'Radarr:' -Column2 $status.status -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Radarr:' -Column2 $status.exception -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
+ }
+ if ((Get-Date) -gt $endTime)
+ {
+ Write-HTMLLog -Column1 'Radarr:' -Column2 $status.status -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Radarr:' -Column2 "Import Timeout: ($RadarrTimeOutMinutes) minutes" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
+ }
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Radarr:' -Column2 $response.status -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Radarr Error: $DownloadLabel - $DownloadName"
+ }
+}
\ No newline at end of file
diff --git a/functions/New-Mutex.ps1 b/functions/New-Mutex.ps1
new file mode 100644
index 0000000..1a67920
--- /dev/null
+++ b/functions/New-Mutex.ps1
@@ -0,0 +1,66 @@
+function New-Mutex
+{
+ <#
+ .SYNOPSIS
+ Create a Mutex
+ .DESCRIPTION
+ This function attempts to get a lock to a mutex with a given name. If a lock
+ cannot be obtained this function waits until it can.
+
+ Using mutexes, multiple scripts/processes can coordinate exclusive access
+ to a particular work product. One script can create the mutex then go about
+ doing whatever work is needed, then release the mutex at the end. All other
+ scripts will wait until the mutex is released before they too perform work
+ that only one at a time should be doing.
+
+ This function outputs a PSObject with the following NoteProperties:
+
+ Name
+ Mutex
+
+ Use this object in a followup call to Remove-Mutex once done.
+ .PARAMETER MutexName
+ The name of the mutex to create.
+ .INPUTS
+ None. You cannot pipe objects to this function.
+ .OUTPUTS
+ PSObject
+ #Requires -Version 2.0
+ #>
+ [CmdletBinding()]
+ [OutputType(
+ [PSObject]
+ )]
+ Param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [ValidateNotNullOrEmpty()]
+ [string] $MutexName
+ )
+
+ $MutexWasCreated = $false
+ $Mutex = $Null
+ Write-Host "Waiting to acquire lock [$MutexName]..." -ForegroundColor DarkGray
+ [void][System.Reflection.Assembly]::LoadWithPartialName('System.Threading')
+ try
+ {
+ $Mutex = [System.Threading.Mutex]::OpenExisting($MutexName)
+ }
+ catch
+ {
+ $Mutex = New-Object System.Threading.Mutex($true, $MutexName, [ref]$MutexWasCreated)
+ }
+ try
+ {
+ if (!$MutexWasCreated)
+ {
+ $Mutex.WaitOne() | Out-Null
+ }
+ }
+ catch
+ {
+ }
+ Write-Host "Lock [$MutexName] acquired. Executing..." -ForegroundColor DarkGray
+ Write-Output ([PSCustomObject]@{ Name = $MutexName; Mutex = $Mutex })
+} # New-Mutex
\ No newline at end of file
diff --git a/functions/Remove-Mutex.ps1 b/functions/Remove-Mutex.ps1
new file mode 100644
index 0000000..bfc6ce9
--- /dev/null
+++ b/functions/Remove-Mutex.ps1
@@ -0,0 +1,35 @@
+function Remove-Mutex
+{
+ <#
+ .SYNOPSIS
+ Removes a previously created Mutex
+ .DESCRIPTION
+ This function attempts to release a lock on a mutex created by an earlier call
+ to New-Mutex.
+ .PARAMETER MutexObject
+ The PSObject object as output by the New-Mutex function.
+ .INPUTS
+ None. You cannot pipe objects to this function.
+ .OUTPUTS
+ None.
+ #Requires -Version 2.0
+ #>
+ [CmdletBinding()]
+ Param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [ValidateNotNull()]
+ [PSObject] $MutexObject
+ )
+
+ # $MutexObject | fl * | Out-String | Write-Host
+ Write-Host "Releasing lock [$($MutexObject.Name)]..." -ForegroundColor DarkGray
+ try
+ {
+ [void]$MutexObject.Mutex.ReleaseMutex()
+ }
+ catch
+ {
+ }
+} # Remove-Mutex
\ No newline at end of file
diff --git a/functions/Send-Mail.ps1 b/functions/Send-Mail.ps1
new file mode 100644
index 0000000..8bb7cd8
--- /dev/null
+++ b/functions/Send-Mail.ps1
@@ -0,0 +1,106 @@
+function Send-Mail
+{
+ <#
+ .SYNOPSIS
+ Send mail
+
+ .DESCRIPTION
+ Send email with file contents as body
+
+ .PARAMETER SMTPserver
+ SMTP server
+
+ .PARAMETER SMTPport
+ SMTP Port
+
+ .PARAMETER MailTo
+ Mail to
+
+ .PARAMETER MailFrom
+ Mail From
+
+ .PARAMETER MailFromName
+ Mail From Name
+
+ .PARAMETER MailSubject
+ Mail Subject
+
+ .PARAMETER MailBody
+ Path to html file as mail body
+
+ .PARAMETER SMTPuser
+ SMTP User
+
+ .PARAMETER SMTPpass
+ SMTP Password
+
+ .EXAMPLE
+ Send-Mail -SMTPserver 'mail.domain.com' -SMTPPort '25' -MailTo 'recipient@mail.com' -MailFrom 'sender@mail.com' -MailFromName 'Sender Name' -MailSubject 'Mail Subject' -MailBody 'C:\Temp\log.html' -SMTPuser 'user' -SMTPpass 'p@ssw0rd'
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $SMTPserver,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $SMTPport,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $MailTo,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $MailFrom,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $MailFromName,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $MailSubject,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $MailBody,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $SMTPuser,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $SMTPpass
+ )
+
+ $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $StartInfo.FileName = $MailSendPath
+ $StartInfo.RedirectStandardError = $true
+ $StartInfo.RedirectStandardOutput = $true
+ $StartInfo.UseShellExecute = $false
+ $StartInfo.Arguments = @("-smtp $SMTPserver", "-port $SMTPport", "-domain $SMTPserver", "-t $MailTo", "-f $MailFrom", "-fname `"$MailFromName`"", "-sub `"$MailSubject`"", 'body', "-file `"$MailBody`"", "-mime-type `"text/html`"", '-ssl', "auth -user $SMTPuser -pass $SMTPpass")
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo = $StartInfo
+ $Process.Start() | Out-Null
+ # $stdout = $Process.StandardOutput.ReadToEnd()
+ # $stderr = $Process.StandardError.ReadToEnd()
+ # Write-Host "stdout: $stdout"
+ # Write-Host "stderr: $stderr"
+ $Process.WaitForExit()
+ # Write-Host "exit code: " + $p.ExitCode
+ # return $stdout
+}
\ No newline at end of file
diff --git a/functions/Start-MKV-Subtitle-Strip.ps1 b/functions/Start-MKV-Subtitle-Strip.ps1
new file mode 100644
index 0000000..9e7fa5a
--- /dev/null
+++ b/functions/Start-MKV-Subtitle-Strip.ps1
@@ -0,0 +1,291 @@
+function Start-MKV-Subtitle-Strip
+{
+ <#
+ .SYNOPSIS
+ Extract wanted SRT subtitles from MKVs in root folder and remux MKVs to strip out unwanted subtitle languages
+ .DESCRIPTION
+ Searches for all MKV files in root folder and extracts the SRT that are defined in $WantedLanguages
+ Remux any MKV that has subtitles of unwanted languages or Track_name in $SubtitleNamesToRemove.
+ Rename srt subtitle files based on $LanguageCodes
+ .PARAMETER Source
+ Defines the root folder to start the search for MKV files
+ .EXAMPLE
+ Start-MKV-Subtitle-Strip 'C:\Temp\Source'
+ .OUTPUTS
+ SRT files of the desired languages
+ file.en.srt
+ file.2.en.srt
+ file.nl.srt
+ file.de.srt
+ MKV files without the unwanted subtitles
+ file.mkv
+ #>
+ param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Source
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+
+ $episodes = @()
+ $SubsExtracted = $false
+ $TotalSubsToExtract = 0
+ $TotalSubsToRemove = 0
+
+ Write-HTMLLog -Column1 '*** Extract srt files from MKV ***' -Header
+ Get-ChildItem -LiteralPath $Source -Recurse -Filter '*.mkv' | ForEach-Object {
+ Get-ChildItem -LiteralPath $_.FullName | ForEach-Object {
+ $fileName = $_.BaseName
+ $filePath = $_.FullName
+ $fileRoot = $_.Directory
+
+ # Start the json export with MKVMerge on the available tracks
+ $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $StartInfo.FileName = $MKVMergePath
+ $StartInfo.RedirectStandardError = $true
+ $StartInfo.RedirectStandardOutput = $true
+ $StartInfo.UseShellExecute = $false
+ $StartInfo.Arguments = @('-J', "`"$filePath`"")
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo = $StartInfo
+ $Process.Start() | Out-Null
+ $stdout = $Process.StandardOutput.ReadToEnd()
+ # $stderr = $Process.StandardError.ReadToEnd()
+ # Write-Host "stdout: $stdout"
+ # Write-Host "stderr: $stderr"
+ $Process.WaitForExit()
+ if ($Process.ExitCode -eq 2)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvmerge:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ }
+ elseif ($Process.ExitCode -eq 1)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvmerge:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Warning' -ColorBg 'Error'
+ }
+ elseif ($Process.ExitCode -eq 0)
+ {
+ $fileMetadata = $stdout | ConvertFrom-Json
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvmerge:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Warning' -ColorBg 'Error'
+ }
+
+ $file = @{
+ FileName = $fileName
+ FilePath = $filePath
+ FileRoot = $fileRoot
+ FileTracks = $fileMetadata.tracks
+ FileAttachments = $fileMetadata.attachments
+ }
+
+ $episodes += New-Object PSObject -Property $file
+ }
+ }
+
+ # Exctract wanted SRT subtitles
+ $episodes | ForEach-Object {
+ $episode = $_
+ $SubIDsToExtract = @()
+ $SubIDsToRemove = @()
+ $SubsToExtract = @()
+ $SubNamesToKeep = @()
+
+ $episode.FileTracks | ForEach-Object {
+ $FileTrack = $_
+ if ($FileTrack.id)
+ {
+ # Check if subtitle is srt
+ if ($FileTrack.type -eq 'subtitles' -and $FileTrack.codec -eq 'SubRip/SRT')
+ {
+
+ # Check to see if track_name is part of $SubtitleNamesToRemove list
+ if ($null -ne ($SubtitleNamesToRemove | Where-Object { $FileTrack.properties.track_name -match $_ }))
+ {
+ $SubIDsToRemove += $FileTrack.id
+ }
+ # Check is subtitle is in $WantedLanguages list
+ elseif ($FileTrack.properties.language -in $WantedLanguages)
+ {
+
+ # Handle multiple subtitles of same language, if exist append ID to file
+ if ("$($episode.FileName).$($FileTrack.properties.language).srt" -in $SubNamesToKeep)
+ {
+ $prefix = "$($FileTrack.id).$($FileTrack.properties.language)"
+ }
+ else
+ {
+ $prefix = "$($FileTrack.properties.language)"
+ }
+
+ # Add Subtitle name and ID to be extracted
+ $SubsToExtract += "`"$($FileTrack.id):$($episode.FileRoot)\$($episode.FileName).$($prefix).srt`""
+
+ # Keep track of subtitle file names that will be extracted to handle possible duplicates
+ $SubNamesToKeep += "$($episode.FileName).$($prefix).srt"
+
+ # Add subtitle ID to for MKV remux
+ $SubIDsToExtract += $FileTrack.id
+ }
+ else
+ {
+ $SubIDsToRemove += $FileTrack.id
+ }
+ }
+ }
+ }
+
+ # Count all subtitles to keep and remove of logging
+ $TotalSubsToExtract = $TotalSubsToExtract + $SubIDsToExtract.count
+ $TotalSubsToRemove = $TotalSubsToRemove + $SubIDsToRemove.count
+
+ # Extract the wanted subtitle languages
+ if ($SubIDsToExtract.count -gt 0)
+ {
+ $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $StartInfo.FileName = $MKVExtractPath
+ $StartInfo.RedirectStandardError = $true
+ $StartInfo.RedirectStandardOutput = $true
+ $StartInfo.UseShellExecute = $false
+ $StartInfo.Arguments = @("`"$($episode.FilePath)`"", 'tracks', "$SubsToExtract")
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo = $StartInfo
+ $Process.Start() | Out-Null
+ $stdout = $Process.StandardOutput.ReadToEnd()
+ # $stderr = $Process.StandardError.ReadToEnd()
+ # Write-Host "stdout: $stdout"
+ # Write-Host "stderr: $stderr"
+ $Process.WaitForExit()
+ if ($Process.ExitCode -eq 2)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvextract:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ }
+ elseif ($Process.ExitCode -eq 1)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvextract:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Warning' -ColorBg 'Error'
+ }
+ elseif ($Process.ExitCode -eq 0)
+ {
+ $SubsExtracted = $true
+ # Write-HTMLLog -Column1 "Extracted:" -Column2 "$($SubsToExtract.count) Subtitles"
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvextract:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Unknown' -ColorBg 'Error'
+ }
+ }
+
+ # Remux and strip out all unwanted subtitle languages
+ if ($SubIDsToRemove.Count -gt 0)
+ {
+ $TmpFileName = $Episode.FileName + '.tmp'
+ $TmpMkvPath = Join-Path $episode.FileRoot $TmpFileName
+ $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $StartInfo.FileName = $MKVMergePath
+ $StartInfo.RedirectStandardError = $true
+ $StartInfo.RedirectStandardOutput = $true
+ $StartInfo.UseShellExecute = $false
+ $StartInfo.Arguments = @("-o `"$TmpMkvPath`"", "-s !$($SubIDsToRemove -join ',')", "`"$($episode.FilePath)`"")
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo = $StartInfo
+ $Process.Start() | Out-Null
+ $stdout = $Process.StandardOutput.ReadToEnd()
+ # $stderr = $Process.StandardError.ReadToEnd()
+ # Write-Host "stdout: $stdout"
+ # Write-Host "stderr: $stderr"
+ $Process.WaitForExit()
+ if ($Process.ExitCode -eq 2)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvmerge:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ }
+ elseif ($Process.ExitCode -eq 1)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvmerge:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Warning' -ColorBg 'Error'
+ }
+ elseif ($Process.ExitCode -eq 0)
+ {
+ # Overwrite original mkv after successful remux
+ Move-Item -Path $TmpMkvPath -Destination $($episode.FilePath) -Force
+ # Write-HTMLLog -Column1 "Removed:" -Column2 "$($SubIDsToRemove.Count) unwanted subtitle languages"
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'mkvmerge:' -Column2 $stdout -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Warning' -ColorBg 'Error'
+ }
+ }
+ }
+
+ # Rename extracted subs to correct 2 county code based on $LanguageCodes
+ if ($SubsExtracted)
+ {
+ $SrtFiles = Get-ChildItem -LiteralPath $Source -Recurse -Filter '*.srt'
+ foreach ($srt in $SrtFiles)
+ {
+ $FileDirectory = $srt.Directory
+ $FilePath = $srt.FullName
+ $FileName = $srt.Name
+ foreach ($LanguageCode in $Config.LanguageCodes)
+ {
+ $FileNameNew = $FileName.Replace(".$($LanguageCode.alpha3).", ".$($LanguageCode.alpha2).")
+ $ReplacementWasMade = $FileName -cne $FileNameNew
+ if ($ReplacementWasMade)
+ {
+ $Destination = Join-Path -Path $FileDirectory -ChildPath $FileNameNew
+ Move-Item -Path $FilePath -Destination $Destination -Force
+ break
+ }
+ }
+ }
+ if ($TotalSubsToExtract -gt 0)
+ {
+ Write-HTMLLog -Column1 'Subtitles:' -Column2 "$TotalSubsToExtract Extracted"
+ }
+ if ($TotalSubsToRemove -gt 0)
+ {
+ Write-HTMLLog -Column1 'Subtitles:' -Column2 "$TotalSubsToRemove Removed"
+ }
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Result:' -Column2 'No SRT subs found in MKV'
+ }
+}
\ No newline at end of file
diff --git a/functions/Start-RoboCopy.ps1 b/functions/Start-RoboCopy.ps1
new file mode 100644
index 0000000..522ef9a
--- /dev/null
+++ b/functions/Start-RoboCopy.ps1
@@ -0,0 +1,188 @@
+function Start-RoboCopy
+{
+ <#
+ .SYNOPSIS
+ RoboCopy wrapper
+ .DESCRIPTION
+ Wrapper for RoboCopy since it it way faster to copy that way.
+ This Function relies on Write-HTMLLog Function and Stop-Script Function
+ .PARAMETER Source
+ Source path
+ .PARAMETER Destination
+ Destination path
+ .PARAMETER File
+ File patern to copy *.* or name.ext
+ This allows for folder or single filecopy
+ .EXAMPLE
+ Start-RoboCopy -Source 'C:\Temp\Source' -Destination 'C:\Temp\Destination' -File '*.*'
+ Start-RoboCopy -Source 'C:\Temp\Source' -Destination 'C:\Temp\Destination' -File 'file.ext'
+ #>
+ param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Source,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Destination,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $File
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog', 'Stop-Script', 'Format-Size'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+
+ # Start
+ if ($File -ne '*.*')
+ {
+ $options = @('/R:1', '/W:1', '/J', '/NP', '/NP', '/NJH', '/NFL', '/NDL', '/MT8')
+ }
+ elseif ($File -eq '*.*')
+ {
+ $options = @('/R:1', '/W:1', '/E', '/J', '/NP', '/NJH', '/NFL', '/NDL', '/MT8')
+ }
+
+ $cmdArgs = @("`"$Source`"", "`"$Destination`"", "`"$File`"", $options)
+
+ # executing unrar command
+ Write-HTMLLog -Column1 'Starting:' -Column2 'Copy files'
+ try
+ {
+ # executing Robocopy command
+ $Output = robocopy @cmdArgs
+ }
+ catch
+ {
+ Write-Host 'Exception:' $_.Exception.Message -ForegroundColor Red
+ Write-Host 'RoboCopy not found' -ForegroundColor Red
+ exit 1
+ }
+
+
+ foreach ($line in $Output)
+ {
+ switch -Regex ($line)
+ {
+ # Dir metrics
+ '^\s+Dirs\s:\s*'
+ {
+ # Example: Dirs : 35 0 0 0 0 0
+ $dirs = $_.Replace('Dirs :', '').Trim()
+ # Now remove the white space between the values.'
+ $dirs = $dirs -split '\s+'
+
+ # Assign the appropriate column to values.
+ $TotalDirs = $dirs[0]
+ $CopiedDirs = $dirs[1]
+ $FailedDirs = $dirs[4]
+ }
+ # File metrics
+ '^\s+Files\s:\s[^*]'
+ {
+ # Example: Files : 8318 0 8318 0 0 0
+ $files = $_.Replace('Files :', '').Trim()
+ # Now remove the white space between the values.'
+ $files = $files -split '\s+'
+
+ # Assign the appropriate column to values.
+ $TotalFiles = $files[0]
+ $CopiedFiles = $files[1]
+ $FailedFiles = $files[4]
+ }
+ # Byte metrics
+ '^\s+Bytes\s:\s*'
+ {
+ # Example: Bytes : 1.607 g 0 1.607 g 0 0 0
+ $bytes = $_.Replace('Bytes :', '').Trim()
+ # Now remove the white space between the values.'
+ $bytes = $bytes -split '\s+'
+
+ # The raw text from the log file contains a k,m,or g after the non zero numers.
+ # This will be used as a multiplier to determin the size in kb.
+ $counter = 0
+ $tempByteArray = 0, 0, 0, 0, 0, 0
+ $tempByteArrayCounter = 0
+ foreach ($column in $bytes)
+ {
+ if ($column -eq 'k')
+ {
+ $tempByteArray[$tempByteArrayCounter - 1] = '{0:N2}' -f ([single]($bytes[$counter - 1])* 1024)
+ $counter += 1
+ }
+ elseif ($column -eq 'm')
+ {
+ $tempByteArray[$tempByteArrayCounter - 1] = '{0:N2}' -f ([single]($bytes[$counter - 1]) * 1048576)
+ $counter += 1
+ }
+ elseif ($column -eq 'g')
+ {
+ $tempByteArray[$tempByteArrayCounter - 1] = '{0:N2}' -f ([single]($bytes[$counter - 1]) * 1073741824)
+ $counter += 1
+ }
+ else
+ {
+ $tempByteArray[$tempByteArrayCounter] = $column
+ $counter += 1
+ $tempByteArrayCounter += 1
+ }
+ }
+ # Assign the appropriate column to values.
+ $TotalSize = Format-Size -SizeInBytes ([double]::Parse($tempByteArray[0]))
+ $CopiedSize = Format-Size -SizeInBytes ([double]::Parse($tempByteArray[1]))
+ $FailedSize = Format-Size -SizeInBytes ([double]::Parse($tempByteArray[4]))
+ # array columns 2,3, and 5 are available, but not being used currently.
+ }
+ # Speed metrics
+ '^\s+Speed\s:.*sec.$'
+ {
+ # Example: Speed : 120.816 Bytes/min.
+ $speed = $_.Replace('Speed :', '').Trim()
+ $speed = $speed.Replace('Bytes/sec.', '').Trim()
+ # Assign the appropriate column to values.
+ $speed = Format-Size -SizeInBytes $speed
+ }
+ }
+ }
+
+
+ if ($FailedDirs -gt 0 -or $FailedFiles -gt 0)
+ {
+ Write-HTMLLog -Column1 'Dirs' -Column2 "$TotalDirs Total" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Dirs' -Column2 "$FailedDirs Failed" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Files:' -Column2 "$TotalFiles Total" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Files:' -Column2 "$FailedFiles Failed" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Size:' -Column2 "$TotalSize Total" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Size:' -Column2 "$FailedSize Failed" -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Copy Error: $DownloadLabel - $DownloadName"
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Dirs:' -Column2 "$CopiedDirs Copied"
+ Write-HTMLLog -Column1 'Files:' -Column2 "$CopiedFiles Copied"
+ Write-HTMLLog -Column1 'Size:' -Column2 "$CopiedSize"
+ Write-HTMLLog -Column1 'Throughput:' -Column2 "$Speed/s"
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+ }
+}
\ No newline at end of file
diff --git a/functions/Start-SubEdit.ps1 b/functions/Start-SubEdit.ps1
new file mode 100644
index 0000000..5a6de09
--- /dev/null
+++ b/functions/Start-SubEdit.ps1
@@ -0,0 +1,78 @@
+function Start-SubEdit
+{
+ <#
+ .SYNOPSIS
+ Start Subtitle Edit
+
+ .DESCRIPTION
+ Start Subtitle Edit to clean up subtitles
+
+ .PARAMETER Source
+ Path to process and clean subtitles
+
+ .PARAMETER Files
+ The files to process, this will be *.srt typically
+
+ .EXAMPLE
+ Start-SubEdit -File '*.srt' -Source 'C:\Temp\Episode'
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Source,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Files
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+
+ Write-HTMLLog -Column1 '*** Clean up Subtitles ***' -Header
+ $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $StartInfo.FileName = $SubtitleEditPath
+ $StartInfo.RedirectStandardError = $true
+ $StartInfo.RedirectStandardOutput = $true
+ $StartInfo.UseShellExecute = $false
+ $StartInfo.Arguments = @('/convert', "$Files", 'subrip', "/inputfolder`:`"$Source`"", '/overwrite', '/MergeSameTexts', '/fixcommonerrors', '/removetextforhi', '/fixcommonerrors', '/fixcommonerrors')
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo = $StartInfo
+ $Process.Start() | Out-Null
+ $stdout = $Process.StandardOutput.ReadToEnd()
+ $stderr = $Process.StandardError.ReadToEnd()
+ $Process.WaitForExit()
+ if ($Process.ExitCode -gt 1)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Error:' -Column2 $stderr -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "SubEdit Error: $DownloadLabel - $DownloadName"
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+ }
+}
\ No newline at end of file
diff --git a/functions/Start-Subliminal.ps1 b/functions/Start-Subliminal.ps1
new file mode 100644
index 0000000..69edf07
--- /dev/null
+++ b/functions/Start-Subliminal.ps1
@@ -0,0 +1,103 @@
+function Start-Subliminal
+{
+ <#
+ .SYNOPSIS
+ Start Subliminal to download subs
+
+ .DESCRIPTION
+ Start Subliminal to download needed subtitles
+
+ .PARAMETER Source
+ Path to files that need subtitles
+
+ .EXAMPLE
+ Start-Subliminal -Source 'C:\Temp\Episode'
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Source
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+
+ Write-HTMLLog -Column1 '*** Download missing Subtitles ***' -Header
+ $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $StartInfo.FileName = $SubliminalPath
+ $StartInfo.RedirectStandardError = $true
+ $StartInfo.RedirectStandardOutput = $true
+ $StartInfo.UseShellExecute = $false
+ $StartInfo.Arguments = @('--opensubtitles', $OpenSubUser, $OpenSubPass, "--omdb $omdbAPI", 'download', '-r omdb', '-p opensubtitles', '-l eng', '-l nld', "`"$Source`"")
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo = $StartInfo
+ $Process.Start() | Out-Null
+ $stdout = $Process.StandardOutput.ReadToEnd()
+ $stderr = $Process.StandardError.ReadToEnd()
+ $Process.WaitForExit()
+ # Write-Host $stdout
+ # Write-Host $stderr
+ if ($stdout -match '(\d+)(?=\s*video collected)')
+ {
+ $VideoCollected = $Matches.0
+ }
+ if ($stdout -match '(\d+)(?=\s*video ignored)')
+ {
+ $VideoIgnored = $Matches.0
+ }
+ if ($stdout -match '(\d+)(?=\s*error)')
+ {
+ $VideoError = $Matches.0
+ }
+ if ($stdout -match '(\d+)(?=\s*subtitle)')
+ {
+ $SubsDownloaded = $Matches.0
+ }
+ if ($stdout -match 'Some providers have been discarded due to unexpected errors')
+ {
+ $SubliminalExitCode = 1
+ }
+ if ($SubliminalExitCode -gt 0)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Error:' -Column2 $stderr -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ }
+ else
+ {
+ if ($SubsDownloaded -gt 0)
+ {
+ # Write-HTMLLog -Column1 "Downloaded:" -Column2 "$SubsDownloaded Subtitles"
+ Write-HTMLLog -Column1 'Collected:' -Column2 "$VideoCollected Videos"
+ Write-HTMLLog -Column1 'Ignored:' -Column2 "$VideoIgnored Videos"
+ Write-HTMLLog -Column1 'Error:' -Column2 "$VideoError Videos"
+ Write-HTMLLog -Column1 'Downloaded:' -Column2 "$SubsDownloaded Subtitles"
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Result:' -Column2 'No subs downloaded with Subliminal'
+ }
+ }
+}
\ No newline at end of file
diff --git a/functions/Start-UnRar.ps1 b/functions/Start-UnRar.ps1
new file mode 100644
index 0000000..abf39b7
--- /dev/null
+++ b/functions/Start-UnRar.ps1
@@ -0,0 +1,75 @@
+function Start-UnRar
+{
+ <#
+ .SYNOPSIS
+ Unrar file
+ .DESCRIPTION
+ Takes rar file and unrar them to target
+ .PARAMETER UnRarSourcePath
+ Path of rar file to extract
+ .PARAMETER UnRarTargetPath
+ Destination folder path
+ .EXAMPLE
+ Start-UnRar -UnRarSourcePath 'C:\Temp\Source\file.rar' -UnRarTargetPath 'C:\Temp\Destination'
+ #>
+ Param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $UnRarSourcePath,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $UnRarTargetPath
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog', 'Stop-Script'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+ $RarFile = Split-Path -Path $UnRarSourcePath -Leaf
+
+ # executing unrar command
+ Write-HTMLLog -Column1 'File:' -Column2 "$RarFile"
+ $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $StartInfo.FileName = $WinRarPath
+ $StartInfo.RedirectStandardError = $true
+ $StartInfo.RedirectStandardOutput = $true
+ $StartInfo.UseShellExecute = $false
+ $StartInfo.Arguments = @('x', "`"$UnRarSourcePath`"", "`"$UnRarTargetPath`"", '-y', '-idq')
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo = $StartInfo
+ $Process.Start() | Out-Null
+ # $stdout = $Process.StandardOutput.ReadToEnd()
+ $stderr = $Process.StandardError.ReadToEnd()
+ # Write-Host "stdout: $stdout"
+ # Write-Host "stderr: $stderr"
+ $Process.WaitForExit()
+ if ($Process.ExitCode -gt 0)
+ {
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 $($Process.ExitCode) -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Error:' -Column2 $stderr -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Failed' -ColorBg 'Error'
+ Stop-Script -ExitReason "Unrar Error: $DownloadLabel - $DownloadName"
+ }
+ else
+ {
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+ }
+}
\ No newline at end of file
diff --git a/functions/Stop-Script.ps1 b/functions/Stop-Script.ps1
new file mode 100644
index 0000000..0824376
--- /dev/null
+++ b/functions/Stop-Script.ps1
@@ -0,0 +1,60 @@
+function Stop-Script
+{
+ <#
+ .SYNOPSIS
+ Stops the script and removes Mutex
+
+ .DESCRIPTION
+ Stops the script and removes the Mutex
+
+ .PARAMETER ExitReason
+ Reason for exit
+
+ .EXAMPLE
+ An example
+
+ .NOTES
+ General notes
+ #>
+
+ Param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $ExitReason
+ )
+
+ # Make sure needed functions are available otherwise try to load them.
+ $commands = 'Write-HTMLLog', 'Send-Mail', 'Remove-Mutex'
+ foreach ($commandName in $commands)
+ {
+ if (!($command = Get-Command $commandName -ErrorAction SilentlyContinue))
+ {
+ Try
+ {
+ . $PSScriptRoot\$commandName.ps1
+ Write-Host "$commandName Function loaded." -ForegroundColor Green
+ }
+ Catch
+ {
+ Write-Error -Message "Failed to import $commandName function: $_"
+ exit 1
+ }
+ }
+ }
+ # Start
+
+ # Stop the Stopwatch
+ $StopWatch.Stop()
+
+ Write-HTMLLog -Column1 '*** Script Exection time ***' -Header
+ Write-HTMLLog -Column1 'Time Taken:' -Column2 $($StopWatch.Elapsed.ToString('mm\:ss'))
+
+ Format-Table
+ Write-Log -LogFile $LogFilePath
+ Send-Mail -SMTPserver $SMTPserver -SMTPport $SMTPport -MailTo $MailTo -MailFrom $MailFrom -MailFromName $MailFromName -MailSubject $ExitReason -MailBody $LogFilePath -SMTPuser $SMTPuser -SMTPpass $SMTPpass
+
+ # Clean up the Mutex
+ Remove-Mutex -MutexObject $ScriptMutex
+ Exit
+}
\ No newline at end of file
diff --git a/functions/Test-Variable-Path.ps1 b/functions/Test-Variable-Path.ps1
new file mode 100644
index 0000000..354fe2a
--- /dev/null
+++ b/functions/Test-Variable-Path.ps1
@@ -0,0 +1,40 @@
+function Test-Variable-Path
+{
+ <#
+ .SYNOPSIS
+ Test path to variables
+
+ .DESCRIPTION
+ Test path to
+
+ .PARAMETER Path
+ File path to test if exist
+
+ .PARAMETER Name
+ Variable that uses this path
+
+ .EXAMPLE
+ Test-Variable-Path -Path 'c:\Windows\notepad.exe' -Name 'NotepadPath'
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Path,
+
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Name
+ )
+ if (!(Test-Path -LiteralPath $Path))
+ {
+ Write-Host "Cannot find: $Path" -ForegroundColor Red
+ Write-Host "As defined in variable: $Name" -ForegroundColor Red
+ Write-Host 'Will now exit!' -ForegroundColor Red
+ Exit 1
+ }
+}
\ No newline at end of file
diff --git a/functions/Write-HTMLLog.ps1 b/functions/Write-HTMLLog.ps1
new file mode 100644
index 0000000..2f92dd1
--- /dev/null
+++ b/functions/Write-HTMLLog.ps1
@@ -0,0 +1,158 @@
+function Format-Table
+{
+ <#
+ .SYNOPSIS
+ Starts and stops Log file
+
+ .DESCRIPTION
+ Will either initiate the Log Variable in memory and open the HTML Table or clos the table
+
+ .PARAMETER Start
+ If defined indicated to open the HTML Table, without it the HTML table will be closed
+
+ .EXAMPLE
+ Format-Table -Start
+ Format-Table
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(
+ Mandatory = $false
+ )]
+ [switch] $Start
+ )
+
+ if ($Start)
+ {
+ $global:Log = @()
+ $global:Log += ""
+ $global:Log += ""
+ $global:Log += ""
+ $global:Log += ''
+ }
+ else
+ {
+ $global:Log += ''
+ $global:Log += '
'
+ }
+}
+
+Function Write-HTMLLog
+{
+ <#
+ .SYNOPSIS
+ Add line to in memory log
+
+ .DESCRIPTION
+ Adds a line to the in memory log file and based on the parameters will do formating
+
+ .PARAMETER Column1
+ Text to be put in first column, mandatory
+
+ .PARAMETER Column2
+ Text to be put in the second column, not mandatory
+
+ .PARAMETER Header
+ Define that the Text from the parameter Column1 should be treated as new Header in the log table.
+ If switch is defined Column2 is ignored
+
+ .PARAMETER ColorBg
+ Background color of Table Cell, this is a switch indicating a Success or Error. If not defined the standard color will be used.
+
+ Success will get Green Table Cell color
+ Error will get Red Table Cell Color
+
+ .EXAMPLE
+ Write-HTMLLog -Column1 '*** Header of the table ***' -Header
+ Write-HTMLLog -Column1 'Column1 Text' -Column2 'Column2 Text'
+ Write-HTMLLog -Column1 'Exit Code:' -Column2 'Failed to do X' -ColorBg 'Error'
+ Write-HTMLLog -Column1 'Result:' -Column2 'Successful' -ColorBg 'Success'
+
+ .NOTES
+ General notes
+ #>
+ Param(
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $Column1,
+
+ [Parameter(
+ Mandatory = $false
+ )]
+ [string] $Column2,
+
+ [Parameter(
+ Mandatory = $false
+ )]
+ [switch] $Header,
+
+ [Parameter(
+ Mandatory = $false
+ )]
+ [ValidateSet(
+ 'Success', 'Error'
+ )]
+ [string] $ColorBg
+ )
+
+ $global:Log += ''
+ if ($Header)
+ {
+ $global:Log += "$Column1 | "
+ }
+ else
+ {
+ if ($ColorBg -eq '')
+ {
+ $global:Log += "$Column1 | "
+ $global:Log += "$Column2 | "
+ $global:Log += '
'
+ }
+ elseif ($ColorBg -eq 'Success')
+ {
+ $global:Log += "$Column1 | "
+ $global:Log += "$Column2 | "
+ $global:Log += ''
+ }
+ elseif ($ColorBg -eq 'Error')
+ {
+ $global:Log += "$Column1 | "
+ $global:Log += "$Column2 | "
+ $global:Log += ''
+ }
+ }
+ Write-Output "$Column1 $Column2"
+}
+
+
+function Write-Log
+{
+ <#
+ .SYNOPSIS
+ Write log to disk
+
+ .DESCRIPTION
+ Takes the Global Variable that hold the log in memory and writes it to disk
+
+ .PARAMETER LogFile
+ Log File including the Path to write
+
+ .EXAMPLE
+ Write-Log -LogFile 'C:\Temp\logfile.html'
+
+ .NOTES
+ General notes
+ #>
+ param (
+ [Parameter(
+ Mandatory = $true
+ )]
+ [string] $LogFile
+ )
+ Set-Content -Path $LogFile -Value $global:Log
+}
\ No newline at end of file