【第三方插件】MNPinner - 搭建属于你自己的 MarginNote 中控台(Pin 卡片、页面、UI 状态、文本、图片、链接)(v5.5)

MNPinner

这是一个 AI 快速发展的时代。数据和知识的获取变得越来越容易,你可以轻松地下载大量文档,让 MNAI 进行大量卡片生成。但如果任由它们堆砌,你只会陷于信息的泥潭中无法自拔。

MNPinner 为此诞生,它并非能让你快速管理你的所有卡片和文档的卡片盒,而是能让你在任何时候都能清楚,你现在关注的是什么,你当前的任务是什么,不管出现什么样的干扰和波动,你都能够快速地回到你的主线上,减少心流中断,节省你宝贵的专注力流失。

MNPinner 的设计理念:“控源”——卡片、文档页面、文本、链接、图片,甚至是你的 UI 状态都可以进行管理和回源!

MNPinner 不生产数据,它只是数据的搬运工。

MNPinner 将辅助你进行 MarginNote 内的全局调度,搭建属于你的 MarginNote 中控台!

MarginNote 4 Compatible Platform iOS/macOS Version

版本历史

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

开始之前

详细版本教程

教程模式下的菜单大致包含下面几种内容

  • 单击/长按后的效果(可点击触发,点击后即为非教程模式下的实际效果)
  • 功能介绍
  • (部分有)相关的配置
  • (部分有)功能演示示例

教程模式还不太完善,可能还存在 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 大核心应用场景 (你可以这样用)

“感觉插件很强,但不知道怎么用?” 看看这些真实场景,总有一个击中你:

:one: 任务管理:游戏存档般的「回到现场」

场景:每天学习结束,第二天打开软件需要很久才能重新继续昨日任务。

  • 怎么做:结束前,Pin 一个 UIState (界面状态),备注“推导公式中,明天继续”。

  • 效果:第二天点击 Pin,像加载游戏存档一样,文档位置、脑图坐标、缩放比例瞬间恢复,一秒启动。

:two: 深度阅读:超越页码的「原子级定位」

场景:原生页码颗粒度太大,特别是长页面的 PDF,跳转后找不到具体的行。

  • 怎么做:使用 Page Pin图片 Pin(框选截图)。

  • 效果:利用 UIState 技术,精确记录视图坐标和缩放层级。点击跳转,直接聚焦到那一行文字,而不是那一页。

:three: 沉浸学习:不打断心流的「灵感 Inbox」

场景:做主线任务时,脑子里突然冒出新想法,或者看到一个以后有用的知识点。

  • 怎么做

    • 灵感速录:长按“灵感速录”按钮,迅速用在输入框中记下想法,然后关掉插件,继续专注。

    • 稍后阅读:遇到想看但不想打断思路的卡片、文档,打开“灵感速录”模式,直接“Pin 卡片”、“Pin 页面”。

  • 效果:想法统一汇总到“Inbox”文件夹待稍后查看,保护你的专注力,不被支线任务带跑偏。

:four: 知识库构建:Pin 即文件夹

场景“Pin 了一个章节标题页面,想往里面放这一章的笔记,它既是入口又是容器。”

  • 怎么做:利用 Pin 与文件夹二合一 特性。任何一个 Pin 都可以转化为文件夹。

  • 玩法

    • 子脑图导航:将各个子脑图入口 Pin 起来,形成可视化的“项目目录”。

    • 文献管理:为每篇论文建一个 Pin,转化为文件夹,内存该论文的核心图表、笔记和引用。

    • 文献阅读:每篇论文的文件夹中,可以把不同章节的页面 Pin 进来,形成“章节导航”。阅读时只需要把对应章节转化为文件夹即可开始阅读,阅读过程中的中途知识、疑问都可以 Pin 进来,形成“章节笔记”。

:five: 写作生产力:悬浮富文本工作台

场景:MN 原生卡片编辑不够灵活,需要频繁切换视图。

  • 怎么做:Pin 一个文本,点击 进入悬浮编辑模式。

  • 功能

    • 悬浮多开:同时打开多个文本窗口对比。

    • 分屏预览:左侧 Markdown 编辑,右侧实时预览。

    • 内置文本工具BigBang (炸词)正则替换TitleCase (标题规范)时间戳

    • LaTeX 公式:行内和块级数学公式渲染。

    • 插件联动:一键发送到 MNEditor 进行专业编辑。

:six: 跨应用联动:打通工作流

  • 图片处理: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 组合直接保存,通过增量导入快速调用,重复工作流的福音。

  • 迁移文件夹:发现文件夹的内容想快速移到新文件夹中?试试“迁移文件夹”的功能!


快速上手指南

  1. Pin 一下:选中一张卡片、一段文字或一个选区,点击底部工具栏的按钮。

  2. 整理:点击上下箭头排序不同的 Pin

  3. 定位:点击某个 Pin,瞬间跳转到对应位置/状态/编辑。

小贴士:点击主面板右侧的 ? 按钮,弹出菜单中可以选择打开内置的手册,或者开启「教程模式」,手把手教你每个按钮的用法。


安装

前置要求

  1. MarginNote 4 (核心功能依赖 MN4)。

  2. 必须安装 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,达标后两台设备都能拿到对应档位奖励。

详细规则:

  1. 核心规则:按档位发放奖励(20/30/45 档对应 10/20/30 天)。
  2. 严格限制
    • 作为邀请人:累计最多获得 180 天 奖励(不是固定 6 次;按档位累计封顶)。
    • 作为被邀请人:每台设备仅能享受 1 次 邀请奖励。
  3. 自动领取:奖励产生后,打开订阅页面即自动入账。
  4. 绑定窗口:绑定后 10 分钟内可更改;兑换/订阅后 24 小时内可补填邀请码。
  5. FAQ:邀请码永久有效;<¥20 档可绑定但不触发奖励;奖励到账后「本机天数」自动增加。
如何充值/兑换(3 分钟完成)

Step 1: 购买令牌

前往购买中心,选择适合你的方案:立即购买

支付方式

  • 支付宝:已开通,可直接使用
  • 微信支付:正在审核中,预计近期开通

购买后主流程如下:

  • 余额令牌档位(¥9.9 / ¥20 / ¥30 / ¥45):在平台查看令牌(格式:sk-...
  • 永久买断 / 补差价买断:在平台查看买断兑换码
  • 邮件通知是可选备份,不是主流程

Step 2: 进入订阅面板

方式一:点击主面板右侧的设置按钮

方式二:在设置面板中点击顶部的「订阅」标签


Step 3: 粘贴令牌 / 兑换码 / 邀请码

在订阅面板底部找到「我已经买好了」区域:

普通兑换(余额令牌):

  1. 粘贴令牌码 → 点击「兑换」
  2. 完成!

永久买断 / 补差价买断

  1. 粘贴买断兑换码
  2. 点击「兑换」
  3. 完成激活

使用邀请码(达标档位可触发奖励):

推荐流程:

  1. 先粘贴邀请码 → 点击「兑换」(自动识别为邀请码并绑定)
  2. 再粘贴令牌码 → 点击「兑换」
  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.noteIdmarginnote4app://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) locateUrlnodeId 或任一查询条件
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; if noteId is empty, the new excerpt card id is used; if noteId equals 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):

  • none
  • scroll
  • openEditor
  • openMarkdown
  • locateMindmap
  • bindCurrentUIStateToCard
  • convertToFolder
  • convertToFolderLocate
  • openNoteURL
  • pinChildCountText
  • convertToFolderAndPinChildCountText

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 自动检测 显式传入选中文本

路由优先级:

  1. 检测到文本选区:默认页面 Pin;textSelectionMode=text 时改为文本 Pin。
  2. 检测到框选:默认页面 Pin;boxSelectionMode=image 时改为图片 Pin。
  3. 无选区:用 noteId(或自动兜底的选中/焦点卡片)走卡片 Pin。
  4. 仍无可用输入: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.typepin.nodePathTextpin.locateUrlpin.instanceIdpin.refKey
  • 类型重点:cardpin.data.noteIdpagepin.data.docMd5pin.data.pageIndexpin.data.uiState

