aboutsummarylogtreecommitdiffstats
path: root/linuxqq-get-url.sh
blob: 1cbffa6202d8841a919b5aa0a9d8e14c37dd0b5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/usr/bin/env bash
# linuxqq-get-url.sh - 动态获取 QQ Linux 的带签名下载链接
#
# QQ 的 deb 包下载需经过 im.qq.com 的 GetSign 服务换取带 sign 的临时链接,
# 否则 qqdl.gtimg.cn 上的原始 URL 会被拒绝。本脚本封装该流程:
#   1) 从 pcConfig.json 解析指定架构的原始 deb 链接
#   2) 请求 im.qq.com/index/ 抓取 tgw_l7_route cookie
#   3) 调用 GetSign 换取带 sign 的下载链接
#
# 用法:
#   linuxqq-get-url.sh <arch>                      输出指定架构的带签名 deb 链接
#   linuxqq-get-url.sh --dlagent <url> <output>    签名并下载到 <output>(DLAGENT 模式)
#
# 参数:
#   arch    目标架构,可选值: x86_64, aarch64, loong64
#   url     待签名的 deb 链接(仅 DLAGENT 模式)
#   output  下载文件保存路径(仅 DLAGENT 模式)
#
# 依赖: bash, curl, python3

set -euo pipefail

CONFIG_URL="https://qq-web.cdn-go.cn/im.qq.com_new/latest/rainbow/pcConfig.json"
COOKIE_URL="https://im.qq.com/index/"
SIGN_URL="https://im.qq.com/http2rpc/gotrpc/noauth/trpc.qqntv2.urlsign.UrlSign/GetSign"
USER_AGENT="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36"

# 从 im.qq.com/index/ 抓取 tgw_l7_route cookie
_fetch_route_cookie() {
    local cookie
    cookie=$(curl -fsSL -A "$USER_AGENT" -c - "$COOKIE_URL" 2>/dev/null \
        | awk '/tgw_l7_route/ {print $7; exit}')
    if [[ -z "$cookie" ]]; then
        echo "无法从 $COOKIE_URL 获取 tgw_l7_route cookie" >&2
        return 1
    fi
    printf '%s' "$cookie"
}

# 对指定 deb 链接换取带 sign 的临时链接
_sign_url() {
    local url="$1"
    local cookie signed_url

    cookie=$(_fetch_route_cookie)

    signed_url=$(curl -fsSL -A "$USER_AGENT" \
        -H "Content-Type: application/json" \
        -H "Origin: https://im.qq.com" \
        -H "Referer: https://im.qq.com/index/" \
        -H "x-oidb: {\"uint32_command\":\"0x9b8e\",\"uint32_service_type\":1}" \
        -b "tgw_l7_route=$cookie" \
        --data-binary "$(python3 -c "import json,sys; print(json.dumps({'url': sys.argv[1]}))" "$url")" \
        "$SIGN_URL" \
        | python3 -c "import json,sys; print(json.load(sys.stdin)['data']['url'])")

    if [[ -z "$signed_url" ]]; then
        echo "GetSign 返回结果中无 data.url" >&2
        return 1
    fi
    printf '%s\n' "$signed_url"
}

# 从 pcConfig.json 解析指定架构的原始 deb 链接
_resolve_deb_url() {
    local arch="$1"
    local key config deb_url

    case "$arch" in
        x86_64)  key="x64DownloadUrl" ;;
        aarch64) key="armDownloadUrl" ;;
        loong64) key="loongarchDownloadUrl" ;;
        *)
            echo "未知架构: $arch" >&2
            return 1
            ;;
    esac

    config=$(curl -fsSL -A "$USER_AGENT" "$CONFIG_URL")

    if [[ "$key" == "loongarchDownloadUrl" ]]; then
        deb_url=$(printf '%s' "$config" | python3 -c "
import json, sys
print(json.load(sys.stdin)['Linux']['loongarchDownloadUrl'])
")
    else
        deb_url=$(printf '%s' "$config" | python3 -c "
import json, sys
print(json.load(sys.stdin)['Linux']['$key']['deb'])
")
    fi

    if [[ -z "$deb_url" ]]; then
        echo "无法解析 $arch 的 deb 链接" >&2
        return 1
    fi
    printf '%s\n' "$deb_url"
}

# DLAGENT 模式:签名并下载到指定路径
if [[ "${1:-}" == "--dlagent" ]]; then
    url="$2"
    output="$3"

    signed_url=$(_sign_url "$url")
    curl -fsSL -A "$USER_AGENT" -o "$output" "$signed_url"
    exit 0
fi

# 独立调用模式:根据架构输出带签名链接
if [[ $# -lt 1 ]]; then
    echo "用法: $0 <arch>  或  $0 --dlagent <url> <output>" >&2
    exit 1
fi

arch="$1"
deb_url=$(_resolve_deb_url "$arch")
_sign_url "$deb_url"