From e7605d7b3813753fd846f6aeeb1f041a044dec3a Mon Sep 17 00:00:00 2001 From: bryan cook <3217452+bryanbcook@users.noreply.github.com> Date: Wed, 23 Jul 2025 19:01:46 -0400 Subject: [PATCH 1/5] Get-BloggerPost without labels #24 --- src/public/Get-BloggerPost.ps1 | 13 ++++++++++--- src/tests/Get-BloggerPost.Tests.ps1 | 12 ++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/public/Get-BloggerPost.ps1 b/src/public/Get-BloggerPost.ps1 index b570367..9fdad7a 100644 --- a/src/public/Get-BloggerPost.ps1 +++ b/src/public/Get-BloggerPost.ps1 @@ -68,6 +68,7 @@ Function Get-BloggerPost { if ($null -eq $result) { throw "No post found with PostId '$PostId' in blog '$BlogId'." } + Write-Verbose "Post: $($result | ConvertTo-Json -Depth 10)" # Construct a subfolder based on the published date if ($FolderDateFormat -and $result.published) { @@ -80,12 +81,14 @@ Function Get-BloggerPost { # Ensure the output directory exists if (!(Test-Path -Path $OutDirectory)) { try { + Write-Verbose "Creating output directory: $OutDirectory" New-Item -ItemType Directory -Path $OutDirectory -Force | Out-Null } catch { throw "Failed to create output directory '$OutDirectory': $($_.Exception.Message)" } } + Write-Verbose "Using output directory: $OutDirectory" # Extract the HTML content $htmlContent = $result.content @@ -111,17 +114,21 @@ Function Get-BloggerPost { # Save the Post to a Markdown file "Markdown" { - + $title = $result.title $frontMatter = [ordered]@{ postId = $result.id } - if ($result['labels']) { + if ($result.PSObject.Properties.Name -contains "labels") { + Write-Verbose "Using post labels: $($result.labels)" $frontMatter['tags'] = $result.labels } else { + Write-Verbose "No labels found in post, using empty tags." $frontMatter['tags'] = @() } + Write-Verbose "Saving frontmatter: $($frontMatter | ConvertTo-Json -Depth 10)" $file = "$title.md" + $filePath = Join-Path -Path $OutDirectory -ChildPath $file ConvertTo-MarkdownFromHtml -Content $result.content -OutFile $filePath > $null Set-MarkdownFrontMatter -File $filePath -Replace $frontMatter @@ -140,7 +147,7 @@ Function Get-BloggerPost { return $result } catch { - throw "Failed to save post content to file '$filePath': $($_.Exception.Message)" + throw "Failed to save post content: $($_.Exception.Message)" } } catch { diff --git a/src/tests/Get-BloggerPost.Tests.ps1 b/src/tests/Get-BloggerPost.Tests.ps1 index 0d396fc..c16aacb 100644 --- a/src/tests/Get-BloggerPost.Tests.ps1 +++ b/src/tests/Get-BloggerPost.Tests.ps1 @@ -40,7 +40,7 @@ Describe "Get-BloggerPost" { # setup blog post retrieval Mock Invoke-GAPi { - return @{ content = "Test content" } + return [pscustomobject]@{ content = "Test content" } } } @@ -64,7 +64,7 @@ Describe "Get-BloggerPost" { It "Should call correct API endpoint" { InModuleScope PSBlogger { Mock Invoke-GApi { - return @{ content = "Test content" } + return [pscustomobject]@{ content = "Test content" } } -ParameterFilter { $uri -eq "https://www.googleapis.com/blogger/v3/blogs/test-blog-id/posts/123" } -Verifiable @@ -179,7 +179,7 @@ Describe "Get-BloggerPost" { # mock post retrieval Mock Invoke-GApi { - return @{ + return [pscustomobject]@{ id = $postId title = "Test Post" published = [datetime]"2023-10-01T17:30:00-04:00" @@ -232,7 +232,7 @@ Describe "Get-BloggerPost" { # mock post retrieval Mock Invoke-GApi { - return @{ + return [pscustomobject]@{ id = $postId title = "Test Post" published = [datetime]"2023-10-01T17:30:00-04:00" @@ -260,7 +260,7 @@ Describe "Get-BloggerPost" { # mock post retrieval Mock Invoke-GApi { - return @{ + return [pscustomobject]@{ id = $postId title = "Test Post" published = [datetime]"2023-10-01T17:30:00-04:00" @@ -306,7 +306,7 @@ Describe "Get-BloggerPost" { # mock post retrieval Mock Invoke-GApi { - return @{ + return [pscustomobject]@{ id = $postId title = "Test Post" published = [datetime]"2023-10-01T17:30:00-04:00" From f76f377ece852fc9389bc434e484f3e63b9411cc Mon Sep 17 00:00:00 2001 From: bryan cook <3217452+bryanbcook@users.noreply.github.com> Date: Thu, 24 Jul 2025 10:49:28 -0400 Subject: [PATCH 2/5] corrected indentation of files --- src/public/Add-GoogleDriveFile.ps1 | 286 ++++++++++--------- src/public/Add-GoogleDriveFolder.ps1 | 54 ++-- src/public/ConvertTo-HtmlFromMarkdown.ps1 | 92 +++--- src/public/ConvertTo-MarkdownFromHtml.ps1 | 8 +- src/public/Find-MarkdownImages.ps1 | 183 ++++++------ src/public/Get-GoogleDriveItems.ps1 | 120 ++++---- src/public/Initialize-Blogger.ps1 | 74 +++-- src/public/Publish-BloggerPost.ps1 | 142 +++++---- src/public/Publish-MarkdownDriveImages.ps1 | 14 +- src/public/Set-BloggerConfig.ps1 | 18 ++ src/public/Set-GoogleDriveFilePermission.ps1 | 51 ++-- src/public/Set-MarkdownFrontMatter.ps1 | 22 ++ src/public/Update-MarkdownImages.ps1 | 112 ++++---- 13 files changed, 625 insertions(+), 551 deletions(-) diff --git a/src/public/Add-GoogleDriveFile.ps1 b/src/public/Add-GoogleDriveFile.ps1 index 1a877ad..66730ca 100644 --- a/src/public/Add-GoogleDriveFile.ps1 +++ b/src/public/Add-GoogleDriveFile.ps1 @@ -1,135 +1,136 @@ <# .SYNOPSIS - Uploads a file to Google Drive in a specified folder. + Uploads a file to Google Drive in a specified folder. .DESCRIPTION - Uploads a file to Google Drive, places it in the "Open Live Writer" subfolder, - preserves the original filename. + Uploads a file to Google Drive, places it in the "Open Live Writer" subfolder, + preserves the original filename. .PARAMETER FilePath - The local path to the file to upload. + The local path to the file to upload. .PARAMETER FileName - Optional custom name for the file. If not specified, uses the original filename. + Optional custom name for the file. If not specified, uses the original filename. .PARAMETER Force - If specified, will overwrite an existing file with the same name in the target folder. - If not specified and the file already exists, it will return the existing file's metadata. + If specified, will overwrite an existing file with the same name in the target folder. + If not specified and the file already exists, it will return the existing file's metadata. .EXAMPLE - Add-GoogleDriveFile -FilePath "C:\images\photo.jpg" + Add-GoogleDriveFile -FilePath "C:\images\photo.jpg" #> function Add-GoogleDriveFile { - [CmdletBinding()] - param( - [Parameter(Mandatory=$true)] - [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] - [string]$FilePath, + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] + [string]$FilePath, - [Parameter()] - [string]$FileName, + [Parameter()] + [string]$FileName, - [Parameter()] - [string]$TargetFolderName = "Open Live Writer", + [Parameter()] + [string]$TargetFolderName = "Open Live Writer", - [Parameter()] - [switch]$Force - ) + [Parameter()] + [switch]$Force + ) - $sourceItem = Get-Item (Resolve-Path $FilePath) - Write-Verbose "Add-GoogleDriveFile: Uploading file: $($sourceItem.FullName) to Google Drive" + $sourceItem = Get-Item (Resolve-Path $FilePath) + Write-Verbose "Add-GoogleDriveFile: Uploading file: $($sourceItem.FullName) to Google Drive" - if (-not $FileName) { - $FileName = $sourceItem.Name + if (-not $FileName) { + $FileName = $sourceItem.Name + } + + # First, find or create the upload folder in Google Drive + Write-Verbose "Add-GoogleDriveFile: Verifying target folder: $TargetFolderName" + $folder = Get-GoogleDriveItems -ResultType "Folders" -Title $TargetFolderName + + if (-not $folder) { + # Create the folder if it doesn't exist + Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' not found. Creating new folder." + $folder = Add-GoogleDriveFolder -Name $TargetFolderName + } + else { + # Get the first folder if multiple exist + Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' found." + $folder = $folder | Select-Object -First 1 + } + + # Determine if the file already exists in the target folder + Write-Verbose "Add-GoogleDriveFile: Checking if file '$FileName' already exists in folder '$TargetFolderName'" + $existingFile = Get-GoogleDriveItems -ResultType "Files" -Title $FileName -ParentId $folder.id + if ($existingFile) { + if (-not $Force) { + # use existing file + return New-GoogleDriveMetadata -id $existingFile.id -name $existingFile.name } + # address multiple file issue + # todo: evaluate additional meta-data of the file to ensure it's not deleted + $existingFile = $existingFile | Select-Object -First 1 + } - # First, find or create the upload folder in Google Drive - Write-Verbose "Add-GoogleDriveFile: Verifying target folder: $TargetFolderName" - $folder = Get-GoogleDriveItems -ResultType "Folders" -Title $TargetFolderName - - if (-not $folder) { - # Create the folder if it doesn't exist - Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' not found. Creating new folder." - $folder = Add-GoogleDriveFolder -Name $TargetFolderName - } else { - # Get the first folder if multiple exist - Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' found." - $folder = $folder | Select-Object -First 1 - } - - # Determine if the file already exists in the target folder - Write-Verbose "Add-GoogleDriveFile: Checking if file '$FileName' already exists in folder '$TargetFolderName'" - $existingFile = Get-GoogleDriveItems -ResultType "Files" -Title $FileName -ParentId $folder.id + $sourceMime = Get-ImageMimeType -Extension $sourceItem.Extension + + # Prepare metadata for the file + $metadata = @{ + name = $FileName + parents = @($folder.id) + } | ConvertTo-Json -Compress + + $fileContent = [System.IO.File]::ReadAllBytes($sourceItem.FullName) + $fileContentBase64 = [Convert]::ToBase64String($fileContent) + + # Create multipart body + $boundary = "boundary_" + [System.Guid]::NewGuid().ToString() + + $body = @( + + # Metadata part + "--$boundary" + "Content-Type: application/json; charset=UTF-8" + "" + $metadata + "--$boundary" + + # File content part + "Content-Type: $sourceMime" + "Content-Transfer-Encoding: base64" + "" + $fileContentBase64 + "--$boundary--" + ) -join "`r`n" + + $additionalHeaders = @{ + "Content-Type" = "multipart/related; boundary=$boundary" + } + + try { + if ($existingFile) { - if (-not $Force) { - # use existing file - return New-GoogleDriveMetadata -id $existingFile.id -name $existingFile.name - } - # address multiple file issue - # todo: evaluate additional meta-data of the file to ensure it's not deleted - $existingFile = $existingFile | Select-Object -First 1 - } + # If the file exists and Force is specified, update it + $uri = "https://www.googleapis.com/upload/drive/v3/files/$($existingFile.id)?uploadType=media" + $method = "PATCH" - $sourceMime = Get-ImageMimeType -Extension $sourceItem.Extension - - # Prepare metadata for the file - $metadata = @{ - name = $FileName - parents = @($folder.id) - } | ConvertTo-Json -Compress - - $fileContent = [System.IO.File]::ReadAllBytes($sourceItem.FullName) - $fileContentBase64 = [Convert]::ToBase64String($fileContent) - - # Create multipart body - $boundary = "boundary_" + [System.Guid]::NewGuid().ToString() - - $body = @( - - # Metadata part - "--$boundary" - "Content-Type: application/json; charset=UTF-8" - "" - $metadata - "--$boundary" - - # File content part - "Content-Type: $sourceMime" - "Content-Transfer-Encoding: base64" - "" - $fileContentBase64 - "--$boundary--" - ) -join "`r`n" - - $additionalHeaders = @{ - "Content-Type" = "multipart/related; boundary=$boundary" - } + "Add-GoogleDriveFile: $Method $uri" | Write-Verbose - try { - - if ($existingFile) { - # If the file exists and Force is specified, update it - $uri = "https://www.googleapis.com/upload/drive/v3/files/$($existingFile.id)?uploadType=media" - $method = "PATCH" - - "Add-GoogleDriveFile: $Method $uri" | Write-Verbose - - $uploadResult = Invoke-GApi -uri $uri -InFile $sourceItem.FullName -method $method -ContentType $sourceMime -Verbose:$false - } - else { - $uri = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" - $method = "POST" - "Add-GoogleDriveFile: $Method $uri" | Write-Verbose - - $uploadResult = Invoke-GApi -uri $uri -body $body -method $method -ContentType "multipart/related; boundary=$boundary" -AdditionalHeaders $additionalHeaders -Verbose:$false - } - - # Return the file information with public URL - return New-GoogleDriveMetadata -id $uploadResult.id -name $uploadResult.name + $uploadResult = Invoke-GApi -uri $uri -InFile $sourceItem.FullName -method $method -ContentType $sourceMime -Verbose:$false } - catch { - Write-Error "Failed to upload file to Google Drive: $($_.Exception.Message). $($_.ErrorDetails | ConvertTo-Json -Depth 10)" -ErrorAction Stop + else { + $uri = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" + $method = "POST" + "Add-GoogleDriveFile: $Method $uri" | Write-Verbose + + $uploadResult = Invoke-GApi -uri $uri -body $body -method $method -ContentType "multipart/related; boundary=$boundary" -AdditionalHeaders $additionalHeaders -Verbose:$false } + + # Return the file information with public URL + return New-GoogleDriveMetadata -id $uploadResult.id -name $uploadResult.name + } + catch { + Write-Error "Failed to upload file to Google Drive: $($_.Exception.Message). $($_.ErrorDetails | ConvertTo-Json -Depth 10)" -ErrorAction Stop + } } <# @@ -146,45 +147,46 @@ The file extension (including the dot). Get-ImageMimeType -Extension ".jpg" #> function Get-ImageMimeType { - [CmdletBinding()] - param( - [Parameter(Mandatory=$true)] - [string]$Extension - ) - - $mimeTypes = @{ - '.jpg' = 'image/jpeg' - '.jpeg' = 'image/jpeg' - '.png' = 'image/png' - '.gif' = 'image/gif' - '.bmp' = 'image/bmp' - '.webp' = 'image/webp' - '.svg' = 'image/svg+xml' - '.ico' = 'image/x-icon' - '.tiff' = 'image/tiff' - '.tif' = 'image/tiff' - } - - $normalizedExtension = $Extension.ToLower() + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Extension + ) + + $mimeTypes = @{ + '.jpg' = 'image/jpeg' + '.jpeg' = 'image/jpeg' + '.png' = 'image/png' + '.gif' = 'image/gif' + '.bmp' = 'image/bmp' + '.webp' = 'image/webp' + '.svg' = 'image/svg+xml' + '.ico' = 'image/x-icon' + '.tiff' = 'image/tiff' + '.tif' = 'image/tiff' + } + + $normalizedExtension = $Extension.ToLower() - if ($mimeTypes.ContainsKey($normalizedExtension)) { - return $mimeTypes[$normalizedExtension] - } else { - return 'application/octet-stream' - } + if ($mimeTypes.ContainsKey($normalizedExtension)) { + return $mimeTypes[$normalizedExtension] + } + else { + return 'application/octet-stream' + } } function New-GoogleDriveMetadata { - param( - [string]$id, - [string]$name - ) - $publicUrl = "https://lh3.googleusercontent.com/d/$id" + param( + [string]$id, + [string]$name + ) + $publicUrl = "https://lh3.googleusercontent.com/d/$id" - return [PSCustomObject]@{ - Id = $id - Name = $name - PublicUrl = $publicUrl - DriveUrl = "https://drive.google.com/file/d/$id/view" - } + return [PSCustomObject]@{ + Id = $id + Name = $name + PublicUrl = $publicUrl + DriveUrl = "https://drive.google.com/file/d/$id/view" + } } diff --git a/src/public/Add-GoogleDriveFolder.ps1 b/src/public/Add-GoogleDriveFolder.ps1 index 398b7f2..d501bb8 100644 --- a/src/public/Add-GoogleDriveFolder.ps1 +++ b/src/public/Add-GoogleDriveFolder.ps1 @@ -3,45 +3,45 @@ Creates a new folder in Google Drive. .DESCRIPTION - Creates a new folder in Google Drive with the specified name. + Creates a new folder in Google Drive with the specified name. .PARAMETER Name - The name of the folder to create. + The name of the folder to create. .PARAMETER ParentId - Optional parent folder ID. If not specified, creates in root. + Optional parent folder ID. If not specified, creates in root. .EXAMPLE - New-GoogleDriveFolder -Name "Open Live Writer" + New-GoogleDriveFolder -Name "Open Live Writer" #> function Add-GoogleDriveFolder { - [CmdletBinding()] - param( - [Parameter(Mandatory=$true)] - [string]$Name, + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Name, - [Parameter(Mandatory=$false)] - [string]$ParentId - ) + [Parameter(Mandatory = $false)] + [string]$ParentId + ) - Write-Verbose ("Creating folder '$Name' {0}" -f ($ParentId ? "in parent '$ParentId'" : "in root")) + Write-Verbose ("Creating folder '$Name' {0}" -f ($ParentId ? "in parent '$ParentId'" : "in root")) - $metadata = @{ - name = $Name - mimeType = "application/vnd.google-apps.folder" - } + $metadata = @{ + name = $Name + mimeType = "application/vnd.google-apps.folder" + } - if ($ParentId) { - $metadata.parents = @($ParentId) - } + if ($ParentId) { + $metadata.parents = @($ParentId) + } - $body = $metadata | ConvertTo-Json -Compress - $uri = "https://www.googleapis.com/drive/v3/files" + $body = $metadata | ConvertTo-Json -Compress + $uri = "https://www.googleapis.com/drive/v3/files" - try { - return Invoke-GApi -uri $uri -body $body -Verbose:$false - } - catch { - Write-Error "Failed to create folder in Google Drive: $($_.Exception.Message)" -ErrorAction Stop - } + try { + return Invoke-GApi -uri $uri -body $body -Verbose:$false + } + catch { + Write-Error "Failed to create folder in Google Drive: $($_.Exception.Message)" -ErrorAction Stop + } } diff --git a/src/public/ConvertTo-HtmlFromMarkdown.ps1 b/src/public/ConvertTo-HtmlFromMarkdown.ps1 index 46da4fe..c0a9623 100644 --- a/src/public/ConvertTo-HtmlFromMarkdown.ps1 +++ b/src/public/ConvertTo-HtmlFromMarkdown.ps1 @@ -1,68 +1,66 @@ <# .SYNOPSIS - Convert a Markdown file to HTML using Pandoc + Convert a Markdown file to HTML using Pandoc .PARAMETER File - The file path of the markdown file + The file path of the markdown file .PARAMETER OutFile - The resulting html. If this parameter is not specified an HTML file with the same name of the markdown file will be created. + The resulting html. If this parameter is not specified an HTML file with the same name of the markdown file will be created. #> -function ConvertTo-HtmlFromMarkdown -{ - param( - [Parameter(Mandatory=$true, HelpMessage="Path to Markdown file")] - [ValidateScript({ Test-Path $_ -PathType Leaf})] - [string]$File, +function ConvertTo-HtmlFromMarkdown { + param( + [Parameter(Mandatory = $true, HelpMessage = "Path to Markdown file")] + [ValidateScript({ Test-Path $_ -PathType Leaf })] + [string]$File, - [Parameter(HelpMessage="File path to create")] - #[ValidateScript({ Test-Path $_ -Include "*.html" -PathType Container})] - [string]$OutFile - ) + [Parameter(HelpMessage = "File path to create")] + #[ValidateScript({ Test-Path $_ -Include "*.html" -PathType Container})] + [string]$OutFile + ) - # ensure that the file is an absolute path because pandoc.exe doesn't like powershell relative paths - $File = (Resolve-Path $File).Path + # ensure that the file is an absolute path because pandoc.exe doesn't like powershell relative paths + $File = (Resolve-Path $File).Path - # Use pandoc to convert the markdown to Html - $pandocArgs = "`"{0}`" " -f $File - $pandocArgs += "-f {0} " -f $BloggerSession.PandocMarkdownFormat - $pandocArgs += "-t {0} " -f $BloggerSession.PandocHtmlFormat + # Use pandoc to convert the markdown to Html + $pandocArgs = "`"{0}`" " -f $File + $pandocArgs += "-f {0} " -f $BloggerSession.PandocMarkdownFormat + $pandocArgs += "-t {0} " -f $BloggerSession.PandocHtmlFormat - # add template and toc if template is available - if (Test-Path $BloggerSession.PandocTemplate) { - Write-Verbose "Using template" - $pandocArgs += "--template `"{0}`" --toc " -f $BloggerSession.PandocTemplate - } - # add additional command-line arguments - if ($BloggerSession.PandocAdditionalArgs) { - Write-Verbose "Using additional args" - $pandocArgs += "{0} " -f $BloggerSession.PandocAdditionalArgs - } + # add template and toc if template is available + if (Test-Path $BloggerSession.PandocTemplate) { + Write-Verbose "Using template" + $pandocArgs += "--template `"{0}`" --toc " -f $BloggerSession.PandocTemplate + } + # add additional command-line arguments + if ($BloggerSession.PandocAdditionalArgs) { + Write-Verbose "Using additional args" + $pandocArgs += "{0} " -f $BloggerSession.PandocAdditionalArgs + } - if (!($OutFile)) - { - $OutFile = Join-Path (Split-Path $File -Parent) ((Split-Path $File -LeafBase) + ".html") - Write-Verbose "Using OutFile: $OutFile" - } + if (!($OutFile)) { + $OutFile = Join-Path (Split-Path $File -Parent) ((Split-Path $File -LeafBase) + ".html") + Write-Verbose "Using OutFile: $OutFile" + } - $pandocArgs += "-o `"{0}`" " -f $OutFile + $pandocArgs += "-o `"{0}`" " -f $OutFile - Write-Verbose ">> pandoc $($pandocArgs)" - Start-Process pandoc -ArgumentList $pandocArgs -NoNewWindow -Wait + Write-Verbose ">> pandoc $($pandocArgs)" + Start-Process pandoc -ArgumentList $pandocArgs -NoNewWindow -Wait - # Apply additional transforms - $content = Get-Content $OutFile -Raw + # Apply additional transforms + $content = Get-Content $OutFile -Raw - ## TEMP: My blog doesn't support
yet, so I'm trimming it out.
- # convert ->
- $content = $content -replace '',''
- # convert
->
- $content = $content -replace '
',''
+ ## TEMP: My blog doesn't support yet, so I'm trimming it out.
+ # convert ->
+ $content = $content -replace '', ''
+ # convert
->
+ $content = $content -replace '
', ''
- Set-Content -Path $OutFile -Value $content
+ Set-Content -Path $OutFile -Value $content
- Remove-Item $OutFile
+ Remove-Item $OutFile
- return $content
+ return $content
}
\ No newline at end of file
diff --git a/src/public/ConvertTo-MarkdownFromHtml.ps1 b/src/public/ConvertTo-MarkdownFromHtml.ps1
index a350b44..0d4b431 100644
--- a/src/public/ConvertTo-MarkdownFromHtml.ps1
+++ b/src/public/ConvertTo-MarkdownFromHtml.ps1
@@ -1,15 +1,15 @@
<#
.SYNOPSIS
- Convert HTML content or a HTML file to Markdown using Pandoc
+ Convert HTML content or a HTML file to Markdown using Pandoc
.PARAMETER File
- The file path of the html file. Required when Content is not specified.
+ The file path of the html file. Required when Content is not specified.
.PARAMETER Content
- The HTML content to convert to Markdown. Required when File is not specified.
+ The HTML content to convert to Markdown. Required when File is not specified.
.PARAMETER OutFile
- The resulting markdown file, if specified.
+ The resulting markdown file, if specified.
#>
function ConvertTo-MarkdownFromHtml {
diff --git a/src/public/Find-MarkdownImages.ps1 b/src/public/Find-MarkdownImages.ps1
index 29176ae..d4e4f8f 100644
--- a/src/public/Find-MarkdownImages.ps1
+++ b/src/public/Find-MarkdownImages.ps1
@@ -15,114 +15,115 @@
Find-MarkdownImages -File "post.md"
#>
function Find-MarkdownImages {
- [CmdletBinding()]
- param(
- [Parameter(Mandatory=$true)]
- [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
- [string]$File
- )
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
+ [string]$File
+ )
- $content = Get-Content -Path $File -Raw
- $images = @()
- $fileDirectory = Split-Path -Path $File -Parent
+ $content = Get-Content -Path $File -Raw
+ $images = @()
+ $fileDirectory = Split-Path -Path $File -Parent
- # If the file is in the current directory, use the current directory
- if ([string]::IsNullOrEmpty($fileDirectory)) {
- $fileDirectory = "."
- }
+ # If the file is in the current directory, use the current directory
+ if ([string]::IsNullOrEmpty($fileDirectory)) {
+ $fileDirectory = "."
+ }
- # Regex pattern for standard markdown images: 
- $standardPattern = '!\[([^\]]*)\]\(([^)]+?)(?:\s+"([^"]*)")?\)'
+ # Regex pattern for standard markdown images: 
+ $standardPattern = '!\[([^\]]*)\]\(([^)]+?)(?:\s+"([^"]*)")?\)'
- # Regex pattern for Obsidian images: ![[image_path|alt text]]
- $obsidianPattern = '!\[\[([^|\]]+?)(?:\|([^\]]*))?\]\]'
+ # Regex pattern for Obsidian images: ![[image_path|alt text]]
+ $obsidianPattern = '!\[\[([^|\]]+?)(?:\|([^\]]*))?\]\]'
- # Collect all matches with their positions
- $allMatches = @()
+ # Collect all matches with their positions
+ $allMatches = @()
- # Find all standard markdown image matches
- $standardMatches = [regex]::Matches($content, $standardPattern)
- foreach ($match in $standardMatches) {
- $allMatches += @{
- Match = $match
- Position = $match.Index
- Format = "Standard"
- }
+ # Find all standard markdown image matches
+ $standardMatches = [regex]::Matches($content, $standardPattern)
+ foreach ($match in $standardMatches) {
+ $allMatches += @{
+ Match = $match
+ Position = $match.Index
+ Format = "Standard"
}
+ }
- # Find all Obsidian image matches
- $obsidianMatches = [regex]::Matches($content, $obsidianPattern)
- foreach ($match in $obsidianMatches) {
- $allMatches += @{
- Match = $match
- Position = $match.Index
- Format = "Obsidian"
- }
+ # Find all Obsidian image matches
+ $obsidianMatches = [regex]::Matches($content, $obsidianPattern)
+ foreach ($match in $obsidianMatches) {
+ $allMatches += @{
+ Match = $match
+ Position = $match.Index
+ Format = "Obsidian"
}
+ }
- # Sort matches by position in document
- $allMatches = $allMatches | Sort-Object Position
+ # Sort matches by position in document
+ $allMatches = $allMatches | Sort-Object Position
- # Process each match in document order
- foreach ($matchInfo in $allMatches) {
- $match = $matchInfo.Match
- $format = $matchInfo.Format
+ # Process each match in document order
+ foreach ($matchInfo in $allMatches) {
+ $match = $matchInfo.Match
+ $format = $matchInfo.Format
- if ($format -eq "Standard") {
- $altText = $match.Groups[1].Value
- $imagePath = $match.Groups[2].Value.Trim()
- $title = if ($match.Groups[3].Success) { $match.Groups[3].Value } else { "" }
- } else {
- # Obsidian format
- $imagePath = $match.Groups[1].Value.Trim()
- $altText = if ($match.Groups[2].Success) { $match.Groups[2].Value } else { "" }
- $title = "" # Obsidian format doesn't support titles
- }
+ if ($format -eq "Standard") {
+ $altText = $match.Groups[1].Value
+ $imagePath = $match.Groups[2].Value.Trim()
+ $title = if ($match.Groups[3].Success) { $match.Groups[3].Value } else { "" }
+ }
+ else {
+ # Obsidian format
+ $imagePath = $match.Groups[1].Value.Trim()
+ $altText = if ($match.Groups[2].Success) { $match.Groups[2].Value } else { "" }
+ $title = "" # Obsidian format doesn't support titles
+ }
- # Skip URLs (images already hosted online)
- if ($imagePath -match '^https?://') {
- continue
- }
+ # Skip URLs (images already hosted online)
+ if ($imagePath -match '^https?://') {
+ continue
+ }
- # Resolve relative paths
- if (-not [System.IO.Path]::IsPathRooted($imagePath)) {
- $resolvedPath = Join-Path -Path $fileDirectory -ChildPath $imagePath
- } else {
- $resolvedPath = $imagePath
- }
+ # Resolve relative paths
+ if (-not [System.IO.Path]::IsPathRooted($imagePath)) {
+ $resolvedPath = Join-Path -Path $fileDirectory -ChildPath $imagePath
+ }
+ else {
+ $resolvedPath = $imagePath
+ }
- # Check if the file exists
- if (Test-Path -Path $resolvedPath -PathType Leaf) {
- $images += New-MarkdownImage `
- -OriginalMarkdown $match.Value `
- -AltText $altText `
- -LocalPath $resolvedPath `
- -RelativePath $imagePath `
- -Title $title `
- -FileName $(Split-Path -Path $resolvedPath -Leaf)
- }
+ # Check if the file exists
+ if (Test-Path -Path $resolvedPath -PathType Leaf) {
+ $images += New-MarkdownImage `
+ -OriginalMarkdown $match.Value `
+ -AltText $altText `
+ -LocalPath $resolvedPath `
+ -RelativePath $imagePath `
+ -Title $title `
+ -FileName $(Split-Path -Path $resolvedPath -Leaf)
}
+ }
- return $images
+ return $images
}
-Function New-MarkdownImage
-{
- param(
- [string]$OriginalMarkdown,
- [string]$AltText,
- [string]$LocalPath,
- [string]$RelativePath,
- [string]$Title = "",
- [string]$FileName
- )
- return [PSCustomObject]@{
- OriginalMarkdown = $OriginalMarkdown
- AltText = $AltText
- LocalPath = $LocalPath
- RelativePath = $RelativePath
- Title = $Title
- FileName = $FileName
- NewUrl = $null # This will be set after uploading to Google Drive
- }
+Function New-MarkdownImage {
+ param(
+ [string]$OriginalMarkdown,
+ [string]$AltText,
+ [string]$LocalPath,
+ [string]$RelativePath,
+ [string]$Title = "",
+ [string]$FileName
+ )
+ return [PSCustomObject]@{
+ OriginalMarkdown = $OriginalMarkdown
+ AltText = $AltText
+ LocalPath = $LocalPath
+ RelativePath = $RelativePath
+ Title = $Title
+ FileName = $FileName
+ NewUrl = $null # This will be set after uploading to Google Drive
+ }
}
\ No newline at end of file
diff --git a/src/public/Get-GoogleDriveItems.ps1 b/src/public/Get-GoogleDriveItems.ps1
index a056d44..9ee5e20 100644
--- a/src/public/Get-GoogleDriveItems.ps1
+++ b/src/public/Get-GoogleDriveItems.ps1
@@ -1,85 +1,85 @@
<#
.DESCRIPTION
- Queries files and folders in the Google drive associated with the authenticated account
+ Queries files and folders in the Google drive associated with the authenticated account
.PARAMETER ResultType
- Optional filter to specify the type of results to return. Valid values are:
- - All: Returns all files and folders
- - Files: Returns only files
- - Folders: Returns only folders
+ Optional filter to specify the type of results to return. Valid values are:
+ - All: Returns all files and folders
+ - Files: Returns only files
+ - Folders: Returns only folders
- Default is All.
+ Default is All.
.PARAMETER Title
- Optional filter to return files or folders with a specific title.
+ Optional filter to return files or folders with a specific title.
.PARAMETER ParentId
- Optional filter to return files or folders that are children of a specific parent folder.
- If not specified, returns items from the root directory.
+ Optional filter to return files or folders that are children of a specific parent folder.
+ If not specified, returns items from the root directory.
#>
-function Get-GoogleDriveItems
-{
- [CmdletBinding()]
- param(
- [Parameter()]
- [ValidateSet("All","Files","Folders")]
- [string]$ResultType = "All",
-
- [Parameter()]
- [string]$Title,
-
- [Parameter()]
- [string]$ParentId
- )
-
- $q = @()
-
- # mimeType
- if ($ResultType -ne "All") {
- if ($ResultType -eq "Folders") {
- $q += "mimeType='application/vnd.google-apps.folder'"
- }
- else {
- $q += "mimeType!='application/vnd.google-apps.folder'"
- }
+function Get-GoogleDriveItems {
+ [CmdletBinding()]
+ param(
+ [Parameter()]
+ [ValidateSet("All", "Files", "Folders")]
+ [string]$ResultType = "All",
+
+ [Parameter()]
+ [string]$Title,
+
+ [Parameter()]
+ [string]$ParentId
+ )
+
+ $q = @()
+
+ # mimeType
+ if ($ResultType -ne "All") {
+ if ($ResultType -eq "Folders") {
+ $q += "mimeType='application/vnd.google-apps.folder'"
}
-
- # title
- if (![string]::IsNullOrEmpty($Title)) {
- $q += "name='$Title'"
+ else {
+ $q += "mimeType!='application/vnd.google-apps.folder'"
}
+ }
- # parents
- if (![string]::IsNullOrEmpty($ParentId)) {
- $q += "'$ParentId' in parents"
- }
+ # title
+ if (![string]::IsNullOrEmpty($Title)) {
+ $q += "name='$Title'"
+ }
+
+ # parents
+ if (![string]::IsNullOrEmpty($ParentId)) {
+ $q += "'$ParentId' in parents"
+ }
- $queryArgs = @{
- q = [System.Web.HttpUtility]::UrlEncode($q -join ' and ')
- pageSize=40
- }
+ $queryArgs = @{
+ q = [System.Web.HttpUtility]::UrlEncode($q -join ' and ')
+ pageSize = 40
+ }
- do {
+ do {
- $queryString = $queryArgs.GetEnumerator() | ForEach-Object { "$($_.Name)=$($_.Value)"} | Join-String -Separator "&"
+ $queryString = $queryArgs.GetEnumerator() | ForEach-Object { "$($_.Name)=$($_.Value)" } | Join-String -Separator "&"
- $uri = "https://www.googleapis.com/drive/v3/files?$queryString"
+ $uri = "https://www.googleapis.com/drive/v3/files?$queryString"
- "Get-GoogleDriveItems: $uri" | Write-Verbose
+ "Get-GoogleDriveItems: $uri" | Write-Verbose
- $result = Invoke-GApi -uri $uri
+ $result = Invoke-GApi -uri $uri
- # stream results
- $result.files
+ # stream results
+ $result.files
- if ('nextPageToken' -in $result.PSObject.Properties.Name) {
- $queryArgs.pageToken = $result.nextPageToken
- } else {
- $queryArgs.pageToken = $null
- }
+ if ('nextPageToken' -in $result.PSObject.Properties.Name) {
+ $queryArgs.pageToken = $result.nextPageToken
+ }
+ else {
+ $queryArgs.pageToken = $null
+ }
- $result | Out-String | Write-Verbose
+ $result | Out-String | Write-Verbose
- } while($queryArgs.pageToken)
+ } while ($queryArgs.pageToken)
}
\ No newline at end of file
diff --git a/src/public/Initialize-Blogger.ps1 b/src/public/Initialize-Blogger.ps1
index 82729ed..ad41697 100644
--- a/src/public/Initialize-Blogger.ps1
+++ b/src/public/Initialize-Blogger.ps1
@@ -1,70 +1,68 @@
<#
.SYNOPSIS
- Initialize the local system to use Pandoc + Blogger together
+ Initialize the local system to use Pandoc + Blogger together
.DESCRIPTION
- This prepares your system to use Pandoc + Blogger together by obtaining an authtoken that is
- authorized to communicate with blogger.
+ This prepares your system to use Pandoc + Blogger together by obtaining an authtoken that is
+ authorized to communicate with blogger.
.PARAMETER clientId
- Google API Client ID. This currently defaults to the one I use, but you
- will need to create your own until the Google Application is published and verified
+ Google API Client ID. This currently defaults to the one I use, but you
+ will need to create your own until the Google Application is published and verified
-
.PARAMETER clientSecret
- Google API Client Secret. A default value is provided, but you can provide your own if you don't trust me.
+ Google API Client Secret. A default value is provided, but you can provide your own if you don't trust me.
.PARAMETER redirectUri
- The oAuth redirect URL specifed in the Google API Consent Form.
+ The oAuth redirect URL specifed in the Google API Consent Form.
.EXAMPLE
Initiate a login flow with Google
- Initialize-Blogger
+ Initialize-Blogger
#>
-Function Initialize-Blogger
-{
- Param(
- [Parameter(HelpMessage="Google API ClientId")]
- [string]$clientId = "284606892422-ribvo7oodlbtd70e8onn8rg4hm58mluj.apps.googleusercontent.com",
+Function Initialize-Blogger {
+ Param(
+ [Parameter(HelpMessage = "Google API ClientId")]
+ [string]$clientId = "284606892422-ribvo7oodlbtd70e8onn8rg4hm58mluj.apps.googleusercontent.com",
- [Parameter(HelpMessage="Google API Client Secret")]
- [string]$clientSecret = "PUK0j9ig-GHcSByQao2i1aIa",
+ [Parameter(HelpMessage = "Google API Client Secret")]
+ [string]$clientSecret = "PUK0j9ig-GHcSByQao2i1aIa",
- [Parameter(HelpMessage="Redirect Uri specified in Google API Consent Form")]
- [string]$redirectUri = "http://localhost/oauth2callback"
- )
+ [Parameter(HelpMessage = "Redirect Uri specified in Google API Consent Form")]
+ [string]$redirectUri = "http://localhost/oauth2callback"
+ )
- $ErrorActionPreference = 'Stop'
+ $ErrorActionPreference = 'Stop'
- Write-Information "Let's get an auth-code."
+ Write-Information "Let's get an auth-code."
- # specify the scopes we want in our auth token
- $scope = @(
- "https://www.googleapis.com/auth/blogger"
- #"https://www.googleapis.com/auth/drive.file"
- "https://www.googleapis.com/auth/drive"
+ # specify the scopes we want in our auth token
+ $scope = @(
+ "https://www.googleapis.com/auth/blogger"
+ #"https://www.googleapis.com/auth/drive.file" # TODO: fix
+ "https://www.googleapis.com/auth/drive"
- ) -join " "
+ ) -join " "
- $url = "https://accounts.google.com/o/oauth2/auth?client_id=$clientId&scope=$scope&response_type=code&redirect_uri=$redirectUri&access_type=offline&approval_prompt=force"
+ $url = "https://accounts.google.com/o/oauth2/auth?client_id=$clientId&scope=$scope&response_type=code&redirect_uri=$redirectUri&access_type=offline&approval_prompt=force"
- Start-Process $url
+ Start-Process $url
- $code = Wait-GoogleAuthApiToken
+ $code = Wait-GoogleAuthApiToken
- Write-Information "Sucessfully obtained auth-code!"
+ Write-Information "Sucessfully obtained auth-code!"
- # trade the auth-code for an token that has a short-lived expiry
- $expiringToken = Get-GoogleAccessToken -clientId $clientId -clientSecret $clientSecret -redirectUri $redirectUri -code $code
+ # trade the auth-code for an token that has a short-lived expiry
+ $expiringToken = Get-GoogleAccessToken -clientId $clientId -clientSecret $clientSecret -redirectUri $redirectUri -code $code
- # use the refresh-token to get an updated access-token
- $token = Update-GoogleAccessToken -clientId $clientId -clientSecret $clientSecret -refreshToken $expiringToken.refresh_token
+ # use the refresh-token to get an updated access-token
+ $token = Update-GoogleAccessToken -clientId $clientId -clientSecret $clientSecret -refreshToken $expiringToken.refresh_token
- # save the token in the credential_cache.json
- Set-CredentialCache -clientId $clientId -clientSecret $clientSecret -refreshToken $expiringToken -token $token
+ # save the token in the credential_cache.json
+ Set-CredentialCache -clientId $clientId -clientSecret $clientSecret -refreshToken $expiringToken -token $token
- Write-Information "Awesome. We're all set."
+ Write-Information "Awesome. We're all set."
}
\ No newline at end of file
diff --git a/src/public/Publish-BloggerPost.ps1 b/src/public/Publish-BloggerPost.ps1
index 0a0de15..1a37dc6 100644
--- a/src/public/Publish-BloggerPost.ps1
+++ b/src/public/Publish-BloggerPost.ps1
@@ -1,65 +1,91 @@
-Function Publish-BloggerPost
-{
- [CmdletBinding()]
- param(
- [Parameter(Mandatory=$true)]
- [string]$BlogId,
-
- [Parameter()]
- [string]$PostId,
-
- [Parameter(Mandatory=$true)]
- [string]$Title,
-
- [Parameter(Mandatory=$true)]
- [string]$Content,
-
- [string[]]$Labels,
-
- [switch]$Draft
- )
-
- $uri = "https://www.googleapis.com/blogger/v3/blogs/$BlogId/posts"
- $method = "POST"
-
- # if the postId exists, we're performing an update
- if ($PostId)
- {
- $uri += "/$PostId"
- $method = "PUT"
-
- if (-not $Draft) {
- $uri += "?publish=true"
- }
-
- } else {
- if ($Draft) {
- $uri += "?isDraft=true"
- }
- }
-
- $body = @{
- kind= "blogger#post"
- blog = @{
- id = $BlogId
- }
- title = $Title
- content = $Content
- labels = $Labels
+<#
+.SYNOPSIS
+ Publish a blog post to Blogger.
+
+.DESCRIPTION
+ Publish a blog post to blogger as a final or draft post
+
+.PARAMETER BlogId
+ Required. The Id of the blog to publish the post to.
+
+.PARAMETER PostId
+ Optional. The Id of the post to update. If not specified, a new post will be created.
+
+.PARAMETER Title
+ Required. The title of the post.
+
+.PARAMETER Content
+ Required. The content of the post in HTML format.
+
+.PARAMETER Labels
+ Optional. An array of labels (tags) to apply to the post.
+
+.PARAMETER Draft
+ Optional. If specified, the post will be saved as a draft instead of being published.
+
+#>
+Function Publish-BloggerPost {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$BlogId,
+
+ [Parameter()]
+ [string]$PostId,
+
+ [Parameter(Mandatory = $true)]
+ [string]$Title,
+
+ [Parameter(Mandatory = $true)]
+ [string]$Content,
+
+ [string[]]$Labels,
+
+ [switch]$Draft
+ )
+
+ $uri = "https://www.googleapis.com/blogger/v3/blogs/$BlogId/posts"
+ $method = "POST"
+
+ # if the postId exists, we're performing an update
+ if ($PostId) {
+ $uri += "/$PostId"
+ $method = "PUT"
+
+ if (-not $Draft) {
+ $uri += "?publish=true"
+ }
+
+ }
+ else {
+ if ($Draft) {
+ $uri += "?isDraft=true"
+ }
+ }
+
+ $body = @{
+ kind = "blogger#post"
+ blog = @{
+ id = $BlogId
}
+ title = $Title
+ content = $Content
+ labels = $Labels
+ }
- $body | ConvertTo-Json | Write-Verbose
+ $body | ConvertTo-Json | Write-Verbose
- $post = Invoke-GApi -Uri $uri -Body ($body | ConvertTo-Json) -Method $method
+ $post = Invoke-GApi -Uri $uri -Body ($body | ConvertTo-Json) -Method $method
- $postUrl = `
- if ($Draft) {
- "https://www.blogger.com/blog/post/edit/preview/$BlogId/$($post.id)"
- } else {
- $post.url
- }
+ $postUrl = `
+ if ($Draft) {
+ "https://www.blogger.com/blog/post/edit/preview/$BlogId/$($post.id)"
+ }
+ else {
+ $post.url
+ }
- Start-Process $postUrl
+ Start-Process $postUrl
- return $post
+ return $post
}
\ No newline at end of file
diff --git a/src/public/Publish-MarkdownDriveImages.ps1 b/src/public/Publish-MarkdownDriveImages.ps1
index 2a7dba5..27589aa 100644
--- a/src/public/Publish-MarkdownDriveImages.ps1
+++ b/src/public/Publish-MarkdownDriveImages.ps1
@@ -1,22 +1,22 @@
<#
.SYNOPSIS
- Publishes local images from a markdown file to Google Drive and updates the markdown file with the new URLs.
+ Publishes local images from a markdown file to Google Drive and updates the markdown file with the new URLs.
.DESCRIPTION
- This function finds all local images referenced in a markdown file, uploads them to Google Drive,
- sets public permissions, and updates the markdown file with the new Google Drive URLs.
+ This function finds all local images referenced in a markdown file, uploads them to Google Drive,
+ sets public permissions, and updates the markdown file with the new Google Drive URLs.
.PARAMETER File
- The path to the markdown file containing image references.
+ The path to the markdown file containing image references.
.PARAMETER Force
- If specified, will overwrite existing files in Google Drive with the same name.
+ If specified, will overwrite existing files in Google Drive with the same name.
.EXAMPLE
- Publish-MarkdownDriveImages -File "blog-post.md"
+ Publish-MarkdownDriveImages -File "blog-post.md"
.EXAMPLE
- Publish-MarkdownDriveImages -File "blog-post.md" -Force
+ Publish-MarkdownDriveImages -File "blog-post.md" -Force
#>
Function Publish-MarkdownDriveImages
{
diff --git a/src/public/Set-BloggerConfig.ps1 b/src/public/Set-BloggerConfig.ps1
index d4e9619..8355602 100644
--- a/src/public/Set-BloggerConfig.ps1
+++ b/src/public/Set-BloggerConfig.ps1
@@ -1,3 +1,21 @@
+<#
+.SYNOPSIS
+ Updates the local user preferences
+
+.DESCRIPTION
+ Updates local user preferences that are used in Cmdlets in this module.
+
+.PARAMETER Name
+ Name of the user preferene to set. Valid values are:
+ - BlogId: The ID of the Blogger blog to use.
+ - PandocAdditionalArgs: Additional arguments to pass to Pandoc when converting Markdown to HTML.
+ - PandocHtmlFormat: The HTML format to use when converting Markdown to HTML.
+ - PandocMarkdownFormat: The Markdown format to use when converting HTML to Markdown.
+ - ExcludeLabels: Labels to exclude when publishing to Blogger.
+
+.PARAMETER Value
+ The value to set for the specified user preference. Specify an empty string to remove the preference.
+#>
Function Set-BloggerConfig
{
[CmdletBinding()]
diff --git a/src/public/Set-GoogleDriveFilePermission.ps1 b/src/public/Set-GoogleDriveFilePermission.ps1
index e0797cd..8ecf353 100644
--- a/src/public/Set-GoogleDriveFilePermission.ps1
+++ b/src/public/Set-GoogleDriveFilePermission.ps1
@@ -1,41 +1,40 @@
<#
.SYNOPSIS
-Sets public read permissions on a Google Drive file.
+ Sets public read permissions on a Google Drive file.
.DESCRIPTION
-Configures a Google Drive file to be publicly accessible without authentication.
+ Configures a Google Drive file to be publicly accessible without authentication.
.PARAMETER FileId
-The ID of the Google Drive file to make public.
+ The ID of the Google Drive file to make public.
.EXAMPLE
-Set-GoogleDriveFilePermission -FileId "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
+ Set-GoogleDriveFilePermission -FileId "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
#>
-# Change to Set-GoogleDriveFile Permission
function Set-GoogleDriveFilePermission {
- [CmdletBinding()]
- param(
- [Parameter(Mandatory=$true)]
- [string]$FileId,
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$FileId,
- [Parameter(Mandatory=$true)]
- [PSCustomObject]$PermissionData
- )
+ [Parameter(Mandatory = $true)]
+ [PSCustomObject]$PermissionData
+ )
- # $permissionData = @{
- # role = "reader"
- # type = "anyone"
- # } | ConvertTo-Json
- $body = $PermissionData | ConvertTo-Json -Compress
+ # $permissionData = @{
+ # role = "reader"
+ # type = "anyone"
+ # } | ConvertTo-Json
+ $body = $PermissionData | ConvertTo-Json -Compress
- $uri = "https://www.googleapis.com/drive/v3/files/$FileId/permissions"
+ $uri = "https://www.googleapis.com/drive/v3/files/$FileId/permissions"
- try {
- $result = Invoke-GApi -uri $uri -body $body
- Write-Verbose "Set-GoogleDriveFilePermission: Set public permissions for file ID: $FileId"
- return $result
- }
- catch {
- Write-Error "Failed to set public permissions on Google Drive file: $($_.Exception.Message)$([Environment]::NewLine)$($_.ErrorDetails | ConvertTo-Json -Depth 10)" -ErrorAction Stop
- }
+ try {
+ $result = Invoke-GApi -uri $uri -body $body
+ Write-Verbose "Set-GoogleDriveFilePermission: Set public permissions for file ID: $FileId"
+ return $result
+ }
+ catch {
+ Write-Error "Failed to set public permissions on Google Drive file: $($_.Exception.Message)$([Environment]::NewLine)$($_.ErrorDetails | ConvertTo-Json -Depth 10)" -ErrorAction Stop
+ }
}
diff --git a/src/public/Set-MarkdownFrontMatter.ps1 b/src/public/Set-MarkdownFrontMatter.ps1
index 6511748..188373f 100644
--- a/src/public/Set-MarkdownFrontMatter.ps1
+++ b/src/public/Set-MarkdownFrontMatter.ps1
@@ -1,3 +1,25 @@
+<#
+.SYNOPSIS
+ Updates or Replaces the FrontMatter in a Markdown document
+
+.DESCRIPTION
+ Updates or Replaces the FrontMatter in a Markdown document with the specified values.
+
+.PARAMETER File
+ The path to the Markdown file to update.
+
+.PARAMETER Update
+ A hashtable of values to update in the front matter. If a key does not exist, it will be added.
+
+.PARAMETER Replace
+ An ordered dictionary to replace the entire front matter. This will overwrite any existing front matter.
+
+.EXAMPLE
+ Set-MarkdownFrontMatter -File "post.md" -Update @{title="New Title"; postid="12345"}
+
+.EXAMPLE
+ Set-MarkdownFrontMatter -File "post.md" -Replace @{title="New Title"; postid="12345"; date="2023-10-01"}
+#>
Function Set-MarkdownFrontMatter
{
[CmdletBinding(SupportsShouldProcess=$true)]
diff --git a/src/public/Update-MarkdownImages.ps1 b/src/public/Update-MarkdownImages.ps1
index 2ced776..88ff720 100644
--- a/src/public/Update-MarkdownImages.ps1
+++ b/src/public/Update-MarkdownImages.ps1
@@ -1,74 +1,84 @@
<#
.SYNOPSIS
-Updates markdown content by replacing local image references with Google Drive URLs.
+ Updates markdown content by replacing local image references with Google Drive URLs.
.DESCRIPTION
-Takes a markdown file and replaces local image references with Google Drive public URLs,
-converting all images to standard markdown format while preserving alt text and titles.
+ Takes a markdown file and replaces local image references with Google Drive public URLs,
+ converting all images to standard markdown format while preserving alt text and titles.
.PARAMETER File
-The path to the markdown file to update.
+ The path to the markdown file to update.
+
+.PARAMETER OutFile
+ Optional. If specified, writes the updated markdown content to this file instead of overwriting the original file.
.PARAMETER ImageMappings
-An array of objects containing the mapping between original markdown and new URLs.
-Each object should have OriginalMarkdown and NewUrl properties.
+ An array of objects containing the mapping between original markdown and new URLs.
+ Each object should have OriginalMarkdown and NewUrl properties.
.EXAMPLE
-$mappings = @(
+ $mappings = @(
@{ OriginalMarkdown = ""; NewUrl = "https://drive.google.com/uc?export=view&id=123"; AltText = "alt"; Title = "" }
@{ OriginalMarkdown = "![[image.png|description]]"; NewUrl = "https://drive.google.com/uc?export=view&id=456"; AltText = "description"; Title = "" }
-)
-Update-MarkdownImages -File "post.md" -ImageMappings $mappings
+ )
+ Update-MarkdownImages -File "post.md" -ImageMappings $mappings
+
+.EXAMPLE
+ $mappings = Find-MarkdownImages -File "post.md"
+ $mappings[0].NewUrl = "https://drive.google.com/uc?export=view&id=123"
+ Update-MarkdownImages -File "post.md" -ImageMappings $mappings -OutFile "updated-post.md"
#>
function Update-MarkdownImages {
- [CmdletBinding()]
- param(
- [Parameter(Mandatory=$true)]
- [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
- [string]$File,
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
+ [string]$File,
- [Parameter(Mandatory=$true)]
- [array]$ImageMappings,
+ [Parameter(Mandatory = $true)]
+ [array]$ImageMappings,
- [Parameter()]
- [string]$OutFile
- )
- $TargetFile = $File
+ [Parameter()]
+ [string]$OutFile
+ )
+ $TargetFile = $File
- Write-Verbose "UpdateMarkdownImages: Processing file $TargetFile with $($ImageMappings.Count) image mappings"
- $content = Get-Content -Path $TargetFile -Raw
- $originalContent = $content
+ Write-Verbose "UpdateMarkdownImages: Processing file $TargetFile with $($ImageMappings.Count) image mappings"
+ $content = Get-Content -Path $TargetFile -Raw
+ $originalContent = $content
- foreach ($mapping in $ImageMappings) {
- $originalMarkdown = $mapping.OriginalMarkdown
- $newUrl = $mapping.NewUrl
- $altText = $mapping.AltText
- $title = $mapping.Title
-
- # Construct the new markdown image syntax
- if ($title) {
- $newMarkdown = ""
- } else {
- $newMarkdown = ""
- }
+ foreach ($mapping in $ImageMappings) {
+ $originalMarkdown = $mapping.OriginalMarkdown
+ $newUrl = $mapping.NewUrl
+ $altText = $mapping.AltText
+ $title = $mapping.Title
- # Replace the original markdown with the new one
- $content = $content -replace [regex]::Escape($originalMarkdown), $newMarkdown
+ # Construct the new markdown image syntax
+ if ($title) {
+ $newMarkdown = ""
}
-
- # If OutFile is specified, write the updated content to that file
- if ($OutFile) {
- Write-Verbose "UpdateMarkdownImages: Changing output file from $File to $OutFile"
- $TargetFile = $OutFile
+ else {
+ $newMarkdown = ""
}
+
+ # Replace the original markdown with the new one
+ $content = $content -replace [regex]::Escape($originalMarkdown), $newMarkdown
+ }
- # Only write the file if content has changed
- if ($content -ne $originalContent) {
- Set-Content -Path $TargetFile -Value $content -NoNewline
- Write-Verbose "Updated markdown file: $TargetFile"
- return $true
- } else {
- Write-Verbose "No changes made to markdown file: $File"
- return $false
- }
+ # If OutFile is specified, write the updated content to that file
+ if ($OutFile) {
+ Write-Verbose "UpdateMarkdownImages: Changing output file from $File to $OutFile"
+ $TargetFile = $OutFile
+ }
+
+ # Only write the file if content has changed
+ if ($content -ne $originalContent) {
+ Set-Content -Path $TargetFile -Value $content -NoNewline
+ Write-Verbose "Updated markdown file: $TargetFile"
+ return $true
+ }
+ else {
+ Write-Verbose "No changes made to markdown file: $File"
+ return $false
+ }
}
From 936423b52efdd15d8f1817ff2b93b2186d11f658 Mon Sep 17 00:00:00 2001
From: bryan cook <3217452+bryanbcook@users.noreply.github.com>
Date: Thu, 24 Jul 2025 10:53:37 -0400
Subject: [PATCH 3/5] indentation
---
src/public/Get-BloggerBlogs.ps1 | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/src/public/Get-BloggerBlogs.ps1 b/src/public/Get-BloggerBlogs.ps1
index 9171dd1..d4603a7 100644
--- a/src/public/Get-BloggerBlogs.ps1
+++ b/src/public/Get-BloggerBlogs.ps1
@@ -3,21 +3,20 @@
Gets a list of Blogger Blogs associated to the user
#>
-Function Get-BloggerBlogs
-{
- [CmdletBinding()]
- param(
+Function Get-BloggerBlogs {
+ [CmdletBinding()]
+ param(
- )
+ )
- try {
- $uri = "https://www.googleapis.com/blogger/v3/users/self/blogs"
+ try {
+ $uri = "https://www.googleapis.com/blogger/v3/users/self/blogs"
- $result = Invoke-GApi -uri $uri
+ $result = Invoke-GApi -uri $uri
- $result.items
- }
- catch {
- Write-Error $_.ToString() -ErrorAction Stop
- }
+ $result.items
+ }
+ catch {
+ Write-Error $_.ToString() -ErrorAction Stop
+ }
}
\ No newline at end of file
From c2eef0a08b0ec1eb2d228c2fe379e4f23a238b9d Mon Sep 17 00:00:00 2001
From: bryan cook <3217452+bryanbcook@users.noreply.github.com>
Date: Thu, 24 Jul 2025 10:55:04 -0400
Subject: [PATCH 4/5] remove deprecated script
---
src/login.ps1 | 6 ------
1 file changed, 6 deletions(-)
delete mode 100644 src/login.ps1
diff --git a/src/login.ps1 b/src/login.ps1
deleted file mode 100644
index a3768bd..0000000
--- a/src/login.ps1
+++ /dev/null
@@ -1,6 +0,0 @@
-Param(
- [string]$code
-)
-$credential = Get-Content .\credentials.json | ConvertFrom-Json
-
-Initialize-Blogger -$code
\ No newline at end of file
From b61691e6cf148e9c0524243762f05c89c49bdd26 Mon Sep 17 00:00:00 2001
From: bryan cook <3217452+bryanbcook@users.noreply.github.com>
Date: Thu, 24 Jul 2025 11:13:03 -0400
Subject: [PATCH 5/5] Check if nextPageToken exists #23
---
src/public/Get-BloggerPosts.ps1 | 10 ++++++++--
src/tests/Get-BloggerPosts.Tests.ps1 | 11 +++++------
2 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/src/public/Get-BloggerPosts.ps1 b/src/public/Get-BloggerPosts.ps1
index 1d2e88e..10b1b5c 100644
--- a/src/public/Get-BloggerPosts.ps1
+++ b/src/public/Get-BloggerPosts.ps1
@@ -55,8 +55,14 @@ Function Get-BloggerPosts {
$result.items
- # loop if pageToken is present and -All switch is set
- $pageToken = $result.nextPageToken
+ # fetch continuation token
+ if ($result.PSObject.Properties.name -contains "nextPageToken") {
+ $pageToken = $result.nextPageToken
+ }
+ else {
+ $pageToken = $null
+ }
+ # loop if pageToken is present and -All switch is set
$done = ($All.IsPresent -and $All -and [string]::IsNullOrEmpty($pageToken)) -or !$All.IsPresent
}
}
diff --git a/src/tests/Get-BloggerPosts.Tests.ps1 b/src/tests/Get-BloggerPosts.Tests.ps1
index 6d913f5..606a6b7 100644
--- a/src/tests/Get-BloggerPosts.Tests.ps1
+++ b/src/tests/Get-BloggerPosts.Tests.ps1
@@ -12,7 +12,7 @@ Describe "Get-BloggerPosts" {
# Setup initial get-bloggerposts
Mock Invoke-GApi {
- return @{
+ return [pscustomobject]@{
items = @(
@{ id = "1"; title = "Post 1"; published = "2023-10-01T00:00:00Z" },
@{ id = "2"; title = "Post 2"; published = "2023-10-02T00:00:00Z" }
@@ -24,11 +24,10 @@ Describe "Get-BloggerPosts" {
# setup second call
Mock Invoke-GApi {
- @{
+ return [pscustomobject]@{
items = @(
@{ id = "3"; title = "Post 3"; published = "2023-10-03T00:00:00Z" }
)
- nextPageToken = $null
}
} -ParameterFilter { $uri -like "*pageToken*" }
}
@@ -48,7 +47,7 @@ Describe "Get-BloggerPosts" {
InModuleScope PSBlogger {
# Setup initial get-bloggerposts
Mock Invoke-GApi {
- return @{
+ return [pscustomobject]@{
items = @(
@{ id = "1"; title = "Post 1"; published = "2023-10-01T00:00:00Z" },
@{ id = "2"; title = "Post 2"; published = "2023-10-02T00:00:00Z" }
@@ -80,7 +79,7 @@ Describe "Get-BloggerPosts" {
# Mock the API call to return posts after a specific date
Mock Invoke-GApi {
- return @{
+ return [pscustomobject]@{
items = @(
@{ id = "1"; title = "Post 1"; published = "2023-10-01T00:00:00Z" },
@{ id = "2"; title = "Post 2"; published = "2023-10-02T00:00:00Z" }
@@ -105,7 +104,7 @@ Describe "Get-BloggerPosts" {
# Mock the API call to return all posts
Mock Invoke-GApi {
- return @{
+ return [pscustomobject]@{
items = @(
@{ id = "1"; title = "Post 1"; published = "2023-10-01T00:00:00Z" },
@{ id = "2"; title = "Post 2"; published = "2023-10-02T00:00:00Z" }