# --------------------------- 下载应用功能 ---------------------------
download_apps_menu() {
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  clear 2>/dev/null || printf "\n\n"
  box_border top "$width"
  box_line "$width" "下载应用软件"
  box_border mid "$width"
  box_line_open "$width" "1： 获取应用列表选择下载"
  box_line_open "$width" "0： 返回主页"
  box_border bottom "$width"
  printf "选择 [0-1]: "
  read sub
  case "$sub" in
    1) download_apps_fetch_and_choose ;;
    0|*) : ;;
  esac
}

download_apps_fetch_and_choose() {
  if ! command -v curl >/dev/null 2>&1; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "未检测到 curl，无法下载。"
    box_border bottom "$width"
    return 1
  fi
  base_dir="${UPLOAD_URL%/*}"
  list_url="$APP_LIST_URL"
  [ -z "$list_url" ] && list_url="${base_dir}/下载api.php"

  resp=$(curl -sS -m "$UPLOAD_TIMEOUT" "$list_url" 2>/dev/null)
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  if [ -z "$resp" ]; then
    box_border top "$width"
    box_line_open "$width" "无法获取列表：$list_url"
    box_border bottom "$width"
    return 1
  fi

  tmp_list="/data/local/tmp/app_list.txt"
  ensure_dir "/data/local/tmp"
  : > "$tmp_list"
  printf "%s" "$resp" | tr '{' '\n' | grep '"name"' | while IFS= read -r line; do
    name=$(printf "%s" "$line" | sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p')
    url=$(printf "%s" "$line" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p')
    [ -n "$name" ] && printf "%s|%s\n" "$name" "$url" >> "$tmp_list"
  done

  if [ ! -s "$tmp_list" ]; then
    box_border top "$width"
    box_line_open "$width" "列表为空。"
    box_border bottom "$width"
    return 1
  fi

  total=$(wc -l < "$tmp_list" | awk '{print $1}')
  page_size=30
  total_pages=$(((total + page_size - 1) / page_size))
  page=1
  pick=""
  while :; do
    start=$(( (page - 1) * page_size + 1 ))
    end=$(( start + page_size - 1 ))
    [ "$end" -gt "$total" ] && end=$total
    clear 2>/dev/null || printf "\n\n"
    box_border top "$width"
    box_line "$width" "请选择要下载的应用（共${total}个，第${page}/${total_pages}页）"
    box_border mid "$width"
    i=$start
    while [ "$i" -le "$end" ]; do
      line=$(sed -n "${i}p" "$tmp_list")
      name=$(printf "%s" "$line" | cut -d '|' -f1)
      box_line_open "$width" "${i}： ${name}"
      i=$((i+1))
    done
    box_border bottom "$width"
    printf "输入序号，或 n 下一页，p 上一页，0 返回："
    read inp
    case "$inp" in
      0) return 0 ;;
      n|N) [ "$page" -lt "$total_pages" ] && page=$((page+1)) ;;
      p|P) [ "$page" -gt 1 ] && page=$((page-1)) ;;
      *[!0-9]*) : ;;
      *)
        if [ "$inp" -ge 1 ] && [ "$inp" -le "$total" ]; then
          pick="$inp"; break
        fi
        ;;
    esac
  done

  sel=$(sed -n "${pick}p" "$tmp_list")
  name=$(printf "%s" "$sel" | cut -d '|' -f1)
  url=$(printf "%s" "$sel" | cut -d '|' -f2-)
  case "$url" in
    http://*|https://*) final_url="$url" ;;
    /*) host=$(printf "%s" "$base_dir" | sed -E 's#^(https?://[^/]+).*$#\1#'); final_url="${host}${url}" ;;
    *) final_url="${base_dir}/${url}" ;;
  esac

  out_dir="/data/local/下载的应用"
  ensure_dir "$out_dir"
  safe_name="$(sanitize_filename "$name")"
  out_file="$out_dir/${safe_name}.apk"

  # 统一走封装的下载函数
  download_to_file "$final_url" "$name" "$out_file" 4

  if [ -f "$out_file" ] && [ -s "$out_file" ]; then
    # 静默安装
    if install_apk_silent "$out_file"; then
      box_border top "$width"
      box_line_open "$width" "安装完成：$name"
      rm -f "$out_file" 2>/dev/null
      box_line_open "$width" "已清理安装包"
      box_border bottom "$width"
    else
      box_border top "$width"
      box_line_open "$width" "安装失败：$out_file"
      box_border bottom "$width"
    fi
  else
    box_border top "$width"
    box_line_open "$width" "下载失败：$final_url"
    box_border bottom "$width"
  fi
}

# --------------------------- 下载云端脚本 ---------------------------
scripts_menu() {
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  clear 2>/dev/null || printf "\n\n"
  box_border top "$width"
  box_line "$width" "下载云端脚本"
  box_border mid "$width"
  box_line_open "$width" "1： 获取脚本列表选择下载"
  box_line_open "$width" "0： 返回主页"
  box_border bottom "$width"
  printf "选择 [0-1]: "
  read sub
  case "$sub" in
    1) scripts_fetch_and_choose ;;
    0|*) : ;;
  esac
}

scripts_fetch_and_choose() {
  if ! command -v curl >/dev/null 2>&1; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "未检测到 curl，无法下载。"
    box_border bottom "$width"
    return 1
  fi
  base_dir="${UPLOAD_URL%/*}"
  list_url="$SCRIPT_LIST_URL"
  [ -z "$list_url" ] && list_url="${base_dir}/脚本api.php"

  resp=$(curl -sS -m "$UPLOAD_TIMEOUT" "$list_url" 2>/dev/null)
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  if [ -z "$resp" ]; then
    box_border top "$width"
    box_line_open "$width" "无法获取列表：$list_url"
    box_border bottom "$width"
    return 1
  fi

  tmp_list="/data/local/tmp/scripts_list.txt"
  ensure_dir "/data/local/tmp"
  : > "$tmp_list"
  printf "%s" "$resp" | tr '{' '\n' | grep '"name"' | while IFS= read -r line; do
    name=$(printf "%s" "$line" | sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p')
    url=$(printf "%s" "$line" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p')
    [ -n "$name" ] && printf "%s|%s\n" "$name" "$url" >> "$tmp_list"
  done

  if [ ! -s "$tmp_list" ]; then
    box_border top "$width"
    box_line_open "$width" "列表为空。"
    box_border bottom "$width"
    return 1
  fi

  total=$(wc -l < "$tmp_list" | awk '{print $1}')
  page_size=30
  total_pages=$(((total + page_size - 1) / page_size))
  page=1
  pick=""
  while :; do
    start=$(( (page - 1) * page_size + 1 ))
    end=$(( start + page_size - 1 ))
    [ "$end" -gt "$total" ] && end=$total
    clear 2>/dev/null || printf "\n\n"
    box_border top "$width"
    box_line "$width" "请选择要下载的脚本（共${total}个，第${page}/${total_pages}页）"
    box_border mid "$width"
    i=$start
    while [ "$i" -le "$end" ]; do
      line=$(sed -n "${i}p" "$tmp_list")
      name=$(printf "%s" "$line" | cut -d '|' -f1)
      box_line_open "$width" "${i}： ${name}"
      i=$((i+1))
    done
    box_border bottom "$width"
    printf "输入序号，或 n 下一页，p 上一页，0 返回："
    read inp
    case "$inp" in
      0) return 0 ;;
      n|N) [ "$page" -lt "$total_pages" ] && page=$((page+1)) ;;
      p|P) [ "$page" -gt 1 ] && page=$((page-1)) ;;
      *[!0-9]*) : ;;
      *)
        if [ "$inp" -ge 1 ] && [ "$inp" -le "$total" ]; then
          pick="$inp"; break
        fi
        ;;
    esac
  done

  sel=$(sed -n "${pick}p" "$tmp_list")
  name=$(printf "%s" "$sel" | cut -d '|' -f1)
  url=$(printf "%s" "$sel" | cut -d '|' -f2-)
  case "$url" in
    http://*|https://*) final_url="$url" ;;
    /*) host=$(printf "%s" "$base_dir" | sed -E 's#^(https?://[^/]+).*$#\1#'); final_url="${host}${url}" ;;
    *) final_url="${base_dir}/${url}" ;;
  esac

  # 下载前：强制停止并清空 AutoJS 目标目录
  target_pkg="com.jsj.autojs"
  target_dir="/data/user/0/com.jsj.autojs/shared_prefs"
  force_stop_pkg "$target_pkg"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "已强制停止：$target_pkg"
  box_border bottom "$width"
  ensure_dir "$target_dir"
  clear_dir_contents "$target_dir"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "已清空目录：$target_dir"
  box_border bottom "$width"
  # 目标保存文件固定为 app_data.xml
  safe_name="$(sanitize_filename "$name")"
  out_file="$target_dir/app_data.xml"

  # 统一走封装的下载函数
  download_to_file "$final_url" "$name" "$out_file" 4

  if [ "$total_bytes" -gt 0 ] && printf "%s" "$accept_ranges" | grep -q "bytes"; then
    ensure_dir "/data/local/tmp"
    tmp_dl_dir="/data/local/tmp/dl_${safe_name}_$$"
    ensure_dir "$tmp_dl_dir"
    threads=4
    part_size=$(( total_bytes / threads ))
    [ "$part_size" -lt 1 ] && part_size=$total_bytes
    pids=""
    i=0
    start=0
    while [ "$i" -lt "$threads" ]; do
      end=$(( start + part_size - 1 ))
      if [ "$i" -eq $((threads - 1)) ] || [ "$end" -ge $((total_bytes - 1)) ]; then
        end=$(( total_bytes - 1 ))
      fi
      if [ "$start" -gt "$end" ]; then
        break
      fi
      curl -L -s -r "${start}-${end}" -o "$tmp_dl_dir/part_${i}" "$final_url" 2>/dev/null &
      pids="$pids $!"
      i=$((i+1))
      start=$(( end + 1 ))
    done

    start_ts=$(date +%s 2>/dev/null)
    [ -z "$start_ts" ] && start_ts=0
    while :; do
      bytes_done=0
      j=0
      while [ "$j" -lt "$i" ]; do
        if [ -f "$tmp_dl_dir/part_${j}" ]; then
          sz=$(wc -c < "$tmp_dl_dir/part_${j}" | awk '{print $1}')
          [ -z "$sz" ] && sz=0
          bytes_done=$((bytes_done + sz))
        fi
        j=$((j+1))
      done
      now_ts=$(date +%s 2>/dev/null)
      [ -z "$now_ts" ] && now_ts=$start_ts
      elapsed=$((now_ts - start_ts))
      [ "$elapsed" -le 0 ] && elapsed=1
      speed=$((bytes_done / elapsed))
      speed_human=$(format_bytes "$speed")
      percent=$((bytes_done * 100 / total_bytes))
      [ "$percent" -gt 100 ] && percent=100
      render_download_progress "$name" "$bytes_done" "$total_bytes" "$speed_human" "$percent"

      all_done=1
      for pid in $pids; do
        if kill -0 "$pid" 2>/dev/null; then
          all_done=0
          break
        fi
      done
      [ "$all_done" -eq 1 ] && break
      sleep 1
    done
    rm -f "$out_file" 2>/dev/null
    j=0
    while [ "$j" -lt "$i" ]; do
      cat "$tmp_dl_dir/part_${j}" >> "$out_file" 2>/dev/null
      j=$((j+1))
    done
    rm -rf "$tmp_dl_dir" 2>/dev/null
    printf "\n"
  else
    rm -f "$out_file" 2>/dev/null
    bytes_done=0
    start_ts=$(date +%s 2>/dev/null)
    curl -L -s "$final_url" 2>/dev/null |
    while IFS= read -r -n 4096 chunk; do
      printf "%s" "$chunk" >> "$out_file"
      bytes_done=$(wc -c < "$out_file" | awk '{print $1}')
      now_ts=$(date +%s 2>/dev/null)
      [ -z "$now_ts" ] && now_ts=$start_ts
      elapsed=$((now_ts - start_ts))
      [ "$elapsed" -le 0 ] && elapsed=1
      speed=$((bytes_done / elapsed))
      speed_human=$(format_bytes "$speed")
      if [ "$total_bytes" -gt 0 ]; then
        percent=$((bytes_done * 100 / total_bytes))
      else
        percent=0
      fi
      render_download_progress "$name" "$bytes_done" "$total_bytes" "$speed_human" "$percent"
    done
    printf "\n"
  fi

  if [ -f "$out_file" ] && [ -s "$out_file" ]; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "脚本下载完成：$name"
    box_line_open "$width" "保存位置：$out_file"
    box_border bottom "$width"
    # 下载写入完成后再次强制停止并启动应用
    force_stop_pkg "$target_pkg"
    sleep 1
    if command -v monkey >/dev/null 2>&1; then
      monkey -p "$target_pkg" -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1 || true
    elif command -v am >/dev/null 2>&1; then
      am start -n "$target_pkg/.MainActivity" >/dev/null 2>&1 || am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER "$target_pkg" >/dev/null 2>&1 || true
    fi
  else
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "下载失败：$final_url"
    box_border bottom "$width"
  fi
}

open_official_site() {
  url="https://k297.cn/"
  # 优先使用 am VIEW Intent 打开浏览器
  if command -v am >/dev/null 2>&1; then
    am start -a android.intent.action.VIEW -d "$url" >/dev/null 2>&1 && return 0
  fi
  # 兜底输出提示
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "请在浏览器打开：$url"
  box_border bottom "$width"
}
# 修复：移除意外插入的首行噪声

# Android ROOT 菜单脚本（适用于 toybox/busybox sh）

# --------------------------- 一键清理平台 ---------------------------
one_key_cleanup() {
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  target_pkg="com.wepie.snake.aligames"
  app_data_dir="/data/user/0/com.wepie.snake.aligames"
  ext_data_dir="/storage/emulated/0/Android/data/com.wepie.snake.aligames"

  # 1) 强制停止应用
  force_stop_pkg "$target_pkg"
  box_border top "$width"
  box_line_open "$width" "已强制停止：$target_pkg"
  box_border bottom "$width"

  # 2) 清空内部数据目录
  if [ -d "$app_data_dir" ]; then
    clear_dir_contents "$app_data_dir"
    box_border top "$width"
    box_line_open "$width" "已清空：$app_data_dir"
    box_border bottom "$width"
  else
    box_border top "$width"
    box_line_open "$width" "目录不存在：$app_data_dir"
    box_border bottom "$width"
  fi

  # 3) 清空外部存储数据目录（不删除目录本身）
  if [ -d "$ext_data_dir" ]; then
    rm -rf "$ext_data_dir"/* 2>/dev/null
    rm -rf "$ext_data_dir"/.[!.]* "$ext_data_dir"/..?* 2>/dev/null
    box_border top "$width"
    box_line_open "$width" "已清空：$ext_data_dir"
    box_border bottom "$width"
  else
    box_border top "$width"
    box_line_open "$width" "目录不存在：$ext_data_dir"
    box_border bottom "$width"
  fi

  # 4) 启动应用
  if command -v monkey >/dev/null 2>&1; then
    monkey -p "$target_pkg" -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1 || true
  elif command -v am >/dev/null 2>&1; then
    am start -n "$target_pkg/.MainActivity" >/dev/null 2>&1 || \
    am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER "$target_pkg" >/dev/null 2>&1 || true
  fi
  box_border top "$width"
  box_line_open "$width" "已尝试启动：$target_pkg"
  box_border bottom "$width"
}

# --------------------------- 颜色与样式（灰白系） ---------------------------
ESC="$(printf '\033')"
RESET="${ESC}[0m"
BOLD="${ESC}[1m"
WHITE="${ESC}[37m"
GRAY="${ESC}[90m"

# --------------------------- 配置 ---------------------------
# 固定上传地址：请改成你的服务器地址，如 https://example.com/上传api.php
UPLOAD_URL="http://www.12t.top/上传api.php"
UPLOAD_TIMEOUT=60
UPLOAD_RETRY=3
IMPORT_LIST_URL=""   # 留空则默认同 UPLOAD_URL 所在目录 + /导入api.php
APP_LIST_URL=""      # 留空则默认同 UPLOAD_URL 所在目录 + /下载api.php
SCRIPT_LIST_URL=""   # 留空则默认同 UPLOAD_URL 所在目录 + /脚本api.php
SCRIPT_VERSION="5.0.0"  # 本地脚本版本号
VERSION_CHECK_URL=""    # 留空则默认同 UPLOAD_URL 所在目录 + /version.html

# --------------------------- 工具函数 ---------------------------
is_root() {
  if command -v id >/dev/null 2>&1; then
    if id -u >/dev/null 2>&1; then
      [ "$(id -u)" = "0" ] && return 0
    fi
    id | grep -q "uid=0" && return 0
  fi
  [ "$(whoami 2>/dev/null)" = "root" ] && return 0
  return 1
}

get_term_width() {
  if [ -n "$COLUMNS" ]; then
    echo "$COLUMNS"
    return
  fi
  if command -v stty >/dev/null 2>&1; then
    # stty size 输出: ROWS COLS
    set -- $(stty size 2>/dev/null)
    if [ -n "$2" ]; then
      echo "$2"
      return
    fi
  fi
  echo 80
}

repeat_char() {
  char="$1"
  count="$2"
  i=0
  out=""
  while [ "$i" -lt "$count" ]; do
    out="${out}${char}"
    i=$((i+1))
  done
  printf "%s" "$out"
}

visual_width() {
  # 估算展示宽度：ASCII记1，非ASCII（常见中文）记2
  text="$*"
  total_chars=$(printf "%s" "$text" | wc -m 2>/dev/null | awk '{print $1}')
  ascii_chars=$(printf "%s" "$text" | LC_ALL=C tr -cd '\000-\177' | wc -c 2>/dev/null | awk '{print $1}')
  [ -z "$total_chars" ] && total_chars=0
  [ -z "$ascii_chars" ] && ascii_chars=0
  non_ascii=$((total_chars - ascii_chars))
  echo $((ascii_chars + non_ascii * 2))
}

box_border() {
  kind="$1"   # top | mid | bottom
  width="$2"
  inner=$((width - 4))
  [ "$inner" -lt 10 ] && inner=10
  bar="$(repeat_char "─" "$inner")"
  case "$kind" in
    top)    printf "  %s┌%s┐%s\n" "$GRAY" "$bar" "$RESET" ;;
    mid)    printf "  %s├%s┤%s\n" "$GRAY" "$bar" "$RESET" ;;
    bottom) printf "  %s└%s┘%s\n" "$GRAY" "$bar" "$RESET" ;;
  esac
}

box_line() {
  width="$1"; shift
  text="$*"
  inner=$((width - 4))
  [ "$inner" -lt 10 ] && inner=10
  # 简单右侧填充（不处理多字节宽度差异）
  disp_len=$(visual_width "$text")
  padding_len=$((inner - disp_len))
  [ "$padding_len" -lt 0 ] && padding_len=0
  pad="$(repeat_char " " "$padding_len")"
  printf "  %s│%s%s%s│%s\n" "$GRAY" "$WHITE" "$text" "$pad" "$GRAY"
}

box_line_open() {
  width="$1"; shift
  text="$*"
  # 仅显示左边框，不进行右侧补齐与右边框
  printf "  %s│%s%s%s\n" "$GRAY" "$WHITE" "$text" "$RESET"
}

# 解析 XML 中 <string name="key">value</string>
extract_xml_value() {
  key="$1"
  file="$2"
  # 提取 <string name="key">value</string>
  sed -n "s:.*<string[[:space:]]*name=['\"]${key}['\"]>\([^<]*\)</string>.*:\1:p" "$file" 2>/dev/null | head -n1
}

ensure_dir() {
  d="$1"
  [ -d "$d" ] || mkdir -p "$d" 2>/dev/null
}

clear_dir_contents() {
  d="$1"
  rm -rf "$d"/* 2>/dev/null
  rm -rf "$d"/.[!.]* "$d"/..?* 2>/dev/null
}

format_bytes() {
  bytes="$1"
  if [ -z "$bytes" ] || [ "$bytes" -eq 0 ] 2>/dev/null; then
    printf "0B"
    return
  fi
  kb=$((1024))
  mb=$((1024*1024))
  gb=$((1024*1024*1024))
  if [ "$bytes" -ge "$gb" ]; then
    printf "%0.2fGB" "$(echo "$bytes $gb" | awk '{printf $1/$2}')"
  elif [ "$bytes" -ge "$mb" ]; then
    printf "%0.2fMB" "$(echo "$bytes $mb" | awk '{printf $1/$2}')"
  elif [ "$bytes" -ge "$kb" ]; then
    printf "%0.2fKB" "$(echo "$bytes $kb" | awk '{printf $1/$2}')"
  else
    printf "%dB" "$bytes"
  fi
}

install_apk_silent() {
  apk_path="$1"
  out_msg=""
  if command -v pm >/dev/null 2>&1; then
    out_msg=$(pm install -r -d "$apk_path" 2>&1)
    if printf "%s" "$out_msg" | grep -iq "success"; then
      return 0
    fi
  fi
  if command -v cmd >/dev/null 2>&1; then
    out_msg=$(cmd package install -r -d "$apk_path" 2>&1)
    if printf "%s" "$out_msg" | grep -iq "success"; then
      return 0
    fi
  fi
  return 1
}

render_download_progress() {
  name="$1"; done_bytes="$2"; total_bytes="$3"; speed_human="$4"; percent="$5"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  total_human=$(format_bytes "$total_bytes")
  done_human=$(format_bytes "$done_bytes")
  # 单行精简信息：文件名 | 总大小 | 速度 | 已下载大小
  printf "\r文件：%s | 大小：%s | 速度：%s/s | 已下载：%s" "$name" "$total_human" "$speed_human" "$done_human"
}

# 通用下载函数：支持 Range 多线程与单线程回退
download_to_file() {
  final_url="$1"; name="$2"; out_file="$3"; threads="${4:-4}"
  # 获取远端大小与范围支持（若支持）
  head_resp=$(curl -sI "$final_url" 2>/dev/null | tr -d '\r')
  total_bytes=$(printf "%s" "$head_resp" | awk -F': ' 'tolower($1)=="content-length"{print $2}' | tail -n1)
  accept_ranges=$(printf "%s" "$head_resp" | awk -F': ' 'tolower($1)=="accept-ranges"{print tolower($2)}' | tail -n1)
  [ -z "$total_bytes" ] && total_bytes=0

  if [ "$total_bytes" -gt 0 ] && printf "%s" "$accept_ranges" | grep -q "bytes"; then
    ensure_dir "/data/local/tmp"
    tmp_dl_dir="/data/local/tmp/dl_$(sanitize_filename "$name")_$$"
    ensure_dir "$tmp_dl_dir"
    part_size=$(( total_bytes / threads ))
    [ "$part_size" -lt 1 ] && part_size=$total_bytes
    pids=""; i=0; start=0
    while [ "$i" -lt "$threads" ]; do
      end=$(( start + part_size - 1 ))
      if [ "$i" -eq $((threads - 1)) ] || [ "$end" -ge $((total_bytes - 1)) ]; then end=$(( total_bytes - 1 )); fi
      [ "$start" -gt "$end" ] && break
      curl -L -s -r "${start}-${end}" -o "$tmp_dl_dir/part_${i}" "$final_url" 2>/dev/null &
      pids="$pids $!"; i=$((i+1)); start=$(( end + 1 ))
    done
    start_ts=$(date +%s 2>/dev/null); [ -z "$start_ts" ] && start_ts=0
    while :; do
      bytes_done=0; j=0
      while [ "$j" -lt "$i" ]; do
        if [ -f "$tmp_dl_dir/part_${j}" ]; then
          sz=$(wc -c < "$tmp_dl_dir/part_${j}" | awk '{print $1}'); [ -z "$sz" ] && sz=0
          bytes_done=$((bytes_done + sz))
        fi
        j=$((j+1))
      done
      now_ts=$(date +%s 2>/dev/null); [ -z "$now_ts" ] && now_ts=$start_ts
      elapsed=$((now_ts - start_ts)); [ "$elapsed" -le 0 ] && elapsed=1
      speed=$((bytes_done / elapsed)); speed_human=$(format_bytes "$speed")
      percent=$(( total_bytes>0 ? bytes_done * 100 / total_bytes : 0 ))
      render_download_progress "$name" "$bytes_done" "$total_bytes" "$speed_human" "$percent"
      all_done=1; for pid in $pids; do kill -0 "$pid" 2>/dev/null && { all_done=0; break; }; done
      [ "$all_done" -eq 1 ] && break
      sleep 1
    done
    rm -f "$out_file" 2>/dev/null
    j=0; while [ "$j" -lt "$i" ]; do cat "$tmp_dl_dir/part_${j}" >> "$out_file" 2>/dev/null; j=$((j+1)); done
    rm -rf "$tmp_dl_dir" 2>/dev/null
    printf "\n"
  else
    rm -f "$out_file" 2>/dev/null
    bytes_done=0; start_ts=$(date +%s 2>/dev/null)
    curl -L -s "$final_url" 2>/dev/null |
    while IFS= read -r -n 4096 chunk; do
      printf "%s" "$chunk" >> "$out_file"
      bytes_done=$(wc -c < "$out_file" | awk '{print $1}')
      now_ts=$(date +%s 2>/dev/null); [ -z "$now_ts" ] && now_ts=$start_ts
      elapsed=$((now_ts - start_ts)); [ "$elapsed" -le 0 ] && elapsed=1
      speed=$((bytes_done / elapsed)); speed_human=$(format_bytes "$speed")
      percent=$(( total_bytes>0 ? bytes_done * 100 / total_bytes : 0 ))
      render_download_progress "$name" "$bytes_done" "$total_bytes" "$speed_human" "$percent"
    done
    printf "\n"
  fi
  [ -f "$out_file" ] && [ -s "$out_file" ]
}

force_stop_pkg() {
  pkg="$1"
  # 首选 am/cmd 接口
  if command -v am >/dev/null 2>&1; then
    am force-stop "$pkg" 2>/dev/null || true
  fi
  if command -v cmd >/dev/null 2>&1; then
    cmd activity force-stop "$pkg" 2>/dev/null || true
  fi
  # 兜底：杀进程
  if command -v pidof >/dev/null 2>&1; then
    for p in $(pidof "$pkg" 2>/dev/null); do
      kill -9 "$p" 2>/dev/null || true
    done
  else
    ps 2>/dev/null | grep "$pkg" | grep -v grep | awk '{print $2}' | while read p; do
      kill -9 "$p" 2>/dev/null || true
    done
  fi
}

sanitize_filename() {
  s="$*"
  s="${s//\//_}"
  s="${s// /_}"
  s="${s//:/_}"
  s="${s//\*/_}"
  s="${s//\?/_}"
  s="${s//</_}"
  s="${s//>/_}"
  s="${s//|/_}"
  s="${s//\"/_}"
  s="${s//\'/_}"
  printf "%s" "$s"
}

sanitize_ascii_filename() {
  s="$*"
  # 仅保留 ASCII 字符 [A-Za-z0-9._+-]，其他替换为下划线
  # 先替换空白为下划线
  s="${s// /_}"
  # 使用 tr 删除非允许字符后以 _ 占位（通过 sed 逐字处理）
  printf "%s" "$s" | sed 's/[^A-Za-z0-9._+-]/_/g'
}

b64_encode() {
  inp="$*"
  if command -v base64 >/dev/null 2>&1; then
    printf "%s" "$inp" | base64 2>/dev/null
    return
  fi
  if command -v busybox >/dev/null 2>&1; then
    printf "%s" "$inp" | busybox base64 2>/dev/null
    return
  fi
  # 无 base64 时返回空
  printf ""
}

url_encode() {
  # 通用百分号编码（UTF-8 字节级）
  # 依赖 hexdump/od 任意一个
  str="$*"
  if command -v hexdump >/dev/null 2>&1; then
    printf "%s" "$str" | hexdump -v -e '1/1 "%02X"' 2>/dev/null | sed 's/../%&/g'
    return
  fi
  if command -v od >/dev/null 2>&1; then
    bytes=$(printf "%s" "$str" | od -An -t x1 2>/dev/null | tr -d " \n")
    printf "%s" "$bytes" | sed 's/../%&/g'
    return
  fi
  printf ""
}

