文章

从复制Markdown文本到生成帖子

从复制Markdown文本到生成帖子

在我看来博客不仅仅是输出知识的地方,也是归纳知识的地方。在一个博客平台上有效地归纳自己接触过的,学习过的知识可以加深自己的印象。同时也可以为以后快速触发这些归纳的知识提供便利,让自己更好地触达知识。借助现在AI是越来越强了,但输出的知识内容还是需要过滤的,毕竟每个人对知识的理解是不同的,而且那么多AI提供出来的答案,也是需要我们做一些筛选和归纳。每次从AI生成的答案中复制内容,然后再手动修改,再发布到博客上,这就是重复的过程。很多事重复地做就会让人产生无聊感,让人觉得无趣。所以,我想尝试一下,如何从复制Markdown文本开始自动生成帖子。

1.设计思路

  1. 在浏览器中复制Markdown文本并生成Markdown文件然后下载
  2. 监控下载文件的目标文件夹,如果监控到新文件,触发batch脚本处理并生成帖子

2.实现步骤

1. 在浏览器中复制Markdown文本并生成Markdown文件

如果AI提供将回答内容下载为Markdonw文件的话,那其实不用实现这一步,直接下载文件即可。但是有的AI不会提供上述的功能,比如Deepseek,它提供了将回答的内容复制为Markdonw格式的功能,没有下载为markdown文件的功能。所以我们需要在浏览器中复制Markdown文本,然后手动生成Markdown文件。但这个手动生成Markdown文件的过程是重复的,我们可以借助浏览器的插件实现从剪贴板从生成Markdown文件并下载到本地。拓展商店其实有这样插件,但是我没找到可以在生成文件前给文件命名的插件,所以我自己写了一个。

1.1 浏览器插件关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// manifest.json(插件配置文件)
{
    "manifest_version": 3,
    "name": "Extension2MD",
    "version": "1.0.0",
    "description": "将剪贴板内容保存为Markdown文件的扩展。",
    "action": {
        "default_popup": "popup.html",
        "default_icon": {
            "16": "icons/icon16.png",
            "32": "icons/icon32.png",
            "48": "icons/icon48.png",
            "128": "icons/icon128.png"
        }
    },
    "permissions": [
        "activeTab", //激活标签
        "clipboardRead", //读取剪贴板
        "scripting", //执行脚本
        "downloads", //下载
        "tabs", //标签
        "contextMenus" //上下文菜单
    ],
    "host_permissions": [
    "*://*/*" // 如需与网页交互
    ],
    "content_scripts": [
        {
            "matches": [
                "<all_urls>"
            ],
            "js": [
                "content.js"
            ]
        }
    ],
    "icons": {
        "16": "icons/icon16.png",
        "32": "icons/icon32.png",
        "48": "icons/icon48.png",
        "128": "icons/icon128.png"
    },
    "background": {
        "service_worker": "background.js",
        "type": "module" // 如需使用 ES6 模块
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// background.js(后台脚本)
chrome.runtime.onInstalled.addListener(() => {
  chrome.contextMenus.create({
    id: 'save2md',
    title: '下载复制内容',
    contexts: ['page'] // 仅在网页上右键时显示菜单
  });
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === 'save2md') {
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      func: async () => {
        try {
          //保存并下载内容为markdown文件
          const mdContent = await navigator.clipboard.readText();
          alert(`剪贴板内容: ${mdContent}`);
          // 创建并下载 Markdown 文件
          const blob = new Blob([mdContent], { type: 'text/markdown' });
          const url = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          //v2版本就是filename写死一个值,之后直接由bat文件负责让用户输入文件名(标题),
          const filename = prompt('请输入文件名:', '');
          if (!filename) {
            return;
          }
          console.log('用户输入:', filename);
          a.download = filename + '.md';
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(url);
        } catch (err) {
          console.error('读取失败:', err);
          alert('请检查权限或手动粘贴!');
        }
      }
    });
  }
});

按浏览器插件开发者官网教程 获取基本的项目结构模板,然后将以上代码分别添加到manifest.json和background.js中。将插件项目文件夹加载进浏览器,就可以实现右键点击下载剪贴板的功能了。效果如下:右键菜单

