#!/bin/bash # sync_from_upstream.sh - Merge upstream Flowseal changes into Linux version # Handles: proxy (HTTPS_PROXY), offline bundle, lists, .service/hosts, .service/version # Works even if GitHub blocked (with proxy or offline bundle) set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/lib/download_helper.sh" UPSTREAM_REPO="https://github.com/Flowseal/zapret-discord-youtube.git" TMP_DIR="/tmp/zapret-upstream-$$" LOCAL_VERSION_FILE="$SCRIPT_DIR/.service/version.txt" STRATEGIES_DIR="$SCRIPT_DIR/strategies" echo "" echo "==============================================" echo " Upstream Sync" echo " Source: $UPSTREAM_REPO" echo "==============================================" echo "" mkdir -p "$STRATEGIES_DIR" # Load proxy settings load_proxy # Detect if offline mode requested OFFLINE_MODE=0 if [[ "${1:-}" == "--offline" ]]; then OFFLINE_MODE=1 echo "[*] OFFLINE MODE: skipping network, using local files only" fi REBUILD_FLAG=0 UPDATE_COUNT=0 NEW_COUNT=0 # Attempt to clone/update upstream if [[ "$OFFLINE_MODE" -eq 0 ]]; then echo "[*] Cloning upstream (with fallback)..." if ! clone_repo_fallback "Flowseal/zapret-discord-youtube" "main" "$TMP_DIR"; then echo "" echo "[WARN] Cannot reach upstream GitHub." echo " Check proxy, VPN, or prepare_offline_bundle.sh" echo "" read -rp "Continue in offline mode (skip sync)? [Y/n]: " ans if [[ "${ans:-Y}" == [yY]* ]]; then OFFLINE_MODE=1 else exit 1 fi fi fi # Read versions LOCAL_VER=$(cat "$LOCAL_VERSION_FILE" 2>/dev/null | tr -d '[:space:]') UPSTREAM_VER=$(cat "$TMP_DIR/.service/version.txt" 2>/dev/null | tr -d '[:space:]') [[ -z "$LOCAL_VER" ]] && LOCAL_VER="unknown" [[ -z "$UPSTREAM_VER" ]] && UPSTREAM_VER="unknown" echo "Local version: $LOCAL_VER" echo "Upstream version: $UPSTREAM_VER" if [[ "$UPSTREAM_VER" != "$LOCAL_VER" ]]; then REBUILD_FLAG=1 echo "[*] Version changed: $LOCAL_VER → $UPSTREAM_VER" fi # ====================== # MERGE LISTS # ====================== echo "[*] Merging upstream lists..." merge_list() { local file="$1" local src="" if [[ -d "$TMP_DIR" ]] && [[ -f "$TMP_DIR/lists/$file" ]]; then src="$TMP_DIR/lists/$file" elif [[ -f "$SCRIPT_DIR/.bundle/$file" ]]; then src="$SCRIPT_DIR/.bundle/$file" echo " [CACHED] lists/$file (from offline bundle)" else echo " [SKIP] lists/$file (not available)" return fi cp "$src" "$SCRIPT_DIR/lists/$file" echo " [OK] lists/$file" } merge_list "list-general.txt" merge_list "list-google.txt" merge_list "list-exclude.txt" merge_list "ipset-exclude.txt" if [[ -f "$SCRIPT_DIR/.service/ipset_filter_loaded" ]] || [[ -f "$SCRIPT_DIR/.service/ipset_filter_any" ]]; then merge_list "ipset-all.txt" 2>/dev/null || true fi # ====================== # MERGE .service/hosts + version # ====================== echo "[*] Merging .service files..." if [[ -d "$TMP_DIR" ]] && [[ -f "$TMP_DIR/.service/hosts" ]]; then cp "$TMP_DIR/.service/hosts" "$SCRIPT_DIR/.service/hosts" echo " [OK] .service/hosts (GitHub, Telegram, Discord static IPs)" REBUILD_FLAG=1 elif [[ -f "$SCRIPT_DIR/.bundle/hosts" ]]; then cp "$SCRIPT_DIR/.bundle/hosts" "$SCRIPT_DIR/.service/hosts" echo " [OK] .service/hosts (from offline bundle)" REBUILD_FLAG=1 else echo " [SKIP] .service/hosts (not available)" fi if [[ -d "$TMP_DIR" ]] && [[ -f "$TMP_DIR/.service/version.txt" ]]; then echo "$UPSTREAM_VER-linux" > "$LOCAL_VERSION_FILE" echo " [OK] .service/version.txt → $UPSTREAM_VER-linux" REBUILD_FLAG=1 fi # ====================== # PARSE NEW .bat STRATEGIES → .conf # ====================== echo "[*] Checking for new upstream strategies..." parse_bat_to_conf() { local src="$1" local name_raw name_raw=$(basename "$src" .bat) local name name=$(echo "$name_raw" | sed -E 's/general[[:space:]]*//; s/\(|\)//g; s/^[[:space:]]+|[[:space:]]+$//g; s/ /_/g') [[ -z "$name" ]] && name="general" local conf_name="$STRATEGIES_DIR/${name}.conf" local raw_args # Join lines ending with ^, find winws.exe block raw_args=$(cat "$src" | tr '\n' ' ' | \ sed 's/\^/ /g' | \ sed -E 's/start[^"]*"[^"]*"[^"]*"[^"*]*"//i; s/ *\/min //i; s/\^//g') # Extract after winws.exe raw_args=$(echo "$raw_args" | sed -n 's/.*winws\.exe[^"]*"\?//pi') # Remove --wf-* (Windows-only) raw_args=$(echo "$raw_args" | sed -E 's/--wf-tcp=[^ "]+//g; s/--wf-udp=[^ "]+//g') # Normalize paths raw_args=$(echo "$raw_args" | sed 's|\\|/|g') raw_args=$(echo "$raw_args" | sed -E 's|"?%BIN%/|"%BIN%/|g; s|"?%LISTS%/|"%LISTS%/|g') # Replace vars raw_args=$(echo "$raw_args" | sed 's/%GameFilterTCP%/%GAME_TCP%/g; s/%GameFilterUDP%/%GAME_UDP%/g') # Split by --new into RULE1=... RULEN=... echo "# Strategy: $name" > "$conf_name" echo "# Auto-converted from upstream: $name_raw.bat" >> "$conf_name" echo "# Version: ${UPSTREAM_VER:-unknown}" >> "$conf_name" echo "" >> "$conf_name" local i=1 local rule while IFS= read -r rule; do rule=$(echo "$rule" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//') [[ -z "$rule" ]] && continue echo "RULE${i}=${rule}" >> "$conf_name" i=$((i + 1)) done <<< "$(echo "$raw_args" | awk 'BEGIN{RS="--new"; ORS="\n"}{print}')" } # Only scan if upstream cloned if [[ -d "$TMP_DIR" ]]; then for bat in "$TMP_DIR"/general*.bat; do [[ -f "$bat" ]] || continue bat_name=$(basename "$bat") [[ "$bat_name" == "service.bat" ]] && continue strategy_name=$(echo "$bat_name" | sed -E 's/^general[[:space:]]*//; s/\(|\)//g; s/\.bat$//; s/ /_/g') [[ -z "$strategy_name" ]] && strategy_name="general" conf_file="$STRATEGIES_DIR/${strategy_name}.conf" if [[ -f "$conf_file" ]]; then # Simple update: mark for manual review parse_bat_to_conf "$bat" UPDATE_COUNT=$((UPDATE_COUNT + 1)) echo " [CHANGED] Strategy updated: $bat_name → $strategy_name.conf" REBUILD_FLAG=1 else parse_bat_to_conf "$bat" NEW_COUNT=$((NEW_COUNT + 1)) echo " [NEW] Strategy detected: $bat_name → $strategy_name.conf" REBUILD_FLAG=1 fi done fi if [[ $NEW_COUNT -gt 0 ]]; then echo " [INFO] $NEW_COUNT new strategy(ies) auto-converted." echo " [WARN] Please verify new strategies manually before using." fi if [[ $UPDATE_COUNT -gt 0 ]]; then echo " [INFO] $UPDATE_COUNT strategy(ies) updated from upstream." fi if [[ $NEW_COUNT -eq 0 ]] && [[ $UPDATE_COUNT -eq 0 ]]; then echo " [OK] All strategies up to date." fi # Cleanup upstream clone rm -rf "$TMP_DIR" # ====================== # ENSURE WRAPPERS # ====================== echo "[*] Checking strategy wrappers (general*.sh)..." bash "$SCRIPT_DIR/ensure_wrappers.sh" 2>/dev/null || true # ====================== # REPORT # ====================== echo "[*] Sync complete." if [[ "$REBUILD_FLAG" -eq 1 ]]; then echo "[*] REBUILD NEEDED: run ./update.sh or ./install.sh" exit 2 else echo "[*] No changes detected." exit 0 fi