magpie-gemini-web 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -699,6 +699,53 @@ index 0000000..e5f1b6f
699
699
  + }
700
700
  + t.Fatal("没有记录这次请求")
701
701
  +}
702
+ diff --git a/internal/app/client.go b/internal/app/client.go
703
+ index 1750391..e613956 100644
704
+ --- a/internal/app/client.go
705
+ +++ b/internal/app/client.go
706
+ @@ -154,17 +154,32 @@ func makeSAPISIDHash(sapisid string) string {
707
+ return fmt.Sprintf("SAPISIDHASH %d_%s", ts, hex.EncodeToString(h[:]))
708
+ }
709
+
710
+ -// ChromeUA 是给 stdlib 走代理时用的 Chrome 146 真实 UA 模板。
711
+ +// ChromeUA 是 Chrome 146 的真实 UA 模板。
712
+ const ChromeUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36"
713
+
714
+ -// applyChromeHeaders 给 stdlib 请求填上模拟 Chrome 146 的应用层 header。
715
+ -// utls 那层做 TLS/HTTP2 指纹我们做不到(走代理),但 header 一定要齐。
716
+ +// chromeHeaders 是模拟 Chrome 146 的应用层 header,两条传输路径都要带齐:
717
+ +// 走代理时 utls 那层的 TLS/HTTP2 指纹我们做不到(stdlib),但 header 一定要齐;
718
+ +// 直连时 tls-client 只管指纹、不填 header,什么都不带的话 UA 是 Go-http-client/2.0,
719
+ +// 跟 Chrome 的握手对不上,同一个账号也会因为走没走代理而呈现两种客户端。
720
+ +var chromeHeaders = [][2]string{
721
+ + {"User-Agent", ChromeUA},
722
+ + {"Sec-CH-UA", `"Chromium";v="146", "Google Chrome";v="146", "Not?A_Brand";v="24"`},
723
+ + {"Sec-CH-UA-Mobile", "?0"},
724
+ + {"Sec-CH-UA-Platform", `"Windows"`},
725
+ + {"Sec-Fetch-Dest", "empty"},
726
+ + {"Sec-Fetch-Mode", "cors"},
727
+ + {"Sec-Fetch-Site", "same-origin"},
728
+ +}
729
+ +
730
+ +// setChromeHeaders 把 chromeHeaders 填进 net/http 或 fhttp 的 Header(两者都有 Set)。
731
+ +// 调用方之后再写自己的 header,同名的以调用方为准。
732
+ +func setChromeHeaders(h interface{ Set(key, value string) }) {
733
+ + for _, kv := range chromeHeaders {
734
+ + h.Set(kv[0], kv[1])
735
+ + }
736
+ +}
737
+ +
738
+ +// applyChromeHeaders 给 stdlib 请求填上 chromeHeaders。
739
+ func applyChromeHeaders(req *http.Request) {
740
+ - req.Header.Set("User-Agent", ChromeUA)
741
+ - req.Header.Set("Sec-CH-UA", `"Chromium";v="146", "Google Chrome";v="146", "Not?A_Brand";v="24"`)
742
+ - req.Header.Set("Sec-CH-UA-Mobile", "?0")
743
+ - req.Header.Set("Sec-CH-UA-Platform", `"Windows"`)
744
+ - req.Header.Set("Sec-Fetch-Dest", "empty")
745
+ - req.Header.Set("Sec-Fetch-Mode", "cors")
746
+ - req.Header.Set("Sec-Fetch-Site", "same-origin")
747
+ + setChromeHeaders(req.Header)
748
+ }
702
749
  diff --git a/internal/app/context_file.go b/internal/app/context_file.go
703
750
  index bfc577b..cb60661 100644
704
751
  --- a/internal/app/context_file.go
@@ -779,7 +826,7 @@ index bfc577b..cb60661 100644
779
826
  + return promptParts{body: parts}.join()
780
827
  }
781
828
  diff --git a/internal/app/conversation.go b/internal/app/conversation.go
782
- index aef12eb..cbf1371 100644
829
+ index aef12eb..8ba963f 100644
783
830
  --- a/internal/app/conversation.go
784
831
  +++ b/internal/app/conversation.go
785
832
  @@ -1,6 +1,7 @@
@@ -790,7 +837,23 @@ index aef12eb..cbf1371 100644
790
837
  "crypto/sha256"
791
838
  "encoding/hex"
792
839
  "encoding/json"
793
- @@ -244,8 +245,11 @@ const webUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
840
+ @@ -205,7 +206,7 @@ func getAnonSession(proxyURL string) (string, error) {
841
+ if err != nil {
842
+ return nil, nil, nil, err
843
+ }
844
+ - r.Header.Set("User-Agent", webUA)
845
+ + setChromeHeaders(r.Header)
846
+ resp, err := getTLSClient().Do(r)
847
+ if err != nil {
848
+ return nil, nil, nil, err
849
+ @@ -237,15 +238,14 @@ func getAnonSession(proxyURL string) (string, error) {
850
+ return strings.Join(pairs, "; "), nil
851
+ }
852
+
853
+ -// webUA 是匿名 GET /app 的 User-Agent(tls-client 路径要手动带)。
854
+ -const webUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
855
+ - "(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36"
856
+ -
794
857
  // streamGenerateConv 发一路会话的一轮。turn==0 是首轮(建会话),>0 是续接(只发新消息)。
795
858
  // 整条会话绑定 conv.cookie / conv.proxyID,中途不换号不换出口。成功后回填 conv 的
796
859
  // cid/rid/rcid/tok26 和 turn+1,供下一轮续接。
@@ -803,7 +866,7 @@ index aef12eb..cbf1371 100644
803
866
  p, slotOK, slotErr := acquireSlot(conv.proxyID)
804
867
  if !slotOK {
805
868
  return &StreamResult{}, slotErr
806
- @@ -365,13 +369,19 @@ func streamGenerateConv(prompt string, mc ModelConfig, conv *convState,
869
+ @@ -365,13 +365,19 @@ func streamGenerateConv(prompt string, mc ModelConfig, conv *convState,
807
870
  t0 := time.Now()
808
871
  var lastErr error
809
872
  for attempt := 0; attempt < rtCfg().RetryAttempts; attempt++ {
@@ -824,7 +887,7 @@ index aef12eb..cbf1371 100644
824
887
  if err == nil && statusCode == 200 {
825
888
  lastErr = fmt.Errorf("续接无内容帧(会话可能已失效,raw %d 字节)", len(raw))
826
889
  } else if err != nil {
827
- @@ -386,7 +396,9 @@ func streamGenerateConv(prompt string, mc ModelConfig, conv *convState,
890
+ @@ -386,7 +392,9 @@ func streamGenerateConv(prompt string, mc ModelConfig, conv *convState,
828
891
  break
829
892
  }
830
893
  if attempt < rtCfg().RetryAttempts-1 {
@@ -835,7 +898,7 @@ index aef12eb..cbf1371 100644
835
898
  }
836
899
  continue
837
900
  }
838
- @@ -427,7 +439,7 @@ func streamGenerateConv(prompt string, mc ModelConfig, conv *convState,
901
+ @@ -427,7 +435,7 @@ func streamGenerateConv(prompt string, mc ModelConfig, conv *convState,
839
902
  // - 没命中 → 新建会话,首轮发全量拼接的历史(含 tools 指令,把当前上下文交给服务端)。
840
903
  //
841
904
  // 支持 tools(续接里也解析 ```tool_call``` 围栏);图片走原单轮路径(callGemini)。
@@ -844,7 +907,7 @@ index aef12eb..cbf1371 100644
844
907
  tools []map[string]interface{}, toolChoice interface{},
845
908
  onDelta, onReasoning func(string)) (string, []ToolCall, *StreamResult, error) {
846
909
  parentKey := convParentKey(messages)
847
- @@ -462,7 +474,7 @@ func callGeminiConv(messages []map[string]interface{}, mc ModelConfig,
910
+ @@ -462,7 +470,7 @@ func callGeminiConv(messages []map[string]interface{}, mc ModelConfig,
848
911
  logf("[conv] 续接命中 turn=%d,只发 %d 字节(历史留服务端)", conv.turn, len(prompt))
849
912
  }
850
913
 
@@ -854,7 +917,7 @@ index aef12eb..cbf1371 100644
854
917
  if !fresh {
855
918
  // 续接失败:这路会话作废,客户端重试时会当新会话全量重发。
856
919
  diff --git a/internal/app/gemini.go b/internal/app/gemini.go
857
- index 723725f..a1e5221 100644
920
+ index 723725f..150b022 100644
858
921
  --- a/internal/app/gemini.go
859
922
  +++ b/internal/app/gemini.go
860
923
  @@ -3,6 +3,7 @@ package app
@@ -1148,7 +1211,7 @@ index 723725f..a1e5221 100644
1148
1211
  if err != nil {
1149
1212
  return resp.StatusCode, nil, ttfb, resp.Header.Values("Set-Cookie"), err
1150
1213
  }
1151
- @@ -844,7 +944,7 @@ func doGeminiRequest(endpoint, body string, headers map[string]string, proxyURL
1214
+ @@ -844,10 +944,11 @@ func doGeminiRequest(endpoint, body string, headers map[string]string, proxyURL
1152
1215
  }
1153
1216
 
1154
1217
  // 直连 → tls-client,保留 chrome146 TLS/HTTP2 真指纹
@@ -1157,7 +1220,11 @@ index 723725f..a1e5221 100644
1157
1220
  if err != nil {
1158
1221
  return 0, nil, 0, nil, err
1159
1222
  }
1160
- @@ -857,7 +957,7 @@ func doGeminiRequest(endpoint, body string, headers map[string]string, proxyURL
1223
+ + setChromeHeaders(req.Header)
1224
+ for k, v := range headers {
1225
+ req.Header.Set(k, v)
1226
+ }
1227
+ @@ -857,7 +958,7 @@ func doGeminiRequest(endpoint, body string, headers map[string]string, proxyURL
1161
1228
  return 0, nil, 0, nil, err
1162
1229
  }
1163
1230
  defer resp.Body.Close()
@@ -1166,6 +1233,14 @@ index 723725f..a1e5221 100644
1166
1233
  if err != nil {
1167
1234
  return resp.StatusCode, nil, ttfb, resp.Header.Values("Set-Cookie"), err
1168
1235
  }
1236
+ @@ -1159,6 +1260,7 @@ func probeGemini(prompt, proxyURL string) ProbeResult {
1237
+ res.Diagnostic = "构建请求失败: " + e.Error()
1238
+ return res
1239
+ }
1240
+ + setChromeHeaders(req.Header)
1241
+ for k, v := range headers {
1242
+ req.Header.Set(k, v)
1243
+ }
1169
1244
  diff --git a/internal/app/gemini_test.go b/internal/app/gemini_test.go
1170
1245
  index 00eb305..2b4c6ca 100644
1171
1246
  --- a/internal/app/gemini_test.go
@@ -1178,12 +1253,114 @@ index 00eb305..2b4c6ca 100644
1178
1253
  }
1179
1254
  for _, c := range cases {
1180
1255
  name, mc, err := resolveModel(c.name)
1256
+ diff --git a/internal/app/headers_test.go b/internal/app/headers_test.go
1257
+ new file mode 100644
1258
+ index 0000000..b80a9fa
1259
+ --- /dev/null
1260
+ +++ b/internal/app/headers_test.go
1261
+ @@ -0,0 +1,96 @@
1262
+ +package app
1263
+ +
1264
+ +import (
1265
+ + "context"
1266
+ + "net/http"
1267
+ + "net/http/httptest"
1268
+ + "testing"
1269
+ +
1270
+ + tls_client "github.com/bogdanfinn/tls-client"
1271
+ +)
1272
+ +
1273
+ +// 同一个账号的请求不能因为走没走代理而呈现两种客户端:两条路径都要带齐 chromeHeaders,
1274
+ +// 调用方自己的 header 照样生效。直连那条以前一个都不带,UA 是 Go-http-client/2.0。
1275
+ +//
1276
+ +// 直连走 tls-client,这里换成跳过证书校验的同款客户端,打本机的 HTTPS 测试服务器;
1277
+ +// 代理那条把 http:// 目标以绝对 URI 发给代理,测试服务器本身就能当代理(同 cancel_test)。
1278
+ +func TestDirectAndProxyPathsSendSameBrowserHeaders(t *testing.T) {
1279
+ + got := map[string]http.Header{}
1280
+ + record := func(name string) http.Handler {
1281
+ + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1282
+ + got[name] = r.Header.Clone()
1283
+ + w.WriteHeader(200)
1284
+ + })
1285
+ + }
1286
+ + direct := httptest.NewUnstartedServer(record("direct"))
1287
+ + direct.EnableHTTP2 = true
1288
+ + direct.StartTLS()
1289
+ + defer direct.Close()
1290
+ + proxy := httptest.NewServer(record("proxy"))
1291
+ + defer proxy.Close()
1292
+ +
1293
+ + key := rtCfg().Impersonate
1294
+ + insecure, err := tls_client.NewHttpClient(tls_client.NewNoopLogger(),
1295
+ + tls_client.WithClientProfile(resolveProfile(key)),
1296
+ + tls_client.WithInsecureSkipVerify(),
1297
+ + tls_client.WithNotFollowRedirects())
1298
+ + if err != nil {
1299
+ + t.Fatal(err)
1300
+ + }
1301
+ + clientCacheMu.Lock()
1302
+ + prev, had := clientCache[key]
1303
+ + clientCache[key] = insecure
1304
+ + clientCacheMu.Unlock()
1305
+ + t.Cleanup(func() {
1306
+ + clientCacheMu.Lock()
1307
+ + defer clientCacheMu.Unlock()
1308
+ + if had {
1309
+ + clientCache[key] = prev
1310
+ + } else {
1311
+ + delete(clientCache, key)
1312
+ + }
1313
+ + })
1314
+ +
1315
+ + own := map[string]string{"Accept-Language": "en-US,en;q=0.9", "X-Same-Domain": "1"}
1316
+ + paths := []struct {
1317
+ + name string
1318
+ + send func(endpoint, proxyURL string)
1319
+ + }{
1320
+ + {"StreamGenerate", func(endpoint, proxyURL string) {
1321
+ + doGeminiRequestStop(context.Background(), endpoint, "f.req=x", own, proxyURL, nil, nil)
1322
+ + }},
1323
+ + {"upload", func(endpoint, proxyURL string) {
1324
+ + uploadPostCtx(context.Background(), endpoint, own, []byte("x"), proxyURL)
1325
+ + }},
1326
+ + {"media", func(endpoint, proxyURL string) {
1327
+ + mediaGetOnce(endpoint, own, proxyURL)
1328
+ + }},
1329
+ + {"image", func(endpoint, proxyURL string) {
1330
+ + fetchImage(endpoint, proxyURL, 0)
1331
+ + }},
1332
+ + }
1333
+ + for _, p := range paths {
1334
+ + clear(got)
1335
+ + p.send(direct.URL+"/x", "")
1336
+ + p.send("http://upstream.invalid/x", proxy.URL)
1337
+ + d, pr := got["direct"], got["proxy"]
1338
+ + if d == nil || pr == nil {
1339
+ + t.Fatalf("%s: 没收到请求(direct=%v proxy=%v)", p.name, d != nil, pr != nil)
1340
+ + }
1341
+ + if ua := d.Get("User-Agent"); ua != ChromeUA {
1342
+ + t.Errorf("%s: 直连 UA = %q", p.name, ua)
1343
+ + }
1344
+ + for _, kv := range chromeHeaders {
1345
+ + if d.Get(kv[0]) != pr.Get(kv[0]) {
1346
+ + t.Errorf("%s: %s 直连 %q,代理 %q", p.name, kv[0], d.Get(kv[0]), pr.Get(kv[0]))
1347
+ + }
1348
+ + }
1349
+ + if p.name != "image" {
1350
+ + for k, v := range own {
1351
+ + if d.Get(k) != v || pr.Get(k) != v {
1352
+ + t.Errorf("%s: 调用方的 %s 没生效(直连 %q,代理 %q)", p.name, k, d.Get(k), pr.Get(k))
1353
+ + }
1354
+ + }
1355
+ + }
1356
+ + }
1357
+ +}
1181
1358
  diff --git a/internal/app/latency_test.go b/internal/app/latency_test.go
1182
1359
  new file mode 100644
1183
- index 0000000..9329309
1360
+ index 0000000..b30336f
1184
1361
  --- /dev/null
1185
1362
  +++ b/internal/app/latency_test.go
1186
- @@ -0,0 +1,299 @@
1363
+ @@ -0,0 +1,297 @@
1187
1364
  +package app
1188
1365
  +
1189
1366
  +import (
@@ -1406,17 +1583,15 @@ index 0000000..9329309
1406
1583
  + }
1407
1584
  +}
1408
1585
  +
1409
- +// 轮转后重取失败时必须作废缓存,否则失效的号会一直拿着旧 token 被当成可用。
1410
- +func TestRefreshXSRFFailureDropsCache(t *testing.T) {
1586
+ +// 后台重取失败时必须作废缓存,否则失效的号会一直拿着旧 token 被当成可用。
1587
+ +func TestRefreshAppTokensFailureDropsCache(t *testing.T) {
1411
1588
  + cookie := "SAPISID=sap2; __Secure-1PSID=psid2"
1412
1589
  + xsrfMu.Lock()
1413
1590
  + xsrfCache[cookieKey(cookie)] = xsrfEntry{token: "stale", fetched: time.Now()}
1414
1591
  + xsrfMu.Unlock()
1415
1592
  + t.Cleanup(func() { invalidateXSRF(cookie) })
1416
1593
  +
1417
- + if err := refreshXSRF(cookie, "http://127.0.0.1:1"); err == nil {
1418
- + t.Fatal("不可达出口应报错")
1419
- + }
1594
+ + refreshAppTokens(cookieKey(cookie), cookie, "http://127.0.0.1:1")
1420
1595
  + xsrfMu.Lock()
1421
1596
  + _, ok := xsrfCache[cookieKey(cookie)]
1422
1597
  + xsrfMu.Unlock()
@@ -1483,6 +1658,18 @@ index 0000000..9329309
1483
1658
  + t.Fatalf("非流式: stop=%v reads=%d tracker=%q", lh.stop.Load(), src.reads, lh.tracker.emitted)
1484
1659
  + }
1485
1660
  +}
1661
+ diff --git a/internal/app/media.go b/internal/app/media.go
1662
+ index 9844778..03610f9 100644
1663
+ --- a/internal/app/media.go
1664
+ +++ b/internal/app/media.go
1665
+ @@ -505,6 +505,7 @@ func mediaGetOnce(rawURL string, headers map[string]string, proxyURL string) (in
1666
+ if err != nil {
1667
+ return 0, nil, nil, err
1668
+ }
1669
+ + setChromeHeaders(req.Header)
1670
+ for k, v := range headers {
1671
+ req.Header.Set(k, v)
1672
+ }
1486
1673
  diff --git a/internal/app/messages.go b/internal/app/messages.go
1487
1674
  index 376171f..87b91fe 100644
1488
1675
  --- a/internal/app/messages.go
@@ -1680,26 +1867,6 @@ index 376171f..87b91fe 100644
1680
1867
  // parseToolChoice 解析 OpenAI 的 tool_choice。
1681
1868
  // 返回 (mode, forcedName):mode ∈ {"auto","none","required"};
1682
1869
  // forcedName 非空表示客户端点名了某个函数。
1683
- diff --git a/internal/app/rotate.go b/internal/app/rotate.go
1684
- index e082b15..908a052 100644
1685
- --- a/internal/app/rotate.go
1686
- +++ b/internal/app/rotate.go
1687
- @@ -95,7 +95,14 @@ func rotateAccount(a CookieAccount) (time.Duration, []string, error) {
1688
- if cookie != a.Cookie {
1689
- old := a.Cookie
1690
- updateAccountCookie(a.ID, cookie)
1691
- - invalidateXSRF(old)
1692
- + // 轮转本身不在请求路径上,顺手用新 cookie 重取 token:既验证轮转结果,
1693
- + // 又让下一个请求直接命中缓存。失败时缓存已作废,下个请求同步重取。
1694
- + if err := refreshXSRF(cookie, proxyURL); err != nil {
1695
- + logf("[rotate] 账号 #%d 轮转后取 XSRF 失败: %v", a.ID, err)
1696
- + }
1697
- + if cookieKey(old) != cookieKey(cookie) {
1698
- + invalidateXSRF(old) // 身份项都变了(理论上不会):旧键别留着
1699
- + }
1700
- }
1701
- if len(names) > 0 {
1702
- logf("[rotate] 账号 #%d 刷新了 %s", a.ID, strings.Join(names, ", "))
1703
1870
  diff --git a/internal/app/server.go b/internal/app/server.go
1704
1871
  index c3a7df1..eb02909 100644
1705
1872
  --- a/internal/app/server.go
@@ -1808,7 +1975,7 @@ index c3a7df1..eb02909 100644
1808
1975
  if stream {
1809
1976
  writeEvent("response.failed", map[string]interface{}{
1810
1977
  diff --git a/internal/app/upload.go b/internal/app/upload.go
1811
- index 7747a72..09e8a04 100644
1978
+ index 7747a72..2753f93 100644
1812
1979
  --- a/internal/app/upload.go
1813
1980
  +++ b/internal/app/upload.go
1814
1981
  @@ -2,6 +2,7 @@ package app
@@ -1865,7 +2032,7 @@ index 7747a72..09e8a04 100644
1865
2032
  if err != nil {
1866
2033
  return 0, nil, nil, err
1867
2034
  }
1868
- @@ -131,7 +142,7 @@ func uploadPost(url string, headers map[string]string, body []byte, proxyURL str
2035
+ @@ -131,10 +142,11 @@ func uploadPost(url string, headers map[string]string, body []byte, proxyURL str
1869
2036
  }
1870
2037
  return resp.StatusCode, h, b, err
1871
2038
  }
@@ -1874,6 +2041,10 @@ index 7747a72..09e8a04 100644
1874
2041
  if err != nil {
1875
2042
  return 0, nil, nil, err
1876
2043
  }
2044
+ + setChromeHeaders(req.Header)
2045
+ for k, v := range headers {
2046
+ req.Header.Set(k, v)
2047
+ }
1877
2048
  diff --git a/internal/app/videos.go b/internal/app/videos.go
1878
2049
  index 390b580..0365a78 100644
1879
2050
  --- a/internal/app/videos.go
@@ -1895,8 +2066,20 @@ index 390b580..0365a78 100644
1895
2066
  if err != nil {
1896
2067
  recordRequest("videos", j.Model, j.Prompt, "", res, 502, err.Error(), false)
1897
2068
  finishVideoJob(j, nil, "", err.Error())
2069
+ diff --git a/internal/app/vision.go b/internal/app/vision.go
2070
+ index b0c9724..b1ca7cb 100644
2071
+ --- a/internal/app/vision.go
2072
+ +++ b/internal/app/vision.go
2073
+ @@ -160,6 +160,7 @@ func fetchImage(src, proxyURL string, idx int) (pendingUpload, error) {
2074
+ if err != nil {
2075
+ return pendingUpload{}, err
2076
+ }
2077
+ + setChromeHeaders(req.Header)
2078
+ resp, err := getTLSClient().Do(req)
2079
+ if err != nil {
2080
+ return pendingUpload{}, fmt.Errorf("image %d: fetch failed: %w", idx, err)
1898
2081
  diff --git a/internal/app/xsrf.go b/internal/app/xsrf.go
1899
- index c43b104..55634b6 100644
2082
+ index c43b104..d3d7145 100644
1900
2083
  --- a/internal/app/xsrf.go
1901
2084
  +++ b/internal/app/xsrf.go
1902
2085
  @@ -27,15 +27,23 @@ var (
@@ -1961,7 +2144,7 @@ index c43b104..55634b6 100644
1961
2144
 
1962
2145
  e, err := fetchAppTokens(cookie, proxyURL)
1963
2146
  if err != nil {
1964
- @@ -84,16 +99,59 @@ func getXSRF(cookie, proxyURL string) (string, error) {
2147
+ @@ -84,16 +99,48 @@ func getXSRF(cookie, proxyURL string) (string, error) {
1965
2148
  return e.token, nil
1966
2149
  }
1967
2150
 
@@ -1988,17 +2171,6 @@ index c43b104..55634b6 100644
1988
2171
  + }
1989
2172
  +}
1990
2173
  +
1991
- +// refreshXSRF 立即重抓页面并写回缓存,失败则作废缓存。
1992
- +//
1993
- +// 给本来就不在请求关键路径上的调用方用(cookie 轮转):轮转后直接作废的话,
1994
- +// 缓存按账号身份取键,下一个请求就得同步抓一次页面(实测约 1.2 秒)。
1995
- +func refreshXSRF(cookie, proxyURL string) error {
1996
- + if cookie == "" {
1997
- + return nil
1998
- + }
1999
- + return storeAppTokens(cookieKey(cookie), cookie, proxyURL)
2000
- +}
2001
- +
2002
2174
  +func storeAppTokens(key, cookie, proxyURL string) error {
2003
2175
  + e, err := fetchAppTokens(cookie, proxyURL)
2004
2176
  + xsrfMu.Lock()
@@ -2025,3 +2197,11 @@ index c43b104..55634b6 100644
2025
2197
 
2026
2198
  e, err := fetchAppTokens(cookie, proxyURL)
2027
2199
  if err != nil {
2200
+ @@ -146,6 +193,7 @@ func fetchAppPage(cookie, proxyURL string) ([]byte, error) {
2201
+ if err != nil {
2202
+ return nil, err
2203
+ }
2204
+ + setChromeHeaders(req.Header)
2205
+ for k, v := range headers {
2206
+ req.Header.Set(k, v)
2207
+ }
@@ -41,7 +41,7 @@ async function main() {
41
41
  const sha256 = crypto.createHash('sha256').update(bytes).digest('hex');
42
42
 
43
43
  const manifest = {
44
- version: '4.22.0-argon.1',
44
+ version: '4.22.0-argon.2',
45
45
  sourceCommit: pinned,
46
46
  sha256,
47
47
  platform: 'darwin',