2.编写注册事件的powershell脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 定义要监控的文件夹路径
$watchFolder = "$env:USERPROFILE\Downloads"  # 替换为你的文件夹路径

# 创建 FileSystemWatcher 对象
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Filter = "*.md"  # 监控所有文件,可以改成 "*.pdf" 等特定类型
$watcher.Path = $watchFolder
$watcher.IncludeSubdirectories = $false  # 是否监控子文件夹

# 定义文件创建时的动作
$action = {
    # 定义要触发的脚本路径(可以是 .ps1、.bat 或 .exe),要在action的作用域内定义,不然无效
    $scriptToRun = "$env:USERPROFILE\desktop\22md.bat"  # 替换为你的任务脚本路径,用以处理下载的文件
    $watchFolder = "$env:USERPROFILE\Downloads"  # 替换为你的文件夹路径
    $filePath = $Event.SourceEventArgs.FullPath
    $changeType = $Event.SourceEventArgs.ChangeType
    $fileName = $Event.SourceEventArgs.Name
    $logline = "$(Get-Date), $changeType, $filePath"
    Add-Content "$env:USERPROFILE\desktop\watch_log.txt" -value $logline
    # Write-Host 检测到新文件: $fileName ($changeType)
    # 调用你的脚本,并传递文件路径作为参数
    # 需要反引号转义双引号,否则会因为文件名有空格而异常
    Start-Process -FilePath $scriptToRun -ArgumentList "`"$watchFolder`", `"$fileName`""
    Start-Sleep -Seconds 7  # 等待脚本执行完毕
    

}
# 注册创建文件事件(当文件创建时触发)
# Register-ObjectEvent -InputObject $watcher -EventName Created -SourceIdentifier FileCreated -Action $action
# 注册重命名文件事件(当文件重命名时触发)
Register-ObjectEvent -InputObject $watcher -EventName Renamed -SourceIdentifier FileRenamed -Action $action
$watcher.EnableRaisingEvents = $true  # 启用事件监听
# 保持脚本运行
Write-Host 正在监控文件夹: $watchFolder
# try {
#     Write-Host 按 Ctrl+C 停止监控...
#     while(${true}){
#         Start-Sleep -Seconds 1  # 防止脚本退出
#     }
# }
# finally {
#     # 清理(按 Ctrl+C 后取消监控)
#     $watcher.EnableRaisingEvents = $false
#     $watcher.Dispose()
#     Write-Host 监控已停止。
# }

注意:上面的代码中我之所以将try和catch语句注释,是因为加上后,下载文件的事件根本无法触发脚本任务的执行。另外,浏览器下载文件的过程是先创建临时文件再变更临时文件的拓展名为.md。所以注册的事件监听器对文件监听的动作应是“Renamed”,而不是“Created”,否则会导致脚本任务处理的是错误文件。

3. 编写处理下载的markdown文件的bat脚本v1版本

3.1 v1版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@echo off&chcp 65001
@REM echo %1
@REM echo %2
cd /d %1
@REM echo %cd%
@REM echo %date%
set today=%date:~3,13%
set today=%today:/=-%
@REM set today=!date!
echo %today%
@REM echo 去除双引号再拼接文件名
set raw_file_name=%~1\%~2
echo 文件名:%raw_file_name%
@REM pause
setlocal enabledelayedexpansion
set new_file_name=%~2
@REM echo 专门处理豆包提供的下载文件名,去除空格和《》符号
set new_file_name=!new_file_name: =!
set new_file_name=!new_file_name:《=!
set new_file_name=!new_file_name:》=!
set doc_tittle=!new_file_name:~0,-3!
set new_file_name=%~1\!today!-!new_file_name!
echo !new_file_name!
@REM pause
@REM echo 开始处理文档:!raw_file_name!
@REM pause
(
echo ---
echo title: !doc_tittle!
echo date: %today%
echo categories: [未知]
echo tags: [未知]
echo image:
echo  path: assets/img/blog_face/默认封面.png
echo  alt:
echo ---
) > "!new_file_name!"
@REM pause
type "!raw_file_name!" >> "!new_file_name!"
@REM more +1 "!raw_file_name!" >> "!new_file_name!"
@REM echo 去除头行并去除空行然后输出到新文件中
@REM more +1 "!raw_file_name!"|findstr /v "^$" >> "!new_file_name!"
echo 已生成新博客!
@REM pause
@REM echo 开始移动文件至博客目录,要根据自己博客的实际目录更改
set "wsl_dest_path=\\wsl.localhost\Ubuntu-22.04\home\feelord\BryceSun.github.io\_posts"
move "!new_file_name!" "!wsl_dest_path!"
@REM echo 已将新文件移动至WSL目录!
pause
endlocal

