Skip to content

Commit 2bf12f7

Browse files
authored
Add Get-BloggerPost (#16)
* initial implementation of Get-BloggerPost * Add Format parameter for Get-BloggerPost * added ConvertTo-HtmlFromMarkdown * resolve pspath when using pandoc * Add support for saving as markdown * Added ability to save post in published folder using FolderDateFormat * install pandoc for executing tests
1 parent 6340c60 commit 2bf12f7

8 files changed

Lines changed: 617 additions & 12 deletions

.github/workflows/pester-tests.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ jobs:
2020
Set-PSRepository PSGallery -InstallationPolicy Trusted
2121
Install-Module -Name Pester -Force -SkipPublisherCheck
2222
Install-Module -Name PowerShell-Yaml -Force -SkipPublisherCheck
23+
24+
- name: Install pandoc
25+
shell: pwsh
26+
run: |
27+
choco install pandoc -y
2328
2429
- name: Run Pester Tests
2530
shell: pwsh

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,35 @@ A PowerShell library for publishing markdown files authored in markdown to Blogg
5252
Get-BloggerPosts
5353
```
5454

55+
1. Fetch an individual post from your blog
56+
57+
```
58+
Get-BloggerPost -PostId <postid>
59+
```
60+
61+
You can also persist the post to disk as HTML or markdown in the current directory.
62+
63+
When using `HTML` format, files are saved as `<postid>.html`
64+
65+
When using `Markdown` format, files are saved as `<title>.md`
66+
67+
```
68+
Get-BloggerPost -PostId <postid> -Format HTML
69+
Get-BloggerPost -PostId <postid> -Format Markdown
70+
```
71+
72+
You can specify an output directory where the file will be saved.
73+
74+
```
75+
Get-BloggerPost -PostId <postid> -OutDirectory "C:\MyPosts" -Format HTML
76+
```
77+
78+
You can also include a `FolderDateFormat` that uses the `published` property of the blog post to construct a subfolder.
79+
80+
```
81+
Get-BloggerPost -PostId <postId> -OutDirectory ".\Blog" -FolderDateFormat "YYYY\\MM" -Format Markdown
82+
```
83+
5584
1. Publish a markdown file to your blog as draft
5685

5786
```

src/public/ConvertTo-HtmlFromMarkdown.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<#
22
.SYNOPSIS
3-
Convert a file to Markdown using Pandoc
3+
Convert a Markdown file to HTML using Pandoc
44
55
.PARAMETER File
66
The file path of the markdown file
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<#
2+
.SYNOPSIS
3+
Convert HTML content or a HTML file to Markdown using Pandoc
4+
5+
.PARAMETER File
6+
The file path of the html file. Required when Content is not specified.
7+
8+
.PARAMETER Content
9+
The HTML content to convert to Markdown. Required when File is not specified.
10+
11+
.PARAMETER OutFile
12+
The resulting markdown file, if specified.
13+
14+
#>
15+
function ConvertTo-MarkdownFromHtml {
16+
param(
17+
[Parameter(Mandatory, ParameterSetName = "FromFile")]
18+
[ValidateScript({ Test-Path $_ -PathType Leaf })]
19+
[string]$File,
20+
21+
[Parameter(Mandatory, ParameterSetName = "FromContent")]
22+
[string]$Content,
23+
24+
[Parameter(ParameterSetName = "FromFile")]
25+
[Parameter(Mandatory=$false, ParameterSetName = "FromContent")]
26+
[string]$OutFile
27+
)
28+
29+
# when FromContent is specified, write the content to a temporary file
30+
if ($PSCmdlet.ParameterSetName -eq "FromContent") {
31+
# If content is provided, create a temporary file
32+
$tempFile = [System.IO.Path]::GetTempFileName() + ".html"
33+
Set-Content -Path $tempFile -Value $Content
34+
$File = $tempFile
35+
}
36+
37+
# ensure that the file is an absolute path because pandoc.exe doesn't like powershell relative paths
38+
$File = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($File)
39+
40+
# Use pandoc to convert the markdown to Html
41+
$pandocArgs = "`"{0}`" " -f $File
42+
$pandocArgs += "-f {0} " -f $BloggerSession.PandocHtmlFormat
43+
$pandocArgs += "-t {0} " -f $BloggerSession.PandocMarkdownFormat
44+
45+
# add additional command-line arguments
46+
if ($BloggerSession.PandocAdditionalArgs) {
47+
Write-Verbose "Using additional args"
48+
$pandocArgs += "{0} " -f $BloggerSession.PandocAdditionalArgs
49+
}
50+
51+
if (!($OutFile)) {
52+
$OutFile = Join-Path (Split-Path $File -Parent) ((Split-Path $File -LeafBase) + ".md")
53+
Write-Verbose "Using OutFile: $OutFile"
54+
}
55+
# ensure that the file is an absolute path because pandoc.exe doesn't like powershell relative paths
56+
$OutFile = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutFile)
57+
58+
$pandocArgs += "-o `"{0}`" " -f $OutFile
59+
60+
Write-Verbose ">> pandoc $($pandocArgs)"
61+
Start-Process pandoc -ArgumentList $pandocArgs -NoNewWindow -Wait
62+
63+
$content = Get-Content $OutFile -Raw
64+
65+
# remove temporary files
66+
if ($PSCmdlet.ParameterSetName -eq "FromContent") {
67+
Remove-Item $File
68+
} elseif (!$PSBoundParameters.ContainsKey("OutFile")) {
69+
Remove-Item $OutFile
70+
}
71+
72+
return $content
73+
}

src/public/Get-BloggerPost.ps1

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<#
2+
.DESCRIPTION
3+
Retrieves an individual post from a specified Blogger blog and optionally saves the content to a file as HTML or Markdown.
4+
5+
.PARAMETER BlogId
6+
The ID of the blog to retrieve the post from. If not specified, uses the BlogId in the user preferences.
7+
8+
.PARAMETER PostId
9+
The ID of the post to retrieve. This parameter is required.
10+
11+
.PARAMETER Format
12+
The format of the post content to retrieve. Use either Markdown or HTML.
13+
14+
.PARAMETER FolderDateFormat
15+
The folder name as expressed in a DateTime format string. For example, "YYYY/MM" which will save files
16+
in a folder structure like "2023/10" based on the date of the post.
17+
18+
.PARAMETER OutDirectory
19+
The directory where the HTML file will be saved. If not specified, uses the current directory.
20+
21+
.EXAMPLE
22+
Get-BloggerPost -PostId "1234567890123456789"
23+
24+
.EXAMPLE
25+
Get-BloggerPost -BlogId "9876543210987654321" -PostId "1234567890123456789" -Format HTML -OutDirectory "C:\temp"
26+
27+
.EXAMPLE
28+
Get-BloggerPost -BlogId "9876543210987654321" -PostId "1234567890123456789" -Format Markdown -DateFormat "YYYY\\MM" -OutDirectory "C:\blogposts"
29+
#>
30+
Function Get-BloggerPost {
31+
[CmdletBinding()]
32+
param(
33+
[Parameter(ParameterSetName = "Default")]
34+
[Parameter(ParameterSetName = "Persist")]
35+
[string]$BlogId,
36+
37+
[Parameter(Mandatory,ParameterSetName = "Default")]
38+
[Parameter(Mandatory,ParameterSetName = "Persist")]
39+
[string]$PostId,
40+
41+
[Parameter(Mandatory, ParameterSetName = "Persist")]
42+
[ValidateSet("HTML", "Markdown")]
43+
[string]$Format,
44+
45+
[Parameter(ParameterSetName ="Persist")]
46+
[string]$FolderDateFormat,
47+
48+
[Parameter(ParameterSetName = "Persist")]
49+
[string]$OutDirectory = (Get-Location).Path
50+
)
51+
52+
if (!$PSBoundParameters.ContainsKey("BlogId")) {
53+
$BlogId = $BloggerSession.BlogId
54+
if ([string]::IsNullOrEmpty($BlogId) -or $BlogId -eq 0) {
55+
throw "BlogId not specified and no default BlogId found in settings."
56+
}
57+
}
58+
59+
if ([string]::IsNullOrEmpty($PostId)) {
60+
throw "PostId is required."
61+
}
62+
63+
try {
64+
$uri = "https://www.googleapis.com/blogger/v3/blogs/$BlogId/posts/$PostId"
65+
66+
$result = Invoke-GApi -uri $uri
67+
68+
if ($null -eq $result) {
69+
throw "No post found with PostId '$PostId' in blog '$BlogId'."
70+
}
71+
72+
# Construct a subfolder based on the published date
73+
if ($FolderDateFormat -and $result.published) {
74+
$date = [datetime]::Parse($result.published)
75+
$formattedDate = $date.ToString($FolderDateFormat)
76+
$OutDirectory = Join-Path -Path $OutDirectory -ChildPath $formattedDate
77+
}
78+
79+
# Ensure the output directory exists
80+
if (!(Test-Path -Path $OutDirectory)) {
81+
try {
82+
New-Item -ItemType Directory -Path $OutDirectory -Force | Out-Null
83+
}
84+
catch {
85+
throw "Failed to create output directory '$OutDirectory': $($_.Exception.Message)"
86+
}
87+
}
88+
89+
# Extract the HTML content
90+
$htmlContent = $result.content
91+
92+
if ([string]::IsNullOrEmpty($htmlContent)) {
93+
Write-Warning "Post '$PostId' has no content."
94+
$htmlContent = ""
95+
}
96+
97+
# Create the output file path
98+
try {
99+
100+
switch ($Format) {
101+
102+
# Save the HTML content to a file
103+
"HTML" {
104+
105+
$fileName = "$PostId.html"
106+
$filePath = Join-Path -Path $OutDirectory -ChildPath $fileName
107+
$htmlContent | Out-File -FilePath $filePath -Encoding UTF8
108+
Write-Verbose "Post content saved to: $filePath"
109+
}
110+
111+
# Save the Post to a Markdown file
112+
"Markdown" {
113+
114+
$title = $result.title
115+
$frontMatter = [ordered]@{
116+
postId = $result.id
117+
}
118+
$file = "$title.md"
119+
$filePath = Join-Path -Path $OutDirectory -ChildPath $file
120+
ConvertTo-MarkdownFromHtml -Content $result.content -OutFile $filePath > $null
121+
Set-MarkdownFrontMatter -File $filePath -Replace $frontMatter
122+
Write-Verbose "Post content saved to: $filePath"
123+
}
124+
}
125+
126+
# Return the post object for further processing if needed
127+
return $result
128+
}
129+
catch {
130+
throw "Failed to save post content to file '$filePath': $($_.Exception.Message)"
131+
}
132+
}
133+
catch {
134+
# Handle specific HTTP errors
135+
if ($_.Exception -like "*404*" -or $_.Exception -like "*Not Found*") {
136+
throw "Post with PostId '$PostId' not found in blog '$BlogId'. Please verify the PostId and BlogId are correct."
137+
}
138+
elseif ($_.Exception -like "*403*" -or $_.Exception -like "*Forbidden*") {
139+
throw "Access denied to blog '$BlogId' or post '$PostId'. Please verify your permissions."
140+
}
141+
else {
142+
Write-Error $_.ToString() -ErrorAction Stop
143+
}
144+
}
145+
}

src/tests/ConvertTo-HtmlFromMarkdown.Tests.ps1

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
Describe "ConvertTo-MarkdownFromHtml" {
2+
BeforeAll {
3+
Import-Module $PSScriptRoot\_TestHelpers.ps1 -Force
4+
5+
}
6+
7+
BeforeEach {
8+
Import-Module $PSScriptRoot\..\PSBlogger.psm1 -Force
9+
}
10+
11+
Context "Using Content" {
12+
13+
BeforeEach {
14+
$outFile = "TestDrive:\123.md"
15+
$htmlContent = "<h1>Hello World</h1>"
16+
}
17+
18+
AfterEach {
19+
if (Test-Path $outFile) {
20+
Remove-Item $outFile -Force
21+
}
22+
}
23+
24+
It "Should save HTML content to a markdown file" {
25+
# act
26+
ConvertTo-MarkdownFromHtml -Content $htmlContent -OutFile $outFile
27+
28+
# assert
29+
Test-Path $outFile | Should -BeTrue
30+
}
31+
32+
It "Should convert HTML content to Markdown file" {
33+
# act
34+
$content = ConvertTo-MarkdownFromHtml -Content $htmlContent -OutFile $outFile
35+
36+
# assert
37+
$content = (Get-Content -Path $outFile -Raw).Split("`r")
38+
$content[0] | Should -Be "# Hello World"
39+
}
40+
41+
It "Should not persist to disk if OutFile is not specified" {
42+
# act
43+
$content = ConvertTo-MarkdownFromHtml -Content $htmlContent
44+
45+
# assert
46+
$content | Should -Not -BeNullOrEmpty
47+
Test-Path $outFile | Should -BeFalse
48+
}
49+
}
50+
51+
Context "Using File" {
52+
53+
BeforeEach {
54+
$htmlContent = "<h1>Hello World</h1>"
55+
$htmlFile = "TestDrive:\123.html"
56+
$markdownFile = "TestDrive:\123.md"
57+
Set-Content -Path $htmlFile -Value $htmlContent
58+
}
59+
60+
It "Should convert HTML file to Markdown" {
61+
# act
62+
$content = ConvertTo-MarkdownFromHtml -File $htmlFile -OutFile $markdownFile
63+
64+
# assert
65+
Test-Path $markdownFile | Should -BeTrue
66+
$content = (Get-Content -Path $markdownFile -Raw).Split("`r")
67+
$content[0] | Should -Be "# Hello World"
68+
}
69+
70+
It "Should delete temporary file" {
71+
# act
72+
$content = ConvertTo-MarkdownFromHtml -File $htmlFile
73+
74+
# assert
75+
$content | Should -Not -BeNullOrEmpty
76+
Test-Path $markdownFile | Should -BeFalse
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)