MNPinner
这是一个 AI 快速发展的时代。数据和知识的获取变得越来越容易,你可以轻松地下载大量文档,让 MNAI 进行大量卡片生成。但如果任由它们堆砌,你只会陷于信息的泥潭中无法自拔。
MNPinner 为此诞生,它并非能让你快速管理你的所有卡片和文档的卡片盒,而是能让你在任何时候都能清楚,你现在关注的是什么,你当前的任务是什么,不管出现什么样的干扰和波动,你都能够快速地回到你的主线上,减少心流中断,节省你宝贵的专注力流失。
MNPinner 的设计理念:“控源”——卡片、文档页面、文本、链接、图片,甚至是你的 UI 状态都可以进行管理和回源!
MNPinner 不生产数据,它只是数据的搬运工。
MNPinner 将辅助你进行 MarginNote 内的全局调度,搭建属于你的 MarginNote 中控台!
版本历史
v5.5
-
购买流程革新:从闲鱼淘口令改为支付宝/微信直接购买,新增独立购买中心页面,补差价买断改为固定商品(¥9.9/¥20/¥30/¥45 → ¥128),计费周期表述优化(“每天” → “/ 24h”),二维码显示质量提升(无损渲染)
-
主面板分组系统升级:支持 3 层树形分组结构,批量建组并移动功能,分组拖拽重组,分组添加模式(长按进入),分组折叠/展开状态持久化
-
整理模式增强:新增「替换入口」操作(拖拽到文件夹入口),新增副屏功能(轻量双屏整理),支持批量拖拽整理,拖拽体验优化(手势响应更流畅)
-
Pin 动作布局编辑器:一级按钮支持短标题设置,新增操作引导和快捷入口,草稿自动保存功能,系统固定按钮标识
-
术语优化:“复习” → “重复计划/轮次”,“分区” → “顶层视图”,“复习模式” → “学习模式”
-
性能优化:工作区拖拽响应时间从 3-4s 降至 500ms 以内,视图切换从 1.8-2s 降至 300ms 以内,精准缓存失效机制
-
其他改进:灵感速录支持文件夹入口类型选择,更新检查稳定性提升(本地备份机制),文本 Pin 编辑器草稿缓存清理修复
v5.4
-
全新工作区模式:双车道布局(上区固定 + 流动区),可展开/折叠资料库视图,支持左侧快捷操作栏,打造类似看板的知识工作流体验
-
工作区分区功能:支持创建多个独立工作区,每个分区独立管理内容;支持分区重命名、删除、左右移动调整顺序;通过标签页快速切换不同工作场景
-
文件夹快捷方式:将文件夹拖入工作区后自动创建快捷方式,点击可直接跳转到原文件夹;支持从工作区拖回原文件夹,保持工作区整洁的同时快速访问资料库内容
-
递归 Pin 卡片树:长按工具栏「Pin 卡片」按钮可选择「递归 Pin 卡片树」,按 MarginNote 卡片层级递归导入,有子卡片的项会自动转为文件夹;支持批量处理多张卡片
-
配置导入/导出支持范围选择:可选择「仅资料库」、「仅工作区」或「全量(含工作区)」,灵活控制数据迁移范围;导入时自动检测数据包范围,防止误操作清空错误的数据
-
整理拖拽体验大幅提升:拖拽时显示左右分区视觉反馈,左侧「剪切」右侧「引用」,操作意图更清晰;优化拖拽幽灵视图样式,更紧凑现代;修复拖动时按钮位置闪烁问题
-
跨插件协作 API:新增 queryPins API,支持其他插件通过定位链接或查询条件获取 Pin 的详细信息(类型、标题、关联内容等),实现跨插件数据共享和协作
-
正则替换功能增强:Markdown 编辑器和文本编辑器的正则替换支持转义字符(\n 换行、\t 制表符、\ 反斜杠)和捕获组引用($1、$2 等),满足更复杂的文本处理需求
-
卡片标题新增「只取第一个标题变体」选项:支持按英文分号分隔标题变体,自动保留第一个变体;适用于 Pin 卡片时的标题处理、编辑器引用卡片等场景
-
国际化支持:输入提示框、操作菜单、文件夹搜索等界面自动根据系统语言切换中英文,无需手动设置;支持中文和英文两种语言,覆盖所有按钮、标签、提示文本
-
Markdown 编辑器优化:隐藏 Vditor 内置大纲功能,避免界面冗余;增强滚动位置记忆机制,切换标签页后更准确地恢复滚动位置;编辑器初始化后光标自动定位到末尾
-
工作区数据分离优化:关闭工作区模式时不再自动创建工作区结构,默认导出/同步只处理资料库数据;修复删除操作的误删风险,优化来源信息显示
v5.3
-
新增整理模式:长按 Pin 拖到目标文件夹,快速整理内容;支持拖拽到面包屑导航或文件夹入口 Pin;自动边缘滚动,拖拽时自动高亮可放置区域
-
灵感速录支持批量模式:按缩进或列表自动建层级,一次输入多条内容;输入框顶部新增目标文件夹切换按钮,可在「固定文件夹」和「当前文件夹」之间快速切换
-
新增「拆分选中文本为多个 Pin」功能:支持批量创建文本 Pin 和文件夹,可选择是否删除原 Pin
-
Markdown 编辑器新增「提取选中为新 Pin」功能:支持复制或剪切模式,可选择仅创建或创建后继续编辑新 Pin
-
文本 Pin 处理器简易模式新增快捷短语面板:显示勾选了「简易」的快捷短语,支持插入、追加、新行、替换四种模式
-
Pin 菜单新增「剪切绑定卡片到 MN 选中卡片下」功能:可将 Pin 绑定的 MN 卡片剪切为当前选中卡片的子卡片
-
编辑器拖动手柄增大(宽度 150→180,高度 8→12),更容易抓取和移动窗口
-
优化文本选区保持机制:打开工具菜单后选区不会丢失,操作更流畅
-
长按「Pin 链接」按钮现在弹出操作菜单:可选「手动输入链接」或「创建 Pin 定位链接」
-
买断补差页面优化:移除订阅天数门槛,改为直接显示报价依据和可抵扣金额进度
-
修复菜单关闭逻辑,防止错误关闭其他菜单导致遮罩残留
-
修复 BigBang 打开后选中高亮消失的问题,替换结果更准确
-
修复订阅激活后界面未立即刷新的问题,访问权限和节点内容现在同步更新
v5.2
-
订阅面板全面重设计:买断进度可视化(进度条 + 达标状态摘要)、历史记录归档、新用户引导一目了然
-
新增重复计划系统:支持将文件夹设为「重复文件夹」,从 Pin 菜单加入重复计划,设置计划策略(有限/无限轮次)和首轮日期;重复计划管理器可查看、编辑和删除计划条目
-
文件导入/导出:支持从文件系统导入 Markdown/TXT/Word 文件为文本 Pin;支持批量导出为 ZIP 文件(Markdown/TXT/Word 格式)
-
新增 Pin 剪切功能,可将 Pin 剪切后粘贴到其他文件夹
-
新增 Pin 链接引用编辑器,支持前缀/变量/后缀组合生成链接文本,可搜索已有 Pin 快速定位
-
菜单支持自定义排序(上移/下移)、分组折叠/展开;滚动时不再误触,长按识别更准确
-
BigBang 长按复制可自定义开关和延迟时间(0.2-0.9 秒),新增清除选择按钮
-
UIState Pin 支持绑定学习集 ID;Card Pin 支持跨学习集定位,自动切换到对应学习集
-
模板变量增强:新增子卡/子树数量变量(childCount / descendantCount),支持方括号语法(如 note.comments[0])
-
新用户首次使用自动领取免费体验天数,无需手动操作
-
「一键安装」按钮仅在检测到可用更新时显示,界面更简洁
-
新增文件夹收藏栏:可将文件夹标记为收藏,主面板顶部显示收藏栏,支持左移/右移调整顺序;可在设置中开启「局部结构菜单也显示收藏栏」
-
新增文本 Pin 处理器面板:Pin 文本时支持简易、正则表达式、多行处理三种模式;多行模式支持自定义分隔符、「粘贴并处理」及 OCR 框选(需 MNOCR 插件);可在设置中固定指定 OCR 模型
-
移除「自动 Pin 剪贴板文本」功能(原属 v5.0 自动 Pin 系统的一部分)
-
修复关闭菜单后遮罩层可能残留、导致界面无法点击的问题
v5.1
-
令牌自动订阅全面集成:余额充足时自动扣费续订,操作无需中断
-
模板制卡后自动回 Pin:新卡片自动添加到指定文件夹
-
引用入口返回时自动定位:从引用入口进入文件夹后返回,会自动滚动到原入口位置
-
兑换码预览增加错误提示,无效码不再允许点击兑换
-
新增 ¥1 档倍率码(可用于 ≥¥1 令牌订单)
-
导入/导出/备份操作前自动保存未写入的配置,避免数据丢失
-
Markdown 编辑器大纲面板支持折叠/展开子孙标题
-
单选类菜单项增加高亮样式,当前选中项更醒目
-
关闭 HUD 提示总开关后,错误提示不再被误屏蔽
v5.0
-
国际化系统:完整中英文界面切换,1200+ 翻译条目
-
文件夹管理器改版:左右分栏布局,拖拽调整宽度
-
本地备份系统:自动备份配置,支持历史版本恢复
-
自动 Pin 系统:手动建卡、摘录、MNOCR 识别、剪贴板文本均可自动 Pin
-
灵感速录增强:所有 Pin 类型均可汇总到固定文件夹
-
菜单界面升级:全新选择菜单,支持搜索筛选、图标分组、层级缩进、当前项高亮
-
正则表达式预设:保存常用正则替换,一键应用
-
教程模式演示:一键创建示例 Pin 快速理解功能
-
订阅系统优化:倍率码重构、订阅追加、解绑买断
-
配置搜索:跨标签页搜索配置项,自动切换定位
-
Markdown 编辑器升级:多标签页、WYSIWYG 工具栏、OCR 引用、LaTeX 数学公式
详细更新日志
核心功能升级
文件夹管理器全新改版
-
支持拖拽调整宽度,自由定制界面布局
-
新增单文件夹编辑模式,操作更聚焦
-
配置管理器重构,文件夹管理独立为专用面板
智能 Pin 系统
-
自动 Pin 系统:手动建卡、文档摘录、MNOCR 识别、剪贴板文本均可自动 Pin,支持保存到当前文件夹或固定文件夹
-
Pin 引用:统一命名(原"粘贴引用"),更直观易懂
-
增量导入:支持从剪切板导入 Pin 到指定文件夹
-
快速定位:Pin 管理器和搜索面板新增快速定位功能
-
MNOCR 自动 Pin:识别结果自动保存为文本 Pin
-
剪贴板自动 Pin:剪贴板文本自动创建 Pin
-
MNChatAI 集成增强:自动收集 AI 回答,支持 Prompt 收藏分组、发送文本到 AI 浮窗
-
图片 Pin 增强:支持 UIState 定位到文档原始位置,缓存清理后自动恢复
-
页面 Pin 导出:支持导出页面所属的 PDF 文档
灵感速录
-
双重交互:右侧新增按钮,单击切换开关状态,长按弹窗输入文本
-
全局路由:开启后,所有 Pin 创建操作自动路由到目标文件夹
-
两种模式:固定文件夹模式(统一收集)/ 当前文件夹模式(项目分类)
-
长按反向:长按按钮可临时使用相反模式,无需打开菜单切换
快捷操作中心
-
移动按钮快捷菜单:一键访问语言切换、更新、订阅、教程模式等常用功能
-
ActionMenu 系统:统一的菜单选择界面,支持搜索筛选、图标、危险标记、缩进层级
-
输入弹窗系统:重命名 Pin 时使用全新的浮层输入界面
-
菜单搜索:文件夹树、图标选择器等菜单均支持搜索筛选
-
图标选择器:支持分组(常用/场景/内容/结构/操作)和使用频率统计
Markdown 编辑器全面升级
-
多标签页:同时打开多个编辑器并快速切换
-
WYSIWYG 工具栏:所见即所得模式新增格式化工具栏
-
OCR 引用:从文档选区或框选图片插入引用链接,文本选区和框型选区可分别控制 OCR
-
LaTeX 数学公式:行内公式和块级公式均可正确渲染
-
追加文本:从选区或剪贴板追加内容,长按可追加引用链接
-
内置炸词(BigBang):简约黑白风格界面
-
光标定位优化:失焦后也能准确插入到原位置
用户体验优化
界面与交互
-
工具栏按钮图标自动缩放,视觉效果更统一
-
Pin 标题图标对齐问题彻底解决,多行文本显示完美
-
样式系统重构:提取独立 CSS 文件,统一主题变量
-
ActionMenu 点击响应优化:改进触摸事件处理,防止滚动时误触发
-
多选模式优化:所有按钮在多选时统一为选中操作,支持反选
-
UIState 定位优化:有 UIState 的 Pin 直接按 UIState 定位
-
配置管理器性能提升:标签切换更快,加载速度优化
-
文件夹树折叠/展开全部
-
OCR 识别准确率提升:压缩质量优化,识别不完整时自动重试
搜索与配置
-
配置搜索功能完善:支持跨标签页搜索,自动切换到匹配项所在标签页
-
配置管理器 UI 优化:快捷访问按钮、搜索快捷键提示、样式模块化重构
教程与帮助
-
教程模式新增演示功能:一键创建示例 Pin 并执行操作
-
README 新增应用场景说明和邀请码机制详解
订阅系统改进
倍率码系统重构
-
改为应用到云端积分余额,支持余额预览和过期检测
-
新增订阅追加功能:支持在 24 小时内给最近一次积分订阅追加倍率码或邀请码
权限与管理
-
订阅系统权限检查修正,批量操作更可靠
-
新增解绑买断授权功能,支持在新设备重新兑换
-
订阅系统迁移逻辑全面优化,彻底解决旧版本升级兼容性问题
国际化完善
-
200+ 翻译条目新增/优化,主面板、配置管理器、订阅系统全部支持中英文
-
配置管理器顶部新增语言快速切换
-
国际化基础设施修正:语言设置相关翻译 key 统一为英文
技术优化
备份系统
-
新增本地备份系统:支持自动备份配置(每日首次打开/启动 MN/配置修改)
-
可保留 1-5 个历史版本
-
配置管理器备份历史优化:新增触发来源标识、立即备份按钮
导入导出
-
配置管理器导入/导出功能重构:历史版本管理、导入预览、卡片化 UI
-
导入自动续订:导入时订阅过期会自动续订并继续
其他改进
-
正则表达式预设:保存常用正则替换,在文本编辑器一键应用
-
插件更新流程优化:统一为「一键安装」,新增安装确认对话框
-
术语规范化:移除装饰性 emoji,改为纯文本标签
-
术语统一:将节点统一改为文件夹,提升用户理解
-
输入框特殊字符编码传输:中文标点、换行等不再丢失
v4.4
-
文件夹树菜单支持长标题自动换行
-
全新文件夹管理器,结构一目了然
-
回收站功能完善,支持批量操作和智能搜索
-
灵感速录增强,长按反向录入更灵活
-
图片预览新增定位按钮
-
链接 Pin 新增「打开前编辑链接」开关
v4.3
-
新增「维护」工具:安全扫描与清理
-
UIState 解析与调试
-
引用选择器:全局搜索 + 多选粘贴
-
快捷短语功能上线
v4.2
-
AI 协作:自然语言创建按钮;联动 MNChatGLM
-
写作体验:Markdown 分屏预览;内置 BigBang 分词
-
图片支持自动 OCR
开始之前
详细版本教程
- b站视频
- MNPinner 自带手册和教程模式(逐步完善中,但可能存在少量历史版本的内容,一切以最新功能为准,但不会偏差太大)
- 手册
- 教程模式开启后,点击按钮后不会马上执行,而是弹出菜单
- 手册
教程模式下的菜单大致包含下面几种内容
- 单击/长按后的效果(可点击触发,点击后即为非教程模式下的实际效果)
- 功能介绍
- (部分有)相关的配置
- (部分有)功能演示示例
教程模式还不太完善,可能还存在 Bug 或者未完善的部分,均可与开发者反馈
反馈
有任何问题反馈、功能建议可以直接在论坛中提出,或是通过下面的方式
-
Email:
kangweixia_xdyy@163.com -
QQ 群:
1045708101
FAQ
-
Q: MNPinner 支持手写 Pin 吗?
A: 目前手写没有开放 API,无法直接支持。但你可以通过 Pin 页面、Pin 图片(选区截图)等方式来间接定位手写内容。
-
Q: MNPinner 支持 MarginNote 3 吗?
A: 可能不支持,没测试过。另外 MNPinner 的“Pin UI 状态”功能为 Marginnote 4 独有的功能。
-
Q: 为什么“Pin UI 状态”会显示“获取失败”
A:大概率是因为此时 Marginnote 4 “还没激活”,也就是说你此时可能是刚重启,或者是 Marginnote 4 某个操作之后就一直没动界面了。你可以通过随便双击一张卡片的标题进入编辑,然后点击脑图空白退出编辑(或者其它操作,目前发现比较可行的是这个)重新激活,此时再去 Pin UI 状态就不会失败了。
-
Q: 为什么某些内容点击后会先是空白,几秒后才出现内容?
A: 因为这些部分的内容底层都是 HTML 的加载,除了主面板的主要菜单,其余都是按需加载(否则会很卡)初始加载后的再次加载就会很快了。
为什么你需要 MNPinner?
在使用 MarginNote 深度学习时,你是否经历过这些**「心流中断」**的时刻?
-
文档迷宫:资料库里躺着几百个文档。想找刚刚看过的论文,却忘了文件名;或者页码定位太粗糙,跳转后还要重新人眼扫描寻找段落。
-
思维断层:正在构建主脑图,突然需要参考另一个笔记本里的卡片。等你费劲找完回来,“我刚刚思考的卡片是哪一张来着?”
-
视图漂移:手势误触导致文档飞到了九霄云外。找回那个特定的缩放比例和位置,花掉了宝贵的 30 秒心流时间。
-
任务中断:昨天学到一半退出 MN。今天重新打开 MN 后,面对庞大的脑图,“我昨天学到什么程度了?今天要从哪里开始?”
MNPinner 的诞生,就是为了终结这些痛点。
它遵循 All in one & 控源 的核心理念,是你学习流中的全局导航中控台。
6 大核心应用场景 (你可以这样用)
“感觉插件很强,但不知道怎么用?” 看看这些真实场景,总有一个击中你:
任务管理:游戏存档般的「回到现场」
场景:每天学习结束,第二天打开软件需要很久才能重新继续昨日任务。
-
怎么做:结束前,Pin 一个 UIState (界面状态),备注“推导公式中,明天继续”。
-
效果:第二天点击 Pin,像加载游戏存档一样,文档位置、脑图坐标、缩放比例瞬间恢复,一秒启动。
深度阅读:超越页码的「原子级定位」
场景:原生页码颗粒度太大,特别是长页面的 PDF,跳转后找不到具体的行。
-
怎么做:使用 Page Pin 或 图片 Pin(框选截图)。
-
效果:利用 UIState 技术,精确记录视图坐标和缩放层级。点击跳转,直接聚焦到那一行文字,而不是那一页。
沉浸学习:不打断心流的「灵感 Inbox」
场景:做主线任务时,脑子里突然冒出新想法,或者看到一个以后有用的知识点。
-
怎么做:
-
灵感速录:长按“灵感速录”按钮,迅速用在输入框中记下想法,然后关掉插件,继续专注。
-
稍后阅读:遇到想看但不想打断思路的卡片、文档,打开“灵感速录”模式,直接“Pin 卡片”、“Pin 页面”。
-
-
效果:想法统一汇总到“Inbox”文件夹待稍后查看,保护你的专注力,不被支线任务带跑偏。
知识库构建:Pin 即文件夹
场景:“Pin 了一个章节标题页面,想往里面放这一章的笔记,它既是入口又是容器。”
-
怎么做:利用 Pin 与文件夹二合一 特性。任何一个 Pin 都可以转化为文件夹。
-
玩法:
-
子脑图导航:将各个子脑图入口 Pin 起来,形成可视化的“项目目录”。
-
文献管理:为每篇论文建一个 Pin,转化为文件夹,内存该论文的核心图表、笔记和引用。
-
文献阅读:每篇论文的文件夹中,可以把不同章节的页面 Pin 进来,形成“章节导航”。阅读时只需要把对应章节转化为文件夹即可开始阅读,阅读过程中的中途知识、疑问都可以 Pin 进来,形成“章节笔记”。
-
写作生产力:悬浮富文本工作台
场景:MN 原生卡片编辑不够灵活,需要频繁切换视图。
-
怎么做:Pin 一个文本,点击 进入悬浮编辑模式。
-
功能:
-
悬浮多开:同时打开多个文本窗口对比。
-
分屏预览:左侧 Markdown 编辑,右侧实时预览。
-
内置文本工具:BigBang (炸词)、正则替换、TitleCase (标题规范)、时间戳。
-
LaTeX 公式:行内和块级数学公式渲染。
-
插件联动:一键发送到 MNEditor 进行专业编辑。
-
跨应用联动:打通工作流
-
图片处理:Pin 住的截图,支持调用 MNOCR 识别文字,或发送到 MNSnipaste 贴图。
-
与 AI 插件联动:一键(或自动)收集 MNChatAI 的精彩回答,支持 Prompt 收藏分组、发送文本到 AI 浮窗。
-
外部链接:支持“打开前编辑链接”,并且支持自动优先调用 MNBrowser 打开链接,并支持选择在研究视图、外部浏览器中打开。
核心功能清单
全场景 Pin (数据类型)
-
卡片 (Card):支持主视图和浮窗定位,配合 MNPinner 开放的 API 还可以实现点击卡片在 MNPinner 中定位。支持模板制卡。
-
页面 (Page):基于 UIState 的高精度定位。
-
文本 (Text):来自剪切板/输入/文档选中文本。支持 Markdown 编辑(多标签页、WYSIWYG、LaTeX 公式)、快捷短语、正则处理。
-
图片 (Image):支持剪贴板/文档选区截图。文档选区支持 UIState 的高精度定位。支持调用 MNOCR 插件进行 OCR。
-
链接 (Link):网页或插件内部协议跳转。
-
UIState:记录视图状态(文档比例、选中状态/脑图缩放比例/复习模式开关等)。
手写目前没有 API 开放,无法支持,可以考虑非手写模式下的页面/UIState/图片 Pin 来代替定位。
强大的文件管理
-
文件夹树:多层级结构,支持面包屑导航。
-
分组系统:支持 3 层树形分组,批量建组移动,拖拽重组。
-
显隐控制:支持隐藏文件夹,保持文件夹菜单清爽。
-
回收站:误删不怕,支持搜索与批量恢复。
-
引用 (Reference):支持”复制/粘贴引用”。修改本体,所有引用同步更新。
-
全局检索:毫秒级搜索标题与内容。
-
整理模式副屏:轻量双屏整理,主屏副屏间拖拽移动。
数据安全与备份
-
增量导入/导出:跨设备同步神器。
-
优势:数据量小;两台设备的文件夹结构可以不同,只同步新增的 Pin。
-
全量备份:导入前自动备份,支持手动导出 JSON。
效率提升工具
-
自动 Pin 模式:开启后,手动建卡、摘录、MNOCR 识别、剪贴板文本均可自动 Pin 到当前/固定文件夹。
-
灵感速录模式:悬浮输入框,快速记录灵感,支持 Pin 卡片/页面/图片。
-
批量操作:多选 Pin,批量移动/删除/转化为文件夹。
-
模板制卡:自定义标题模板,支持 Mustache 语法。
-
快捷短语:自定义常用文本片段,一键插入。
-
快捷导入固定 Pin/文件夹结构:常用 Pin 组合直接保存,通过增量导入快速调用,重复工作流的福音。
-
迁移文件夹:发现文件夹的内容想快速移到新文件夹中?试试“迁移文件夹”的功能!
快速上手指南
-
Pin 一下:选中一张卡片、一段文字或一个选区,点击底部工具栏的按钮。
-
整理:点击上下箭头排序不同的 Pin
-
定位:点击某个 Pin,瞬间跳转到对应位置/状态/编辑。
小贴士:点击主面板右侧的 ? 按钮,弹出菜单中可以选择打开内置的手册,或者开启「教程模式」,手把手教你每个按钮的用法。
安装
前置要求:
-
MarginNote 4 (核心功能依赖 MN4)。
-
必须安装 MNUtils (基础依赖库,需 v0.2.2_alpha0117+)。
方式一: MNUtils 的插件商店 (推荐)
打开 MNUtils,打开
-
插件商店,找到
MNPinner一键安装正式版; -
插件商店(测试版),找到
MNPinner一键安装测试版;
测试版更新更快,功能更新更及时,但可能存在轻微 Bug。正式版更稳定,适合日常使用。
方式二:手动安装
访问 123 网盘下载安装(无需登录):正式版下载 | 测试版下载
更新
方式一: MNUtils 的插件商店
与安装相同,打开 MNUtils,进入插件商店,找到 MNPinner,点击更新即可。
方式二:MNPinner 内置更新
进入更新界面,选择正式版或测试版进行更新。
点击检查更新后右上角会显示最新版本和当前版本
MNPinner 内置更新功能的优势在于,可以查看不同版本的更新日志,选择性更新。
- 增量:比较两个不同的版本之间的“更新差”
- 版本:此版本所有的更新内容
订阅与支持
安装即享 5 天 Pro 全功能体验,无需付费、无需注册。 试用到期后自动回退免费版,不会扣费。不确定是否需要?先装上用 5 天再说。
免费版 vs Pro 版
| 功能 | 免费版 | Pro 版 |
|---|---|---|
| 6 种 Pin 类型(卡片/页面/文本/图片/链接/UIState) | ✓ | ✓ |
| UIState 高精度定位(精确到行级别) | ✓ | ✓ |
| Markdown 编辑(多标签页/WYSIWYG/LaTeX) | ✓ | ✓ |
| 模板制卡 + 快捷短语 | ✓ | ✓ |
| AI 联动(MNChatAI 回答收集/Prompt 收藏) | ✓ | ✓ |
| 增量导入/导出 + 全量备份 | ✓ | ✓ |
| 回收站 + 全局搜索 | ✓ | ✓ |
| 无限 Pin(免费版限 50 个) | ✗ | ✓ |
| 多层文件夹(免费版仅 Focus) | ✗ | ✓ |
| 批量操作(多选移动/删除/转化) | ✗ | ✓ |
| 灵感速录(不打断心流快速记录) | ✗ | ✓ |
| 自动 Pin(新建卡片自动归档) | ✗ | ✓ |
免费版 = 50 个 Pin + Focus 文件夹,Pro 版 = 无限制
定价
像充话费一样——充值余额,用一天扣一天(¥0.1 / 24h),不用不扣。
| 方案 | 价格 | 说明 |
|---|---|---|
| 免费版 | ¥0 | 50 个 Pin + Focus 文件夹,功能已经很强大 |
| 入门 | ¥9.9 | 到账 ¥10 余额,约可用 100 天,适合试水 |
| 推荐 | ¥30 | 到账 ¥33 余额,约可用 330 天,性价比之选 |
| 买断 | ¥128 | 终身使用,不再扣余额,附赠 1 年额度令牌(¥36.5,约 365 天,可给副设备使用);已订阅用户可补差价升级,历史实付金额直接抵扣 |
查看全部档位
| 方案 | 支付金额 | 到账余额 | 约可用天数 | 折算日成本 |
|---|---|---|---|---|
| 入门档 | ¥9.9 | ¥10.0 | 约 100 天 | ¥0.099 / 24h |
| 进阶档 | ¥20 | ¥21.5 | 约 215 天 | ¥0.093 / 24h |
| 高阶档 | ¥30 | ¥33.0 | 约 330 天 | ¥0.091 / 24h |
| 年度档 | ¥45 | ¥51.0 | 约 510 天 | ¥0.088 / 24h |
| 买断 | ¥128 | 不扣余额 | 永久 | – |
补差价买断:现在改成固定商品,不再走人工改价
已买过 ¥9.9 / ¥20 / ¥30 / ¥45 的用户,现在可以在插件订阅页里直接选择对应的固定补差价商品,不再走“先问报价、再改价”的旧流程。
当前补差价路径:
¥9.9 -> ¥128¥20 -> ¥128¥30 -> ¥128¥45 -> ¥128
说明:
- 补差价商品付款后,拿到的仍然是买断兑换码
- 页面会尝试静默识别你的历史档位并预选,但你也可以手动切换
- 买断后仍附赠 1 年额度令牌
旧的动态报价 / 迁移补贴信息仍保留在订阅页,作为辅助校验信息,不再作为主购买流程
还没安装? 先免费体验 5 天,5 天后你会知道答案 → 安装指南
决定购买? 支付宝/微信直接购买,支付完成后在平台查看令牌/买断兑换码 → 立即购买
微信支付通道正在审核中,预计近期开通。目前可使用支付宝支付。
余额制怎么算?
核心机制:购买令牌 → 充值余额 → 使用 Pro 功能时按天扣除余额
| 概念 | 说明 |
|---|---|
| 余额 | 你的「Pro 功能余额」(单位:¥) |
| 扣费规则 | 每使用 Pro 功能满 24 小时,扣除 ¥0.1(优先扣离线天数) |
| 买断特权 | 买断用户 不再扣余额,一次付费,终身使用 |
| 不用不扣 | 当天没用 Pro 功能?一分钱不扣 |
举个例子:你买了 ¥30 余额令牌,到账 ¥33 余额。若每天都用 Pro,约可用 330 天;若间歇使用,实际可用更久。
常见计费问题
| 问题 | 答案 |
|---|---|
| 多设备共用令牌? | 支持!同一令牌余额在多设备共享,任一设备扣费都会减少同一余额 |
| 什么算「用了一天」? | 从首次使用 Pro 功能起算 24 小时,非自然日 |
| 怎么开启自动订阅? | 设置中开启后,点击 Pro 功能会自动激活,无需每次手动操作 |
| 买断用户换设备? | 支持解绑 → 重新绑定,无限次 |
| 买断赠送 1 年怎么发? | 兑换买断码后,¥36.5 余额令牌(约 365 天)会显示在订阅页,如未显示点「刷新」即可,令牌可在多台设备使用 |
省钱攻略:签到 / 邀请码 / 旧倍率码兼容
5 天免费试用
- 新用户:内置免费 5 天本机天数,首次使用自动发放,无需购买即可体验 Pro。
- 老用户:升级后会自动补发这 5 天;如未到账,可点击「检查领取」手动补发/同步状态。
每日签到领余额
订阅页支持每日签到,点击「签到」可随机领取余额奖励(需先设置令牌)。
老用户历史补贴
本次订阅体系改动较大,老用户可在订阅页看到「可领取历史购买补贴」,点击「领取补贴」可手动到账;若已领取但有差额,可点「重新校验」补差。
旧倍率码兼容
如果你之前通过旧闲鱼方案拿到倍率码,插件订阅页里仍然保留了旧倍率码兼容折叠区,可以继续输入 / 暂存 / 补挂。
但对新用户来说,主路径已经改成直接购买,不需要再围着倍率码理解购买流程。
邀请码机制
用户可以分享邀请码给好友;好友在达标档位(¥20/¥30/¥45)完成兑换或订阅后,双方按档位获得额外时长。
触发条件:兑换码成功兑换 或 令牌成功订阅扣费,均可触发邀请奖励。
| 达标订单档位 | 邀请人奖励 | 被邀请人奖励 |
|---|---|---|
| ≥¥20 | +10 天 | +10 天 |
| ≥¥30 | +20 天 | +20 天 |
| ≥¥45 | +30 天 | +30 天 |
多设备可以 “左脚踩右脚”:用 Mac 的邀请码发给 iPad,达标后两台设备都能拿到对应档位奖励。
详细规则:
- 核心规则:按档位发放奖励(20/30/45 档对应 10/20/30 天)。
- 严格限制:
- 作为邀请人:累计最多获得 180 天 奖励(不是固定 6 次;按档位累计封顶)。
- 作为被邀请人:每台设备仅能享受 1 次 邀请奖励。
- 自动领取:奖励产生后,打开订阅页面即自动入账。
- 绑定窗口:绑定后 10 分钟内可更改;兑换/订阅后 24 小时内可补填邀请码。
- FAQ:邀请码永久有效;<¥20 档可绑定但不触发奖励;奖励到账后「本机天数」自动增加。
如何充值/兑换(3 分钟完成)
Step 1: 购买令牌
前往购买中心,选择适合你的方案:立即购买
支付方式:
- 支付宝:已开通,可直接使用
- 微信支付:正在审核中,预计近期开通
购买后主流程如下:
- 余额令牌档位(
¥9.9 / ¥20 / ¥30 / ¥45):在平台查看令牌(格式:sk-...) - 永久买断 / 补差价买断:在平台查看买断兑换码
- 邮件通知是可选备份,不是主流程
Step 2: 进入订阅面板
方式一:点击主面板右侧的设置按钮
方式二:在设置面板中点击顶部的「订阅」标签
Step 3: 粘贴令牌 / 兑换码 / 邀请码
在订阅面板底部找到「我已经买好了」区域:
普通兑换(余额令牌):
- 粘贴令牌码 → 点击「兑换」
- 完成!
永久买断 / 补差价买断:
- 粘贴买断兑换码
- 点击「兑换」
- 完成激活
使用邀请码(达标档位可触发奖励):
推荐流程:
- 先粘贴邀请码 → 点击「兑换」(自动识别为邀请码并绑定)
- 再粘贴令牌码 → 点击「兑换」
- 达标后双方按档位获得奖励(10/20/30 天),打开订阅页自动到账
忘记了?没关系:兑换/订阅后 24 小时内,可以补填邀请码
Step 4: 开启订阅
兑换令牌后,你的余额已到账,但订阅还未激活。
手动开启:
- 点击「开启 24h」按钮 → 激活 24 小时订阅
- 次日需再次点击「续费 24h」
自动订阅(推荐):
- 勾选「离线天数不足时自动扣余额续费」
- 效果:系统自动续费,无需每天手动操作
Step 5: 了解订阅面板
当前状态
- 订阅状态徽章:永久买断 / 已激活 / 未激活 / 未订阅
- 离线天数:本机可用天数(不联网也能用)
- 云端余额:多设备共享的令牌余额(点击「刷新余额」查询最新余额)
预订阅(可选,离线备用)
- 场景:即将出差/旅行,网络不稳定
- 操作:输入天数 → 点击「预订阅」
- 效果:一次性扣余额,将天数存入本机离线余额
- 特点:不会立即激活,只是提前充值离线天数
| 功能 | 预订阅 | 开启 24h |
|---|---|---|
| 立即激活 | 否 | 是 |
| 扣费对象 | 仅扣余额 | 优先扣离线天数 |
| 使用场景 | 提前充值,离线备用 | 立即使用 Pro 功能 |
常见问题
| 问题 | 解答 |
|---|---|
| 令牌可以多设备用吗? | 可以!同一令牌余额在多设备共享,任一设备扣费都会减少同一余额 |
| 兑换失败怎么办? | 检查令牌是否完整复制(以 sk- 开头),或联系客服 |
| 邀请码忘记填了? | 兑换/订阅后 24 小时内可以补填,超时则无法追加 |
| 邀请码没生效? | 仅 ≥¥20 档位触发奖励;<¥20 不触发。打开订阅页即自动到账 |
| 自动订阅需要开吗? | 强烈推荐开启,省去每天手动续费的麻烦 |
| 预订阅和开启 24h 有什么区别? | 预订阅只充值不激活,开启 24h 立即激活 |
备用购买方式:闲鱼
闲鱼现在只作为副方案保留。
- 主购买流程:支付宝 / 微信直接购买
- 备用购买流程:闲鱼
如果你更习惯旧路径,插件订阅页里仍然保留了折叠式的闲鱼入口,但帮助菜单、升级弹窗、README 主叙事都已经切到新方案。
进阶 (Advanced)
开发者 API / 插件通信
这段是给插件开发者的实战文档:明确用途、调用方式、参数类型、默认值、行为边界。
This is a practical API reference for add-on developers.
协议与调用入口 / Transport
- 通道:
MNUtil.postNotification("AddonBroadcast", { message }) - message 格式:
mnpinner?action=<action>&key=value... - 建议:参数值统一走
encodeURIComponent(下面 helper 已处理)
/**
* [CN] 统一 AddonBroadcast 调用入口
* [EN] Unified AddonBroadcast helper
* @param {string} action
* @param {Record<string, string|number|boolean|null|undefined>} [params]
*/
function postToMNPinner(action, params = {}) {
const query = Object.entries(params)
.filter(([, value]) => value !== undefined && value !== null && value !== "")
.map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`)
.join("&")
const message = `mnpinner?action=${encodeURIComponent(action)}${query ? `&${query}` : ""}`
MNUtil.postNotification("AddonBroadcast", { message })
}
全局参数语义 / Global Parameter Rules
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
action |
string |
无 | 要执行的 API 名称 |
noteId |
string |
无 | 支持 note.noteId 或 marginnote4app://note/... |
nodeId |
string |
action 相关 | 目标节点。存在 nodeId 时优先于 section |
section |
string |
action 相关 | nodeId 旧别名,兼容保留 |
position |
`“top” | “bottom” | number` |
| 布尔型开关 | `boolean | “0/1” | “true/false” |
关键边界:
- 非
focus节点会触发订阅/权限校验,失败时调用会被拦截。 pinText/pinClipboard当前实现不会强制截断text到 10000 字符。- 参数键名建议使用文档里的标准写法,不要依赖历史别名。
API 总览 / API Index
| Action | 用途 | 最少参数 |
|---|---|---|
pin |
把卡片 Pin 到指定节点(通用) | noteId(或 beforePin=excerptFromSelection) |
pinCardToSection |
把卡片 Pin 到指定节点(标题归一更严格) | noteId(或 beforePin=excerptFromSelection) |
pinToCurrentNode |
把卡片 Pin 到当前打开节点 | noteId(或 beforePin=excerptFromSelection) |
pinFromSelectionOrCard |
统一入口:文本选区 > 框选 > 卡片 | 无(建议传 noteId 兜底) |
pinText |
创建文本 Pin | text |
pinClipboard |
pinText 别名 |
text |
showPinBoard |
打开 MNPinner 主面板 | 无 |
navigateToNode |
打开面板并跳转指定节点 | nodeId |
locateSelectedCardPin |
按卡片或当前文档定位 Pin | 无(有 noteId 更准) |
locatePin |
按实例 ID / ref / 搜索条件定位 Pin | 至少 1 个定位参数 |
queryPins |
查询 Pin 结构化信息(协作 API) | locateUrl 或 nodeId 或任一查询条件 |
updateCardPinNoteId |
批量把旧 noteId 映射到新 noteId | old, new |
API 详情 / Action Reference
1) pin
用途:Pin 卡片到指定节点。
调用:postToMNPinner("pin", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
noteId |
string |
是 | 无 | 卡片 ID 或 URL |
beforePin |
string |
否 | none |
Pin 前置动作;excerptFromSelection 会先摘录当前文档选区为卡片,并优先回填该新卡片 ID |
title |
string |
否 | 卡片标题 | 自定义 Pin 标题 |
nodeId |
string |
否 | focus |
目标节点 |
section |
string |
否 | 同上 | nodeId 旧别名 |
position |
`“top” | “bottom” | number` | 否 |
2) pinCardToSection
用途:Pin 卡片到指定节点,标题生成逻辑更偏“卡片语义”。
调用:postToMNPinner("pinCardToSection", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
noteId |
string |
是 | 无 | 卡片 ID 或 URL |
beforePin |
string |
否 | none |
Pin 前置动作;excerptFromSelection 会先摘录当前文档选区为卡片,并优先回填该新卡片 ID |
title |
string |
否 | 自动生成 | 不传则基于卡片标题自动归一 |
nodeId |
string |
否 | focus |
目标节点 |
section |
string |
否 | 同上 | nodeId 旧别名 |
position |
`“top” | “bottom” | number` | 否 |
3) pinToCurrentNode
用途:把卡片 Pin 到“当前打开节点”。
调用:postToMNPinner("pinToCurrentNode", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
noteId |
string |
是 | 无 | 卡片 ID 或 URL |
beforePin |
string |
否 | none |
Pin 前置动作;excerptFromSelection 会先摘录当前文档选区为卡片,并优先回填该新卡片 ID |
title |
string |
否 | 卡片标题 | 自定义 Pin 标题 |
position |
`“top” | “bottom” | number` | 否 |
目标节点解析顺序:当前节点 -> lastSection/defaultSection -> focus。
beforePin(当前实现):
none:不做前置处理excerptFromSelection:先摘录当前选区创建卡片,再继续 Pin;若noteId为空,自动使用摘录后的新卡片 ID;若noteId等于摘录源卡片 ID,会自动映射到新卡片 ID。
beforePin (current implementation):
none: no pre-pin processing.excerptFromSelection: create an excerpt card from current selection first, then continue pinning; ifnoteIdis empty, the new excerpt card id is used; ifnoteIdequals the source card id, it is remapped to the excerpt card id.
4) pinText / pinClipboard
用途:创建文本 Pin。pinClipboard 是别名。
调用:postToMNPinner("pinText", params) 或 postToMNPinner("pinClipboard", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
text |
string |
是 | 无 | 文本内容;空白文本会被拒绝 |
title |
string |
否 | 自动生成 | 默认由 clipboardTitleStrategy + clipboardTitleLength 生成 |
nodeId |
string |
否 | focus |
目标节点 |
section |
string |
否 | 同上 | nodeId 旧别名 |
position |
`“top” | “bottom” | number` | 否 |
afterPin |
string |
否 | "" |
Pin 后动作 |
openEditor |
`boolean | bool-like` | 否 | false |
afterPin 常用值(canonical):
nonescrollopenEditoropenMarkdownlocateMindmapbindCurrentUIStateToCardconvertToFolderconvertToFolderLocateopenNoteURLpinChildCountTextconvertToFolderAndPinChildCountText
5) pinFromSelectionOrCard(推荐)
用途:单按钮统一入口,优先处理文档选区。
调用:postToMNPinner("pinFromSelectionOrCard", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
noteId |
string |
否 | 自动兜底 | 无选区时用于卡片路由 |
title |
string |
否 | 路由相关默认标题 | 自定义标题 |
nodeId |
string |
否 | 当前节点/last/default/focus |
目标节点 |
section |
string |
否 | 同上 | nodeId 旧别名 |
position |
`“top” | “bottom” | number` | 否 |
promptTitle |
`boolean | bool-like` | 否 | 文本/卡片=false,框选=true |
textSelectionMode |
`“page” | “text”` | 否 | "page" |
boxSelectionMode |
`“page” | “image”` | 否 | "page" |
selectionKind |
`“text” | “box”` | 否 | 自动检测 |
selectionText |
string |
否 | 自动检测 | 显式传入选中文本 |
路由优先级:
- 检测到文本选区:默认页面 Pin;
textSelectionMode=text时改为文本 Pin。 - 检测到框选:默认页面 Pin;
boxSelectionMode=image时改为图片 Pin。 - 无选区:用
noteId(或自动兜底的选中/焦点卡片)走卡片 Pin。 - 仍无可用输入:HUD 提示。
6) showPinBoard
用途:打开主面板。
调用:postToMNPinner("showPinBoard")
参数:无。
7) navigateToNode
用途:打开面板并跳转到指定节点。
调用:postToMNPinner("navigateToNode", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
nodeId |
string |
是 | 无 | 目标节点 ID |
section |
string |
否 | 无 | nodeId 旧别名 |
8) locateSelectedCardPin
用途:根据卡片定位 Pin;多结果时自动打开搜索。
调用:postToMNPinner("locateSelectedCardPin", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
noteId |
string |
否 | 无 | 卡片 ID 或 URL;建议传 |
docMd5 |
string |
否 | 当前文档 docMd5 | 不传 noteId 时可按文档页面 Pin 回退定位 |
行为补充:有 noteId 时会尝试卡片祖先链(最多 5 层)匹配,提高命中率。
9) locatePin
用途:精确/模糊定位某个 Pin(供深度互操作)。
调用:postToMNPinner("locatePin", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
instanceId |
string |
否 | 无 | Pin 实例 ID(最推荐) |
refKey |
string |
否 | 无 | Pin 引用 key |
nodeId |
string |
否 | 全局扫描 | 限定目标节点 |
type |
string |
否 | 无 | Pin 类型 |
pinnedAt |
`string | number` | 否 | 无 |
noteId |
string |
否 | 无 | 卡片 ID |
docMd5 |
string |
否 | 无 | 文档 MD5 |
pageIndex |
`string | number` | 否 | 无 |
url |
string |
否 | 无 | 链接或 uistate URL |
index |
`string | number` | 否 | 无 |
要求:以上参数至少提供 1 个,否则会直接提示“缺少定位参数”。
10) queryPins
用途:查询 Pin 结构化信息,供其他插件与 MNPinner 协作。
调用:postToMNPinner("queryPins", params) 或 await globalThis.mnpinnerPublicApi.queryPins(params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
locateUrl |
string |
否 | 无 | 推荐:直接传 MNPinner 导出的定位链接 |
nodeId |
string |
否 | 全局扫描 | 限定节点;单独传时返回该节点下所有 Pin |
section |
string |
否 | 无 | nodeId 旧别名 |
instanceId |
string |
否 | 无 | Pin 实例 ID |
refKey |
string |
否 | 无 | Pin 引用 key |
type |
string |
否 | 无 | Pin 类型:card/page/text/image/uistate/link |
pinnedAt |
`string | number` | 否 | 无 |
noteId |
string |
否 | 无 | 卡片 ID |
docMd5 |
string |
否 | 无 | 文档 MD5 |
pageIndex |
`string | number` | 否 | 无 |
url |
string |
否 | 无 | Link / UIState / Page 关联 URL |
index |
`string | number` | 否 | 无 |
includeDescendants |
`boolean | bool-like` | 否 | false |
replyNotificationName |
string |
否 | 无 | 仅广播模式:查询完成后回传到该通知名 |
requestId |
string |
否 | 无 | 仅广播模式:请求 ID,会原样带回 |
返回值(direct call)示例:
{
ok: true,
code: "OK",
action: "queryPins",
total: 2,
multiple: true,
query: { ... },
pins: [
{
type: "page",
title: "Page 12",
nodeId: "library/a/b",
nodePath: ["Library", "A", "B"],
nodePathText: "Library / A / B",
index: 3,
locateUrl: "marginnote4app://addon/mnpinner?...",
instanceId: "...",
refKey: "...",
data: {
docMd5: "...",
pageIndex: 11,
pageNumber: 12,
uiState: "...",
url: "..."
},
pin: { ...原始 Pin 快照... }
}
]
}
Quick Take
- 推荐顺序:先用
direct call,拿不到globalThis.mnpinnerPublicApi再回退AddonBroadcast - 推荐入参:优先传
locateUrl;只知道节点时再传nodeId - 常用字段:优先读
pin.type、pin.nodePathText、pin.locateUrl、pin.instanceId、pin.refKey - 类型重点:
card看pin.data.noteId;page看pin.data.docMd5、pin.data.pageIndex、pin.data.uiState
Return Notes
card:至少返回原卡片noteId/noteURLpage:至少返回docMd5、pageIndex、uiState/urltext:返回text、textLength、firstLineimage:返回imageRef、uistateUrl、OCR 文本等uistate:返回uiState/urllink:返回url- 多个命中会返回数组,不会偷偷只给你第一个
Recommended
最省事的调用:
const api = globalThis.mnpinnerPublicApi
const result = await api.queryPins({ locateUrl })
广播兜底:
MNUtil.postNotification("AddonBroadcast", {
message: `mnpinner?action=queryPins&locateUrl=${encodeURIComponent(locateUrl)}&replyNotificationName=${encodeURIComponent("myAddon.mnpinnerReply")}&requestId=${encodeURIComponent(requestId)}`
})
Full Examples
最小接入规则:
- 优先使用 direct call;拿不到
globalThis.mnpinnerPublicApi时,再回退到AddonBroadcast。 card重点读pin.data.noteId;page重点读pin.data.docMd5、pin.data.pageIndex、pin.data.uiState。- 通用协作字段优先看:
pin.type、pin.nodePathText、pin.locateUrl、pin.instanceId、pin.refKey。
按定位链接查询(direct call,推荐):
async function queryMNPinnerPinByLocateUrl(locateUrl) {
const api = globalThis.mnpinnerPublicApi
if (!api || typeof api.queryPins !== "function") {
throw new Error("MNPinner API 不可用;请先确保 MNPinner 已安装并至少打开过一次")
}
const result = await api.queryPins({ locateUrl })
if (!result || result.ok === false) {
throw new Error((result && result.code) || "queryPins failed")
}
return result.pins || []
}
async function demoQueryPagePin(locateUrl) {
const pins = await queryMNPinnerPinByLocateUrl(locateUrl)
const first = pins[0]
if (!first) return null
if (first.type === "card") {
return { noteId: first.data.noteId }
}
if (first.type === "page") {
return {
docMd5: first.data.docMd5,
pageIndex: first.data.pageIndex,
uiState: first.data.uiState,
url: first.data.url,
nodePath: first.nodePathText
}
}
return first
}
按 nodeId 查询(direct call):
async function queryMNPinnerPinsInNode(nodeId) {
const api = globalThis.mnpinnerPublicApi
if (!api || typeof api.queryPins !== "function") {
throw new Error("MNPinner API 不可用")
}
const result = await api.queryPins({
nodeId,
includeDescendants: false
})
if (!result || result.ok === false) {
throw new Error((result && result.code) || "queryPins failed")
}
return result.pins || []
}
async function queryPagePinsInNode(nodeId) {
const api = globalThis.mnpinnerPublicApi
const result = await api.queryPins({ nodeId, type: "page" })
if (!result || result.ok === false) {
throw new Error((result && result.code) || "queryPins failed")
}
return result.pins || []
}
广播查询(AddonBroadcast fallback):
function postToMNPinner(action, params = {}) {
const query = Object.entries(params)
.filter(([, value]) => value !== undefined && value !== null && value !== "")
.map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`)
.join("&")
MNUtil.postNotification("AddonBroadcast", {
message: `mnpinner?action=${encodeURIComponent(action)}${query ? `&${query}` : ""}`
})
}
function queryMNPinnerByBroadcast(locateUrl) {
return new Promise((resolve, reject) => {
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2)}`
const replyName = "myAddon.mnpinnerReply"
globalThis.__myAddonMNPinnerReplyMap = globalThis.__myAddonMNPinnerReplyMap || {}
globalThis.__myAddonMNPinnerReplyMap[requestId] = { resolve, reject }
postToMNPinner("queryPins", {
locateUrl,
replyNotificationName: replyName,
requestId
})
setTimeout(() => {
const pending = globalThis.__myAddonMNPinnerReplyMap[requestId]
if (!pending) return
delete globalThis.__myAddonMNPinnerReplyMap[requestId]
reject(new Error("MNPinner query timeout"))
}, 5000)
})
}
广播回调接收(selector 必须写在 lifecycle 里):
// 注册:MNUtil.addObserver(self, 'onMNPinnerReply:', 'myAddon.mnpinnerReply')
onMNPinnerReply: function(sender) {
try {
const info = (sender && sender.userInfo) || {}
const requestId = String(info.requestId || "")
const raw = info.resultJSON ? String(info.resultJSON) : ""
const result = raw ? JSON.parse(raw) : (info.result || null)
const map = globalThis.__myAddonMNPinnerReplyMap || {}
const pending = map[requestId]
if (!pending) return
delete map[requestId]
if (!result || result.ok === false) {
pending.reject(new Error((result && result.code) || "queryPins failed"))
return
}
pending.resolve(result.pins || [])
} catch (error) {
// 这里按你自己的日志系统处理
}
}
11) updateCardPinNoteId
用途:卡片 ID 迁移时,批量更新已有 Card Pin 的 noteId。
调用:postToMNPinner("updateCardPinNoteId", params)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
old |
string |
是 | 无 | 旧 noteId 或 noteURL |
new |
string |
是 | 无 | 新 noteId 或 noteURL |
兼容别名:oldId/oldNoteId/oldNoteURL、newId/newNoteId/newNoteURL/toId/targetId。
可直接复制的 Helper
function mnpinner_pin(params) { postToMNPinner("pin", params) }
function mnpinner_pinCardToSection(params) { postToMNPinner("pinCardToSection", params) }
function mnpinner_pinToCurrentNode(params) { postToMNPinner("pinToCurrentNode", params) }
function mnpinner_pinFromSelectionOrCard(params = {}) { postToMNPinner("pinFromSelectionOrCard", params) }
function mnpinner_pinText(params) { postToMNPinner("pinText", params) }
function mnpinner_pinClipboard(params) { postToMNPinner("pinClipboard", params) }
function mnpinner_showPinBoard() { postToMNPinner("showPinBoard") }
function mnpinner_navigateToNode(params) { postToMNPinner("navigateToNode", params) }
function mnpinner_locateSelectedCardPin(params) { postToMNPinner("locateSelectedCardPin", params) }
function mnpinner_locatePin(params) { postToMNPinner("locatePin", params) }
function mnpinner_queryPins(params) { postToMNPinner("queryPins", params) }
function mnpinner_updateCardPinNoteId(params) { postToMNPinner("updateCardPinNoteId", params) }
MNToolbar JSON(mnpinnerPin)快速上手
30 秒决策表(先选 pinApi)
| 你现在要做什么 | 选哪个 pinApi |
至少再填什么 |
|---|---|---|
| 一键智能 Pin(选区优先,卡片兜底) | pinFromSelectionOrCard |
可不填,常加 pinPosition |
| 文本选区要做“文本 Pin” | pinFromSelectionOrCard |
pinTextSelectionMode: "text" 或直接传 pinText |
| 框选要做“图片 Pin” | pinFromSelectionOrCard |
pinBoxSelectionMode: "image" |
| 把当前卡片 Pin 到当前节点 | pinToCurrentNode |
pinNoteId |
| 把当前卡片 Pin 到指定节点 | pinCardToSection |
pinNoteId, pinNodeId |
| 直接创建文本 Pin | pinText |
pinText |
| 打开 MNPinner 面板 | showPinBoard |
无 |
| 跳转到某个节点 | navigateToNode |
pinNodeId |
| 按卡片定位 Pin | locateSelectedCardPin |
pinNoteId |
最小可用
{
"action": "mnpinnerPin",
"pinApi": "pinFromSelectionOrCard"
}
常用模板
- 文本选区优先走文本 Pin
{
"action": "mnpinnerPin",
"pinApi": "pinFromSelectionOrCard",
"pinText": "{{selectionText}}",
"pinTitle": "{{selectionText | firstLine | trim}}",
"pinPosition": "top"
}
- 框选优先走图片 Pin
{
"action": "mnpinnerPin",
"pinApi": "pinFromSelectionOrCard",
"pinBoxSelectionMode": "image",
"pinPromptTitle": false
}
- 把当前卡片 Pin 到当前节点
{
"action": "mnpinnerPin",
"pinApi": "pinToCurrentNode",
"pinNoteId": "{{note.id}}",
"pinPosition": "top"
}
字段说明(只看“填了会发生什么”)
| 键 | 什么时候填 | 你填了会发生什么 | 常用值 |
|---|---|---|---|
action |
永远填 | 固定触发 MNToolbar 的 MNPinner 动作 | mnpinnerPin |
pinApi |
永远填 | 决定调用哪一个 MNPinner 接口 | 见下方 pinApi 清单 |
pinNoteId |
需要按卡片 Pin/定位时填 | 指定目标卡片(支持 noteId 或 noteURL) | {{note.id}}, {{note.url}} |
pinText |
想明确传文本内容时填 | 作为文本 Pin 的内容;在 pinFromSelectionOrCard 下会自动映射成 selectionText |
{{selectionText}} |
pinNodeId |
要 Pin 到指定节点时填 | 覆盖默认目标节点 | focus 或真实 nodeId |
pinPosition |
要控制插入位置时填 | 设置新 Pin 插在顶部或底部 | top, bottom |
pinTitle |
需要自定义标题时填 | 覆盖自动标题 | 任意模板字符串 |
pinPromptTitle |
需要人工输入标题时填 | 打开或关闭标题输入框 | true, false |
pinTextSelectionMode |
pinApi=pinFromSelectionOrCard 且有文本选区时填 |
文本选区走页面 Pin 还是文本 Pin | page, text |
pinBoxSelectionMode |
pinApi=pinFromSelectionOrCard 且有框选时填 |
框选走页面 Pin 还是图片 Pin | page, image |
pinAfterPin |
pinApi=pinText/pinClipboard 时填 |
Pin 完后的追加动作 | none, openEditor, locatePin 等 |
pinOpenEditor |
pinApi=pinText/pinClipboard 时填 |
Pin 后是否直接打开编辑器 | true, false |
pinSelectionKind |
自动识别不稳定时才填 | 手工声明当前选区类型 | text, box |
pinSelectionText |
自动取不到选中文本时才填 | 手工传入选中文本兜底 | 任意字符串 |
pinParams |
需要传额外参数时填 | 额外键值会合并到 query,一起发给 MNPinner | {} |
pinApi 清单(完整)
pinApi 值 |
用途 | 常见搭配参数 |
|---|---|---|
pinFromSelectionOrCard |
统一入口:选区优先,卡片兜底 | pinPosition, pinPromptTitle, pinTextSelectionMode, pinBoxSelectionMode |
pinToCurrentNode |
把卡片 Pin 到当前节点 | pinNoteId, pinPosition, pinTitle |
pinCardToSection |
把卡片 Pin 到指定节点 | pinNoteId, pinNodeId, pinPosition, pinTitle |
pin |
显式执行卡片 Pin | pinNoteId, pinNodeId, pinPosition, pinTitle |
pinText |
创建文本 Pin | pinText, pinTitle, pinAfterPin, pinOpenEditor |
pinClipboard |
用文本内容创建文本 Pin | pinText, pinTitle, pinAfterPin, pinOpenEditor |
showPinBoard |
打开 MNPinner 面板 | 无 |
navigateToNode |
跳转到节点 | pinNodeId |
locateSelectedCardPin |
根据卡片定位 Pin | pinNoteId |
locatePin |
按上下文定位 Pin | 无 |
updateCardPinNoteId |
更新旧卡片 ID 到新卡片 ID | 建议放 pinParams.old 与 pinParams.new |
pinAfterPin 可用值(当前 JSON 编辑器枚举)
"" | "scroll" | "highlight" | "locatePin" | "openEditor" | "openMarkdown" | "locateMindMap" | "openNoteURL" | "none"
自动兜底规则
pinApi不填时,自动用pinFromSelectionOrCard。pinApi=pinToCurrentNode/pinCardToSection/pin/locateSelectedCardPin且没填pinNoteId时,会自动补{{note.id}}。pinApi=pinText且没填pinText时,会自动补{{selectionText}}。pinApi=pinFromSelectionOrCard且你填了pinText时,会自动转成selectionText,并默认按文本选区处理(等价于pinSelectionKind=text+pinTextSelectionMode=text)。pinParams与顶层同义参数同时存在时,顶层参数优先。
接入建议
- 新集成优先用
pinFromSelectionOrCard,容错最好。 - 只做“文本摘录”按钮时,优先用
pinText,配置最直。 - 行为不符合预期时,先记录实际 JSON,再看
MNUtils -> Logs。
致谢
特别感谢插件开发者 @linlifei 开发的众多优秀插件,MNPinner 开发过程中参考了许多设计和源码,包括但不限于:
- MNUtils:基建插件,MNPinner 调用了 MNUtils 中许多实用工具函数,极大提升了开发效率和代码质量
- MNSnipaste:可以视为 MNPinner 的前身,图片面板的设计和部分代码参考了 MNSnipaste 的实现
- MNEditor:MNPinner 的 Markdown 编辑器参考了 MNEditor 的设计,并进行了一些适配和优化
- MNBigbang:MNPinner 基于 MNBigbang 实现兼容自身数据的定制版
















