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