install.sh 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. #!/bin/sh
  2. #
  3. # One-click installation script for DDNS
  4. # 一键安装脚本
  5. #
  6. # Usage:
  7. # curl -fsSL https://ddns.newfuture.cc/install.sh | sh
  8. # wget -qO- https://ddns.newfuture.cc/install.sh | sh
  9. #
  10. # With version:
  11. # curl -fsSL https://ddns.newfuture.cc/install.sh | sh -s -- v4.0.2
  12. # curl -fsSL https://ddns.newfuture.cc/install.sh | sh -s -- beta
  13. # curl -fsSL https://ddns.newfuture.cc/install.sh | sh -s -- latest
  14. #
  15. # Note: This script handles SSL certificate verification gracefully.
  16. # In container environments where CA certificates may be missing,
  17. # it will fallback to insecure downloads after SSL verification fails.
  18. # 注意:此脚本会优雅地处理SSL证书验证。
  19. # 在可能缺少CA证书的容器环境中,SSL验证失败后会回退到不安全的下载。
  20. #
  21. set -e
  22. # Color definitions
  23. RED='\033[0;31m'
  24. GREEN='\033[0;32m'
  25. YELLOW='\033[1;33m'
  26. BLUE='\033[0;34m'
  27. NC='\033[0m' # No Color
  28. # Default values
  29. VERSION=""
  30. INSTALL_DIR="/usr/local/bin"
  31. BINARY_NAME="ddns"
  32. REPO="NewFuture/DDNS"
  33. USER_AGENT="DDNS-Installer/1.0"
  34. FORCE_INSTALL=false
  35. # Whether user explicitly passed a VERSION argument
  36. USER_VERSION_SPECIFIED=false
  37. # Uninstall mode
  38. UNINSTALL_MODE=false
  39. # Default network timeout (seconds) for downloads; override with env DOWNLOAD_TIMEOUT
  40. DOWNLOAD_DEFAULT_TIMEOUT="${DOWNLOAD_TIMEOUT:-90}"
  41. # Optional proxy base URL to prefix the original GitHub URL, e.g.
  42. # Final download will be: "$PROXY_URL" + "https://github.com/..." (PROXY_URL always ends with '/')
  43. PROXY_URL=""
  44. PROXY_CANDIDATES="https://hub.gitmirror.com/ https://proxy.gitwarp.com/ https://gh.200112.xyz/"
  45. # Language detection
  46. detect_language() {
  47. if [ -n "$LANG" ]; then
  48. case "$LANG" in
  49. zh_* | zh-* | *zh*)
  50. LANGUAGE="zh"
  51. ;;
  52. *)
  53. LANGUAGE="en"
  54. ;;
  55. esac
  56. else
  57. LANGUAGE="en"
  58. fi
  59. }
  60. # Initialize language detection
  61. detect_language
  62. # Helper function to select message based on language
  63. select_message() {
  64. local en="$1"
  65. local zh="$2"
  66. if [ "$LANGUAGE" = "zh" ] && [ -n "$zh" ]; then
  67. echo "$zh"
  68. else
  69. echo "$en"
  70. fi
  71. }
  72. # Print colored messages
  73. print_info() {
  74. printf "${BLUE}[INFO]${NC} %s\n" "$(select_message "$1" "$2")"
  75. }
  76. print_success() {
  77. printf "${GREEN}[SUCCESS]${NC} %s\n" "$(select_message "$1" "$2")"
  78. }
  79. print_warning() {
  80. printf "${YELLOW}[WARNING]${NC} %s\n" "$(select_message "$1" "$2")"
  81. }
  82. print_error() {
  83. printf "${RED}[ERROR]${NC} %s\n" "$(select_message "$1" "$2")"
  84. }
  85. # Show usage information
  86. show_usage() {
  87. if [ "$LANGUAGE" = "zh" ]; then
  88. cat << EOF
  89. DDNS 一键安装脚本
  90. 用法:
  91. $0 [VERSION] [OPTIONS]
  92. 版本:
  93. latest 安装最新稳定版本 (默认)
  94. beta 安装最新测试版本
  95. v4.0.2 安装指定版本 (例如: v4.0.2)
  96. 选项:
  97. --install-dir PATH 安装目录 (默认: /usr/local/bin)
  98. --proxy URL 代理域名/前缀,例如: https://hub.gitmirror.com/
  99. --force 强制安装,即使已存在
  100. --uninstall 卸载已安装的 ddns 可执行文件
  101. --help 显示此帮助信息
  102. 说明:
  103. 显式指定 VERSION 时(如: v4.0.2/beta/latest),即使已安装也会覆盖,无需 --force
  104. 示例:
  105. $0 # 安装最新稳定版本
  106. $0 beta # 安装最新测试版本
  107. $0 v4.0.2 # 安装指定版本
  108. $0 latest --force # 强制重新安装最新版本
  109. $0 --uninstall # 卸载 ddns
  110. EOF
  111. else
  112. cat << EOF
  113. DDNS One-Click Installation Script
  114. Usage:
  115. $0 [VERSION] [OPTIONS]
  116. VERSION:
  117. latest Install latest stable version (default)
  118. beta Install latest beta version
  119. v4.0.2 Install specific version (e.g., v4.0.2)
  120. OPTIONS:
  121. --install-dir PATH Installation directory (default: /usr/local/bin)
  122. --proxy URL Proxy domain/prefix, e.g. https://hub.gitmirror.com/
  123. --force Force installation even if already exists
  124. --uninstall Uninstall the ddns executable
  125. --help Show this help message
  126. Notes:
  127. When a VERSION is explicitly provided (e.g., v4.0.2/beta/latest), the installer
  128. will overwrite an existing installation without requiring --force
  129. Examples:
  130. $0 # Install latest stable version
  131. $0 beta # Install latest beta version
  132. $0 v4.0.2 # Install specific version
  133. $0 latest --force # Force reinstall latest version
  134. $0 --uninstall # Uninstall ddns
  135. EOF
  136. fi
  137. }
  138. # Check if running on supported OS
  139. check_os() {
  140. case "$(uname -s)" in
  141. Linux*) OS="linux" ;;
  142. Darwin*) OS="mac" ;;
  143. *)
  144. print_error "Unsupported operating system: $(uname -s)" "不支持的操作系统: $(uname -s)"
  145. print_error "This script only supports Linux and macOS" "此脚本仅支持 Linux 和 macOS"
  146. exit 1
  147. ;;
  148. esac
  149. print_info "Detected OS: $OS" "检测到操作系统: $OS"
  150. }
  151. # Detect system architecture
  152. detect_arch() {
  153. local arch
  154. arch="$(uname -m)"
  155. case "$arch" in
  156. x86_64|amd64)
  157. if [ "$OS" = "mac" ]; then
  158. ARCH="x64"
  159. else
  160. ARCH="amd64"
  161. fi
  162. ;;
  163. arm64|aarch64)
  164. ARCH="arm64"
  165. ;;
  166. armv7l|armv7)
  167. ARCH="arm_v7"
  168. ;;
  169. armv6l)
  170. ARCH="arm_v6"
  171. ;;
  172. i386|i686)
  173. ARCH="386"
  174. ;;
  175. *)
  176. print_error "Unsupported architecture: $arch" "不支持的架构: $arch"
  177. exit 1
  178. ;;
  179. esac
  180. print_info "Detected architecture: $ARCH" "检测到架构: $ARCH"
  181. }
  182. # Detect libc type on Linux
  183. detect_libc() {
  184. if [ "$OS" != "linux" ]; then
  185. return
  186. fi
  187. LIBC="glibc"
  188. if ldd --version 2>&1 | grep -i musl > /dev/null; then
  189. LIBC="musl"
  190. elif ldd /bin/sh 2>&1 | grep -i musl > /dev/null; then
  191. # musl detected via ldd on /bin/sh
  192. LIBC="musl"
  193. fi
  194. print_info "Detected libc: $LIBC" "检测到 libc: $LIBC"
  195. }
  196. # Check for download tool (curl or wget)
  197. check_download_tool() {
  198. if command -v curl > /dev/null 2>&1; then
  199. DOWNLOAD_TOOL="curl"
  200. print_info "Using curl for downloads" "使用 curl 进行下载"
  201. elif command -v wget > /dev/null 2>&1; then
  202. DOWNLOAD_TOOL="wget"
  203. print_info "Using wget for downloads" "使用 wget 进行下载"
  204. else
  205. print_error "Neither curl nor wget found. Please install one of them." "未找到 curl 或 wget,请安装其中一个"
  206. exit 1
  207. fi
  208. }
  209. # Download file using available tool
  210. download_file() {
  211. local url="$1"
  212. local output="$2"
  213. local timeout="$3" # optional seconds; falls back to DOWNLOAD_DEFAULT_TIMEOUT
  214. local retries=1
  215. if [ -z "$timeout" ]; then
  216. timeout="$DOWNLOAD_DEFAULT_TIMEOUT"
  217. retries=3 # If timeout is not specified
  218. fi
  219. if [ "$DOWNLOAD_TOOL" = "curl" ]; then
  220. curl -#fSL --retry $retries -H "User-Agent: $USER_AGENT" --connect-timeout "$timeout" --max-time "$timeout" "$url" -o "$output"
  221. rc=$?
  222. case "$rc" in
  223. 35|51|60|77)
  224. # SSL-related errors only: retry insecurely
  225. print_warning "Download failed due to SSL (code $rc), trying with --insecure" "下载因 SSL 问题失败(代码 $rc),尝试使用 --insecure"
  226. curl -fSL --retry $retries -H "User-Agent: $USER_AGENT" --insecure --connect-timeout "$timeout" --max-time "$timeout" "$url" -o "$output"
  227. return $?
  228. ;;
  229. *)
  230. # Non-SSL errors: do not retry insecurely
  231. return "$rc"
  232. ;;
  233. esac
  234. else
  235. wget -q --user-agent="$USER_AGENT" --timeout="$timeout" "$url" -O "$output"
  236. rc=$?
  237. if [ "$rc" -eq 5 ]; then
  238. # SSL verification failure: retry insecurely
  239. print_warning "Download failed due to SSL (code $rc), trying with --no-check-certificate" "下载因 SSL 问题失败(代码 $rc),尝试使用 --no-check-certificate"
  240. wget --user-agent="$USER_AGENT" --no-check-certificate --timeout="$timeout" "$url" -O "$output"
  241. return $?
  242. fi
  243. # Non-SSL errors: do not retry insecurely
  244. return "$rc"
  245. fi
  246. }
  247. # Auto-detect a working proxy (or direct GitHub) when PROXY_URL not specified
  248. find_working_proxy() {
  249. print_info "Testing Github and proxy connectivity..." "测试GitHub和代理连接..."
  250. local mirror test_url
  251. # Try direct first (empty mirror), then known proxy candidates
  252. for mirror in "" $PROXY_CANDIDATES; do
  253. print_info "Testing: ${mirror:-"github.com"}" "测试: ${mirror:-"github.com"}"
  254. # Probe using a real release asset to validate proxy behavior
  255. test_url="${mirror}https://github.com/NewFuture/DDNS/releases/download/v4.0.0/create-task.sh"
  256. if download_file "$test_url" "/dev/null" 8; then
  257. PROXY_URL="$mirror"
  258. if [ -n "$PROXY_URL" ]; then
  259. print_success "Using proxy: $PROXY_URL" "使用代理: $PROXY_URL"
  260. else
  261. print_success "Using direct GitHub" "使用直连 GitHub"
  262. fi
  263. return 0
  264. fi
  265. print_info "Failed to connect to $test_url" "无法连接到 $test_url"
  266. done
  267. print_warning "All proxy checks failed; using direct GitHub" "所有代理检查失败,使用直连 GitHub"
  268. return 0
  269. }
  270. # Get latest beta version from api.github.com only
  271. get_beta_version() {
  272. local temp_file url
  273. # Reset VERSION to avoid using a stale value on API failures
  274. VERSION=""
  275. temp_file="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/ddns.releases.$$")"
  276. url="https://api.github.com/repos/$REPO/tags?per_page=1"
  277. print_info "Fetching version from api.github.com..." "正在从 api.github.com 获取版本信息..."
  278. # Simple download and parse - let download_file handle errors and retries
  279. if download_file "$url" "$temp_file" && [ -s "$temp_file" ]; then
  280. # Tags API returns objects with a "name" field for the tag
  281. VERSION=$(grep -m1 -o '"name":"[^"]*"' "$temp_file" | cut -d '"' -f4)
  282. fi
  283. # Cleanup temp file
  284. rm -f "$temp_file" 2>/dev/null || true
  285. # Validate result
  286. if [ -z "$VERSION" ]; then
  287. print_error "Failed to get version from GitHub API. Try using 'latest' instead." "无法从 GitHub API 获取版本,请尝试使用 'latest'。"
  288. exit 1
  289. fi
  290. print_success "Found version: $VERSION" "找到版本: $VERSION"
  291. }
  292. # Build binary filename based on OS and architecture
  293. build_binary_name() {
  294. case "$OS" in
  295. "linux")
  296. BINARY_FILE="ddns-${LIBC}-linux_${ARCH}"
  297. ;;
  298. "mac")
  299. BINARY_FILE="ddns-mac-${ARCH}"
  300. ;;
  301. esac
  302. print_info "Target binary: $BINARY_FILE" "二进制文件: $BINARY_FILE"
  303. }
  304. # Download and install binary
  305. install_binary() {
  306. # Build release path and original GitHub URL
  307. local download_url
  308. if [ "$VERSION" = "latest" ]; then
  309. download_url="${PROXY_URL}https://github.com/$REPO/releases/latest/download/$BINARY_FILE"
  310. else
  311. download_url="${PROXY_URL}https://github.com/$REPO/releases/download/$VERSION/$BINARY_FILE"
  312. fi
  313. local temp_file
  314. temp_file="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/ddns.bin.$$")"
  315. print_info "Downloading DDNS binary..." "正在下载 DDNS 二进制文件..."
  316. print_info "URL: $download_url"
  317. if ! download_file "$download_url" "$temp_file"; then
  318. print_error "Failed to download binary" "下载二进制文件失败"
  319. print_error "Make sure the version $VERSION exists and supports your platform" "请确保版本 $VERSION 存在并支持您的平台"
  320. rm -f "$temp_file" 2>/dev/null || true
  321. exit 1
  322. fi
  323. # Verify download
  324. if [ ! -f "$temp_file" ] || [ ! -s "$temp_file" ]; then
  325. print_error "Downloaded file is empty or missing" "下载的文件为空或缺失"
  326. rm -f "$temp_file" 2>/dev/null || true
  327. exit 1
  328. fi
  329. # Check if install directory exists and create if needed
  330. if [ ! -d "$INSTALL_DIR" ]; then
  331. print_info "Creating installation directory: $INSTALL_DIR" "创建安装目录: $INSTALL_DIR"
  332. if ! mkdir -p "$INSTALL_DIR"; then
  333. print_error "Failed to create installation directory: $INSTALL_DIR" "创建安装目录失败: $INSTALL_DIR"
  334. print_error "Try running with sudo or choose a different directory" "请尝试使用 sudo 运行或选择其他目录"
  335. exit 1
  336. fi
  337. fi
  338. # Install binary
  339. local target_path="$INSTALL_DIR/$BINARY_NAME"
  340. # Check if already exists and not forcing
  341. if [ -f "$target_path" ] && [ "$FORCE_INSTALL" = false ]; then
  342. if [ "$USER_VERSION_SPECIFIED" = true ]; then
  343. print_warning "DDNS already installed at $target_path; version specified, proceeding to overwrite" "DDNS 已安装在 $target_path;已指定版本,继续覆盖"
  344. else
  345. print_warning "DDNS is already installed at $target_path" "DDNS 已安装在 $target_path"
  346. print_info "Use --force to overwrite or run: $BINARY_NAME --version" "使用 --force 覆盖或运行: $BINARY_NAME --version"
  347. exit 0
  348. fi
  349. fi
  350. print_info "Installing binary to $target_path" "正在安装二进制文件到 $target_path"
  351. # Make executable before moving
  352. chmod +x "$temp_file"
  353. # Try to move directly, auto-detect if sudo is needed
  354. if ! mv "$temp_file" "$target_path" 2>/dev/null; then
  355. # Check if it's a permission issue and try with sudo
  356. if [ ! -w "$(dirname "$target_path")" ]; then
  357. print_warning "Permission denied, trying with sudo..." "权限被拒绝,尝试使用 sudo..."
  358. if command -v sudo >/dev/null 2>&1; then
  359. if sudo mv "$temp_file" "$target_path"; then
  360. print_info "Successfully installed with sudo" "使用 sudo 安装成功"
  361. else
  362. print_error "Failed to install binary even with sudo" "即使使用 sudo 也无法安装二进制文件"
  363. rm -f "$temp_file" 2>/dev/null || true
  364. exit 1
  365. fi
  366. else
  367. print_error "Failed to install binary: Permission denied" "安装二进制文件失败: 权限被拒绝"
  368. print_error "Please run this script with administrator privileges" "请以管理员权限运行此脚本"
  369. rm -f "$temp_file" 2>/dev/null || true
  370. exit 1
  371. fi
  372. else
  373. print_error "Failed to install binary" "安装二进制文件失败"
  374. rm -f "$temp_file" 2>/dev/null || true
  375. exit 1
  376. fi
  377. fi
  378. print_success "DDNS installed successfully!" "DDNS 安装成功!"
  379. }
  380. # Uninstall binary
  381. uninstall_binary() {
  382. print_info "Starting uninstallation..." "开始卸载..."
  383. local target_path=""
  384. # If a specific install dir is provided, prefer that
  385. if [ -n "$INSTALL_DIR" ] && [ -f "$INSTALL_DIR/$BINARY_NAME" ]; then
  386. target_path="$INSTALL_DIR/$BINARY_NAME"
  387. fi
  388. # Otherwise look up in PATH
  389. if [ -z "$target_path" ]; then
  390. local resolved
  391. resolved=$(command -v "$BINARY_NAME" 2>/dev/null || true)
  392. if [ -n "$resolved" ] && [ -f "$resolved" ]; then
  393. target_path="$resolved"
  394. fi
  395. fi
  396. # Fallback to default location
  397. if [ -z "$target_path" ]; then
  398. if [ -f "/usr/local/bin/$BINARY_NAME" ]; then
  399. target_path="/usr/local/bin/$BINARY_NAME"
  400. fi
  401. fi
  402. if [ -z "$target_path" ]; then
  403. print_warning "ddns not found. Nothing to uninstall." "未找到 ddns,无需卸载"
  404. return 0
  405. fi
  406. print_info "Removing: $target_path" "正在移除: $target_path"
  407. if rm -f "$target_path" 2>/dev/null; then
  408. print_success "Uninstalled ddns" "已卸载 ddns"
  409. return 0
  410. fi
  411. # Try with sudo when permission denied
  412. if command -v sudo >/dev/null 2>&1; then
  413. if sudo rm -f "$target_path"; then
  414. print_success "Uninstalled ddns (with sudo)" "已卸载 ddns (使用 sudo)"
  415. return 0
  416. fi
  417. print_error "Failed to uninstall ddns even with sudo" "即使使用 sudo 也无法卸载 ddns"
  418. return 1
  419. else
  420. print_error "Permission denied removing $target_path. Try running with sudo." "删除 $target_path 权限被拒绝,请尝试使用 sudo 运行"
  421. return 1
  422. fi
  423. }
  424. # Verify installation
  425. verify_installation() {
  426. local target_path="$INSTALL_DIR/$BINARY_NAME"
  427. if [ -x "$target_path" ]; then
  428. print_success "Installation verified!" "安装验证成功!"
  429. print_info "DDNS version: $($target_path --version 2>/dev/null || echo 'Version check failed')" "DDNS 版本: $($target_path --version 2>/dev/null || echo '版本检查失败')"
  430. print_info "Binary location: $target_path" "二进制文件位置: $target_path"
  431. # Check if installation directory is in PATH
  432. if echo "$PATH" | grep -q "$INSTALL_DIR"; then
  433. print_success "Installation directory is in PATH" "安装目录已在 PATH 中"
  434. print_info "You can now run: $BINARY_NAME --help" "现在可以运行: $BINARY_NAME --help"
  435. else
  436. print_warning "Installation directory is not in PATH" "安装目录不在 PATH 中"
  437. print_info "Add to PATH temporarily: export PATH=\"$INSTALL_DIR:\$PATH\"" "临时添加到 PATH: export PATH=\"$INSTALL_DIR:\$PATH\""
  438. print_info "Add to shell profile permanently:" "永久添加到 shell 配置文件:"
  439. # Suggest adding to shell profile
  440. if [ -n "$BASH_VERSION" ]; then
  441. print_info " echo 'export PATH=\"$INSTALL_DIR:\$PATH\"' >> ~/.bashrc"
  442. elif [ -n "$ZSH_VERSION" ]; then
  443. print_info " echo 'export PATH=\"$INSTALL_DIR:\$PATH\"' >> ~/.zshrc"
  444. else
  445. print_info " echo 'export PATH=\"$INSTALL_DIR:\$PATH\"' >> ~/.profile"
  446. fi
  447. print_info "Or run directly: $target_path --help" "或直接运行: $target_path --help"
  448. fi
  449. else
  450. print_error "Installation verification failed" "安装验证失败"
  451. exit 1
  452. fi
  453. }
  454. # Parse command line arguments
  455. parse_args() {
  456. while [ $# -gt 0 ]; do
  457. case "$1" in
  458. --help|-h)
  459. show_usage
  460. exit 0
  461. ;;
  462. --install-dir)
  463. INSTALL_DIR="$2"
  464. shift 2
  465. ;;
  466. --proxy)
  467. PROXY_URL="$2"
  468. shift 2
  469. ;;
  470. --force)
  471. FORCE_INSTALL=true
  472. shift
  473. ;;
  474. --uninstall)
  475. UNINSTALL_MODE=true
  476. shift
  477. ;;
  478. -*)
  479. print_error "Unknown option: $1" "未知选项: $1"
  480. show_usage
  481. exit 1
  482. ;;
  483. *)
  484. if [ -z "$VERSION" ]; then
  485. VERSION="$1"
  486. USER_VERSION_SPECIFIED=true
  487. else
  488. print_error "Too many arguments" "参数过多"
  489. show_usage
  490. exit 1
  491. fi
  492. shift
  493. ;;
  494. esac
  495. done
  496. # Normalize PROXY_URL: add https:// if missing, ensure trailing slash
  497. if [ -n "$PROXY_URL" ]; then
  498. case "$PROXY_URL" in
  499. http://*|https://*) : ;; # keep
  500. *) PROXY_URL="https://$PROXY_URL" ;;
  501. esac
  502. PROXY_URL="${PROXY_URL%/}/"
  503. fi
  504. # Set default version if not specified
  505. if [ -z "$VERSION" ]; then
  506. VERSION="latest"
  507. fi
  508. }
  509. # Main installation function
  510. main() {
  511. print_info "DDNS One-Click Installation Script" "DDNS 一键安装脚本"
  512. print_info "======================================="
  513. # Parse arguments
  514. parse_args "$@"
  515. # Uninstall early: no network required
  516. if [ "$UNINSTALL_MODE" = true ]; then
  517. uninstall_binary
  518. print_success "======================================="
  519. print_success "DDNS uninstallation completed" "DDNS 卸载完成"
  520. exit 0
  521. fi
  522. # System checks (only needed for install)
  523. check_os
  524. detect_arch
  525. detect_libc
  526. check_download_tool
  527. # Auto-select proxy only when not explicitly set
  528. if [ -z "$PROXY_URL" ]; then
  529. find_working_proxy
  530. fi
  531. # Version handling
  532. # For 'latest', skip API query and use GitHub's latest download URL directly.
  533. # For 'beta', fetch the latest available tag via API.
  534. if [ "$VERSION" = "beta" ]; then
  535. get_beta_version
  536. fi
  537. # Build and install
  538. build_binary_name
  539. install_binary
  540. verify_installation
  541. print_success "======================================="
  542. print_success "DDNS installation completed" "DDNS 安装完成"
  543. print_info "Get started: $BINARY_NAME --help" "开始使用: $BINARY_NAME --help"
  544. print_info "Documentation: https://ddns.newfuture.cc/" "文档: https://ddns.newfuture.cc/"
  545. }
  546. # Run main function with all arguments
  547. main "$@"