|
| 1 | +<# |
| 2 | +.SYNOPSIS |
| 3 | + Rename source repo's legacy ep##-<slug> files to canonical names from |
| 4 | + docs/EPISODE_MAP.json. Idempotent. Use -DryRun to preview. |
| 5 | +
|
| 6 | +.DESCRIPTION |
| 7 | + Mirrors c:\code\ggg\canonicalize-site.ps1 on the deploy side. Renames: |
| 8 | + - podcasts/scripts/chapters/ep##-*.txt |
| 9 | + - podcasts/scripts/appendices/ep##-*.txt |
| 10 | + - podcasts/transcripts/chapters/ep##-*-chapters.json |
| 11 | + - podcasts/transcripts/chapters/ep##-*-segments.json |
| 12 | + - podcasts/transcripts/appendices/ep##-*-chapters.json |
| 13 | + - podcasts/transcripts/appendices/ep##-*-segments.json |
| 14 | +
|
| 15 | + Skips podcasts/bundles/ -- already canonical. |
| 16 | + Does NOT regenerate HTML; run scripts/build-html.js after to refresh |
| 17 | + html/docs/*.html companion sections. |
| 18 | +
|
| 19 | +.PARAMETER DryRun |
| 20 | + Print planned operations without renaming. |
| 21 | +#> |
| 22 | +[CmdletBinding()] |
| 23 | +param( |
| 24 | + [switch]$DryRun |
| 25 | +) |
| 26 | + |
| 27 | +Set-StrictMode -Version Latest |
| 28 | +$ErrorActionPreference = 'Stop' |
| 29 | + |
| 30 | +$Root = $PSScriptRoot |
| 31 | +$EpisodeMapPath = Join-Path $Root 'docs\EPISODE_MAP.json' |
| 32 | +$ScriptsRoot = Join-Path $Root 'podcasts\scripts' |
| 33 | +$TranscriptsRoot = Join-Path $Root 'podcasts\transcripts' |
| 34 | + |
| 35 | +if (-not (Test-Path $EpisodeMapPath)) { |
| 36 | + throw "Episode map not found: $EpisodeMapPath" |
| 37 | +} |
| 38 | + |
| 39 | +Write-Host "== Loading canonical map from EPISODE_MAP.json ==" |
| 40 | +$epMap = (Get-Content $EpisodeMapPath -Raw | ConvertFrom-Json) |
| 41 | +$narrationToCanonical = @{} |
| 42 | +foreach ($ep in $epMap.episodes) { |
| 43 | + if ($ep.group -ne 'ep') { continue } |
| 44 | + $canonical = $ep.filename -replace '\.mp3$', '' |
| 45 | + $narrationToCanonical[$ep.narration_id] = $canonical |
| 46 | +} |
| 47 | +Write-Host ("Loaded {0} narration_id -> canonical mappings" -f $narrationToCanonical.Count) |
| 48 | + |
| 49 | +function Get-CanonicalBase { |
| 50 | + param([string]$LegacyBaseName) |
| 51 | + # Parse leading 'ep##' from a name like 'ep00-welcome' or 'ep00-welcome-chapters' |
| 52 | + if ($LegacyBaseName -match '^(ep\d{2,})-') { |
| 53 | + $narration = $matches[1] |
| 54 | + if ($narrationToCanonical.ContainsKey($narration)) { |
| 55 | + return $narrationToCanonical[$narration] |
| 56 | + } |
| 57 | + } |
| 58 | + return $null |
| 59 | +} |
| 60 | + |
| 61 | +function Invoke-CanonicalRename { |
| 62 | + param( |
| 63 | + [string]$Dir, |
| 64 | + [string]$Filter, |
| 65 | + [string[]]$KeepSuffixes |
| 66 | + ) |
| 67 | + if (-not (Test-Path $Dir)) { |
| 68 | + Write-Host " (skip, not present) $Dir" |
| 69 | + return @{ planned = 0; done = 0; skipped = 0 } |
| 70 | + } |
| 71 | + $stats = @{ planned = 0; done = 0; skipped = 0; unmapped = @() } |
| 72 | + Get-ChildItem $Dir -Filter $Filter | ForEach-Object { |
| 73 | + $base = $_.BaseName |
| 74 | + $ext = $_.Extension |
| 75 | + # Detect suffix like '-chapters' / '-segments' |
| 76 | + $suffix = '' |
| 77 | + $core = $base |
| 78 | + foreach ($s in $KeepSuffixes) { |
| 79 | + if ($base.EndsWith($s)) { |
| 80 | + $suffix = $s |
| 81 | + $core = $base.Substring(0, $base.Length - $s.Length) |
| 82 | + break |
| 83 | + } |
| 84 | + } |
| 85 | + $canonical = Get-CanonicalBase $core |
| 86 | + if (-not $canonical) { |
| 87 | + # Not a legacy ep##-* file (might already be canonical) |
| 88 | + if ($core -match '^(ch|ref|tools|git|a11y|agents|sec|cc)-\d+-') { |
| 89 | + $stats.skipped++ |
| 90 | + } else { |
| 91 | + $stats.unmapped += $_.Name |
| 92 | + } |
| 93 | + return |
| 94 | + } |
| 95 | + $newName = "$canonical$suffix$ext" |
| 96 | + $newPath = Join-Path $Dir $newName |
| 97 | + if ($newName -eq $_.Name) { |
| 98 | + $stats.skipped++ |
| 99 | + return |
| 100 | + } |
| 101 | + $stats.planned++ |
| 102 | + if (Test-Path $newPath) { |
| 103 | + Write-Host (" CONFLICT: {0} -> {1} (target already exists)" -f $_.Name, $newName) -ForegroundColor Yellow |
| 104 | + return |
| 105 | + } |
| 106 | + if ($DryRun) { |
| 107 | + Write-Host (" DRY: {0} -> {1}" -f $_.Name, $newName) |
| 108 | + } else { |
| 109 | + Rename-Item -LiteralPath $_.FullName -NewName $newName |
| 110 | + Write-Host (" RENAME: {0} -> {1}" -f $_.Name, $newName) |
| 111 | + $stats.done++ |
| 112 | + } |
| 113 | + } |
| 114 | + if ($stats.unmapped.Count -gt 0) { |
| 115 | + Write-Host (" UNMAPPED ({0}):" -f $stats.unmapped.Count) -ForegroundColor Yellow |
| 116 | + $stats.unmapped | ForEach-Object { Write-Host " $_" } |
| 117 | + } |
| 118 | + return $stats |
| 119 | +} |
| 120 | + |
| 121 | +Write-Host "" |
| 122 | +Write-Host "== podcasts/scripts/chapters ==" |
| 123 | +$s1 = Invoke-CanonicalRename -Dir (Join-Path $ScriptsRoot 'chapters') -Filter '*.txt' -KeepSuffixes @() |
| 124 | +Write-Host (" planned={0} done={1} skipped={2}" -f $s1.planned, $s1.done, $s1.skipped) |
| 125 | + |
| 126 | +Write-Host "" |
| 127 | +Write-Host "== podcasts/scripts/appendices ==" |
| 128 | +$s2 = Invoke-CanonicalRename -Dir (Join-Path $ScriptsRoot 'appendices') -Filter '*.txt' -KeepSuffixes @() |
| 129 | +Write-Host (" planned={0} done={1} skipped={2}" -f $s2.planned, $s2.done, $s2.skipped) |
| 130 | + |
| 131 | +Write-Host "" |
| 132 | +Write-Host "== podcasts/transcripts/chapters ==" |
| 133 | +$s3 = Invoke-CanonicalRename -Dir (Join-Path $TranscriptsRoot 'chapters') -Filter '*.json' -KeepSuffixes @('-chapters','-segments') |
| 134 | +Write-Host (" planned={0} done={1} skipped={2}" -f $s3.planned, $s3.done, $s3.skipped) |
| 135 | + |
| 136 | +Write-Host "" |
| 137 | +Write-Host "== podcasts/transcripts/appendices ==" |
| 138 | +$s4 = Invoke-CanonicalRename -Dir (Join-Path $TranscriptsRoot 'appendices') -Filter '*.json' -KeepSuffixes @('-chapters','-segments') |
| 139 | +Write-Host (" planned={0} done={1} skipped={2}" -f $s4.planned, $s4.done, $s4.skipped) |
| 140 | + |
| 141 | +Write-Host "" |
| 142 | +$totalPlanned = $s1.planned + $s2.planned + $s3.planned + $s4.planned |
| 143 | +$totalDone = $s1.done + $s2.done + $s3.done + $s4.done |
| 144 | +Write-Host ("== SUMMARY == planned={0} done={1}" -f $totalPlanned, $totalDone) |
| 145 | + |
| 146 | +if ($DryRun) { |
| 147 | + Write-Host "" |
| 148 | + Write-Host "Dry run only. Re-run without -DryRun to apply." -ForegroundColor Cyan |
| 149 | +} |
0 commit comments