170 lines
5.8 KiB
Bash
Executable File
170 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Unified asset updater — downloads all external data files used by the app.
|
|
# Usage: ./scripts/update-assets.sh [--group bangs|bridges|url-cleaner|url-shorteners] ...
|
|
# Without --group flags, all groups are updated.
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
MAX_RETRIES=3
|
|
RETRY_DELAY=5
|
|
CURL_TIMEOUT=30
|
|
|
|
# ── helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
log() { printf '[INFO] %s\n' "$*"; }
|
|
err() { printf '[ERROR] %s\n' "$*" >&2; }
|
|
|
|
# Fetch a URL to a local path with retries and atomic write.
|
|
# Uses a temp file so a failed download never clobbers an existing asset.
|
|
fetch() {
|
|
local url="$1" dest="$2"
|
|
local tmp="${dest}.tmp.$$"
|
|
|
|
mkdir -p "$(dirname "$dest")"
|
|
|
|
for attempt in $(seq 1 "$MAX_RETRIES"); do
|
|
log "Attempt $attempt/$MAX_RETRIES: $url"
|
|
if curl --proto '=https' --tlsv1.2 -fsSL \
|
|
--max-time "$CURL_TIMEOUT" \
|
|
--retry 0 \
|
|
-o "$tmp" "$url"; then
|
|
|
|
# Basic sanity: reject empty files
|
|
if [ ! -s "$tmp" ]; then
|
|
err "Downloaded file is empty: $url"
|
|
rm -f "$tmp"
|
|
return 1
|
|
fi
|
|
|
|
mv "$tmp" "$dest"
|
|
log "OK: $dest"
|
|
return 0
|
|
fi
|
|
|
|
err "Failed (attempt $attempt/$MAX_RETRIES): $url"
|
|
rm -f "$tmp"
|
|
[ "$attempt" -lt "$MAX_RETRIES" ] && sleep "$RETRY_DELAY"
|
|
done
|
|
|
|
err "Giving up after $MAX_RETRIES attempts: $url"
|
|
return 1
|
|
}
|
|
|
|
# ── asset groups ─────────────────────────────────────────────────────────────
|
|
|
|
update_bangs() {
|
|
local dir="$REPO_ROOT/apps/weblibre/assets/bangs"
|
|
log "Updating bangs..."
|
|
|
|
fetch "https://raw.githubusercontent.com/FaFre/bangs/main/data/bangs.json" \
|
|
"$dir/bangs.json"
|
|
fetch "https://raw.githubusercontent.com/FaFre/bangs/main/data/kagi_bangs.json" \
|
|
"$dir/kagi_bangs.json"
|
|
fetch "https://raw.githubusercontent.com/FaFre/bangs/refs/heads/custom/data/custom.json" \
|
|
"$dir/custom.json"
|
|
|
|
date -u --iso-8601=seconds > "$dir/last_sync.txt"
|
|
log "Bangs sync completed at $(cat "$dir/last_sync.txt")"
|
|
}
|
|
|
|
update_bridges() {
|
|
local dir="$REPO_ROOT/apps/weblibre/assets/preferences"
|
|
log "Updating Tor bridges..."
|
|
|
|
fetch "https://bridges.torproject.org/moat/circumvention/builtin" \
|
|
"$dir/builtin-bridges.json"
|
|
}
|
|
|
|
update_url_cleaner() {
|
|
local dir="$REPO_ROOT/apps/weblibre/assets/preferences"
|
|
log "Updating URL cleaner catalog..."
|
|
|
|
fetch "https://rules2.clearurls.xyz/data.minify.json" \
|
|
"$dir/url_cleaner_data.minify.json"
|
|
}
|
|
|
|
update_url_shorteners() {
|
|
local dir="$REPO_ROOT/apps/weblibre/assets/preferences"
|
|
log "Updating URL shortener list..."
|
|
|
|
fetch "https://raw.githubusercontent.com/MISP/misp-warninglists/refs/heads/main/lists/url-shortener/list.json" \
|
|
"$dir/url-shortener-list.json"
|
|
}
|
|
|
|
update_ublock() {
|
|
local dir="$REPO_ROOT/apps/weblibre/assets/ublock"
|
|
log "Updating uBlock Origin assets..."
|
|
|
|
fetch "https://raw.githubusercontent.com/gorhill/uBlock/master/assets/assets.json" \
|
|
"$dir/assets.json"
|
|
|
|
date -u --iso-8601=seconds > "$dir/last_sync.txt"
|
|
log "uBlock assets sync completed at $(cat "$dir/last_sync.txt")"
|
|
}
|
|
|
|
# Raw inputs for the popular-sites database. These are build-time only and are
|
|
# consumed by scripts/build_sites_db.py to produce assets/sites/sites.db. The
|
|
# raw/ directory is gitignored; only the compiled sites.db is committed.
|
|
update_popular_sites() {
|
|
local dir="$REPO_ROOT/apps/weblibre/assets/sites/raw"
|
|
log "Updating popular-sites source lists..."
|
|
|
|
# Tranco top-1M (manipulation-resistant aggregate ranking). The download
|
|
# endpoint 307-redirects to the latest list; fetch() follows redirects.
|
|
fetch "https://tranco-list.eu/top-1m.csv.zip" \
|
|
"$dir/tranco-top-1m.csv.zip"
|
|
|
|
# StevenBlack "gambling-porn-only": the porn + gambling category domains
|
|
# WITHOUT the unified malware/ad base list mixed in.
|
|
fetch "https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/gambling-porn-only/hosts" \
|
|
"$dir/stevenblack-gambling-porn.txt"
|
|
|
|
# Disconnect tracker list (basis of Firefox ETP). build_sites_db.py pulls
|
|
# only the Advertising/Analytics/FingerprintingInvasive/Cryptomining
|
|
# categories so first-party Social/Content sites are preserved.
|
|
fetch "https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/services.json" \
|
|
"$dir/disconnect-services.json"
|
|
|
|
date -u --iso-8601=seconds > "$dir/last_sync.txt"
|
|
log "Popular-sites sources sync completed at $(cat "$dir/last_sync.txt")"
|
|
}
|
|
|
|
# ── main ─────────────────────────────────────────────────────────────────────
|
|
|
|
ALL_GROUPS=(bangs bridges url-cleaner url-shorteners ublock popular-sites)
|
|
SELECTED_GROUPS=()
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--group) SELECTED_GROUPS+=("$2"); shift 2 ;;
|
|
*) err "Unknown option: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
if [ ${#SELECTED_GROUPS[@]} -eq 0 ]; then
|
|
SELECTED_GROUPS=("${ALL_GROUPS[@]}")
|
|
fi
|
|
|
|
FAILURES=0
|
|
|
|
for group in "${SELECTED_GROUPS[@]}"; do
|
|
case "$group" in
|
|
bangs) update_bangs || ((FAILURES++)) ;;
|
|
bridges) update_bridges || ((FAILURES++)) ;;
|
|
url-cleaner) update_url_cleaner || ((FAILURES++)) ;;
|
|
url-shorteners) update_url_shorteners || ((FAILURES++)) ;;
|
|
ublock) update_ublock || ((FAILURES++)) ;;
|
|
popular-sites) update_popular_sites || ((FAILURES++)) ;;
|
|
*) err "Unknown group: $group"; ((FAILURES++)) ;;
|
|
esac
|
|
done
|
|
|
|
if [ "$FAILURES" -gt 0 ]; then
|
|
err "$FAILURES group(s) failed"
|
|
exit 1
|
|
fi
|
|
|
|
log "All assets updated successfully."
|