3.2 v2版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@echo off&chcp 65001
@REM echo %1
@REM echo %2
cd /d %1
@REM echo %cd%
@REM cd C:\Users\wjw\Downloads
@REM echo %date%
set today=%date:~3,13%
set today=%today:/=-%
@REM set today=!date!
echo %today%
@REM echo 去除双引号再拼接文件名
set raw_file_name=%~1\%~2
echo 文件名:%raw_file_name%
@REM pause
setlocal enabledelayedexpansion
set /p title=请输入标题:
set /p categories=请输入分类:
set /p tags=请输入标签:
set new_file_name=%~1\!today!-!title!.md
echo !new_file_name!
@REM pause
@REM echo 开始处理文档:!raw_file_name!
@REM pause
(
echo ---
echo title: !title!
echo date: %today%
echo categories: !categories!
echo tags: !tags!
echo image:
echo  path: assets/img/blog_face/默认封面.png
echo  alt:
echo ---
) > "!new_file_name!"
@REM pause
type "!raw_file_name!" >> "!new_file_name!"
@REM more +1 "!raw_file_name!" >> "!new_file_name!"
@REM echo 去除头行并去除空行然后输出到新文件中
@REM more +1 "!raw_file_name!"|findstr /v "^$" >> "!new_file_name!"
echo 已生成新博客!
@REM pause
set "wsl_dest_path=\\wsl.localhost\Ubuntu-22.04\home\feelord\BryceSun.github.io\_posts"
move "!new_file_name!" "!wsl_dest_path!"
@REM echo 已将新文件移动至WSL目录!
del "!raw_file_name!"
endlocal

此脚本用来给下截的.md文件内容的加上博客框架约定的头部信息,并按规范在文件名前面加上日期,以表示为发布状态。然后将文件移动到博客目录,以便发布到Jekyll博客平台。

4. 运行脚本

1
2
3
4
5
6
7
8
# 临时调用注册事件的脚本,以便在终端关闭后系统设置即恢复原状
Set-ExecutionPolicy RemoteSigned -Scope Process 
# 执行注册事件的脚本
C:\Users\wjw\Desktop\watch_mdfile.ps1

#终端窗口保持时,需要注销事件监控任务则可执行以下命令
get-eventSubscriber | Unregister-Event
get-job | stop-job

5. 调试Start-Process命令的脚本

1
2
3
4
5
6
7
$scriptToRun = "C:\Users\wjw\desktop\22md.bat"
$watchFolder = "C:\Users\wjw\Downloads"
$fileName = "如何在windows平台下载文件时触发脚本.md"

# 调用批处理脚本的两种方式
Start-Process -FilePath $scriptToRun -ArgumentList "$watchFolder", "$fileName"
Start-Process -FilePath "powershell.exe" -ArgumentList "-Command `"$scriptToRun`" `"$watchFolder`" `"$fileName`""

6. 开发中遇到的问题

  1. 浏览器插插件运行时访问浏览器的资源时需要权限,如读取剪贴板,调用下载功能,给页面注入js脚本,访问当前活动的标签页。
  2. 使用Start-Process命令时,需要将参数用引号包起来,否则会导致路径解析出错。而引号在PowerShell中有特殊含义,需要用反引号进行转义。
  3. 编写事件监控器脚本时,要在Action的作用域内定义要引用的文件路径,不然会报错。
本文由作者按照 CC BY 4.0 进行授权