I have switched to OpenBox recently, so today I will use dynamic menus to integrate Firefox bookmarks with an existing OpenBox menu.

2018.04.18 update

Please use the following code repository as these shell scripts were updated over time.

How to create dynamic menu?

At first you need to to know the location of the OpenBox menu configuration:

~/.config/openbox/menu.xml

Study it for a while to get comfortable with its simple XML syntax, then look at the following example as it shows a code used to define pipe menu.

<menu execute="sh ~/bin/scriptmenu.sh" id="pipe-961648" label="Script Menu"/>

Do I need to modify OpenBox menu by hand?

No. You can use obmenu utility to edit menu using graphical user interface.

How sample script output should look like?

If you wonder how sample script output should look like then skim through the following code.

<?xml version="1.0" encoding="UTF-8"?> <openbox_pipe_menu> <menu id="pipe-menu-1" label="Pipe menu - 1"> <item label="first item inside Pipe menu - 1"> <action name="Execute"> <execute> first command </execute> </action> </item> </menu> <item label="second item"> <action name="Execute"> <execute> second command </execute> </action> </item> </openbox_pipe_menu>

How to get most popular websites?

To generate Most popular websites menu store the following shell script as the ~/bin/most_popular_websites.sh file.

Notice the used SQL query, separator and location of the places.sqlite database file.

#!/bin/sh # Generate "Most popular websites" OpenBox dynamic menu # path to the sqlite3 binary sqlite_path=`which sqlite3` # sqlite3 parameters (define separator character) sqlite_params="-separator ^" # path to the places.sqlite database bookmarks_database=`ls ~/.mozilla/firefox/*.default/places.sqlite` # SQL query sql_query="select p.title, p.url from moz_places as p where p.hidden=0 order by frecency desc limit 10" # browser path browser_path=`which iceweasel` # header echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" echo "<openbox_pipe_menu>"; # execute and parse sql query $sqlite_path $sqlite_params "$bookmarks_database" "$sql_query" | while IFS=^ read title url; do # special case for empty title if [ -z "$title" ]; then title=$url fi # escape special characters title=$(echo $title | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") url=$(echo $url | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") # add missing apostrophes title="\"$title\"" #item echo "<item label=$title><action name=\"Execute\"><execute>$browser_path $url</execute></action></item>" done # footer echo "</openbox_pipe_menu>"

OpenBox XML menu configuration:

<menu execute="sh ~/bin/most_popular_websites.sh" id="pipe-ff-most-popular" label="Most popular websites"/>

How to get recently visited websites?

This shell script is almost the same as the above one. Only SQL query changed slightly to display recently visited websites. Store it as the ~/bin/recently_visited_websites.sh shell script.

#!/bin/sh # Generate "Recently visited websites" OpenBox dynamic menu # path to the sqlite3 binary sqlite_path=`which sqlite3` # sqlite3 parameters (define separator character) sqlite_params="-separator ^" # path to the places.sqlite database bookmarks_database=`ls ~/.mozilla/firefox/*.default/places.sqlite` # SQL query sql_query="select p.title, p.url from moz_places as p where p.hidden=0 order by last_visit_date desc limit 10" # browser path browser_path=`which iceweasel` # header echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" echo "<openbox_pipe_menu>"; # execute and parse sql query $sqlite_path $sqlite_params "$bookmarks_database" "$sql_query" | while IFS=^ read title url; do # special case for empty title if [ -z "$title" ]; then title=$url fi # escape special characters title=$(echo $title | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") url=$(echo $url | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") # add missing apostrophes title="\"$title\"" #item echo "<item label=$title><action name=\"Execute\"><execute>$browser_path $url</execute></action></item>" done # footer echo "</openbox_pipe_menu>"

OpenBox XML menu configuration:

<menu execute="sh ~/bin/recently_visited_websites.sh" id="pipe-ff-recently-visited" label="Recently visited websites"/>

How to get bookmarks menu?

This shell script is more complicated as it uses recursive function to create bookmarks menu. The idea is the same but there is a lot more data to process.

Store it as ~/bin/personal_bookmarks.sh file.

#!/bin/sh # Generate "Bookmarks" OpenBox dynamic menu # path to the sqlite3 binary sqlite_path=`which sqlite3` # sqlite3 parameters (define separator character) sqlite_params="-separator ^" # path to the places.sqlite database bookmarks_database=`ls ~/.mozilla/firefox/*.default/places.sqlite` # SQL query sql_query="select p.title, p.url from moz_places as p where p.hidden=0 order by last_visit_date desc limit 10" # browser path browser_path=`which iceweasel` # root element root_element="(select folder_id from moz_bookmarks_roots where root_name='menu')" # process bookmarks process_bookmarks(){ # SQL query - bookmarks sql_bookmarks_query="select b.title, p.url from moz_bookmarks as b left outer join moz_places as p on b.fk=p.id where b.type = 1 and p.hidden=0 and b.title not null and parent=$1" $sqlite_path $sqlite_params "$bookmarks_database" "$sql_bookmarks_query" | while IFS=^ read title url; do # special case for empty title if [ -z "$title" ]; then title=$url fi # escape special characters title=$(echo $title | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") url=$(echo $url | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") # add missing apostrophes title="\"$title\"" echo "<item label=$title><action name=\"Execute\"><execute>$browser_path $url</execute></action></item>" done } # process the folders function process_folders(){ # execute only when there is an exactly one parameter if [ "$#" = 1 ]; then # SQL query - folders sql_folder_query="select id, title from moz_bookmarks where parent=$1 and type=2 and (select count(*) from moz_bookmarks as b2 where b2.parent=moz_bookmarks.id)>0" # process folders $sqlite_path $sqlite_params "$bookmarks_database" "$sql_folder_query" | while IFS=^ read id title; do # special case for empty title if [ -z "$title" ]; then title="(no title)" fi # escape special characters title=$(echo $title | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") # add missing apostrophes title="\"$title\"" # create new menu for folder echo "<menu id=\"ff-bookmarks-folder-$id\" label=$title>"; # process folders inside process_folders $id # process bookmarks in current folder process_bookmarks $id echo "</menu>" done fi } # header echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" echo "<openbox_pipe_menu>"; # process folders process_folders "$root_element" # process bookmarks for root element process_bookmarks "$root_element" # footer echo "</openbox_pipe_menu>"

OpenBox XML menu configuration:

<menu execute="sh ~/bin/personal_bookmarks.sh" id="pipe-ff-personal-bookmarks" label="Bookmarks"/>

How to get bookmarks from specified folders?

If you want to display bookmarks from specified folders (non-recursively) then you will need to know id values so use the following SQL query:

$ sqlite3 -column -header ~/.mozilla/firefox/*.default/places.sqlite "select b.id,b.title,b.parent,(select b1.title from moz_bookmarks as b1 where b1.id=b.parent) as parent_name,(select count(*) from moz_bookmarks as b2 where b2.type=1 and b2.parent=b.id) as bookmarks_count from moz_bookmarks as b where b.type = 2 and length(parent_name) > 0 and length(title) > 0 and b.parent <> 4 order by parent,id" id title parent parent_name bookmarks_count ---------- --------------- ---------- -------------- --------------- 7 Mozilla Firefox 2 Bookmarks Menu 4 84 OS 2 Bookmarks Menu 1 85 Personal 2 Bookmarks Menu 5 86 News 2 Bookmarks Menu 12 96 Forums 85 Personal 4 97 Testing 85 Personal 5

The following shell script ( ~/bin/specified_bookmarks.sh ) will include bookmarks from folders (id field) 2, 84, 85.

#!/bin/sh # Generate "Bookmarks from specified folders" OpenBox dynamic menu # path to the sqlite3 binary sqlite_path=`which sqlite3` # sqlite3 parameters (define separator character) sqlite_params="-separator ^" # path to the places.sqlite database bookmarks_database=`ls ~/.mozilla/firefox/*.default/places.sqlite` # folders folders="2,84,86" # SQL query sql_query="select b.title, p.url from moz_bookmarks as b left outer join moz_places as p on b.fk=p.id where p.hidden=0 and b.type = 1 and b.title is not null and p.hidden=0 and b.parent in (${folders})" # browser path browser_path=`which iceweasel` # header echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" echo "<openbox_pipe_menu>"; # execute and parse sql query $sqlite_path $sqlite_params "$bookmarks_database" "$sql_query" | while IFS=^ read title url; do # special case for empty title if [ -z "$title" ]; then title=$url fi # escape special characters title=$(echo $title | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") url=$(echo $url | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") # add missing apostrophes title="\"$title\"" #item echo "<item label=$title><action name=\"Execute\"><execute>$browser_path $url</execute></action></item>" done # footer echo "</openbox_pipe_menu>"

OpenBox XML menu configuration:

<menu execute="sh ~/bin/specified_bookmarks.sh" id="pipe-ff-specified-bookmarks" label="Personal bookmarks"/>

How to get unsorted bookmarks?

To get unsorted bookmarks use the following shell script ( sh ~/bin/unsorted_bookmarks.sh ) as you need to get contents from unfiled folder.

#!/bin/sh # Generate "Unsorted bookmarks" OpenBox dynamic menu # path to the sqlite3 binary sqlite_path=`which sqlite3` # sqlite3 parameters (define separator character) sqlite_params="-separator ^" # path to the places.sqlite database bookmarks_database=`ls ~/.mozilla/firefox/*.default/places.sqlite` # root folder - "unfiled" root_folder="select br.folder_id from moz_bookmarks_roots as br where br.root_name='unfiled'" # SQL query sql_query="select b.title, p.url from moz_bookmarks as b left outer join moz_places as p on b.fk=p.id where p.hidden=0 and b.type = 1 and b.title is not null and p.hidden=0 and b.parent=(${root_folder}) order by b.dateAdded limit 25" # browser path browser_path=`which iceweasel` # header echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" echo "<openbox_pipe_menu>"; # execute and parse sql query $sqlite_path $sqlite_params "$bookmarks_database" "$sql_query" | while IFS=^ read title url; do # special case for empty title if [ -z "$title" ]; then title=$url fi # escape special characters title=$(echo $title | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") url=$(echo $url | sed -e "s/&/\&/g" -e "s/\"/\"/g" -e "s/</\</g" -e "s/>/\>/g") # add missing apostrophes title="\"$title\"" #item echo "<item label=$title><action name=\"Execute\"><execute>$browser_path $url</execute></action></item>" done # footer echo "</openbox_pipe_menu>"

OpenBox XML menu configuration:

<menu execute="sh ~/bin/unsorted_bookmarks.sh" id="pipe-ff-most-popular" label="Most popular websites"/>

Notes

As you can see you can easily apply modifications to display additional data like parent name, used protocol, date related fields, or anything else you can compute.