Robert Cranston authored on 11/05/2026 05:31:50
Showing 2 changed files

... ...
@@ -6,6 +6,33 @@ Export [Firefox][] [session][]s to plain text.
6 6
 [Firefox]: https://en.wikipedia.org/wiki/Firefox
7 7
 [session]: https://support.mozilla.org/kb/how-restore-browsing-session-backup#w_restoring-from-a-backup-file
8 8
 
9
+## Requirements
10
+
11
+All of these are packaged in [Debian][].
12
+
13
+-   [POSIX][]-compatible [shell][]
14
+-   [`lz4json`][]
15
+-   [`jq`][]
16
+
17
+[Debian]: https://en.wikipedia.org/wiki/Debian
18
+[POSIX]: https://en.wikipedia.org/wiki/POSIX
19
+[shell]: https://en.wikipedia.org/wiki/Unix_shell
20
+[`lz4json`]: https://github.com/andikleen/lz4json
21
+[`jq`]: https://jqlang.org
22
+
23
+## References
24
+
25
+Relevant directories, files, and code in the [Firefox source][]:
26
+
27
+-   [`browser/components/sessionstore/`][]
28
+    -   [`session.schema.json`][]: JSON schema used by session stores.
29
+    -   [`SessionFile.sys.mjs` `SessionFileInternal.Paths`][]: JSON schema used by session stores.
30
+
31
+[Firefox source]: https://github.com/mozilla-firefox/firefox
32
+[`browser/components/sessionstore/`]: https://github.com/mozilla-firefox/firefox/blob/main/browser/components/sessionstore/
33
+[`session.schema.json`]: https://github.com/mozilla-firefox/firefox/blob/FIREFOX_141_0_RELEASE/browser/components/sessionstore/session.schema.json
34
+[`SessionFile.sys.mjs` `SessionFileInternal.Paths`]: https://github.com/mozilla-firefox/firefox/blob/FIREFOX_141_0_RELEASE/browser/components/sessionstore/SessionFile.sys.mjs#L69
35
+
9 36
 ## License
10 37
 
11 38
 Licensed under the [ISC License][] unless otherwise noted, see the
12 39
new file mode 100755
... ...
@@ -0,0 +1,75 @@
1
+#!/bin/sh
2
+set -euC
3
+
4
+# Usage: firefox-session-export [<file>]
5
+
6
+file="${1:-}"
7
+if ! [ "$file" ]
8
+then
9
+  for file_ in \
10
+    "$HOME/.mozilla/firefox/"*default*'/sessionstore.jsonlz4' \
11
+    "$HOME/.mozilla/firefox/"*default*'/sessionstore-backups/recovery.jsonlz4' \
12
+    "$HOME/.mozilla/firefox/"*default*'/sessionstore-backups/previous.jsonlz4' \
13
+    "$HOME/.mozilla/firefox/"*default*'/sessionstore-backups/recovery.baklz4'
14
+  do
15
+    [ -r "$file_" ] || continue
16
+    file="$file_" && break
17
+  done
18
+fi
19
+if ! [ "$file" ]
20
+then
21
+  echo 'Could not find session.' >&2
22
+  exit 1
23
+fi
24
+
25
+# session="$(basename "$file")"
26
+session="${file#$HOME/.mozilla/firefox/}"
27
+lz4jsoncat "$file" | jq --arg session "$session" --raw-output '
28
+  def time:
29
+    . / 1000 | strflocaltime("%Y-%m-%d %H:%M:%S");
30
+
31
+  def entry($isSelected; $lastAccessed):
32
+    (($isSelected | select(.) | "**") // "") as $bold |
33
+    ("\($lastAccessed | time): "?     // "") as $time |
34
+    "\($bold)\($time)[\(.title | @html)](\(.url))\($bold)";
35
+
36
+  def tabs($selected):
37
+    to_entries[] | (.key + 1) as $id | .value |
38
+    ($id == $selected) as $isSlected |
39
+    .lastAccessed      as $lastAccessed |
40
+    .entries | reverse |
41
+      (.[0]    | "-   \(entry($isSlected; $lastAccessed))"),
42
+      (.[1:][] | "    -   \(entry(false; null))");
43
+
44
+  def windows:
45
+    to_entries[] | (.key + 1) as $id | .value |
46
+    .selected as $selected |
47
+      "### Window \($id)",
48
+      "",
49
+      "#### Open tabs",
50
+      "",
51
+      (.tabs | tabs($selected)),
52
+      "",
53
+      "#### Closed tabs",
54
+      "",
55
+      ([._closedTabs[].state] | tabs(0)),
56
+      "";
57
+
58
+  def session($session):
59
+    "# Session `\($session)`",
60
+    "",
61
+    "|             |                     |",
62
+    "| ---         | ---                 |",
63
+    "| Start       | \(.session.startTime  | time) |",
64
+    "| Last update | \(.session.lastUpdate | time) |",
65
+    "",
66
+    "## Open windows",
67
+    "",
68
+    (.windows | windows),
69
+    "",
70
+    "## Closed windows",
71
+    "",
72
+    (._closedWindows | windows);
73
+
74
+  session($session)
75
+'