Return Notes

  • card:至少返回原卡片 noteId / noteURL
  • page:至少返回 docMd5pageIndexuiState / url
  • text:返回 texttextLengthfirstLine
  • image:返回 imageRefuistateUrl、OCR 文本等
  • uistate:返回 uiState / url
  • link:返回 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

最小接入规则:

  1. 优先使用 direct call;拿不到 globalThis.mnpinnerPublicApi 时,再回退到 AddonBroadcast
  2. card 重点读 pin.data.noteIdpage 重点读 pin.data.docMd5pin.data.pageIndexpin.data.uiState
  3. 通用协作字段优先看:pin.typepin.nodePathTextpin.locateUrlpin.instanceIdpin.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/oldNoteURLnewId/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"
}

常用模板

  1. 文本选区优先走文本 Pin
{
  "action": "mnpinnerPin",
  "pinApi": "pinFromSelectionOrCard",
  "pinText": "{{selectionText}}",
  "pinTitle": "{{selectionText | firstLine | trim}}",
  "pinPosition": "top"
}
  1. 框选优先走图片 Pin
{
  "action": "mnpinnerPin",
  "pinApi": "pinFromSelectionOrCard",
  "pinBoxSelectionMode": "image",
  "pinPromptTitle": false
}
  1. 把当前卡片 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.oldpinParams.new

pinAfterPin 可用值(当前 JSON 编辑器枚举)

"" | "scroll" | "highlight" | "locatePin" | "openEditor" | "openMarkdown" | "locateMindMap" | "openNoteURL" | "none"

自动兜底规则

  1. pinApi 不填时,自动用 pinFromSelectionOrCard
  2. pinApi=pinToCurrentNode/pinCardToSection/pin/locateSelectedCardPin 且没填 pinNoteId 时,会自动补 {{note.id}}
  3. pinApi=pinText 且没填 pinText 时,会自动补 {{selectionText}}
  4. pinApi=pinFromSelectionOrCard 且你填了 pinText 时,会自动转成 selectionText,并默认按文本选区处理(等价于 pinSelectionKind=text + pinTextSelectionMode=text)。
  5. pinParams 与顶层同义参数同时存在时,顶层参数优先。

接入建议

  1. 新集成优先用 pinFromSelectionOrCard,容错最好。
  2. 只做“文本摘录”按钮时,优先用 pinText,配置最直。
  3. 行为不符合预期时,先记录实际 JSON,再看 MNUtils -> Logs

致谢

特别感谢插件开发者 @linlifei 开发的众多优秀插件,MNPinner 开发过程中参考了许多设计和源码,包括但不限于:

  • MNUtils:基建插件,MNPinner 调用了 MNUtils 中许多实用工具函数,极大提升了开发效率和代码质量
  • MNSnipaste:可以视为 MNPinner 的前身,图片面板的设计和部分代码参考了 MNSnipaste 的实现
  • MNEditor:MNPinner 的 Markdown 编辑器参考了 MNEditor 的设计,并进行了一些适配和优化
  • MNBigbang:MNPinner 基于 MNBigbang 实现兼容自身数据的定制版
3 Likes

我不是中国人,但我很想花128元人民币永久购买。还有其他付款方式吗,比如PayPal?

2 Likes

Thank you for your support. The MNPinner plugin relies on the MNUtils plugin, which was developed by another developer and also requires subscription. Do you have any instant messaging methods or Email? I can offer any further assistance if you like. Maybe Alipay can support international payments.

I’d like to try Alipay
please Email me
mnnoteuser@gmail.com

I would like also to pay for the lifetime subscription, i already sent an email on kangweixia_xdyy@163.com

Xinyua app not available in my region

Alipay is working or any payment link

It is okay, the issue sorted out, I have completed the purchase via alipay.

Hi there, thank you so much for all of your support for MNPinner! I’ve just sent a reply email with the code you need attached. If you run into any problems when using it, please feel free to let me know anytime.

Best wishes,
Kangwei Xia

1 Like

Received thank you.