Skip to content

Instantly share code, notes, and snippets.

@tmonjalo
Created September 13, 2018 10:42
Show Gist options
  • Star 49 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save tmonjalo/33c4402b0d35f1233020bf427b5539fa to your computer and use it in GitHub Desktop.
Save tmonjalo/33c4402b0d35f1233020bf427b5539fa to your computer and use it in GitHub Desktop.
List all Firefox tabs with title and URL
#! /usr/bin/env python3
"""
List all Firefox tabs with title and URL
Supported input: json or jsonlz4 recovery files
Default output: title (URL)
Output format can be specified as argument
"""
import sys
import pathlib
import lz4.block
import json
path = pathlib.Path.home().joinpath('.mozilla/firefox')
files = path.glob('*default*/sessionstore-backups/recovery.js*')
try:
template = sys.argv[1]
except IndexError:
template = '%s (%s)'
for f in files:
b = f.read_bytes()
if b[:8] == b'mozLz40\0':
b = lz4.block.decompress(b[8:])
j = json.loads(b)
for w in j['windows']:
for t in w['tabs']:
i = t['index'] - 1
print(template % (
t['entries'][i]['title'],
t['entries'][i]['url']
))
@stefan-reich
Copy link

Nice

@c4explosive
Copy link

Perfect

@goeblr
Copy link

goeblr commented May 24, 2019

Very nice!

I expanded it to also work in Windows:

#! /usr/bin/env python3

"""
List all Firefox tabs with title and URL

Supported input: json or jsonlz4 recovery files
Default output: title (URL)
Output format can be specified as argument
"""

import sys
import pathlib
import lz4.block
import json
import os

if os.name == 'nt':
    path = pathlib.Path(os.environ['APPDATA']).joinpath('Mozilla\\Firefox\\Profiles')
else:
    path = pathlib.Path.home().joinpath('.mozilla/firefox')
files = path.glob('*default*/sessionstore-backups/recovery.js*')

try:
    template = sys.argv[1]
except IndexError:
    template = '%s (%s)'

for f in files:
    b = f.read_bytes()
    if b[:8] == b'mozLz40\0':
        b = lz4.block.decompress(b[8:])
    j = json.loads(b)
    for w in j['windows']:
        for t in w['tabs']:
            i = t['index'] - 1
            print(template % (
                t['entries'][i]['title'],
                t['entries'][i]['url']
                ))

@Gorgious56
Copy link

Thanks, exactly what I was looking for ! Cheers.

@iarigby
Copy link

iarigby commented Aug 10, 2019

Sweet

@doronbehar
Copy link

I recommend using this as an alternative: https://github.com/balta2ar/brotab

@kyounger
Copy link

Check out my fork for a small edit that makes it work on MacOS.

@Yevgnen
Copy link

Yevgnen commented Feb 9, 2021

Magic!

@orjanv
Copy link

orjanv commented May 30, 2021

great, thanks for this.

@swiinger
Copy link

@goeblr : got an error with your vesion : TypeError: not all arguments converted during string formatting
any thoughts ? thanks

@RanTalbott
Copy link

Thanks very much for sharing this, Thomas!

Yours wasn't exactly what I wanted, but it was very close, and the fact that you did all the hard work of figuring out how to get the window state data made it easy for me to find the last bits that I needed. I probably wouldn't have done the project if I'd had to find it all myself.

My needs are somewhat different: I usually have several Firefox windows open, sometimes with tabs for more than one project in one window. So I needed to find the right window, and don't usually need to know about the URL. So I produce a list of the windows and their tabs, with URL display optional. I also made the choice of profile a parameter, because I use a few different ones for different purposes. I've attached a copy in case anyone else is interested.

Thanks again,
Ran

`#! /usr/bin/env python3

"""
List all Firefox tabs with title and URL

Supported input: json or jsonlz4 recovery files
Default output:
window title
tab1 title
tab2 title
...

Display of URLs on lines following the tab titles
can be enabled via the "-u" argument
"""

import sys
import pathlib
import lz4.block
import json
import getopt

MY_VERSION = "0.1a"

def usage(my_name):
print("Usage: " + my_name + " [huV] [-p profile]")
print('''
Read a CSV file on stdin, transpose the rows and columns, write to stdout.
Options:
-h, --help - Display this help and exit
-V, --version - Display this program's version and exit
-u, --show_urls - Include the URLs in the output Default is don't.
-p, --profile - The Firefox profile you're using. Default is "default".
''')

def main(argv):
global MY_VERSION
EXIT_OK = 0
EXIT_ERROR = 1
show_urls = False
profile = "default"

try:
    opts, args = getopt.getopt(argv[1 : ], "huVp:", ["help", "show_urls ", "version", "profile "])
except getopt.GetoptError as err:
    # print help information and exit:
    print(err)  # will print something like "option -a not recognized"
    usage()
    sys.exit(EXIT_ERROR)
for o, a in opts:
    if o in ("-V", "--version"):
        print("Version " + MY_VERSION)
        sys.exit(EXIT_OK)
    elif o in ("-h", "--help"):
        usage(argv[0])
        sys.exit(EXIT_OK)
    elif o in ("-u", "--show_urls "):
        show_urls = True
    elif o in ("-p", "--profile "):
        profile = a
    else:
        usage(argv[0])
        sys.exit(EXIT_ERROR)

path = pathlib.Path.home().joinpath('.mozilla/firefox')
files = path.glob('*' + profile + '*/sessionstore-backups/recovery.js*')


for f in files:
    b = f.read_bytes()
    if b[:8] == b'mozLz40\0':
        b = lz4.block.decompress(b[8:])
    j = json.loads(b)
    for w in j['windows']:
        # Lotsa " - 1"s here, because Firefox arrays are 1-origin
        # Find the window title, which is the title of the active tab
        t = w['tabs'][w['selected'] - 1]
        print(t['entries'][t['index'] - 1]['title'])

        # Print the tab titles
        for t in w['tabs']:
            i = t['index'] - 1
#            print(template % (
            print("    %s" % ( 
                t['entries'][i]['title'],
                ))
            if show_urls:
                print("      %s" % ( 
                    t['entries'][i]['url'],
                    ))

if name == "main":
main(sys.argv)

`

@RanTalbott
Copy link

@goeblr : got an error with your vesion : TypeError: not all arguments converted during string formatting any thoughts ? thanks

Just a guess, but maybe the version of Firefox you're running is returning something other than a string for t['entries'][i]['title'] or t['entries'][i]['url']. Maybe a list or a tuple if there's something odd about the tab? I'd do a try/except, and print out type and size info for them on error.

@mwalkerr
Copy link

mwalkerr commented Jun 9, 2023

The location for me was actually ~/snap/firefox/common/.mozilla/firefox/. You can find your profile location by the following the steps here: https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment