# YT Regulation Patreon # Set URL and Location $URL = "https://www.patreon.com/cw/TheRegulationPod" $folderPath = '\\truenas3.kwyjibo.info\RegulationPodcast$' $rejects = @() $RejectString = $rejects -join '|' Set-Location $folderPath function Download-YTDLP { Param( [Parameter(Mandatory = $true)] [string]$videoUrl, [Parameter(Mandatory = $true)] [string]$OutputPath, [string]$RejectString, [switch]$WithCookies ) $ytDlpPath = "D:\yt-dlp\yt-dlp.exe" # Start building an array of arguments using strict comma separation (Recommended format) $arguments = @( "$videoUrl", "--write-info-json", "--write-thumbnail", "--embed-metadata", "--convert-thumbnails", "jpg", "--no-progress", "-t", "sleep", "--rate-limit", "5M", "-o", "$OutputPath", '-f', "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best", "-S", "vcodec:h264", "--reject-title", "$RejectString", "--playlist-reverse", "--download-archive", "ytdlp_archive.txt" ) # --- Conditional Logic Applied Here --- if ($WithCookies) { Write-Verbose "--- Using browser cookies for download. ---" -Verbose $arguments += "--cookies-from-browser", "firefox" } else { Write-Verbose "--- Downloading without specific cookie credentials. ---" -Verbose } # 1. Execute yt-dlp using the call operator (&) and passing the arguments array (@) & $ytDlpPath $arguments # 2. CRITICAL: Check the Exit Code immediately after execution if ($LASTEXITCODE -ne 0) { # If the exit code is not 0, we throw a terminating exception. # This exception will be caught by your external try/catch block! $ErrorMessage = "yt-dlp failed (Exit Code: $($LASTEXITCODE)). Check standard error output for details." throw $ErrorMessage } Write-Verbose "YTDLP finished successfully." # Optional confirmation } # Function to manage Short ID tracking (NEW) function Manage-ShortTracking { Param( [Parameter(Mandatory = $true)] [string]$ShortDirPath, [Parameter(Mandatory = $true)] [string]$VideoId, [switch]$IsNewDownload ) $trackingFile = Join-Path -Path $ShortDirPath -ChildPath "shorts_ids.json" if ($IsNewDownload) { # 1. Check if ID already exists if (Test-Path $trackingFile) { try { $existingIds = Get-Content -Path $trackingFile | ConvertFrom-Json if ($existingIds -contains $VideoId) { return $true # Video ID found, should skip download } } catch { Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)" } } # 2. If not found, write the new ID to the file (or update it) try { if (Test-Path $trackingFile) { # File exists, append without duplicating $existingIds = Get-Content -Path $trackingFile | ConvertFrom-Json if (-not ($existingIds -contains $VideoId)) { $newIds = $existingIds + $VideoId $newIds | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile Write-Verbose "Successfully added ID '$VideoId' to shorts tracking." } else { Write-Verbose "ID '$VideoId' already exists in tracking file." } } else { # File does not exist, create it @($VideoId) | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile Write-Verbose "Created and added ID '$VideoId' to shorts tracking file." } } catch { Write-Error "Failed to write to shorts tracking file: $($_.Exception.Message)" } } else { # Check mode (only needed when checking before download) if (Test-Path $trackingFile) { try { $existingIds = Get-Content -Path $trackingFile | ConvertFrom-Json return $existingIds -contains $VideoId # Returns True if ID is found } catch { Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)" return $false # Assume safe to download if parsing fails } } return $false # No tracking file exists, assume safe to download } } function Parse-URLToIdentifier { param( [Parameter(Mandatory = $true)] [string]$Url ) $platform = "" $name = "" # 1. Determine the Platform if ($Url -match "patreon\.com") { $platform = "patreon" # For Patreon, take the last segment of the URL path (e.g., TheRegulationPod) $name = ($Url -split '/')[-1] } elseif ($Url -match "youtube.com") { $platform = "youtube" # For YouTube, extract everything after the "@" symbol if ($Url -match '@(.*)') { $name = $Matches[1] } else { # Handle cases where @ might not be present (though unlikely for channel URLs) $name = "UnknownChannel" } } else { Write-Error "Unsupported URL platform." return $null } # Construct and return the final identifier return "${platform}_${name}" } $archive_name = Parse-URLToIdentifier -Url $Url # Download flat playlist Write-Verbose -Message "Download flat playlist" $flat = D:\yt-dlp\yt-dlp.exe -j --flat-playlist $URL $flat | Set-Content -Path "$archive_name.json" # load json into memory, convert to psobject $json = Get-Content -Path "$archive_name.json" | ConvertFrom-Json # Load all .mp4 files into memory once at the start $mp4Files = Get-ChildItem -Path $folderPath -Recurse -Filter "*.mp4" ForEach ($obj in ($json | Sort-Object playlist_index -Descending | Select-Object -First 10)) { # Initialize $fileFound as null for each iteration $fileFound = $false # Extract information from the JSON object $videoUrl = $obj.webpage_url $Title = $obj.title $Id = $obj.id $extractor = $obj.extractor # Log the start of the process Write-Verbose -Message "Start $extractor-$Id ##### $Title" -Verbose # Check if the title matches any reject term using wildcards $reject_matches = $rejects | Where-Object { $Title -like "*$($_)*" } If ($reject_matches) { Write-Warning -Message "Skip $Id ##### $Title (Rejected by Title)" continue # Jumps immediately to the next iteration of the loop } # downloaded already? # Regular expression to match the ID, supporting both YouTube and Patreon prefixes # (?:youtube-|patreon-) creates a non-capturing group that matches either prefix $regex = "(?i)(?:youtube-|patreon-)$([regex]::Escape($Id))" # Check if any file already exists that matches the video ID $fileFound = $mp4Files | Where-Object { $_.Name -match $regex } # If no file is found, notify the user if ($fileFound) { Write-Warning "File found with the YouTube ID: $Id" } Else { $outputPath = Join-Path $folderPath "Unsorted/Season %(upload_date>%y|Unknown)s/%(upload_date>%m|Unknown)s/%(release_date>%Y%m%d,upload_date>%Y%m%d)s - %(title).180B [%(extractor)s-%(id)s].%(ext)s" # Execute yt-dlp command for non-rejected videos try { Write-Warning -Message "Dwnld $Id ##### $Title" Download-YTDLP -videoUrl $videoUrl -OutputPath $outputPath -RejectString $RejectString $DownloadSuccessful = $true # Set flag to true if download completes successfully } catch { $DownloadError = $true Write-Error "Failed to download $Id - $_" $DownloadSuccessful = $false # Ensure failure is tracked } If ($DownloadSuccessful -eq $false) { # If the initial download failed, attempt with cookies try { Write-Warning -Message "Dwnld (Cookies Attempt) $Id ##### $Title" Download-YTDLP -videoUrl $videoUrl -OutputPath $outputPath -RejectString $RejectString -WithCookies $DownloadSuccessful = $true # Set flag to true if the second attempt succeeds } catch { $DownloadError = $true Write-Error "Failed to download $Id (Cookies Attempt) - $_" $DownloadSuccessful = $false } } if ($isShort -and $DownloadSuccessful) { $shortDirPath = Split-Path $outputPath -Parent # Gets the directory path (e.g., \RegulationPodcast\YouTube Shorts\...) Manage-ShortTracking -ShortDirPath $shortDirPath -VideoId $Id -IsNewDownload:$true } } # Log the end of the process Write-Verbose -Message "End $Id ##### $Title" }