DL updates

This commit is contained in:
2026-04-28 09:51:21 -05:00
parent 18d5913d5e
commit 57c717aff4
4 changed files with 145 additions and 107 deletions
View File
@@ -3,7 +3,6 @@
$URL = "https://www.youtube.com/@TheRegulationPodcast" $URL = "https://www.youtube.com/@TheRegulationPodcast"
$folderPath = '\\truenas3.kwyjibo.info\RegulationPodcast$' $folderPath = '\\truenas3.kwyjibo.info\RegulationPodcast$'
$rejects = @() $rejects = @()
$RejectString = $rejects -join '|' $RejectString = $rejects -join '|'
+65 -66
View File
@@ -1,9 +1,8 @@
## YT Regulation Podcast # YT Regulation Patreon
# Set URL and Location # Set URL and Location
$URL = "https://www.youtube.com/@theregulationpod" $URL = "https://www.patreon.com/cw/TheRegulationPod"
$folderPath = '\\truenas3.kwyjibo.info\RegulationPodcast$' $folderPath = '\\truenas3.kwyjibo.info\RegulationPodcast$'
$rejects = @() $rejects = @()
$RejectString = $rejects -join '|' $RejectString = $rejects -join '|'
@@ -26,18 +25,20 @@ function Download-YTDLP {
# Start building an array of arguments using strict comma separation (Recommended format) # Start building an array of arguments using strict comma separation (Recommended format)
$arguments = @( $arguments = @(
$videoUrl, "$videoUrl",
"--write-info-json", "--write-info-json",
"--write-thumbnail", "--write-thumbnail",
"--embed-metadata",
"--convert-thumbnails", "jpg", "--convert-thumbnails", "jpg",
"--no-progress", "--no-progress",
"-t", "sleep", "-t", "sleep",
"--rate-limit", "5M", "--rate-limit", "5M",
"-o", $OutputPath, "-o", "$OutputPath",
'-f', "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best", '-f', "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best",
"-S", "vcodec:h264", "-S", "vcodec:h264",
"--reject-title", $RejectString, "--reject-title", "$RejectString",
"--playlist-reverse" "--playlist-reverse",
"--download-archive", "ytdlp_archive.txt"
) )
# --- Conditional Logic Applied Here --- # --- Conditional Logic Applied Here ---
@@ -85,7 +86,8 @@ function Manage-ShortTracking {
if ($existingIds -contains $VideoId) { if ($existingIds -contains $VideoId) {
return $true # Video ID found, should skip download return $true # Video ID found, should skip download
} }
} catch { }
catch {
Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)" Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)"
} }
} }
@@ -99,25 +101,30 @@ function Manage-ShortTracking {
$newIds = $existingIds + $VideoId $newIds = $existingIds + $VideoId
$newIds | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile $newIds | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile
Write-Verbose "Successfully added ID '$VideoId' to shorts tracking." Write-Verbose "Successfully added ID '$VideoId' to shorts tracking."
} else { }
else {
Write-Verbose "ID '$VideoId' already exists in tracking file." Write-Verbose "ID '$VideoId' already exists in tracking file."
} }
} else { }
else {
# File does not exist, create it # File does not exist, create it
@($VideoId) | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile @($VideoId) | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile
Write-Verbose "Created and added ID '$VideoId' to shorts tracking file." Write-Verbose "Created and added ID '$VideoId' to shorts tracking file."
} }
} catch { }
catch {
Write-Error "Failed to write to shorts tracking file: $($_.Exception.Message)" Write-Error "Failed to write to shorts tracking file: $($_.Exception.Message)"
} }
} else { }
else {
# Check mode (only needed when checking before download) # Check mode (only needed when checking before download)
if (Test-Path $trackingFile) { if (Test-Path $trackingFile) {
try { try {
$existingIds = Get-Content -Path $trackingFile | ConvertFrom-Json $existingIds = Get-Content -Path $trackingFile | ConvertFrom-Json
return $existingIds -contains $VideoId # Returns True if ID is found return $existingIds -contains $VideoId # Returns True if ID is found
} catch { }
catch {
Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)" Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)"
return $false # Assume safe to download if parsing fails return $false # Assume safe to download if parsing fails
} }
@@ -126,21 +133,55 @@ function Manage-ShortTracking {
} }
} }
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 # Download flat playlist
Write-Verbose -Message "Download flat playlist" Write-Verbose -Message "Download flat playlist"
$flat = D:\yt-dlp\yt-dlp.exe -j --flat-playlist $URL $flat = D:\yt-dlp\yt-dlp.exe -j --flat-playlist $URL
$flat | Set-Content -Path YT_theregulationpod.json $flat | Set-Content -Path "$archive_name.json"
# load json into memory, convert to psobject # load json into memory, convert to psobject
$json = Get-Content -Path YT_theregulationpod.json | ConvertFrom-Json $json = Get-Content -Path "$archive_name.json" | ConvertFrom-Json
# Load all .mp4 files into memory once at the start # Load all .mp4 files into memory once at the start
$mp4Files = Get-ChildItem -Path $folderPath -Recurse -Filter "*.mp4" $mp4Files = Get-ChildItem -Path $folderPath -Recurse -Filter "*.mp4"
ForEach ($obj in ($json | Sort-Object playlist_index -Descending | Select-Object -First 10)) {
ForEach ($obj in $json) {
# Initialize $fileFound as null for each iteration # Initialize $fileFound as null for each iteration
$fileFound = $false $fileFound = $false
@@ -148,10 +189,10 @@ ForEach ($obj in $json) {
$videoUrl = $obj.webpage_url $videoUrl = $obj.webpage_url
$Title = $obj.title $Title = $obj.title
$Id = $obj.id $Id = $obj.id
$extractor = $obj.extractor
# Log the start of the process # Log the start of the process
Write-Verbose -Message "Start $Id ##### $Title" -Verbose Write-Verbose -Message "Start $extractor-$Id ##### $Title" -Verbose
# Check if the title matches any reject term using wildcards # Check if the title matches any reject term using wildcards
$reject_matches = $rejects | Where-Object { $Title -like "*$($_)*" } $reject_matches = $rejects | Where-Object { $Title -like "*$($_)*" }
@@ -161,62 +202,20 @@ ForEach ($obj in $json) {
} }
# downloaded already? # downloaded already?
# Regular expression to match the ID after "youtube-" and before the closing bracket # Regular expression to match the ID, supporting both YouTube and Patreon prefixes
$regex = "(?i)youtube-$Id" # (?: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 # Check if any file already exists that matches the video ID
$fileFound = $mp4Files | Where-Object { $_.Name -match $regex } $fileFound = $mp4Files | Where-Object { $_.Name -match $regex }
# If no file is found, notify the user # If no file is found, notify the user
if ($fileFound) { if ($fileFound) {
Write-Warning "File found with the YouTube ID: $Id" Write-Warning "File found with the YouTube ID: $Id"
} }
Else { Else {
# Check if this is a YouTube Short by getting video info (aspect ratio or duration)
Write-Verbose -Message "Checking if video is a Short: $Title" -Verbose
$isShort = $false
$videoInfo = D:\yt-dlp\yt-dlp.exe -j $videoUrl
$videoInfoObj = $videoInfo | ConvertFrom-Json
$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"
if ($videoUrl -like "*shorts*") {
Write-Verbose "Identified as Shorts video because the URL contains 'shorts': $Id ##### $Title" -Verbose
$isShort = $true
}
Elseif ($videoInfoObj.duration -and $videoInfoObj.duration -lt 60) {
# Determine if this is a short based on duration
Write-Verbose "Identified as Shorts video because the duration is 60 seconds or less: $Id ##### $Title" -Verbose
$isShort = $true
}
elseif ($videoInfoObj.width -and $videoInfoObj.height) {
# Calculate aspect ratio (height/width for vertical videos)
$aspectRatio = [double]$videoInfoObj.height / [double]$videoInfoObj.width
if ($aspectRatio -gt 1.5) {
# Vertical video ( > 1.5:1)
$isShort = $true
}
}
# Set output path based on whether it's a short or not
if ($isShort) {
Write-Verbose -Message "Video detected as Short: $Title" -Verbose
# Note: This path must be determined before running the tracking check/download
$outputPath = Join-Path $folderPath "YouTube Shorts/%(release_date>%Y%m%d,upload_date>%Y%m%d)s - %(title).180B [%(extractor)s-%(id)s].%(ext)s"
$shortDirPath = Split-Path $outputPath -Parent # Gets the directory path (e.g., \RegulationPodcast\YouTube Shorts\...)
# Check if ID is in the tracking JSON file
$idAlreadyTracked = Manage-ShortTracking -ShortDirPath $shortDirPath -VideoId $Id -IsNewDownload:$false
if ($idAlreadyTracked) {
Write-Warning "Skipping Short $Id ##### $Title because it was previously tracked and deleted."
continue # Skip the download attempt entirely
}
}
else {
Write-Verbose -Message "Video detected as regular: $Title" -Verbose
$outputPath = Join-Path $folderPath "Unsorted/Season %(release_date>%y,upload_date>%y|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 # Execute yt-dlp command for non-rejected videos
try { try {
+60 -20
View File
@@ -3,7 +3,6 @@
$URL = "https://www.youtube.com/@theregulationpod" $URL = "https://www.youtube.com/@theregulationpod"
$folderPath = '\\truenas3.kwyjibo.info\RegulationPodcast$' $folderPath = '\\truenas3.kwyjibo.info\RegulationPodcast$'
$rejects = @() $rejects = @()
$RejectString = $rejects -join '|' $RejectString = $rejects -join '|'
@@ -29,6 +28,7 @@ function Download-YTDLP {
$videoUrl, $videoUrl,
"--write-info-json", "--write-info-json",
"--write-thumbnail", "--write-thumbnail",
"--embed-metadata".
"--convert-thumbnails", "jpg", "--convert-thumbnails", "jpg",
"--no-progress", "--no-progress",
"-t", "sleep", "-t", "sleep",
@@ -85,7 +85,8 @@ function Manage-ShortTracking {
if ($existingIds -contains $VideoId) { if ($existingIds -contains $VideoId) {
return $true # Video ID found, should skip download return $true # Video ID found, should skip download
} }
} catch { }
catch {
Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)" Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)"
} }
} }
@@ -99,25 +100,30 @@ function Manage-ShortTracking {
$newIds = $existingIds + $VideoId $newIds = $existingIds + $VideoId
$newIds | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile $newIds | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile
Write-Verbose "Successfully added ID '$VideoId' to shorts tracking." Write-Verbose "Successfully added ID '$VideoId' to shorts tracking."
} else { }
else {
Write-Verbose "ID '$VideoId' already exists in tracking file." Write-Verbose "ID '$VideoId' already exists in tracking file."
} }
} else { }
else {
# File does not exist, create it # File does not exist, create it
@($VideoId) | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile @($VideoId) | ConvertTo-Json -Depth 3 | Set-Content -Path $trackingFile
Write-Verbose "Created and added ID '$VideoId' to shorts tracking file." Write-Verbose "Created and added ID '$VideoId' to shorts tracking file."
} }
} catch { }
catch {
Write-Error "Failed to write to shorts tracking file: $($_.Exception.Message)" Write-Error "Failed to write to shorts tracking file: $($_.Exception.Message)"
} }
} else { }
else {
# Check mode (only needed when checking before download) # Check mode (only needed when checking before download)
if (Test-Path $trackingFile) { if (Test-Path $trackingFile) {
try { try {
$existingIds = Get-Content -Path $trackingFile | ConvertFrom-Json $existingIds = Get-Content -Path $trackingFile | ConvertFrom-Json
return $existingIds -contains $VideoId # Returns True if ID is found return $existingIds -contains $VideoId # Returns True if ID is found
} catch { }
catch {
Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)" Write-Error "Could not read or parse existing shorts tracking file: $($_.Exception.Message)"
return $false # Assume safe to download if parsing fails return $false # Assume safe to download if parsing fails
} }
@@ -126,20 +132,54 @@ function Manage-ShortTracking {
} }
} }
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 # Download flat playlist
Write-Verbose -Message "Download flat playlist" Write-Verbose -Message "Download flat playlist"
$flat = D:\yt-dlp\yt-dlp.exe -j --flat-playlist $URL $flat = D:\yt-dlp\yt-dlp.exe -j --flat-playlist $URL
$flat | Set-Content -Path YouTube_theregulationpod.json $flat | Set-Content -Path "$archive_name.json"
# load json into memory, convert to psobject # load json into memory, convert to psobject
$json = Get-Content -Path YouTube_theregulationpod.json | ConvertFrom-Json $json = Get-Content -Path "$archive_name.json" | ConvertFrom-Json
# Load all .mp4 files into memory once at the start # Load all .mp4 files into memory once at the start
$mp4Files = Get-ChildItem -Path $folderPath -Recurse -Filter "*.mp4" $mp4Files = Get-ChildItem -Path $folderPath -Recurse -Filter "*.mp4"
ForEach ($obj in $json) { ForEach ($obj in $json) {
# Initialize $fileFound as null for each iteration # Initialize $fileFound as null for each iteration
$fileFound = $false $fileFound = $false
@@ -149,7 +189,6 @@ ForEach ($obj in $json) {
$Title = $obj.title $Title = $obj.title
$Id = $obj.id $Id = $obj.id
# Log the start of the process # Log the start of the process
Write-Verbose -Message "Start $Id ##### $Title" -Verbose Write-Verbose -Message "Start $Id ##### $Title" -Verbose
@@ -161,25 +200,26 @@ ForEach ($obj in $json) {
} }
# downloaded already? # downloaded already?
# Regular expression to match the ID after "youtube-" and before the closing bracket # Regular expression to match the ID, supporting both YouTube and Patreon prefixes
$regex = "(?i)youtube-$Id" # (?: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 # Check if any file already exists that matches the video ID
$fileFound = $mp4Files | Where-Object { $_.Name -match $regex } $fileFound = $mp4Files | Where-Object { $_.Name -match $regex }
# If no file is found, notify the user # If no file is found, notify the user
if ($fileFound) { if ($fileFound) {
Write-Warning "File found with the YouTube ID: $Id" Write-Warning "File found with the YouTube ID: $Id"
} }
Else { Else {
# Check if this is a YouTube Short by getting video info (aspect ratio or duration) <# Check if this is a YouTube Short by getting video info (aspect ratio or duration)
Write-Verbose -Message "Checking if video is a Short: $Title" -Verbose Write-Verbose -Message "Checking if video is a Short: $Title" -Verbose
$isShort = $false $isShort = $false
$videoInfo = D:\yt-dlp\yt-dlp.exe -j $videoUrl $videoInfo = D:\yt-dlp\yt-dlp.exe -j $videoUrl
$videoInfoObj = $videoInfo | ConvertFrom-Json $videoInfoObj = $videoInfo | ConvertFrom-Json
if ($videoUrl -like "*shorts*") { if ($videoUrl -like "*shorts*") {
Write-Verbose "Identified as Shorts video because the URL contains 'shorts': $Id ##### $Title" -Verbose Write-Verbose "Identified as Shorts video because the URL contains 'shorts': $Id ##### $Title" -Verbose
$isShort = $true $isShort = $true
@@ -188,7 +228,7 @@ ForEach ($obj in $json) {
# Determine if this is a short based on duration # Determine if this is a short based on duration
Write-Verbose "Identified as Shorts video because the duration is 60 seconds or less: $Id ##### $Title" -Verbose Write-Verbose "Identified as Shorts video because the duration is 60 seconds or less: $Id ##### $Title" -Verbose
$isShort = $true $isShort = $true
} } <#
elseif ($videoInfoObj.width -and $videoInfoObj.height) { elseif ($videoInfoObj.width -and $videoInfoObj.height) {
# Calculate aspect ratio (height/width for vertical videos) # Calculate aspect ratio (height/width for vertical videos)
$aspectRatio = [double]$videoInfoObj.height / [double]$videoInfoObj.width $aspectRatio = [double]$videoInfoObj.height / [double]$videoInfoObj.width
@@ -196,13 +236,13 @@ ForEach ($obj in $json) {
# Vertical video ( > 1.5:1) # Vertical video ( > 1.5:1)
$isShort = $true $isShort = $true
} }
} }#>
# Set output path based on whether it's a short or not # Set output path based on whether it's a short or not
if ($isShort) { if ($isShort) {
Write-Verbose -Message "Video detected as Short: $Title" -Verbose Write-Verbose -Message "Video detected as Short: $Title" -Verbose
# Note: This path must be determined before running the tracking check/download # Note: This path must be determined before running the tracking check/download
$outputPath = Join-Path $folderPath "YouTube Shorts/%(release_date>%Y%m%d,upload_date>%Y%m%d)s - %(title).180B [%(extractor)s-%(id)s].%(ext)s" $outputPath = Join-Path $folderPath "Unsorted/%(release_date>%Y%m%d,upload_date>%Y%m%d)s - %(title).180B [%(extractor)s-%(id)s].%(ext)s"
$shortDirPath = Split-Path $outputPath -Parent # Gets the directory path (e.g., \RegulationPodcast\YouTube Shorts\...) $shortDirPath = Split-Path $outputPath -Parent # Gets the directory path (e.g., \RegulationPodcast\YouTube Shorts\...)
# Check if ID is in the tracking JSON file # Check if ID is in the tracking JSON file
@@ -215,7 +255,7 @@ ForEach ($obj in $json) {
} }
else { else {
Write-Verbose -Message "Video detected as regular: $Title" -Verbose Write-Verbose -Message "Video detected as regular: $Title" -Verbose
$outputPath = Join-Path $folderPath "Unsorted/Season %(release_date>%y,upload_date>%y|Unknown)s/%(release_date>%Y%m%d,upload_date>%Y%m%d)s - %(title).180B [%(extractor)s-%(id)s].%(ext)s" $outputPath = Join-Path $folderPath "Unsorted/Season %(release_date>%y|Unknown)s/%(release_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 # Execute yt-dlp command for non-rejected videos