#!/usr/bin/env bash # Fetch and convert browser launcher icons into assets/browser-icons/.png # at 96x96. Uses Wikimedia's Special:FilePath redirector for canonical lookup. # Anything we can't fetch is left unwritten — the app falls back to the # in-app colored swatch for that browser. set -uo pipefail cd "$(dirname "$0")/.." out=assets/browser-icons mkdir -p "$out" UA="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" # id|filename-on-commons-or-en-wikipedia|origin-host entries=( "firefox|Firefox_logo,_2019.svg|commons" "firefox-nightly|Firefox_Nightly_logo,_2017.svg|commons" "chrome|Google_Chrome_icon_(February_2022).svg|commons" "brave|Brave_lion_icon.svg|commons" "tor|Tor-logo-2011-flat.svg|commons" "ddg|The_DuckDuckGo_Duck.png|en" ) # Direct-URL sources for niche browsers Wikimedia doesn't host. direct=( "ironfox|https://ironfoxoss.org/ironfox.png" "vanadium|https://grapheneos.org/apple-touch-icon.png" ) for entry in "${entries[@]}"; do IFS='|' read -r id file host <<<"$entry" case $host in commons) url="https://commons.wikimedia.org/wiki/Special:FilePath/$file" ;; en) url="https://en.wikipedia.org/wiki/Special:FilePath/$file" ;; esac tmp=$(mktemp -t bf-icon).${file##*.} if curl -fsSL -A "$UA" -o "$tmp" "$url"; then ok=0 if [[ ${file##*.} == svg ]] && command -v rsvg-convert >/dev/null; then rsvg-convert -w 96 -h 96 "$tmp" -o "$out/$id.png" 2>/dev/null && ok=1 fi if [ $ok -eq 0 ]; then magick "$tmp" -resize 96x96 -background none -gravity center -extent 96x96 "$out/$id.png" 2>/dev/null && ok=1 fi [ $ok -eq 1 ] && echo "ok($id)" || echo "convert-fail($id)" else echo "fetch-fail($id)" fi rm -f "$tmp" sleep 1 done # ─── Direct-URL sources for niche browsers ────────────────────────────── for entry in "${direct[@]}"; do IFS='|' read -r id url <<<"$entry" if [ -f "$out/$id.png" ]; then echo "skip($id) — already have"; continue; fi tmp=$(mktemp -t bf-icon).png if curl -fsSL -A "$UA" -o "$tmp" "$url"; then magick "$tmp" -resize 96x96 -background none -gravity center -extent 96x96 "$out/$id.png" 2>/dev/null \ && echo "direct($id) ← $url" || echo "convert-fail($id)" else echo "fetch-fail($id) ← $url" fi rm -f "$tmp" sleep 1 done # Firefox Beta has no canonical public icon distinct from Firefox release. # Copy the Firefox icon so the row still gets a brand-correct logo. if [ -f "$out/firefox.png" ] && [ ! -f "$out/firefox-beta.png" ]; then cp "$out/firefox.png" "$out/firefox-beta.png" && echo "alias(firefox-beta ← firefox)" fi # ─── Fallback: scrape privacytests.org/android ─────────────────────────── # Their browser-logo-image tags carry base64 PNG data URIs that map # cleanly to several of our ids — and crucially include Firefox Focus, which # Wikimedia doesn't host. We only fill in ids we don't already have. echo echo "Filling gaps from privacytests.org/android…" pt=$(mktemp -t pt-android).html if curl -fsSL -A "$UA" -o "$pt" "https://privacytests.org/android"; then python3 - "$pt" "$out" <<'PY' import re, base64, pathlib, sys html_path, out_dir = sys.argv[1], pathlib.Path(sys.argv[2]) html = pathlib.Path(html_path).read_text() # privacytests name -> our browser id m = {'brave': 'brave', 'chrome': 'chrome', 'duckduckgo': 'ddg', 'firefox': 'firefox', 'focus': 'focus', 'tor': 'tor'} hits = re.findall( r'(\w+) logo/dev/null | wc -l | tr -d ' ') icons to $out/"