Replace bin/bookmarkmenu with bin/browsermenu
Handles both history and bookmarks. Also, rewritten in ruby.
This commit is contained in:
		
							parent
							
								
									d05afa7ee6
								
							
						
					
					
						commit
						c603422085
					
				|  | @ -1,60 +0,0 @@ | |||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| # Interactively select (in skim) an url from Firefox/Chrome/Chromium history to | ||||
| # open in your browser (depends on $BROWSER). Should work on Linux and MacOS. | ||||
| # | ||||
| # requires: sqlite3 | ||||
| 
 | ||||
| ROFI_CMD='rofi -dmenu -theme theme/bookmarkmenu.rasi -columns 1 -markup-rows -multi-select -p browser -i' | ||||
| SEP=${1:-'{{::}}'} | ||||
| 
 | ||||
| _do_rofi() { | ||||
|   urls=$(awk -F "$SEP" '{printf "<b>%s</b>: <i>%s</i>\n", $1, $2}' | $ROFI_CMD | sed -e 's#&#&#g' -e 's#<#<#g' -e 's#>#>#g') | ||||
|   IFS=$'\n' | ||||
|   for url in $urls; do | ||||
|     url=${url%</i>*} | ||||
|     url=${url##*<i>} | ||||
|     echo $url | ||||
|   done | xargs -r $BROWSER | ||||
| } | ||||
| 
 | ||||
| case ${BROWSER:-firefox} in | ||||
|   firefox) | ||||
|     for dir in ~/.mozilla/firefox/*.default \ | ||||
|                $XDG_CONFIG_HOME/firefox/.mozilla/firefox/*.default \ | ||||
|                $XDG_DATA_HOME/mozilla/firefox/*.default \ | ||||
|                ~/Library/Application\ Support/Firefox/Profiles/*.default; do | ||||
|       if [[ -d "$dir" ]]; then | ||||
|         # The db can be locked from time to time. This is inefficient, but | ||||
|         # places.sqlite is usually under 30mb so this should be instant, and | ||||
|         # /tmp is cleared at boot so... | ||||
|         # if ! find /tmp/rofi-bookmarkmenu -mmin +60 2>&1 >/dev/null; then | ||||
|           cp "$dir/places.sqlite" "/tmp/places.sqlite" | ||||
|           # sqlite3 -separator $SEP "/tmp/places.sqlite" \ | ||||
|           #   "SELECT DISTINCT title, url FROM moz_places \ | ||||
|           #   WHERE title IS NOT NULL \ | ||||
|           #   ORDER BY last_visit_date DESC" >/tmp/rofi-bookmarkmenu | ||||
|           sqlite3 -separator $SEP "/tmp/places.sqlite" \ | ||||
|             "SELECT DISTINCT mb.title, mp.url FROM moz_bookmarks mb \ | ||||
|             INNER JOIN moz_places mp ON mp.id = mb.fk \ | ||||
|             WHERE mb.type = 1 AND mb.title IS NOT NULL \ | ||||
|             ORDER BY mp.frecency DESC \ | ||||
|             LIMIT 200" >>/tmp/rofi-bookmarkmenu | ||||
|         # fi | ||||
|         cat /tmp/rofi-bookmarkmenu | sed -e 's#&#&#g' -e 's#<#<#g' -e 's#>#>#g' | _do_rofi | ||||
|         break | ||||
|       fi | ||||
|     done | ||||
|     ;; | ||||
|   qutebrowser) | ||||
|     { | ||||
|       sed -e 's/ /{{::}}/' urls | awk -F'{{::}}' '{printf "%s{{::}}%s\n", $2, $1}' | ||||
|       # sqlite3 -separator $SEP "$XDG_DATA_HOME/qutebrowser/history.sqlite" \ | ||||
|       #   "SELECT title, url FROM History \ | ||||
|       #   WHERE title != '' \ | ||||
|       #   GROUP BY url \ | ||||
|       #   ORDER BY atime DESC" | ||||
|     } | _do_rofi | ||||
|     ;; | ||||
|   *) rofi -e "No known browser" ;; | ||||
| esac | ||||
							
								
								
									
										137
									
								
								bin/rofi/browsermenu
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										137
									
								
								bin/rofi/browsermenu
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,137 @@ | |||
| #!/usr/bin/env cached-nix-shell | ||||
| #! nix-shell -p ruby rubyPackages.sqlite3 -i "ruby -S" --quiet | ||||
| 
 | ||||
| # Interactively select (in skim) an url from Firefox/Chrome/Chromium history to | ||||
| # open in your browser (depends on $BROWSER). Should work on Linux and MacOS. | ||||
| 
 | ||||
| require 'shellwords' | ||||
| require 'sqlite3' | ||||
| require 'json' | ||||
| require 'fileutils' | ||||
| require 'cgi' | ||||
| 
 | ||||
| def rofi items, *args | ||||
|   cmd = [*%w{rofi -dmenu -theme theme/bookmarkmenu.rasi -columns 1 -markup-rows -multi-select -p browser -i}, *args] | ||||
|   IO.popen(cmd.compact.shelljoin, "r+") do |pipe| | ||||
|     pipe.puts items.keys.join "\n" | ||||
|     pipe.close_write | ||||
|     (pipe.gets || "").split "\n" | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| def db file, command | ||||
|   copy = "/tmp/browsermenu-db-#{File.basename(file)}" | ||||
|   begin | ||||
|     # Copy the sqlite database because history/bookmark info is usually small | ||||
|     # and may be locked by an open browser. | ||||
|     unless File.exists? copy | ||||
|       FileUtils.cp file, copy | ||||
|       FileUtils.chmod 0400, copy, verbose: true | ||||
|     end | ||||
|     results = [] | ||||
|     db = SQLite3::Database.open copy | ||||
|     db.execute(command).each { |r| results.push r } | ||||
|     results | ||||
|   ensure | ||||
|     File.delete copy | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| def walk_json children | ||||
|   result = [] | ||||
|   for c in children | ||||
|     if c['children'] | ||||
|       result += walk_json c['children'] | ||||
|     else | ||||
|       result.push [ c['name'], c['url'] ] | ||||
|     end | ||||
|   end | ||||
|   result | ||||
| end | ||||
| 
 | ||||
| def get_bookmarks browser | ||||
|   bookmarks = [] | ||||
|   case browser | ||||
|   when :firefox | ||||
|     # In my nixos dotfiles I hardcode the default profile to $USER.profile, | ||||
|     # which makes this lookup easier, but means this script won't work on any | ||||
|     # other system. | ||||
|     user = ENV['USER'] | ||||
|     ["#{ENV['HOME']}/.mozilla/firefox/#{user}.default", | ||||
|      "#{ENV['XDG_CONFIG_HOME']}/firefox/.mozilla/firefox/#{user}.default", | ||||
|      "#{ENV['XDG_DATA_HOME']}/mozilla/firefox/#{user}.default"].each do |dir| | ||||
|       if Dir.exists? dir | ||||
|         db "#{dir}/places.sqlite", | ||||
|            ["SELECT DISTINCT mb.title, mp.url FROM moz_bookmarks mb", | ||||
|             "INNER JOIN moz_places mp ON mp.id = mb.fk", | ||||
|             "WHERE mb.type = 1 AND mb.title IS NOT NULL", | ||||
|             "ORDER BY mp.frecency DESC", | ||||
|             "LIMIT 200"].join(' ') | ||||
|       end | ||||
|     end | ||||
|   when :brave | ||||
|     f = File.read "#{ENV['XDG_CONFIG_HOME']}/BraveSoftware/Brave-Browser/Default/Bookmarks" | ||||
|     data = JSON.parse f | ||||
|     walk_json data["roots"]["bookmark_bar"]["children"] | ||||
|   when :qutebrowser | ||||
|     bookmarks = File.readlines "#{ENV['XDG_CONFIG_HOME']}/qutebrowser/bookmarks/urls" | ||||
|     bookmarks.map { |s| s.strip.split(' ', 2).reverse } | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| def get_history browser | ||||
|   case browser | ||||
|   when :firefox | ||||
|     # In my nixos dotfiles I hardcode the default profile to $USER.profile, | ||||
|     # which makes this lookup easier, but means this script won't work on any | ||||
|     # other system. | ||||
|     user = ENV['USER'] | ||||
|     ["#{ENV['HOME']}/.mozilla/firefox/#{user}.default", | ||||
|      "#{ENV['XDG_CONFIG_HOME']}/firefox/.mozilla/firefox/#{user}.default", | ||||
|      "#{ENV['XDG_DATA_HOME']}/mozilla/firefox/#{user}.default"].each do |dir| | ||||
|       if Dir.exists? dir | ||||
|         return db "#{dir}/places.sqlite", | ||||
|                   ["SELECT title, url", | ||||
|                    "FROM moz_places", | ||||
|                    "WHERE title<>''", | ||||
|                    "ORDER BY last_visit_date DESC"].join(' ') | ||||
|       end | ||||
|     end | ||||
|     return [] | ||||
|   when :brave | ||||
|     db "#{ENV['XDG_CONFIG_HOME']}/BraveSoftware/Brave-Browser/Default/History", | ||||
|        "SELECT title, url FROM urls GROUP BY url ORDER BY last_visit_time DESC LIMIT 200" | ||||
|   when :qutebrowser | ||||
|     db "#{ENV['XDG_DATA_HOME']}/qutebrowser/history.sqlite", | ||||
|        ["SELECT title, url FROM History", | ||||
|         "WHERE title != ''", | ||||
|         "GROUP BY url", | ||||
|         "ORDER BY atime DESC"].join(' ') | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| def list urls | ||||
|   items = urls.map do |x| | ||||
|     x.map! { |x| CGI.escapeHTML x } | ||||
|     [x[0].empty? ? | ||||
|        "<b>#{x[1]}</b>" : | ||||
|        "<b>#{x[0]}</b> <span size=\"x-small\">#{x[1]}</span>", | ||||
|      x[1]] | ||||
|   end.to_h | ||||
|   selected = rofi items | ||||
|   selected.map { |key| items[key] } | ||||
| end | ||||
| 
 | ||||
| type, browser = *ARGV | ||||
| browser = (browser || ENV['BROWSER']).to_sym | ||||
| urls = if type == 'history' | ||||
|   get_history browser | ||||
| else | ||||
|   get_bookmarks browser | ||||
| end | ||||
| urls = list urls | ||||
| if urls.empty? | ||||
|   puts "No URL selected. Aborting..." | ||||
|   exit 1 | ||||
| end | ||||
| Process.detach fork { exec ENV['BROWSER'], *urls } | ||||
|  | @ -34,10 +34,16 @@ in { | |||
| 
 | ||||
|       # Fake rofi dmenu entries | ||||
|       (makeDesktopItem { | ||||
|         name = "rofi-bookmarkmenu"; | ||||
|         name = "rofi-browsermenu"; | ||||
|         desktopName = "Open Bookmark in Browser"; | ||||
|         icon = "bookmark-new-symbolic"; | ||||
|         exec = "${binDir}/rofi/bookmarkmenu"; | ||||
|         exec = "${binDir}/rofi/browsermenu"; | ||||
|       }) | ||||
|       (makeDesktopItem { | ||||
|         name = "rofi-browsermenu-history"; | ||||
|         desktopName = "Open Browser History"; | ||||
|         icon = "accessories-clock"; | ||||
|         exec = "${binDir}/rofi/browsermenu history"; | ||||
|       }) | ||||
|       (makeDesktopItem { | ||||
|         name = "rofi-filemenu"; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue