Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
#+TITLE: Zhihu On Emacs #+OPTIONS: toc:2 在 Emacs 中使用 Org 撰写、存档并发布知乎回答和文章,并可以指定文章专栏。 Org 到知乎方言 HTML 的纯导出由同仓库的 =ox-zhihu.el= 提供;本包在导出结果 之上完成登录、图片上传与发布。 #+begin_quote *WARNING*:本项目使用知乎非公开的网页接口,知乎可能随时改变接口行为。 #+end_quote * 依赖 - Emacs 31.1,并启用 SQLite、libxml 和 GnuTLS 支持 - 一个 Cookie 函数:接收完整 URL,返回 =((NAME . VALUE) ...)=;例如 [[https://github.com/DzmingLi/firefox-cookies.el][firefox-cookies.el]] 提供的 =firefox-cookies-get= - [[https://github.com/alphapapa/plz.el][plz.el]] master(=0.10-pre=) - 可选:源稿声明 =#+TYPST_MATH: t= 时需要 [[https://github.com/DzmingLi/org-typst-math][org-typst-math]] 0.1.0 或更高版本, 用它的 Rust helper 把 Typst 数学转成 TeX;普通导出不会加载它 - 可选:转换本地路径 / =data:= URL 中的 SVG 时需要 PATH 中的 [[https://typst.app/][typst]] 0.15.0 或更高版本 - 可选:如果源稿使用 Mermaid 图, [[https://github.com/mermaid-js/mermaid-cli][@mermaid-js/mermaid-cli]] 提供的 =mmdc= * 配置 本包不配置或识别具体浏览器,只调用 =zhihu-cookie-function=。如果使用 =firefox-cookies.el= 实现,请在 Emacs 配置中加载它、选择 Firefox profile, 再把函数交给本包: #+begin_src emacs-lisp (require 'firefox-cookies) (setq firefox-cookies-profile-directory "~/.mozilla/firefox/xxxxxxxx.default-release/") (setq zhihu-cookie-function #'firefox-cookies-get) #+end_src Firefox profile 不会被自动扫描或猜测;Container 等实现细节由 Cookie 函数 自身配置,而不是由 =zhihu.el= 配置。 回答/文章没有单独指定转载权限时,使用 =zhihu-publish-default-reprint-permission=(默认 =allowed=);回答或文章 没有单独指定评论权限时,使用 =zhihu-publish-default-comment-permission=(默认 =all=)。 如需在文章末尾自动追加 Creative Commons 许可引用,可通过 =zhihu-article-cc-statement= 自定义,这一选项将会适用于所有文章。 * 导出 =ox-zhihu.el= 定义了一个从 =html= 派生的 Org 导出后端 =zhihu=,它把 Org 正文转换成知乎方言 HTML。这一层是纯导出:不读 cookie、不访问网络、不上传 图片,可以单独使用: - 导出菜单 =C-c C-e z= 下的 “To Zhihu”; - =M-x org-zhihu-export-as-html=:导出到 =*Org Zhihu Export*= buffer; - =M-x org-zhihu-export-to-html=:导出到同目录的 =.html= 文件。 =zhihu-publish= 内部复用同一个后端,再在上传阶段替换图片地址并调用知乎 接口。 * 工作流 提供问题 ID 或者 URL,写新回答: #+begin_example M-x zhihu-new-answer #+end_example 命令创建并打开 =.org= 回答源稿后会显式启用 =zhihu-mode=。 申请创建新的普通知乎专栏: #+begin_example M-x zhihu-new-column #+end_example 专栏名称必填且最多 20 个字符,简介可空且最多 1000 个字符。封面是可选的, 本命令不会提示或上传封面。 写新文章无需专用的新建命令:创建 =.org= 源稿即可。保留空 =article-id= 时 作为新文章;文章需要文档标题。需要指定专栏、话题或其它发布设置时,再添加 相应 metadata。 更新已有知乎文章或回答,或者把已有文件首次发布到知乎: #+begin_example M-x zhihu-publish #+end_example 发布过程中,本包会把服务端返回的知乎回答或文章 ID 写回源文件;其中空 =article-id= 表示首次发布,非空值表示更新已有文章。 =zhihu-mode= 是不占用键位的编辑辅助 minor mode。本包不会扫描或自动识别 Org 文件;需要编辑辅助时手动运行 =M-x zhihu-mode=。在 =column-id= 值槽运行 =M-x completion-at-point=,候选会显示当前账号可投稿的专栏名称和 ID, 选择后只把实际 ID 写入源稿;=topics= 的字符串元素也支持同样的就地补全。 * 语法 在文章和回答中,数学公式、表格、加粗、斜体、标题层级、超链接、代码块和 脚注均受支持,采用 Org 自带的语法。 ** 数学 默认情况 =$...$=、=\(...\)=、=$$...$$= 和 =\[...\]= 中的内容是 LaTeX, 沿用 =ox-html= 的处理,发布时转换为知乎 equation。 若在源稿中声明 =#+TYPST_MATH: t=,这些容器内的数学改由 [[https://github.com/DzmingLi/org-typst-math][org-typst-math]] 解析为 Typst 数学,并由其 helper 转换成 TeX 后走同一条 equation 路径: #+begin_example #+TYPST_MATH: t #+TYPST_HEADER: #let vect(x) = math.bold(x) 行内 $vect(v)$,或者 \(frac(a, b)\)。 \[ sum_(k=1)^n k = (n(n+1))/2 \] #+end_example =TYPST_HEADER= 可以出现多次,按顺序拼接,用于定义数学宏;其中的本地 =#import= 以源稿所在目录为基解析。未声明 =TYPST_MATH= 时完全保留 Org 原生 的 LaTeX 行为。 ** 文章内章节链接 文章可以用 Org 原生的 fragment 链接跳到同一篇文章的标题。必须同时设置 =#+TOC: headlines N=,目标在最终 HTML 中必须是 =h2= 或 =h3=: #+begin_example [[#conclusion][跳到结论]] * 结论 :PROPERTIES: :CUSTOM_ID: conclusion :END: #+end_example ** 链接卡片 链接卡片就是知乎自己的 HTML,不属于 Org,也不是通用微格式。把它写进 =#+begin_export zhihu= 块,并让它独占一个段落: #+begin_example #+begin_export zhihu <a href="https://github.com/" data-draft-node="block" data-draft-type="link-card" data-draft-title="GitHub" data-draft-cover="">GitHub</a> #+end_export #+end_example =draft-title= 是卡片标题,=data-draft-cover= 留空让知乎自行抓取封面。 =#+begin_export zhihu= 只被 =ox-zhihu= 导出,其它导出器会忽略它;如果同时 希望这段 HTML 出现在别的 HTML 导出里,改用 =#+begin_export html= 即可。 ** @ 知乎用户 运行 =M-x zhihu-insert-user-mention=,搜索并选择用户。命令会插入持久化的 链接标记,发布时转换为知乎原生 =member_mention= 链接。普通用户主页链接 不会自动升级为 mention。 ** 话题 在 =#+ZHIHU_TOPICS:= 的某个 JSON 字符串元素内输入关键词,然后运行: #+begin_example M-x completion-at-point #+end_example #+begin_example #+ZHIHU_TOPICS: ["Emacs", "Org"] #+end_example 补全会按当前元素的文字调用知乎话题搜索,保留远端相关性顺序,并在候选中 显示简介和话题 ID;提交后源稿只保留规范的话题名称。把光标放在引号内即可 补全,空查询不会请求网络。这是按关键词的话题自动补全;知乎网页编辑器根据 已上传正文生成的“推荐话题”不是本地补全的一部分。 发布文章时,本地列表是完整事实来源:远端缺少的话题会绑定,多出的话题会 解绑;源稿没有 =topics= 时表示空集合,会清除远端全部话题。回答不支持 =topics=。源稿只保存话题名称;发布时再从知乎的名称完全匹配候选取得对应 ID。 ** 脚注(知乎引用) 知乎引用只能保存一段纯文本和一个可选 URL。因此脚注目前必须是单段,最多 包含一个带 host 的 HTTP(S) 链接;强调、粗体、删除线和行内代码会转成纯 文本。多段、多链接、列表、代码块、图片、公式或 raw 内容会在发布前报错, 避免静默丢失信息;嵌套脚注不在支持范围内。纯文字脚注会生成空的引用 URL。 ** 分割线 Org 原生的水平分隔线会转换为知乎可接受的分割线: #+begin_example ----- #+end_example * 元数据示例 回答: #+begin_example #+TITLE: 示例回答 #+ZHIHU_QUESTION_ID: 123456 #+end_example 新文章: #+begin_example #+TITLE: 示例文章 #+BANNER: ./images/banner.jpg #+TOC: headlines 2 #+ZHIHU_ARTICLE_ID: #+ZHIHU_TOPICS: ["Emacs", "org-mode"] #+end_example 每篇源稿必须且只能包含 =question-id= 或 =article-id= 之一,分别表示回答 或文章。类型按字段是否存在判定,而不是按 ID 是否非空判定;即使 ID 槽仍为 空也算存在。 =article-id= 是唯一的空值例外:首次发布前保留空槽,发布成功后自动在原位 写入服务端 ID。尚未取得的 =answer-id= 仍应整个省略。 需要加入专栏时,在含 =article-id= 的文章 metadata 下额外填写 =column-id=; =column-id= 不能单独标记文章。发布文章后会检查当前专栏,尚未收录时才发起 收录。启用 =zhihu-mode= 后,可在该字段值槽调用 =completion-at-point=, 按专栏名称选择并写入 ID;候选列表在当前 buffer 中懒加载并缓存,revert 后 重新读取。 =banner= 与 =title= 一样属于通用文档 metadata,使用 =#+BANNER:=,不写进 知乎渠道字段。值是非空的本地图片路径,相对路径以源稿所在目录为基。知乎 文章发布会把它用作题图,字段缺失会清除知乎上的现有封面;回答发布不会读取 或使用它。 目录请求也属于通用文档结构。使用 =#+TOC: headlines 1..3=,只有文章发布会 读取它,并把它映射为知乎原生文章目录;回答会忽略它。没有目录请求时,文章 目录关闭。 以下知乎设置都属于单篇稿件,使用 =#+ZHIHU_*= 关键字: | 设置 | 关键字 | 可用值 | 未填写时 | |----------+---------------------------------+-------------------------------------------------------------------------------------+----------------------| | 创作声明 | =#+ZHIHU_CREATION_STATEMENT:= | =spoiler=、=medical_advice=、=fictional_creation=、=contain_finance=、=ai_creation= | 无创作声明 | | 内容来源 | =#+ZHIHU_CONTENT_SOURCE:= | =officialWebsite=、=newsReport=、=TVMedia=、=printMedia= | 不标注来源 | | 话题 | =#+ZHIHU_TOPICS:= | 文章至多三个;回答不支持 | 文章会清空远端话题 | | 转载权限 | =#+ZHIHU_REPRINT_PERMISSION:= | =allowed=、=disallowed=、=need_payment= | 使用转载权限默认值 | | 评论权限 | =#+ZHIHU_COMMENT_PERMISSION:= | =all=、=censor=、=followee=、=nobody= | 使用评论权限默认值 | =content-source= 对应“内容信息来源”渠道;知乎同一面板中的自行拍摄时间和 地点不是这个标量字段的一部分,目前不写入。 上表中的可选发布设置缺失时使用对应默认值;一旦出现,就必须是非空且类型、 取值有效的值。 * 致谢 - [[https://github.com/pxwg/zhihu.nvim][zhihu.nvim]]:发布 payload、浏览器 Cookie 读取和图片上传协议的主要参考实现。 - [[https://github.com/zly2006/zhihu-sign-kt][zhihu-sign-kt]]:ZSE v4 签名 算法的 MIT 许可实现。