Here is a cli solution using Haskell to get the current tab opened in Firefox, which I run from emacs.
Haskell
The single input argument is the path of the recovery.jsonlz4
file in Firefox’s profile folder, which is decompressed with the lz4-hs
package and traversed using lenses from lens-aeson
. Output is just the tab tile and url in two lines printed to stdout. The code can be found here.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Codec.Lz4
import Control.Lens
import Data.Aeson
import Data.Aeson.Lens
import Data.Bits ( shiftL )
import qualified Data.ByteString.Char8 as BC
import Data.Char ( ord )
import System.Environment
import Data.Text.Lens
readLz4 :: FilePath -> IO BC.ByteString
= do
readLz4 f <- BC.readFile f
contents let bsc = BC.drop 8 contents
= lEBsToInt $ BC.take 4 bsc
sz return $ decompressBlockSz (BC.drop 4 bsc) sz
readJsonLz4 :: FilePath -> IO Value
= do
readJsonLz4 f <- readLz4 f
bs return $ bs ^?! _JSON
-- https://stackoverflow.com/questions/26519579/how-do-i-convert-4-bytes-of-a-bytestring-to-an-int
-- 1. Get the first 4 bytes of a ByteString
-- 2. Calculate the amount to shift by
-- 3. Fold over the ByteString, summing the result of shifting the current byte by the current offset
lEBsToInt :: BC.ByteString -> Int -- littleEndianByteStringToInt
=
lEBsToInt bs let bsI = BC.take 4 bs
in fst $ BC.foldl
->
(\(s, i) b let shiftBy = i * 8 in (s + (ord b `shiftL` shiftBy), i + 1)
)0, 0)
(
bsI
getCurrentTab :: Value -> (String, String)
=
getCurrentTab v let iwindow = v ^?! key "selectedWindow" . _Integer . to fromIntegral - 1
= v ^?! key "windows" . nth iwindow
window = window ^?! key "selected" . _Integer . to fromIntegral - 1
itab = window ^?! key "tabs" . nth itab
tab = tab ^?! key "index" . _Integer . to fromIntegral - 1
ientry in tab ^?! key "entries" . nth ientry . to
->
(\o ^?! key "title" . _String . unpacked
( o ^?! key "url" . _String . unpacked
, o
)
)
extractCurrentTab :: FilePath -> IO (String, String)
= do
extractCurrentTab recoveryJson <- readJsonLz4 recoveryJson
value return $ getCurrentTab value
currentFirefoxTab :: FilePath -> IO ()
= do
currentFirefoxTab recoveryJson <- extractCurrentTab recoveryJson
(title, url) putStrLn title
putStrLn url
main :: IO ()
= do
main <- getArgs
[recoveryJson] currentFirefoxTab recoveryJson
Firefox
The path to firefox’s recovery.jsonlz4
file:
- macos:
"~/Library/Application Support/Firefox/Profiles/*.default-*/sessionstore-backups/recovery.jsonlz4"
- linux:
"~/.mozilla/firefox*/*.default/sessionstore-backups/recovery.jsonlz4"
Emacs
I wrote fftabs
to be used in my doom emacs config to insert the tab in a buffer or open it in eww. Here are some elisp function to achieve this:
;; Use Firefox Tabs
defvar mnd/ff-restore-file
("/Users/mnd/Library/Application\\ Support/Firefox/Profiles/\
<FILLHERE>.default-<FILLHERE>/sessionstore-backups/recovery.jsonlz4")
defun mnd/current-firefox-tab ()
("Run fftabs haskell programm to get the current firefox tab."
"\n"
(s-split
(shell-command-to-stringformat "fftabs %s" mnd/ff-restore-file))
(
'omit-nulls))
defun mnd/current-firefox-tab-url ()
("Insert the url of the current firefox tab."
(interactive)let* ((pair (mnd/current-firefox-tab))
(cadr pair)))
(url (
(insert url)))"i w u" #'mnd/current-firefox-tab-url)
(map! :leader
defun mnd/current-firefox-tab-orglink ()
("Get the current firefox tab in titled org-link format."
let* ((pair (mnd/current-firefox-tab))
(car pair))
(title (cadr pair))
(url (format "[[%s][%s]]" url title)))
(orglink ("%s" orglink)
(message
orglink))
defun mnd/current-firefox-tab-org-cliplink ()
("Insert the current firefox tab in titled org-link format."
(interactive)
(insert (mnd/current-firefox-tab-orglink))
(evil-jump-item))"i w o" #'mnd/current-firefox-tab-org-cliplink)
(map! :leader
defun mnd/current-firefox-tab-eww ()
("Open the current firefox tab in eww."
(interactive)let* ((pair (mnd/current-firefox-tab))
(cadr pair)))
(url (
(eww url)))"o w" #'mnd/current-firefox-tab-eww) (map! :leader