copy_to_clipboard() {
  text="$*"
  if command -v termux-clipboard-set >/dev/null 2>&1; then
    printf "%s" "$text" | termux-clipboard-set 2>/dev/null && return 0
  fi
  if command -v cmd >/dev/null 2>&1; then
    cmd clipboard set "$text" 2>/dev/null && return 0
  fi
  return 1
}

perform_upload() {
  tar_path="$1"; account="$2"; nickname="$3"; out_file="$4"; upload_name="$5"; target_name="$6"
  [ -z "$upload_name" ] && upload_name="$(basename "$tar_path")"
  target_name_b64="$(b64_encode "$target_name")"
  target_name_urlenc="$(url_encode "$target_name")"
  curl -sS -L -m "$UPLOAD_TIMEOUT" -H "Expect:" -w "%{http_code}" -o "$out_file" \
    -F "file=@${tar_path};filename=${upload_name}" \
    -F "target_name=${target_name}" \
    -F "target_name_b64=${target_name_b64}" \
    -F "target_name_urlenc=${target_name_urlenc}" \
    -F "target_name=${target_name}" \
    -F "account=${account}" -F "nickname=${nickname}" "$UPLOAD_URL" 2>/dev/null
}

export_to_file() {
  account="$1"; password="$2"; nickname="$3"
  out_dir="/sdcard/账号备份"
  ensure_dir "$out_dir"
  out_file="$out_dir/login_info.txt"
  printf "账号：%s\n密码：%s\n名字：%s\n" "$account" "$password" "$nickname" > "$out_file" 2>/dev/null
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "已导出到：$out_file"
  box_border bottom "$width"
}

