技巧分享:在 emacs 中获取 firefox 当前标签页并生成 org link

场景

在 emacs 中记笔记时,获取 firefox 正在浏览的页面链接和网页标题。

此前的做法

方法1:手动复制网页链接和标题,通过 org-insert-link 插入

方法2:复制网页链接,通过脚本访问该页面并获取相应的标题,参考这个

上面两个方法的缺点是无论如何都要离开一次 emacs。

新的思路:通过 recovery.jsonlz4 获取 url 和标题

firefox 会记录浏览过的页面信息并将其保存在 recovery.jsonlz4 这个文件中,可以通过 shell 脚本对其进行解析获取当前正在浏览的页面信息,然后在 emacs 通过 shell-command-to-string 获取结果。

需要依赖两个外部工具:lz4jsonjq 。前者用来解压 firefox 的文件,后者用来解析 json 文件。

elisp 代码:

(defcustom FIREFOX-RECOVER-FILE ".mozilla/firefox/[your-profile]/sessionstore-backups/recovery.jsonlz4"
  "current active firefox profile recovery.jsonlz4 file location")
(defcustom FIREFOX-GET-TAB-URL-CMD "lz4jsoncat %s | jq -r '.windows[%d].tabs[%d].entries[-1].url'"
  "shell command template to get current active tab url")
(defcustom FIREFOX-GET-TAB-TITLE-CMD "lz4jsoncat %s | jq -r '.windows[%d].tabs[%d].entries[-1].title'" 
  "shell command template to get current active tab title")
(defun +string-trim-final-newline (string)
  (let ((len (length string)))
    (cond
      ((and (> len 0) (eql (aref string (- len 1)) ?\n))
       (substring string 0 (- len 1)))
      (t string))))
(defun +shell-command-to-string-no-newline (cmd)
  (+string-trim-final-newline (shell-command-to-string cmd)))
(defun +get-current-active-firefox-tab-org-link ()
  (interactive)
  (let* ((selected-window (string-to-number (shell-command-to-string (format "lz4jsoncat %s| jq '.selectedWindow'" FIREFOX-RECOVER-FILE))))
	 (selected-tab (string-to-number (shell-command-to-string (format "lz4jsoncat %s| jq '.windows[%d].selected'" FIREFOX-RECOVER-FILE (- selected-window 1)))))
	 (url (+shell-command-to-string-no-newline (format FIREFOX-GET-TAB-URL-CMD FIREFOX-RECOVER-FILE (- selected-window 1) (- selected-tab 1) )))
	(title (+shell-command-to-string-no-newline (format FIREFOX-GET-TAB-TITLE-CMD  FIREFOX-RECOVER-FILE (- selected-window 1) (- selected-tab 1)))))
    (insert (format "[[%s][%s]]" url title))))

新思路的缺点

firefox 并不是即时同步这个文件,在切换 tab 之后会有大约十几秒钟的延迟,所以会有一段时间得到的是错误的 tab 页。

3 个赞
1 个赞

DIY 自带乐趣,我也很喜欢自己动手解决问题。我已经忘记了,当初是如何解决同样的问题了,没用 Linux 桌面很久了。Mac 平台有官方的自动化工具,如 AppleScript,但是 Linux 桌面端没有同类替代物,导致自动化不够便利。

1 个赞

这个也是上面那个大佬写的。

我用的是org-mac-link,优点是支持多个app ,缺点是只支持macOS。

可惜并不是每个 app 都提供 applescript 支持,比如 firefox…

我写的 grab-mac-link.el 是在 org-mac-link 的基础上,增加了 Markdown 链接的支持,直接用了后者的代码

1 个赞

或许直接通过 org-protocol 直接 capture 到 emacs 里更容易。

+1,org-protocol 预置就有 org-protcol-store-link

我也在尝试解决这个问题:在不切出Emacs的情况下,获取之前访问过的URL的标题并以org-mode的格式插入到Emacs中光标所在的位置。

分析一下限制条件:

  • 不用切换出 Emacs,减少上下文切换
  • 尽可能少的按键、手动操作
  • 可靠、稳定,能够获取用 JavaScript 生成的 Title

我想了两个方案:

  1. 使用 AppleScript。但是发现 Firefox 不支持用 AppleScript 来获取标题,但是在 Chrome 里是可以直接做到的。
  2. 使用 HTTP 服务存储 Firefox 当前的页面地址和标题。这是我最后的解决方式。

最后我使用 deno-bridge 串联了 HTTP 服务、UserScript 脚本、一些 Elisp 代码糊了个 package,并将制作过程记录成博客

2 个赞

我已经把 deno-bridge-echo 加到了 deno-bridge README Add deno-bridge-echo. · manateelazycat/deno-bridge@ad0d7a9 · GitHub

哈哈哈哈。

1 个赞

安装 CopyTabTitleUrl firefox 插件即可,它支持定制内容格式以及快捷键

单纯为了获取链接的话感觉有点太复杂了,基于这个框架应该还能做到其它有意思的事情吧,比如获取网页的 thumbnail 之类的

我最终采用的方案是比较重的,因为引入了 deno 和 userscript,但是在以下场景下没有发现更好的方案:

  • 希望能不离开 Emacs 的情况下实现插入 Firefox 中的 url 和标题
  • 需要支持能获取 React 等框架动态设置的 title

如果是完成 80%的需求角度上来看,本贴已经有足够多的实现了,甚至我换到 Chrome 也就可以用上现有的轮子了。

不过我们可以享受一下 DIY 的乐趣 不是嘛

实际上我仍然在探索 deno-bridge 的使用场景,这也是我写的第一个包

1 个赞

還有一個缺點,這個命令執行需要三五秒的時間,太長了。

grab-mac-link-dwim 這個是瞬時的,但不能一步轉成org或者md格式。

大佬的這個grab-mac-link,可以配置成默認(grab-mac-link 'chrome 'org)嗎?

dwim 可设置为默认 Chrome,见 GitHub - xuchunyang/grab-mac-link.el: Grab link from Mac Apps and insert it into Emacs Chrome + Markdown 的话,建议你自己封装下,写一个新命令。

測試了這句 (global-set-key (kbd “C-c m”) (grab-mac-link 'chrome 'markdown)) ,出現奇怪問題。達不成類似(global-set-key (kbd “C-c l”) 'org-mac-link-chrome-insert-frontmost-url) 的效果。

你需要定义一个新的 Emacs 命令,然后再绑定快捷键,比如:

(defun chinhant-grab-mac-link ()
  "获得并插入 Chrome 页面的 Markdown 链接."
  (interactive)
  (insert (grab-mac-link 'chrome 'markdown)))

(global-set-key (kbd "C-c m") 'chinhant-grab-mac-link)
1 个赞

get到了,謝謝