LinkMind — Social Media Content Capture
When the user provides a social media link and asks you to capture/record/save it,
follow the workflow below.
Step 0: Read configuration
Read the config file at skills/linkmind/config.json to get the user's Obsidian
vault path. If the file does not exist, tell the user:
CODEBLOCK0
This runs an interactive wizard that guides the user through setting their
Obsidian vault path, platform cookies, and ASR credentials.
The config file structure:
CODEBLOCK1
Sensitive credentials (cookies, ASR keys) are configured in
skills/linkmind/.env. See the Cookie and ASR configuration sections below.
Cookies and ASR are optional — basic content capture works without them.
- - If
obsidian_vault is empty, ask the user to configure it. - Verify the vault directory exists. If not, inform the user that the path is invalid.
- The output directory is
{obsidian_vault}/LinkMind/. Create it if it does not exist.
Step 1: Identify the platform
Match the URL against these patterns:
| Platform | URL patterns |
|---|
| Weibo | INLINECODE4 , INLINECODE5 |
| Xiaohongshu |
xiaohongshu.com,
xhslink.com |
|
WeChat |
mp.weixin.qq.com |
|
小宇宙 |
xyzfm.link,
xiaoyuzhoufm.com |
小宇宙分享文本解析: 用户分享的内容可能是纯文本(如 分享播客《...》, 标记时点【17:03】https://xyzfm.link/s/xxx),从中提取 URL 即可,时间点由脚本自动从重定向 URL 的 #ts= 片段解析。
If the URL does not match any supported platform, tell the user:
"目前 LinkMind 支持微博、小红书、微信公众号和小宇宙播客链接,该链接暂不支持。"
Step 2: Run the handler script
The scripts live at skills/linkmind/scripts/.
Run the corresponding script from the project root:
Weibo:
CODEBLOCK2
Xiaohongshu:
CODEBLOCK3
WeChat:
CODEBLOCK4
小宇宙 (Xiaoyuzhou):
CODEBLOCK5
INLINECODE14 是短链接(如 https://xyzfm.link/s/xxx)或完整剧集链接。脚本自动解析重定向、提取时间戳、获取剧集元数据和字幕链接。
The script outputs JSON to stdout. If the JSON contains an "error" field,
the extraction failed — check the "code" field for the error category
(NETWORK, AUTH, RATE_LIMIT, NOT_FOUND, PARSE, UNKNOWN) and the
"details" field for a user-friendly suggestion. Report both to the user.
Step 2.A: 下载小宇宙字幕(仅限小宇宙平台)
仅在 platform 为 xiaoyuzhou 时执行此步骤。
- 1. 检查 JSON 输出中的
subtitleUrl 字段:
- 若为
null:字幕不可用,跳到
Step 2.B(标记
subtitleAvailable = false)。
- 若非
null:继续下载字幕。
- 2. 下载字幕文件:
CODEBLOCK6
- 3. 解析字幕(SRT 或 WebVTT 格式):
- 解析每条字幕:序号、时间戳行(
HH:MM:SS,mmm --> HH:MM:SS,mmm 或
. 分隔)、文本内容。
- 将时间戳转换为秒数:
startSeconds /
endSeconds。
- 4. 标记
subtitleAvailable = true,将解析结果存入 subtitleEntries(用于下一步过滤)。
如果 curl 失败或文件为空: 标记 subtitleAvailable = false,继续流程,不中止。
Step 2.B: 时间窗口过滤(仅限小宇宙平台)
仅在 platform 为 xiaoyuzhou 时执行此步骤。
根据 JSON 中的 timestampSeconds 决定摘要范围:
情况一:timestampSeconds 不为 null(用户分享了时间打点)
- - 窗口范围:
[timestampSeconds - 120, timestampSeconds + 120](前后各 2 分钟) - 从
subtitleEntries 中过滤满足条件的条目(条目与窗口有任意重叠即选入):
entry.startSeconds < windowEnd && entry.endSeconds > windowStart
- - 存入
filteredEntries,并记录 summaryScope = "time_window"。 - 即使有完整字幕,也只对
filteredEntries 生成深度摘要(用户明确指定了关注范围)。
情况二:timestampSeconds 为 null(完整收听)
- - 不过滤,
filteredEntries = subtitleEntries(使用全部字幕)。 - 记录
summaryScope = "full"。
若 subtitleAvailable = false:
- -
filteredEntries = [],在生成摘要时注明字幕不可用。 - 若
timestampSeconds 不为 null,在 Step 3 中提示用户:
"⚠️ 平台字幕不可用,无法提取该时间点的内容。如需转写,请配置 ASR 服务。"
格式化字幕文本: 将 filteredEntries 转为纯文本(去掉时间戳行,每条以换行分隔),
存入 subtitleText,供深度摘要使用。
Step 2.5: Download images to vault
If the JSON contains an images array with one or more URLs, download them
locally so the note is fully viewable offline in Obsidian.
- 1. Determine the slug (see file naming rules in Step 3).
- Set the attachments directory: INLINECODE55
- Run the download script:
CODEBLOCK7
- 4. The script outputs a JSON mapping:
{ "original_url": "img-001.jpg", ... }.
A
null value means that image failed to download.
- 5. For successfully downloaded images, use the relative path in Markdown:

- 6. For failed downloads, fall back to the original remote URL.
For WeChat articles specifically: after obtaining the download mapping, also
prepare the final richContent by replacing each  in the
richContent field with  (using
the local filename from the mapping, or the original URL if download failed).
Store this as the "resolved richContent" — you will use it in Step 3.
If the images array is empty, skip this step.
Step 2.6: Analyze image content (multimodal)
If images were successfully downloaded in Step 2.5, analyze each image to extract
visual content using your multimodal capabilities.
- 1. For each successfully downloaded image (where the download mapping value is not
null):
a. Read the image file from the local path using the Read tool:
{obsidian_vault}/LinkMind/attachments/{date}-{slug}/img-001.jpg
b. Analyze the image and extract:
-
Visible text: Any readable text, captions, watermarks, labels, or OCR content
-
Key visual elements: Charts, screenshots, UI elements, notable objects
-
Contextual information: Anything that supplements the original post text
c. Write a concise description (1-3 sentences) capturing the information value.
- 2. Store the per-image analysis results — you will use them in two places:
-
Step 3 (Markdown): Append as a blockquote immediately after each image
-
Deep Summary: Use all image analysis results as supplementary input
For WeChat articles: after analyzing all images, update the "resolved richContent"
(prepared in Step 2.5) by inserting each image's analysis blockquote immediately
after the corresponding  line. The final richContent should look like:
CODEBLOCK8
Output format per image (used in the Markdown):
CODEBLOCK9
Analysis guidelines:
- - Focus on information value — extract meaningful text and data first,
then briefly describe the visual scene.
- - Be specific: include actual text content, numbers, names from the image.
- Do NOT describe obvious formatting (e.g., "这是一张图片" or "图片显示了文字").
- If the image is purely decorative with no informational value, write:
> **图片内容:** 装饰性图片,无额外信息内容。
- - If reading the image fails, write:
INLINECODE68
Skip conditions (do NOT perform analysis):
- -
images array is empty → no images to analyze - All images failed to download in Step 2.5 → no local files to read
Step 2.C: 小宇宙音频 ASR 降级(仅限小宇宙平台)
仅在以下所有条件同时成立时执行:
- - INLINECODE70
- INLINECODE71 (Step 2.A 字幕不可用)
- INLINECODE72 不为 null
- INLINECODE73 中已配置 ASR 服务(讯飞或 OpenAI)
若条件不满足(ASR 未配置),跳过此步骤,在 Step 3 中提示:
"⚠️ 平台字幕不可用,ASR 服务未配置,无法转写音频。请在 .env 中配置 ASR 凭据。"
执行步骤:
- 1. 确定时间参数(用于只转写用户关心的片段,避免对整集做 ASR):
- 若
timestampSeconds 不为 null:
-
startSeconds = max(0, timestampSeconds - 120)
-
endSeconds = timestampSeconds + 120
- 若
timestampSeconds 为 null:不传时间参数(转写全集)
- 2. 确保 attachments 目录存在(同 Step 2.5)。
- 3. 运行音频转写脚本:
有时间窗口时(timestampSeconds 不为 null):
CODEBLOCK10
转写全集时(timestampSeconds 为 null):
CODEBLOCK11
- 4. 脚本输出 JSON:
{ "srtPath": "transcript.srt", "fullText": "转写纯文本..." }
- 成功后:标记
asrAvailable = true,将
fullText 存入
subtitleText,用于深度摘要
- 失败后(含
"error" 字段):标记
asrAvailable = false,
不中止流程,在 Step 3 中报告错误
Step 2.7: Extract video transcript (if applicable)
此步骤适用于微博、小红书等有 videoUrl 的平台。小宇宙平台请使用 Step 2.C。
If the JSON contains a non-null videoUrl field and the user has configured
ASR credentials in .env, extract the audio and transcribe it.
- 1. Ensure the attachments directory exists (same as Step 2.5):
{obsidian_vault}/LinkMind/attachments/{date}-{slug}/
- 2. Run the transcript extraction script:
CODEBLOCK13
- 3. The script outputs JSON to stdout:
{
"srtPath": "transcript.srt",
"fullText": "完整的转写纯文本..."
}
-
srtPath: the SRT filename saved in the output directory
-
fullText: the complete transcript as plain text (for use in the summary)
- 4. If the script outputs an
"error" field, the transcript extraction failed.
Do NOT abort the entire workflow — continue to Step 3 without the transcript.
Report the error to the user alongside the final result.
Skip conditions (do NOT run the script):
- -
videoUrl is null → no video to transcribe - INLINECODE92 has no ASR variables configured → ASR not configured;
inform the user: "视频转写需要配置 ASR 服务(科大讯飞或 OpenAI Whisper),请在 .env 中配置。参考 .env.example。"
Multilingual transcripts: If fullText is in a non-Chinese language, translate
and present the key points in Chinese when writing the deep summary. The SRT file
itself is kept in the original language.
Step 3: Generate the Markdown file
Using the JSON output, local image paths from Step 2.5, image analysis from
Step 2.6 (if available), and transcript from Step 2.7 (if available), create
a Markdown file with this structure.
YAML frontmatter safety rules:
String values in YAML frontmatter MUST be properly quoted to avoid parse errors.
Apply these rules to title, author, and original_url:
- 1. Default to single quotes
'...' for title and author — these fields
frequently contain characters that break double-quoted YAML strings (Chinese
curly quotes
"", pipes
|, colons
:, etc.).
- 2. If the value itself contains a single quote
', use double quotes "..." and
backslash-escape any inner double quotes.
- 3. Always wrap
original_url in double quotes "..." — URLs contain ?, =,
& which are special in YAML.
- 4. Never leave string values unquoted if they contain any of:
: | ? = & " " ' # [ ] { }.
CODEBLOCK15
小宇宙笔记的深度摘要要求:
在 ## 深度总结 部分,若 timestampSeconds 不为 null(用户指定了时间点):
- - 明确标注摘要的时间范围: INLINECODE113
- 仅基于
filteredEntries 内容生成摘要,不延伸到窗口外 - 说明该时间段的主要观点/讨论内容
- 如有需要,从
description(节目简介)提供背景上下文
若 summaryScope = "full"(用户未指定时间点):
- - 基于全部
subtitleText 生成完整剧集摘要 - 参考
description 补充节目背景
File naming
Name the file as: INLINECODE119
- -
{date} is YYYY-MM-DD format - INLINECODE122 is derived from the title — take the first 30 chars, replace spaces with
hyphens, remove special characters, and lowercase. If the title is in Chinese,
use the first 10 Chinese characters joined by hyphens.
Output directory
Save the file to {obsidian_vault}/LinkMind/ (the vault path from Step 0).
Create the LinkMind/ subdirectory if it does not exist.
Step 4: Report result
After saving, tell the user:
- - The file path where the note was saved (the full Obsidian vault path)
- The title extracted from the content
- The platform and author
- How many images were analyzed and key findings (if image analysis was performed)
- Whether video transcript was generated (and SRT file location if so)
- A brief overview of the deep summary
Deep Summary Guidelines
Read and follow the full guidelines in
skills/linkmind/references/deep-summary-guide.md.
Key points: classify the content type (观点/教程/新闻/故事/测评/清单),
write structured fields + bullets/tables in Chinese, add 2-3 key takeaways,
incorporate image analysis and video transcript when available.
Error handling
- - If the handler script fails, report the error to the user clearly.
- Use the
code field to tailor your response:
-
NETWORK — suggest checking network and retrying
-
AUTH — tell the user the content may require login; suggest configuring
cookies (see below)
-
RATE_LIMIT — suggest waiting a few minutes before retrying
-
NOT_FOUND — ask the user to verify the link is correct
-
PARSE — the platform structure may have changed; suggest reporting the issue
- - If a timeout occurs, suggest the user try again later.
- Never silently fail — always give the user feedback.
Cookie configuration (optional)
Cookies are optional. They are only needed when capturing content that
requires login (e.g. private or restricted posts). Public content can be
captured without any cookie configuration.
Configure platform cookies in skills/linkmind/.env
(copy from .env.example if the file does not exist):
CODEBLOCK16
注:WeChat Cookie 用于获取阅读/点赞/在看统计数据,不影响基础文章提取。
You can also set cookies via config.json:
CODEBLOCK17
Environment variables take precedence over config.json values.
To obtain cookies: log in to the platform in a browser, open DevTools → Application →
Cookies, and copy the relevant cookie values as a semicolon-separated string.
ASR configuration (optional — required for video transcript)
ASR is optional. Without it, video posts are still captured normally — only
the transcript feature is unavailable.
Configure ASR credentials in skills/linkmind/.env
(copy from .env.example if the file does not exist):
CODEBLOCK18
- - Configure at least one service to enable video transcript
- If both are configured, iFlytek is tried first; on failure,
OpenAI is used as fallback
- - To obtain iFlytek credentials: register at https://www.xfyun.cn/, create an
app, enable "语音转写" service, and copy the App ID / API Key / API Secret
- - To obtain OpenAI key: https://platform.openai.com/api-keys
LinkMind — 社交媒体内容捕获
当用户提供社交媒体链接并要求您捕获/记录/保存时,请遵循以下工作流程。
步骤 0:读取配置
读取 skills/linkmind/config.json 配置文件以获取用户的 Obsidian 仓库路径。如果文件不存在,请告知用户:
请先运行配置向导:cd skills/linkmind/scripts && npm run setup
这将运行一个交互式向导,引导用户设置其 Obsidian 仓库路径、平台 Cookie 和 ASR 凭据。
配置文件结构:
json
{
obsidian_vault: /absolute/path/to/vault
}
敏感凭据(Cookie、ASR 密钥)在 skills/linkmind/.env 中配置。请参阅下方的 Cookie 和 ASR 配置部分。Cookie 和 ASR 是可选的——基本内容捕获无需它们即可工作。
- - 如果 obsidianvault 为空,请要求用户进行配置。
- 验证仓库目录是否存在。如果不存在,请告知用户路径无效。
- 输出目录为 {obsidianvault}/LinkMind/。如果不存在则创建它。
步骤 1:识别平台
将 URL 与以下模式进行匹配:
| 平台 | URL 模式 |
|---|
| 微博 | weibo.com、m.weibo.cn |
| 小红书 |
xiaohongshu.com、xhslink.com |
|
微信 | mp.weixin.qq.com |
|
小宇宙 | xyzfm.link、xiaoyuzhoufm.com |
小宇宙分享文本解析: 用户分享的内容可能是纯文本(如 分享播客《...》, 标记时点【17:03】https://xyzfm.link/s/xxx),从中提取 URL 即可,时间点由脚本自动从重定向 URL 的 #ts= 片段解析。
如果 URL 不匹配任何支持的平台,请告知用户:
目前 LinkMind 支持微博、小红书、微信公众号和小宇宙播客链接,该链接暂不支持。
步骤 2:运行处理脚本
脚本位于 skills/linkmind/scripts/。从项目根目录运行相应的脚本:
微博:
bash
npx tsx skills/linkmind/scripts/weibo.ts --config skills/linkmind/config.json
小红书:
bash
npx tsx skills/linkmind/scripts/xiaohongshu.ts --config skills/linkmind/config.json
微信:
bash
npx tsx skills/linkmind/scripts/wechat.ts --config skills/linkmind/config.json
小宇宙:
bash
npx tsx skills/linkmind/scripts/xiaoyuzhou.ts --config skills/linkmind/config.json
是短链接(如 https://xyzfm.link/s/xxx)或完整剧集链接。脚本自动解析重定向、提取时间戳、获取剧集元数据和字幕链接。
脚本将 JSON 输出到标准输出。如果 JSON 包含 error 字段,则提取失败——检查 code 字段以获取错误类别(NETWORK、AUTH、RATELIMIT、NOTFOUND、PARSE、UNKNOWN)以及 details 字段以获取用户友好的建议。将两者都报告给用户。
步骤 2.A:下载小宇宙字幕(仅限小宇宙平台)
仅在 platform 为 xiaoyuzhou 时执行此步骤。
- 1. 检查 JSON 输出中的 subtitleUrl 字段:
- 若为 null:字幕不可用,跳到
Step 2.B(标记 subtitleAvailable = false)。
- 若非 null:继续下载字幕。
- 2. 下载字幕文件:
bash
curl -s
-o /tmp/linkmind-subtitle.srt
- 3. 解析字幕(SRT 或 WebVTT 格式):
- 解析每条字幕:序号、时间戳行(HH:MM:SS,mmm --> HH:MM:SS,mmm 或 . 分隔)、文本内容。
- 将时间戳转换为秒数:startSeconds / endSeconds。
- 4. 标记 subtitleAvailable = true,将解析结果存入 subtitleEntries(用于下一步过滤)。
如果 curl 失败或文件为空: 标记 subtitleAvailable = false,继续流程,不中止。
步骤 2.B:时间窗口过滤(仅限小宇宙平台)
仅在 platform 为 xiaoyuzhou 时执行此步骤。
根据 JSON 中的 timestampSeconds 决定摘要范围:
情况一:timestampSeconds 不为 null(用户分享了时间打点)
- - 窗口范围:[timestampSeconds - 120, timestampSeconds + 120](前后各 2 分钟)
- 从 subtitleEntries 中过滤满足条件的条目(条目与窗口有任意重叠即选入):
entry.startSeconds < windowEnd && entry.endSeconds > windowStart
- - 存入 filteredEntries,并记录 summaryScope = time_window。
- 即使有完整字幕,也只对 filteredEntries 生成深度摘要(用户明确指定了关注范围)。
情况二:timestampSeconds 为 null(完整收听)
- - 不过滤,filteredEntries = subtitleEntries(使用全部字幕)。
- 记录 summaryScope = full。
若 subtitleAvailable = false:
- - filteredEntries = [],在生成摘要时注明字幕不可用。
- 若 timestampSeconds 不为 null,在 Step 3 中提示用户:
⚠️ 平台字幕不可用,无法提取该时间点的内容。如需转写,请配置 ASR 服务。
格式化字幕文本: 将 filteredEntries 转为纯文本(去掉时间戳行,每条以换行分隔),存入 subtitleText,供深度摘要使用。
步骤 2.5:将图片下载到仓库
如果 JSON 包含一个包含一个或多个 URL 的 images 数组,请将它们下载到本地,以便笔记在 Obsidian 中完全可离线查看。
- 1. 确定 slug(请参阅步骤 3 中的文件命名规则)。
- 设置附件目录:{obsidian_vault}/LinkMind/attachments/{date}-{slug}/
- 运行下载脚本:
bash
npx tsx skills/linkmind/scripts/download-images.ts \
--urls {逗号分隔的图片 URL} \
--output-dir {附件目录} \
--referer {平台首页:https://weibo.com / https://www.xiaohongshu.com / https://mp.weixin.qq.com}
- 4. 脚本输出一个 JSON 映射:{ original_url: img-001.jpg, ... }。null 值表示该图片下载失败。
- 对于成功下载的图片,在 Markdown 中使用相对路径:

- 对于下载失败的图片,回退到原始远程 URL。
特别针对微信公众号文章: 获取下载映射后,还需准备最终的 richContent,将 richContent 字段中的每个
替换为
(使用映射中的本地文件名,如果下载失败则使用原始 URL)。将其存储为已解析的 richContent——您将在步骤 3 中使用它。
如果 images 数组为空,则跳过此步骤。
步骤 2.6:分析图片内容(多模态)
如果在步骤 2.5 中成功下载了图片,请使用您的多模态能力分析每张图片以提取视觉内容。
- 1. 对于每张成功下载的图片(下载映射值不为 null):
a. 使用读取工具从本地路径读取图片文件:{obsidian_vault}/LinkMind/attachments/{date}-{slug}/img-001.jpg
b. 分析图片并提取:
- 可见文本:任何可读的文字、字幕、水印、标签或 OCR 内容
- 关键视觉元素:图表、截图、UI 元素、显著物体
- 上下文信息:任何补充原始帖子内容的信息
c. 编写一个简洁的描述(1-3 句话),捕捉信息价值。
- 2. 存储每张图片的分析结果——您将在两个地方使用它们:
- 步骤 3(Markdown):在每张图片后立即附加为引用块
- 深度摘要:将所有图片分析结果作为补充输入
针对微信公众号文章: 分析完所有图片后,更新已解析的 richContent(