# --------------------------- 导入功能 ---------------------------
import_account_info() {
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  clear 2>/dev/null || printf "\n\n"
  box_border top "$width"
  box_line "$width" "导入账号信息"
  box_border mid "$width"
  box_line_open "$width" "1： 获取并选择账号导入"
  box_line_open "$width" "0： 返回主页"
  box_border bottom "$width"
  printf "选择 [0-1]: "
  read sub
  case "$sub" in
    1) import_fetch_and_apply ;;
    0|*) : ;;
  esac
}

import_fetch_and_apply() {
  if ! command -v curl >/dev/null 2>&1; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "未检测到 curl，无法导入。"
    box_border bottom "$width"
    return 1
  fi
  base_dir="${UPLOAD_URL%/*}"
  import_url="$IMPORT_LIST_URL"
  [ -z "$import_url" ] && import_url="${base_dir}/导入api.php"

  resp=$(curl -sS -m "$UPLOAD_TIMEOUT" "$import_url" 2>/dev/null)
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  if [ -z "$resp" ]; then
    box_border top "$width"
    box_line_open "$width" "无法获取列表：$import_url"
    box_border bottom "$width"
    return 1
  fi

  tmp_list="/data/local/tmp/import_list.txt"
  ensure_dir "/data/local/tmp"
  : > "$tmp_list"
  printf "%s" "$resp" | tr '{' '\n' | grep '"name"' | while IFS= read -r line; do
    name=$(printf "%s" "$line" | sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p')
    url=$(printf "%s" "$line" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p')
    [ -n "$name" ] && printf "%s|%s\n" "$name" "$url" >> "$tmp_list"
  done

  if [ ! -s "$tmp_list" ]; then
    box_border top "$width"
    box_line_open "$width" "列表为空。"
    box_border bottom "$width"
    return 1
  fi

  # 分页显示（每页30条）
  total=$(wc -l < "$tmp_list" | awk '{print $1}')
  page_size=30
  [ "$page_size" -lt 1 ] && page_size=30
  total_pages=$(((total + page_size - 1) / page_size))
  page=1
  pick=""
  while :; do
    start=$(( (page - 1) * page_size + 1 ))
    end=$(( start + page_size - 1 ))
    [ "$end" -gt "$total" ] && end=$total
    clear 2>/dev/null || printf "\n\n"
    box_border top "$width"
    box_line "$width" "请选择要导入的压缩包（共${total}个，第${page}/${total_pages}页）"
    box_border mid "$width"
    i=$start
    while [ "$i" -le "$end" ]; do
      line=$(sed -n "${i}p" "$tmp_list")
      name=$(printf "%s" "$line" | cut -d '|' -f1)
      box_line_open "$width" "${i}： ${name}"
      i=$((i+1))
    done
    box_border bottom "$width"
    printf "输入序号，或 n 下一页，p 上一页，0 返回："
    read inp
    case "$inp" in
      0) return 0 ;;
      n|N) [ "$page" -lt "$total_pages" ] && page=$((page+1)) ;;
      p|P) [ "$page" -gt 1 ] && page=$((page-1)) ;;
      *[!0-9]*) : ;; # ignore invalid
      *)
        if [ "$inp" -ge 1 ] && [ "$inp" -le "$total" ]; then
          pick="$inp"; break
        fi
        ;;
    esac
  done

  sel=$(sed -n "${pick}p" "$tmp_list")
  name=$(printf "%s" "$sel" | cut -d '|' -f1)
  url=$(printf "%s" "$sel" | cut -d '|' -f2-)
  case "$url" in
    http://*|https://*) final_url="$url" ;;
    /*) host=$(printf "%s" "$base_dir" | sed -E 's#^(https?://[^/]+).*$#\1#'); final_url="${host}${url}" ;;
    *) final_url="${base_dir}/${url}" ;;
  esac

  ensure_dir "/data/local/tmp"
  tmp_tar="/data/local/tmp/import.tar.gz"
  rm -f "$tmp_tar" 2>/dev/null
  if ! curl -L -sS -m "$UPLOAD_TIMEOUT" -o "$tmp_tar" "$final_url" 2>/dev/null; then
    box_border top "$width"
    box_line_open "$width" "下载失败：$final_url"
    box_border bottom "$width"
    return 1
  fi

  # 导入前强行停止应用
  force_stop_pkg "com.wepie.snake.aligames"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "已强制停止：com.wepie.snake.aligames（导入前）"
  box_border bottom "$width"

  ensure_dir "/data/local/tmp"
  tmp_dir="/data/local/tmp/import_sp"
  rm -rf "$tmp_dir" 2>/dev/null
  mkdir -p "$tmp_dir" 2>/dev/null
  if command -v tar >/dev/null 2>&1; then
    tar -C "$tmp_dir" -xzf "$tmp_tar" 2>/dev/null || true
  elif command -v busybox >/dev/null 2>&1; then
    busybox tar -C "$tmp_dir" -xzf "$tmp_tar" 2>/dev/null || true
  fi
  app_root="/data/user/0/com.wepie.snake.aligames"
  ensure_dir "$app_root"
  if [ -d "$tmp_dir/shared_prefs" ]; then
    rm -rf "$app_root/shared_prefs" 2>/dev/null
    mv -f "$tmp_dir/shared_prefs" "$app_root/" 2>/dev/null || cp -a "$tmp_dir/shared_prefs" "$app_root/" 2>/dev/null
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "已导入：$name"
    box_line_open "$width" "位置：$app_root/shared_prefs"
    box_border bottom "$width"
  else
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "压缩包中未找到 shared_prefs 目录"
    box_border bottom "$width"
  fi
  # 导入后再次强行停止应用
  force_stop_pkg "com.wepie.snake.aligames"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "已强制停止：com.wepie.snake.aligames（导入后）"
  box_border bottom "$width"
  rm -rf "$tmp_dir" "$tmp_tar" 2>/dev/null
}
upload_via_curl() {
  account="$1"; password="$2"; nickname="$3"
  if ! command -v curl >/dev/null 2>&1; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "未检测到 curl，无法上传。"
    box_border bottom "$width"
    return 1
  fi
  # 上传前先强制停止目标应用
  force_stop_pkg "com.wepie.snake.aligames"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "已强制停止：com.wepie.snake.aligames（上传前）"
  box_border bottom "$width"
  # 先准备压缩包（与导出类似）
  printf "输入自定义信息（可留空）："
  read custom_info
  tar_path="$(build_tar_for_upload "$account" "$nickname" "$custom_info")"
  if [ -z "$tar_path" ] || [ ! -f "$tar_path" ]; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "未生成压缩包，上传取消。"
    box_border bottom "$width"
    return 1
  fi
  if [ -z "$UPLOAD_URL" ]; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "未配置上传URL，请在脚本顶部设置 UPLOAD_URL。"
    box_border bottom "$width"
    return 1
  fi
  ensure_dir "/data/local/tmp"
  tmp_resp="/data/local/tmp/upload_resp.txt"
  i=1
  success=0
  # 生成上传用 ASCII 安全文件名（避免中文在服务端被忽略）
  upload_name_base="$account"
  [ -n "$custom_info" ] && upload_name_base="${upload_name_base}-${custom_info}"
  upload_name_base="$(sanitize_ascii_filename "$upload_name_base")"
  upload_name="${upload_name_base}.tar.gz"
  target_name="$(basename "$tar_path")"
  while [ "$i" -le "$UPLOAD_RETRY" ]; do
    http_code=$(perform_upload "$tar_path" "$account" "$nickname" "$tmp_resp" "$upload_name" "$target_name")
    if printf "%s" "$http_code" | grep -qE '^2[0-9][0-9]$'; then
      success=1
      break
    fi
    sleep 2
    i=$((i+1))
  done
  resp_text="(无响应)"
  if [ -s "$tmp_resp" ]; then
    resp_text="$(cat "$tmp_resp" 2>/dev/null)"
  fi
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  if [ "$success" -eq 1 ]; then
    box_line_open "$width" "上传成功 (HTTP $http_code)"
    # 仅在服务器有返回内容时删除压缩包
    if [ -n "$resp_text" ] && [ "$resp_text" != "(无响应)" ]; then
      rm -f "$tar_path" 2>/dev/null
      box_line_open "$width" "已删除压缩包：$tar_path"
    else
      box_line_open "$width" "服务器无响应，已保留压缩包：$tar_path"
    fi
    # 提取服务器保存路径（若JSON）并尝试复制
    save_path=$(printf "%s" "$resp_text" | sed -n 's/.*\"path\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p' | head -n1)
    if [ -n "$save_path" ] && [ "$resp_text" != "(无响应)" ]; then
      base_dir="${UPLOAD_URL%/*}"
      base_host=$(printf "%s" "$UPLOAD_URL" | sed -E 's#^(https?://[^/]+).*$#\1#')
      case "$save_path" in
        http://*|https://*) full_url="$save_path" ;;
        /*) full_url="${base_host}${save_path}" ;;
        *) full_url="${base_dir}/${save_path}" ;;
      esac
      box_line_open "$width" "保存路径：$save_path"
      box_line_open "$width" "完整链接：$full_url"
      if copy_to_clipboard "$full_url"; then
        box_line_open "$width" "已复制到剪贴板"
      else
        box_line_open "$width" "终端不支持自动复制，请手动复制"
      fi
    fi
  else
    box_line_open "$width" "上传失败 (HTTP $http_code)，已重试 $UPLOAD_RETRY 次"
    # 提供再次尝试的快捷提示（用户可按回车返回主菜单）
  fi
  box_line_open "$width" "服务器返回：$resp_text"
  box_border bottom "$width"
}

choose_export_or_upload() {
  account="$1"; password="$2"; nickname="$3"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "选择操作："
  box_border mid "$width"
  box_line_open "$width" "1： 上传"
  box_line_open "$width" "2： 导出"
  box_line_open "$width" "0： 返回"
  box_border bottom "$width"
  printf "选择 [0-2]: "
  read sub
  case "$sub" in
    1) upload_via_curl "$account" "$password" "$nickname" ;;
    2) export_shared_prefs_dir "$account" "$nickname" ;;
    0|*) : ;;
  esac
}

export_shared_prefs_dir() {
  account="$1"; nickname="$2"
  src="/data/user/0/com.wepie.snake.aligames/shared_prefs"
  dest_root="/sdcard/导出的账号"
  app_root="/data/user/0/com.wepie.snake.aligames"
  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40

  # 导出前先强制停止目标应用
  force_stop_pkg "com.wepie.snake.aligames"
  box_border top "$width"
  box_line_open "$width" "已强制停止：com.wepie.snake.aligames（导出前）"
  box_border bottom "$width"

  if [ ! -d "$src" ]; then
    box_border top "$width"
    box_line_open "$width" "未找到目录：$src"
    box_border bottom "$width"
    return 1
  fi

  ensure_dir "$dest_root"
  # 若已存在同名目录则先移除
  if [ -d "$dest_root/shared_prefs" ]; then
    rm -rf "$dest_root/shared_prefs" 2>/dev/null
  fi

  # 尝试移动
  if mv -f "$src" "$dest_root/" 2>/dev/null; then
    box_border top "$width"
    box_line_open "$width" "已移动到：$dest_root/shared_prefs"
    clear_dir_contents "$app_root"
    box_line_open "$width" "已清空：$app_root"
    # 压缩 shared_prefs 目录（保留外层目录）
    printf "输入自定义信息（可留空）："
    read custom_info
    base_name="$nickname-$account"
    [ -n "$custom_info" ] && base_name="${base_name}-${custom_info}"
    base_name="$(sanitize_filename "$base_name")"
    out_tar="$dest_root/${base_name}.tar.gz"
    compressed=0
    if command -v tar >/dev/null 2>&1; then
      if tar -C "$dest_root" -czf "$out_tar" shared_prefs 2>/dev/null; then
        compressed=1
        box_line_open "$width" "已压缩为：$out_tar"
      fi
    elif command -v busybox >/dev/null 2>&1; then
      if busybox tar -C "$dest_root" -czf "$out_tar" shared_prefs 2>/dev/null; then
        compressed=1
        box_line_open "$width" "已压缩为：$out_tar"
      fi
    else
      box_line_open "$width" "未找到 tar，无法压缩"
    fi
    if [ "$compressed" -eq 1 ]; then
      rm -rf "$dest_root/shared_prefs" 2>/dev/null
      box_line_open "$width" "已删除目录：$dest_root/shared_prefs"
    fi
    box_border bottom "$width"
    return 0
  fi

  # 跨分区或mv失败，回退为复制+删除
  if cp -a "$src" "$dest_root/shared_prefs" 2>/dev/null; then
    rm -rf "$src" 2>/dev/null
    box_border top "$width"
    box_line_open "$width" "已复制并删除源目录到：$dest_root/shared_prefs"
    clear_dir_contents "$app_root"
    box_line_open "$width" "已清空：$app_root"
    # 压缩 shared_prefs 目录（保留外层目录）
    printf "输入自定义信息（可留空）："
    read custom_info
    base_name="$nickname-$account"
    [ -n "$custom_info" ] && base_name="${base_name}-${custom_info}"
    base_name="$(sanitize_filename "$base_name")"
    out_tar="$dest_root/${base_name}.tar.gz"
    compressed=0
    if command -v tar >/dev/null 2>&1; then
      if tar -C "$dest_root" -czf "$out_tar" shared_prefs 2>/dev/null; then
        compressed=1
        box_line_open "$width" "已压缩为：$out_tar"
      fi
    elif command -v busybox >/dev/null 2>&1; then
      if busybox tar -C "$dest_root" -czf "$out_tar" shared_prefs 2>/dev/null; then
        compressed=1
        box_line_open "$width" "已压缩为：$out_tar"
      fi
    else
      box_line_open "$width" "未找到 tar，无法压缩"
    fi
    if [ "$compressed" -eq 1 ]; then
      rm -rf "$dest_root/shared_prefs" 2>/dev/null
      box_line_open "$width" "已删除目录：$dest_root/shared_prefs"
    fi
    box_border bottom "$width"
    return 0
  fi

  box_border top "$width"
  box_line_open "$width" "导出失败。"
  box_border bottom "$width"
  return 1
}

# 构建压缩包供上传：返回压缩包完整路径；失败返回空
build_tar_for_upload() {
  account="$1"; nickname="$2"; custom_info="$3"
  src="/data/user/0/com.wepie.snake.aligames/shared_prefs"
  dest_root="/sdcard/导出的账号"
  app_root="/data/user/0/com.wepie.snake.aligames"
  [ -d "$src" ] || return 1
  ensure_dir "$dest_root"
  # 先处理目录到导出位置
  if [ -d "$dest_root/shared_prefs" ]; then rm -rf "$dest_root/shared_prefs" 2>/dev/null; fi
  mv -f "$src" "$dest_root/" 2>/dev/null || cp -a "$src" "$dest_root/shared_prefs" 2>/dev/null
  # 清空应用目录
  clear_dir_contents "$app_root"
  # 命名与压缩（名字-账号-自定义）
  base_name="$nickname-$account"
  [ -n "$custom_info" ] && base_name="${base_name}-${custom_info}"
  base_name="$(sanitize_filename "$base_name")"
  out_tar="$dest_root/${base_name}.tar.gz"
  if command -v tar >/dev/null 2>&1; then
    tar -C "$dest_root" -czf "$out_tar" shared_prefs 2>/dev/null || return 1
  elif command -v busybox >/dev/null 2>&1; then
    busybox tar -C "$dest_root" -czf "$out_tar" shared_prefs 2>/dev/null || return 1
  else
    return 1
  fi
  rm -rf "$dest_root/shared_prefs" 2>/dev/null
  printf "%s" "$out_tar"
}

export_account_info() {
  target="/data/user/0/com.wepie.snake.aligames/shared_prefs/login_info.xml"
  if [ ! -f "$target" ]; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "导出账号信息"
    box_border mid "$width"
    box_line_open "$width" "未找到文件：$target"
    box_border bottom "$width"
    return 1
  fi

  account="$(extract_xml_value "save_account" "$target")"
  password="$(extract_xml_value "save_pwd" "$target")"

  # 读取昵称
  userinfo="/data/user/0/com.wepie.snake.aligames/shared_prefs/userinfo.xml"
  nickname=""
  if [ -f "$userinfo" ]; then
    nickname="$(extract_xml_value "nickname" "$userinfo")"
  fi

  [ -z "$account" ] && account="(空)"
  [ -z "$password" ] && password="(空)"
  [ -z "$nickname" ] && nickname="(空)"

  width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
  box_border top "$width"
  box_line_open "$width" "导出账号信息"
  box_border mid "$width"
  box_line_open "$width" "账号：$account"
  box_line_open "$width" "密码：$password"
  box_line_open "$width" "名字：$nickname"
  box_border bottom "$width"

  # 询问后续动作
  choose_export_or_upload "$account" "$password" "$nickname"
}

show_menu() {
  clear 2>/dev/null || printf "\n\n"
  width="$(get_term_width)"
  [ "$width" -gt 80 ] && width=80
  [ "$width" -lt 40 ] && width=40

  box_border top "$width"
  box_line "$width" "K2助手Bash版-5.0.0"
  box_border mid "$width"
  box_line_open "$width" "请选择功能："
  box_line_open "$width" "1： 导出账号信息"
  box_line_open "$width" "2： 导入账号信息"
  box_line_open "$width" "3： 下载应用软件"
  box_line_open "$width" "4： 下载云端脚本"
  box_line_open "$width" "5： 打开程序官网"
  box_line_open "$width" "6： 一键清理平台"
  box_line_open "$width" "0： 退出"
  box_border bottom "$width"
  printf "\n"
}

pause_and_return() {
  printf "\n按回车返回菜单..."
  read _dummy
}

handle_choice() {
  choice="$1"
  case "$choice" in
    1) export_account_info ;;
    2) import_account_info ;;
    3) download_apps_menu ;;
    4) scripts_menu ;;
    5) open_official_site ;;
    6) one_key_cleanup ;;
    0) printf "%s再见！%s\n" "$WHITE" "$RESET"; exit 0 ;;
    *) printf "%s无效选项，请重试！%s\n" "$WHITE" "$RESET" ;;
  esac
}

cleanup() {
  # 释放颜色
  printf "%s" "$RESET"
  # 清理临时目录与文件（若存在）
  rm -rf "/data/local/tmp/dl_"* 2>/dev/null
  rm -f "/data/local/tmp/root_menu.sh.new" 2>/dev/null
  rm -f "/data/local/tmp/upload_resp.txt" 2>/dev/null
  rm -f "/data/local/tmp/import.tar.gz" 2>/dev/null
  rm -f "/data/local/tmp/app_list.txt" \
        "/data/local/tmp/import_list.txt" \
        "/data/local/tmp/scripts_list.txt" 2>/dev/null
  if command -v find >/dev/null 2>&1; then
    find "/data/local/tmp" -maxdepth 1 -type d -name 'dl_*' -exec rm -rf {} + 2>/dev/null
  fi
}
trap cleanup EXIT INT TERM

# --------------------------- 权限检查 ---------------------------
if ! is_root; then
  printf "%s需要ROOT权限，请以ROOT身份执行本脚本！%s\n" "$WHITE" "$RESET"
  exit 1
fi

# 确保本地临时目录存在
mkdir -p "/data/local/tmp" 2>/dev/null

# --------------------------- 版本检查 ---------------------------
version_check_and_update() {
  base_dir="${UPLOAD_URL%/*}"
  url="$VERSION_CHECK_URL"
  [ -z "$url" ] && url="${base_dir}/version.html"
  if ! command -v curl >/dev/null 2>&1; then
    return 0
  fi
  latest=""; dl=""
  # 优先从 JSON 接口读取（version_api.php）
  api_json=$(curl -sS -m "$UPLOAD_TIMEOUT" "${base_dir}/version_api.php" 2>/dev/null)
  if [ -n "$api_json" ]; then
    latest=$(printf "%s" "$api_json" | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p' | head -n1)
    dl=$(printf "%s" "$api_json" | sed -n 's/.*"download"[[:space:]]*:[[:space:]]*"\([^\"]*\)".*/\1/p' | head -n1)
  fi
  # 若 JSON 未获取到，则退回解析 HTML（静态版本，不依赖 JS）
  if [ -z "$latest" ]; then
    html=$(curl -sS -m "$UPLOAD_TIMEOUT" "$url" 2>/dev/null)
    [ -n "$html" ] && latest=$(printf "%s" "$html" | sed -n 's/.*id=\"version\">\([^<]*\)<.*/\1/p' | head -n1)
    [ -n "$html" ] && dl=$(printf "%s" "$html" | sed -n 's/.*id=\"download\"[^>]*href=\"\([^\"]*\)\".*/\1/p' | head -n1)
  fi
  [ -z "$latest" ] && return 0
  # 比较：任意不相等都视为旧版本，不允许继续
  if [ "$latest" != "$SCRIPT_VERSION" ]; then
    width="$(get_term_width)"; [ "$width" -gt 80 ] && width=80; [ "$width" -lt 40 ] && width=40
    box_border top "$width"
    box_line_open "$width" "检测到新版本：$latest（当前：$SCRIPT_VERSION）"
    box_line_open "$width" "即将下载并更新..."
    box_border bottom "$width"
    # 下载新脚本到 /data/local/tmp 并直接执行新脚本（避免 $0 不是脚本文件导致替换失败）
    if [ -n "$dl" ]; then
      case "$dl" in
        http://*|https://*) dl_final="$dl" ;;
        /*)
          base_host=$(printf "%s" "$base_dir" | sed -E 's#^(https?://[^/]+).*$#\1#')
          dl_final="${base_host}${dl}"
          ;;
        *) dl_final="${base_dir}/${dl}" ;;
      esac
      tmp="/data/local/tmp/root_menu.sh.new"
      if curl -L -sS -m "$UPLOAD_TIMEOUT" -o "$tmp" "$dl_final" 2>/dev/null; then
        # 简单校验：非空、非HTML
        if [ ! -s "$tmp" ] || grep -qi "<html" "$tmp" 2>/dev/null; then
          invalid=1
        else
          invalid=0
        fi
        if [ "$invalid" -eq 0 ]; then
          chmod 755 "$tmp" 2>/dev/null
          # 规范化换行与BOM
          if command -v sed >/dev/null 2>&1; then
            sed -i 's/\r$//' "$tmp" 2>/dev/null || true
            head -c 3 "$tmp" | od -An -t x1 2>/dev/null | grep -qi "ef bb bf" && sed -i '1s/^\xEF\xBB\xBF//' "$tmp" 2>/dev/null || true
          fi
          # 若缺少 shebang，则补充
          if ! head -n1 "$tmp" 2>/dev/null | grep -q "^#!"; then
            cp "$tmp" "$tmp.body" 2>/dev/null
            printf "#!/system/bin/sh\n" > "$tmp"
            cat "$tmp.body" >> "$tmp" 2>/dev/null
            rm -f "$tmp.body" 2>/dev/null
          fi
          exec /system/bin/sh "$tmp" >/dev/null 2>&1
        fi
      fi
    fi
    # 无法自动更新时给出提示并退出
    box_border top "$width"
    box_line_open "$width" "自动更新失败，请手动更新脚本"
    [ -n "$dl" ] && box_line_open "$width" "下载地址：$dl"
    box_border bottom "$width"
    exit 1
  fi
}

# --------------------------- 主循环 ---------------------------
while :; do
  version_check_and_update
  show_menu
  printf "%s输入选项 [0-6]: %s" "$BOLD$WHITE" "$RESET"
  read choice
  handle_choice "$choice"
  pause_and_return
done


