@@ -20,7 +20,7 @@ if (-not [System.IO.Path]::IsPathRooted($FileListPath)) {
2020
2121if (-not (Test-Path $FileListPath )) {
2222 Write-Host " ERROR: File list not found: $FileListPath " - ForegroundColor Red
23- exit 1
23+ Cleanup; exit 1
2424}
2525
2626$files = Get-Content $FileListPath - ErrorAction Stop
@@ -29,7 +29,7 @@ Write-Host "Total files: $($files.Count)"
2929
3030if ($files.Count -eq 0 ) {
3131 Write-Host " ERROR: File list is empty: $FileListPath " - ForegroundColor Red
32- exit 1
32+ Cleanup; exit 1
3333} else {
3434 Write-Host " Sample file list entries (first 10):"
3535 $files | Select-Object - First 10 | ForEach-Object { Write-Host " $_ " }
@@ -101,7 +101,8 @@ $sortedFiles = $files | Sort-Object {
101101 }
102102
103103 # Priority 3: All other files not in SUMMARY - preserve original file-list order -> start at 01000000
104- if ($name -ne ' SUMMARY.md' ) {
104+ # BUT exclude the main SUMMARY.md file entirely from PDF (it's just navigation, not content)
105+ if ($name -ne ' SUMMARY.md' -or $fullPath -ne $mainSummaryFullPath ) {
105106 if ($originalOrderMap.ContainsKey ($fullPath )) {
106107 $origIndex = $originalOrderMap [$fullPath ]
107108 return (" {0:D8}|ORIG" -f (10000000 + $origIndex ))
@@ -110,20 +111,28 @@ $sortedFiles = $files | Sort-Object {
110111 }
111112 }
112113
113- # Priority 4: README.md in subdirectories (place near end but before main SUMMARY )
114+ # Priority 4: README.md in subdirectories (place near end)
114115 if ($name -eq ' README.md' -and $fullPath -ne $mainReadmeFullPath ) {
115116 return (" {0:D8}|README_SUB" -f 80000000 )
116117 }
117118
118- # Priority 5 (Last): Main SUMMARY.md at the end -> prefix 99999999
119+ # Main SUMMARY.md is excluded from PDF - return a value that will be filtered out
119120 if ($fullPath -eq $mainSummaryFullPath ) {
120- return (" {0:D8}|SUMMARY_LAST " -f 99999999 )
121+ return (" {0:D8}|EXCLUDE_SUMMARY " -f 99999999 )
121122 }
122123
123124 # Default fallback
124125 return (" {0:D8}|DEFAULT" -f 99999998 )
125126 }
126127
128+ # Filter out the main SUMMARY.md file from PDF generation (it's navigation, not content)
129+ $sortedFiles = $sortedFiles | Where-Object {
130+ $fullPath = [System.IO.Path ]::GetFullPath($_ )
131+ $fullPath -ne $mainSummaryFullPath
132+ }
133+
134+ Write-Host " Filtered files for PDF (excluding main SUMMARY.md): $ ( $sortedFiles.Count ) files"
135+
127136# Build an anchor map: fullpath -> unique anchor id
128137$anchorMap = @ {}
129138foreach ($f in $sortedFiles ) {
@@ -221,7 +230,7 @@ if ($wkhtmlPath) {
221230 Write-Host " - wkhtmltopdf (Windows): https://wkhtmltopdf.org/downloads.html" - ForegroundColor Yellow
222231 Write-Host " - or install via Chocolatey: choco install wkhtmltopdf -y (requires Chocolatey)" - ForegroundColor Yellow
223232 Write-Host " - weasyprint (requires Python + cairo/pango): pip install weasyprint (see https://weasyprint.org/docs/install/)" - ForegroundColor Yellow
224- exit 1
233+ Cleanup; exit 1
225234}
226235
227236# ---------------------------
@@ -343,6 +352,7 @@ foreach ($file in $sortedFiles) {
343352 ' 1f517' = @ { char = [System.Text.Encoding ]::UTF32.GetString([System.BitConverter ]::GetBytes(0x1F517 )); desc = ' link' }
344353 ' 1f554' = @ { char = [System.Text.Encoding ]::UTF32.GetString([System.BitConverter ]::GetBytes(0x1F554 )); desc = ' clock' }
345354 ' 1f464' = @ { char = [System.Text.Encoding ]::UTF32.GetString([System.BitConverter ]::GetBytes(0x1F464 )); desc = ' user' }
355+ ' 1f4da' = @ { char = [System.Text.Encoding ]::UTF32.GetString([System.BitConverter ]::GetBytes(0x1F4DA )); desc = ' books' }
346356 ' 26a0' = @ { char = [System.Text.Encoding ]::UTF32.GetString([System.BitConverter ]::GetBytes(0x26A0 )); desc = ' warning' }
347357 ' 2705' = @ { char = [System.Text.Encoding ]::UTF32.GetString([System.BitConverter ]::GetBytes(0x2705 )); desc = ' check' }
348358 ' 274c' = @ { char = [System.Text.Encoding ]::UTF32.GetString([System.BitConverter ]::GetBytes(0x274C )); desc = ' cross' }
@@ -359,7 +369,20 @@ foreach ($file in $sortedFiles) {
359369 }
360370
361371 # Remove ## Author and ## Auteur sections (heading and content until next heading or end)
362- $content = $content -replace ' (?ms)^##\s+(Author|Auteur)\s*$.*?(?=^##\s|\z)' , ' '
372+ # Handle variations: different heading levels (#, ##, ###, ####), case variations, emoji (👤 or text), and potential extra spaces
373+ # This regex matches any heading (1-4 levels) with Author/Auteur (with or without emoji) and removes everything until the next heading or end of file
374+ # Enhanced to handle: trailing colons, various whitespace, and any Unicode emoji
375+ $content = $content -replace ' (?mis)^\s{0,3}#{1,6}\s*(?:[\p{So}\p{Sk}\p{P}\p{S}\s]*)*(?:author|auteur)s?\s*:?\s*$.*?(?=^\s{0,3}#{1,6}\s|\z)' , ' '
376+
377+ # Remove single-line patterns such as "Author: Name" or "Auteur: Name"
378+ $content = $content -replace ' (?mi)^\s*(?:author|auteur)s?\s*:\s*.+$' , ' '
379+
380+ # Remove two-line patterns where a bare "Author" / "Auteur" line is followed by a short non-heading line (the author name).
381+ # Use a safer pattern that doesn't embed single-quote/backtick characters inside the literal.
382+ $content = $content -replace ' (?mis)^\s*(?:author|auteur)s?\s*\r?\n\s*(?!#{1,6})(.{1,120})\s*(?=\r?\n|\z)' , ' '
383+
384+ # Also clean up any potential multiple blank lines left behind by the removal
385+ $content = $content -replace ' (?m)^\s*$\n(?:\s*$\n)+' , " `n`n "
363386
364387 # Remove inline width/height attributes from img tags to let CSS control sizing
365388 $content = [regex ]::Replace($content , ' <img([^>]*)\s+width="[^"]*"' , ' <img$1' )
@@ -632,122 +655,47 @@ try {
632655 # Enable emoji support so markdown emojis render correctly instead of as square characters
633656 $pandocArgs += " --from=markdown+emoji"
634657 $pandocArgs += " --css=pdf-style-v2.css"
635- $pandocArgs += " --webtex"
658+ # Use --mathml instead of --webtex to avoid SSL/network issues with external LaTeX rendering services
659+ # MathML is supported by modern browsers and wkhtmltopdf's rendering engine
660+ $pandocArgs += " --mathml"
636661 $pandocArgs += " --syntax-highlighting=pygments"
637662 $pandocArgs += $tempMarkdown
638663 $pandocArgs += " -o"
639664 $pandocArgs += $OutputFile
640665
641666 if (-not (Test-Path $tempMarkdown )) {
642667 Write-Host " ERROR: Combined markdown file not found: $tempMarkdown " - ForegroundColor Red
643- if (Test-Path $convertedDir ) { Remove-Item $convertedDir - Recurse - Force - ErrorAction SilentlyContinue }
644- exit 1
668+ Cleanup; exit 1
645669 }
646670
647671 & pandoc @pandocArgs
648672
649673 # Clean up temporary file
650- Remove-Item $tempMarkdown - ErrorAction SilentlyContinue
674+ Cleanup
651675
652- # Clean up converted images dir
653- if (Test-Path $convertedDir ) {
654- Remove-Item $convertedDir - Recurse - Force - ErrorAction SilentlyContinue
655- }
656-
657676 if (Test-Path $OutputFile ) {
658677 Write-Host " SUCCESS: PDF generated: $OutputFile " - ForegroundColor Green
659- exit 0
678+ Cleanup; exit 0
660679 } else {
661680 Write-Host " ERROR: PDF file was not created" - ForegroundColor Red
662- exit 1
681+ Cleanup; exit 1
663682 }
664683} catch {
665684 Write-Host " ERROR: Pandoc execution failed: $_ " - ForegroundColor Red
666- if (Test-Path $tempMarkdown ) {
667- Remove-Item $tempMarkdown
668- }
669- # Clean up converted images dir on error too
670- if (Test-Path $convertedDir ) {
671- Remove-Item $convertedDir - Recurse - Force
672- }
673- exit 1
685+ Cleanup; exit 1
674686}
675687
676688# ---------------------------
677- # New helper: check command exists with suggestion
678- function Test-CommandExists {
679- param ([string ]$cmd )
680- $found = Get-Command $cmd - ErrorAction SilentlyContinue
681- if (-not $found ) {
682- Write-Host " Warning: '$cmd ' not found on PATH." - ForegroundColor Yellow
683- return $false
684- }
685- return $true
686- }
687-
688- # New helper: centralized SVG -> PNG conversion (returns full png path or $null)
689- function Convert-SvgToPng {
690- param (
691- [string ]$svgRef ,
692- [string ]$fileDir ,
693- [string ]$convertedDir ,
694- [bool ]$useInkscape ,
695- [bool ]$inkscapeNewSyntax
696- )
697-
698- # Resolve svg local path (like previous logic), remove querystring for filename
699- $svgLocal = $svgRef
700- if ($svgLocal -match ' ^file:///' ) {
701- $svgLocal = $svgLocal -replace ' ^file:///' , ' '
702- $svgLocal = $svgLocal -replace ' /' , ' \'
703- } elseif ($svgLocal -notmatch ' ^(?:https?:)?//' -and $svgLocal -notmatch ' ^[A-Za-z]:\\' ) {
704- $svgLocal = Join-Path $fileDir $svgLocal
705- }
706-
707- # Strip any URI query or fragment for filename/hash purposes
708- $svgLocalNoQuery = $svgLocal -replace ' \?.*$' , ' '
709-
710- if (-not (Test-Path $svgLocalNoQuery )) {
711- Write-Host " Warning: SVG file not found, skipping conversion: $svgLocalNoQuery " - ForegroundColor Yellow
712- return $null
713- }
714-
715- $baseName = [System.IO.Path ]::GetFileNameWithoutExtension($svgLocalNoQuery )
716- $hash = [System.BitConverter ]::ToString((New-Object System.Security.Cryptography.MD5CryptoServiceProvider).ComputeHash([System.Text.Encoding ]::UTF8.GetBytes($svgLocalNoQuery ))).Replace(' -' , ' ' ).ToLower().Substring(0 , 8 )
717- $pngPath = Join-Path $convertedDir (" $baseName -$hash .png" )
718-
719- if (Test-Path $pngPath ) {
720- return $pngPath
721- }
722-
689+ # Cleanup helper: remove temp files/dirs if they exist
690+ function Cleanup {
723691 try {
724- if ($useInkscape ) {
725- # prefer Inkscape
726- if ($inkscapeNewSyntax ) {
727- $args = @ (" $svgLocalNoQuery " , " --export-filename=$pngPath " )
728- } else {
729- $args = @ (" --export-png=$pngPath " , $svgLocalNoQuery )
730- }
731- Write-Host " Running inkscape $ ( $args -join ' ' ) " - ForegroundColor Cyan
732- $p = Start-Process - FilePath " inkscape" - ArgumentList $args - NoNewWindow - Wait - PassThru - ErrorAction Stop
733- if ($p.ExitCode -ne 0 ) { throw " Inkscape exit $ ( $p.ExitCode ) " }
734- } else {
735- # fallback to ImageMagick (magick)
736- $args = @ ($svgLocalNoQuery , ' -background' , ' white' , ' -flatten' , ' -resize' , ' 1200x' , $pngPath )
737- Write-Host " Running magick $ ( $args -join ' ' ) " - ForegroundColor Cyan
738- $p = Start-Process - FilePath " magick" - ArgumentList $args - NoNewWindow - Wait - PassThru - ErrorAction Stop
739- if ($p.ExitCode -ne 0 ) { throw " magick exit $ ( $p.ExitCode ) " }
692+ if ($tempMarkdown -and (Test-Path $tempMarkdown )) {
693+ Remove-Item $tempMarkdown - Force - ErrorAction SilentlyContinue
740694 }
741-
742- if (Test-Path $pngPath ) {
743- return $pngPath
744- } else {
745- Write-Host " Conversion did not produce expected file: $pngPath " - ForegroundColor Yellow
746- return $null
695+ } catch { }
696+ try {
697+ if ($convertedDir -and (Test-Path $convertedDir )) {
698+ Remove-Item $convertedDir - Recurse - Force - ErrorAction SilentlyContinue
747699 }
748- } catch {
749- Write-Host " Error converting SVG: $_ " - ForegroundColor Red
750- return $null
751- }
752- }
753- # ---------------------------
700+ } catch { }
701+ }
0 commit comments