clash-linux commited on
Commit
f998986
·
verified ·
1 Parent(s): b30c9da

Upload 15 files

Browse files
.env ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Notion的cookie,请把浏览器Cookie部分完整复制下来,多个cookie用|分割
2
+ NOTION_COOKIE="notion_browser_id=fdf38010-21d4-433e-a2fd-65cab87f49f6; device_id=202d872b-594c-81d6-9a95-003bb32158fc; NEXT_LOCALE=zh-CN; _gcl_au=1.1.132916819.1748542408; _ga=GA1.1.1824875636.1748542409; _fbp=fb.1.1748542411909.266391455622580792; notion_user_id=200d872b-594c-81d3-bb1b-00024f30311d; p_sync_session=%7B%22tokenId%22%3A%22v02%3Async_session%3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlax4r-9CwW1tAnM4hm7SsLu9h-MytbYGKknbSPCj2F07ufgzyShCKc0MIvr1LYGI2ihhhjiqn8aHlsgy2otKQnuChsnq0LwuaQVt%22%2C%22userIds%22%3A%5B%22200d872b-594c-81d3-bb1b-00024f30311d%22%5D%7D; _cioid=200d872b594c81d3bb1b00024f30311d; notion_cookie_sync_completed=%7B%22completed%22%3Atrue%2C%22version%22%3A4%2C%22attempts%22%3A1%7D; notion_users=[%22200d872b-594c-81d3-bb1b-00024f30311d%22]; _hjSessionUser_3664679=eyJpZCI6IjgwYjAzZGViLWUxZmMtNTA3MC1iNDA2LWMyNzhlODdiZDdlNyIsImNyZWF0ZWQiOjE3NDg1NDI0MTE4ODEsImV4aXN0aW5nIjp0cnVlfQ==; notion_check_cookie_consent=false; _cfuvid=Pd_QxMVa8SMbHI8r0zNaAYlgczHrP_plvfapRgoHamE-1749308468696-0.0.1.1-604800000; _rdt_uuid=1748542408747.963fa76b-30e7-4e18-ab01-aba3f7a1457e; _hjSession_3664679=eyJpZCI6IjJmOTk2OTQzLTNjMzktNDE3ZS05YmFjLWVkZGJiNDlmNzBlNSIsImMiOjE3NDkzMDg0Nzc5MzcsInMiOjAsInIiOjAsInNiIjowLCJzciI6MCwic2UiOjAsImZzIjowLCJzcCI6MX0=; __cf_bm=9qEQ2V9hIxBqYj.ajFLUvkgaSFQRRvQbSweUzjulXLQ-1749308501-1.0.1.1-LsQtYoKBUqSSz23TcFlKQ_HKBokINZNca_y_5K4DflDfjU8LrpAylSqnX4tAn97QJ51zBJ9uMZneTnU_tPoBCokRsFffnV2Kt69cp_U5KcvakaUpeNtVModlsviSJKmQ; notion_locale=zh-CN/autodetect; token_v2=v03%3AeyJhbGciOiJkaXIiLCJraWQiOiJwcm9kdWN0aW9uOnRva2VuLXYzOjIwMjQtMTEtMDciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0..udCqaHPmeajJluGEoRCwMQ.KwYcnDQeUSch7kuEiW2rD7T7Pwwg6CaU9UM2b-xfydsnnFdHNnxLFSGBeyVNbFaMfy6sWw0P9rSujhF9iov_tAvnhZ2IFEG4ND9Jwu8VNQwsOLQUAj3WfHGaHnTAGEbgNN2vRXtsb_CHYi4PJtd5bweDEEBtMhZIDBcwUTCIJpXIk9pS8aPfY5N6_weYJSJ6a959TerGpfRMZDasH_C0MDxLgiJZft6qGmarx0XOhU_QkUONs6pFfe1no029nLwy1clKJLAshicHTKx7mqmXIjfMWLaHXbKKTC08Pekxhxwx35kwadnS1JgYI85-I0SQZ9VanCs82_CAfDUBIbw5VWn6xQEmCOTpo1mf68vSX_k.lCEqDypSmYd-LZkB3MvzOpu8YXw6E2Slhy0F1Kh9xPk; _ga_9ZJ8CB186L=GS2.1.s1749308471$o3$g1$t1749308568$j60$l0$h0|notion_browser_id=a8182934-adff-461b-8c79-1506999adea4; device_id=200d872b-594c-812e-b369-003bcda8cdcd; _gcl_au=1.1.1170453355.1748542388; _ga=GA1.1.701605925.1748542389; _hjSessionUser_3664679=eyJpZCI6ImVlMmY4ZDIxLTMxY2QtNWMzNS1hZmQ1LThmYThjMjBiMTdhMCIsImNyZWF0ZWQiOjE3NDg1NDIzOTExMzcsImV4aXN0aW5nIjp0cnVlfQ==; notion_check_cookie_consent=false; _fbp=fb.1.1749309115969.575678538958199822; _hjSession_3664679=eyJpZCI6ImYyMGQ5MThkLTE5MWMtNDJlZi04ZTJlLTQwZTk3ZmQ4MzM2YiIsImMiOjE3NDkzMDkxMTcxODYsInMiOjAsInIiOjAsInNiIjowLCJzciI6MCwic2UiOjAsImZzIjowLCJzcCI6MH0=; NEXT_LOCALE=en-US; _cfuvid=AxS6qsfXNaj6l97fAzOZU19l.Tq0B7u1SDbVVm._.J4-1749309401915-0.0.1.1-604800000; notion_locale=en-US/user_choice; _rdt_uuid=1748542388717.64a3c6ac-6961-4401-9aec-9dfbb27dd932; csrf=3c4feb4b-6326-40c0-9475-4e1884f6cbbd; notion_user_id=20bd872b-594c-81a1-b249-0002d1feacbe; notion_users=%5B%2220bd872b-594c-81a1-b249-0002d1feacbe%22%5D; p_sync_session=%7B%22tokenId%22%3A%22v02%3Async_session%3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGn5K6DxWWr51s8yjzd8Tv7u9h-MytbYGKknbSPCj2F07ufgzySUZeMoMevz1LdHU0yNhhj-uycaHls1l2thMEH6B0pW81u17PwVt%22%2C%22userIds%22%3A%5B%2220bd872b-594c-81a1-b249-0002d1feacbe%22%5D%7D; _cioid=20bd872b594c81a1b2490002d1feacbe; token_v2=v03%3AeyJhbGciOiJkaXIiLCJraWQiOiJwcm9kdWN0aW9uOnRva2VuLXYzOjIwMjQtMTEtMDciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0..g6nQTmUif39kpQiFt5x-1g.lwqScXxX6fzfW4oAw6_bJh1CrPh5N0vjBFNyo0_g3uv424aZFa_1a3pgTfDbJzydbbLnYDaNnLBZcYjfeZkcgz8dMpuZ2WtlHscPQoEPaXVjzD3PidXmUPmRyA2sNVMZJtaLd39_zJra8j8pKLYsCVEdfrgj_QYdedTAvAVjbA1twjdEv0Bl3ur8o63kQUOkzIWro5hDgqAr4AMkkCzmNR2X2AtjvOZFdt9YlnYtLn-tdCYEtOZGV-zhNL34QjXZVWmdnnaQg8p0lBm9ZP-y3hztbjwLTVYPNBDKnhZeu-Qra96KZZitMZDsZt944GbKUTOPL0PF8vULVBrYyoHPQw.y4DOnuNzKTwrPk0WVKUv1RERNMqSt1MuBM9MGuM5uMM; _ga_9ZJ8CB186L=GS2.1.s1749309117$o3$g1$t1749311301$j60$l0$h0; __cf_bm=a09Uutq_rs.5z8Bf6fJvEply_vQblokHM1U6Yd9y4Yo-1749311305-1.0.1.1-H3RXZorJC7x1BR8jgC2fSwewxFUMy2P06KP2_FHT99tHLoZ5EKDfj_Olhohp2qTDbAJXDEM_ofP2_Qywfs4bA7jJgSCAGX_PKpHCoBTOQ_KqFb8DZ40X9cA7KDo3CSSW"
3
+ # 反代密码,没有的话默认密码是 default_token
4
+ PROXY_AUTH_TOKEN="sk-123456"
5
+ # (可选)代理地址,如果填了所有请求将经过代理,针对notion限制ip对策,可使用http或socks5代理(notion支持ipv6哦,有ipv6池子的可以拿出来了)
6
+ PROXY_URL=""
7
+ # 新版本正常用户不需要,如果不是有特殊需求请一定留空(只有使用notion teams白嫖别人space的用户需填写)
8
+ NOTION_SPACE_ID=""
9
+ # 新版本正常用户不需要,如果不是有特殊需求请一定留空(只有使用notion teams白嫖别人space的用户需填写)
10
+ NOTION_ACTIVE_USER_HEADER=""
11
+ # 是否使用原生代理池,如果为true,则使用原生代理池,如果为false,则使用代理池
12
+ USE_NATIVE_PROXY_POOL=true
13
+
14
+ # 代理服务器配置
15
+ # 平台选择:auto(自动检测), windows, linux, android
16
+ PROXY_SERVER_PLATFORM="auto"
17
+ # ���理服务器端口
18
+ PROXY_SERVER_PORT=10655
19
+ # 代理服务器日志文件路径
20
+ PROXY_SERVER_LOG_PATH="./proxy_server.log"
21
+ # 是否启用代理服务器
22
+ ENABLE_PROXY_SERVER=true
Dockerfile CHANGED
@@ -1,32 +1,23 @@
1
- # Use an official Node.js runtime as a parent image
2
- FROM node:18-slim
3
-
4
- # Set the working directory in the container
5
- WORKDIR /app
6
-
7
- # Copy package.json and package-lock.json to the working directory
8
- COPY package*.json ./
9
-
10
- # Install app dependencies
11
- # Using --production flag to install only production dependencies
12
- # Playwright needs special handling to download browsers
13
- # We need to install dependencies first to make sure Playwright downloads its browsers.
14
- RUN npm install --production
15
-
16
- # Copy the rest of the application source code to the working directory
17
- COPY . .
18
-
19
- # Grant execute permission to the proxy server binary
20
- RUN chmod +x /app/src/proxy/chrome_proxy_server_linux_amd64
21
-
22
- # Change ownership of the app directory to the node user
23
- RUN chown -R node:node /app
24
-
25
- # Switch to a non-root user
26
- USER node
27
-
28
- # Make port 7860 available to the world outside this container
29
- EXPOSE 7860
30
-
31
- # Define the command to run the app
32
  CMD ["npm", "start"]
 
1
+ # Use an official Node.js runtime as a parent image
2
+ FROM node:18-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /app
6
+
7
+ # Copy package.json and package-lock.json to the working directory
8
+ COPY package*.json ./
9
+
10
+ # Install app dependencies
11
+ # Using --production flag to install only production dependencies
12
+ # Playwright needs special handling to download browsers
13
+ # We need to install dependencies first to make sure Playwright downloads its browsers.
14
+ RUN npm install --production
15
+
16
+ # Copy the rest of the application source code to the working directory
17
+ COPY . .
18
+
19
+ # Make port 7860 available to the world outside this container
20
+ EXPOSE 7860
21
+
22
+ # Define the command to run the app
 
 
 
 
 
 
 
 
 
23
  CMD ["npm", "start"]
package-lock.json CHANGED
@@ -16,7 +16,8 @@
16
  "https-proxy-agent": "^7.0.2",
17
  "jsdom": "^22.1.0",
18
  "node-fetch": "^3.3.2",
19
- "playwright": "^1.40.1"
 
20
  },
21
  "devDependencies": {
22
  "nodemon": "^3.0.2"
@@ -995,6 +996,18 @@
995
  "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
996
  "license": "ISC"
997
  },
 
 
 
 
 
 
 
 
 
 
 
 
998
  "node_modules/ipaddr.js": {
999
  "version": "1.9.1",
1000
  "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -1056,6 +1069,11 @@
1056
  "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
1057
  "license": "MIT"
1058
  },
 
 
 
 
 
1059
  "node_modules/jsdom": {
1060
  "version": "22.1.0",
1061
  "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
@@ -1772,6 +1790,67 @@
1772
  "node": ">=10"
1773
  }
1774
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1775
  "node_modules/statuses": {
1776
  "version": "2.0.1",
1777
  "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
 
16
  "https-proxy-agent": "^7.0.2",
17
  "jsdom": "^22.1.0",
18
  "node-fetch": "^3.3.2",
19
+ "playwright": "^1.40.1",
20
+ "socks-proxy-agent": "^8.0.5"
21
  },
22
  "devDependencies": {
23
  "nodemon": "^3.0.2"
 
996
  "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
997
  "license": "ISC"
998
  },
999
+ "node_modules/ip-address": {
1000
+ "version": "9.0.5",
1001
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
1002
+ "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
1003
+ "dependencies": {
1004
+ "jsbn": "1.1.0",
1005
+ "sprintf-js": "^1.1.3"
1006
+ },
1007
+ "engines": {
1008
+ "node": ">= 12"
1009
+ }
1010
+ },
1011
  "node_modules/ipaddr.js": {
1012
  "version": "1.9.1",
1013
  "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
 
1069
  "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
1070
  "license": "MIT"
1071
  },
1072
+ "node_modules/jsbn": {
1073
+ "version": "1.1.0",
1074
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
1075
+ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
1076
+ },
1077
  "node_modules/jsdom": {
1078
  "version": "22.1.0",
1079
  "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
 
1790
  "node": ">=10"
1791
  }
1792
  },
1793
+ "node_modules/smart-buffer": {
1794
+ "version": "4.2.0",
1795
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
1796
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
1797
+ "engines": {
1798
+ "node": ">= 6.0.0",
1799
+ "npm": ">= 3.0.0"
1800
+ }
1801
+ },
1802
+ "node_modules/socks": {
1803
+ "version": "2.8.4",
1804
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
1805
+ "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
1806
+ "dependencies": {
1807
+ "ip-address": "^9.0.5",
1808
+ "smart-buffer": "^4.2.0"
1809
+ },
1810
+ "engines": {
1811
+ "node": ">= 10.0.0",
1812
+ "npm": ">= 3.0.0"
1813
+ }
1814
+ },
1815
+ "node_modules/socks-proxy-agent": {
1816
+ "version": "8.0.5",
1817
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
1818
+ "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
1819
+ "dependencies": {
1820
+ "agent-base": "^7.1.2",
1821
+ "debug": "^4.3.4",
1822
+ "socks": "^2.8.3"
1823
+ },
1824
+ "engines": {
1825
+ "node": ">= 14"
1826
+ }
1827
+ },
1828
+ "node_modules/socks-proxy-agent/node_modules/debug": {
1829
+ "version": "4.4.1",
1830
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
1831
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
1832
+ "dependencies": {
1833
+ "ms": "^2.1.3"
1834
+ },
1835
+ "engines": {
1836
+ "node": ">=6.0"
1837
+ },
1838
+ "peerDependenciesMeta": {
1839
+ "supports-color": {
1840
+ "optional": true
1841
+ }
1842
+ }
1843
+ },
1844
+ "node_modules/socks-proxy-agent/node_modules/ms": {
1845
+ "version": "2.1.3",
1846
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1847
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1848
+ },
1849
+ "node_modules/sprintf-js": {
1850
+ "version": "1.1.3",
1851
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
1852
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
1853
+ },
1854
  "node_modules/statuses": {
1855
  "version": "2.0.1",
1856
  "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
package.json CHANGED
@@ -1,33 +1,34 @@
1
- {
2
- "name": "notion2api-nodejs",
3
- "version": "1.0.0",
4
- "description": "Notion API client with lightweight browser-free option",
5
- "main": "src/lightweight-client-express.js",
6
- "type": "module",
7
- "scripts": {
8
- "start": "node src/lightweight-client-express.js",
9
- "dev": "nodemon src/lightweight-client-express.js",
10
- "original": "node src/index.js"
11
- },
12
- "keywords": [
13
- "notion",
14
- "openai",
15
- "api",
16
- "bridge"
17
- ],
18
- "author": "",
19
- "license": "MIT",
20
- "dependencies": {
21
- "axios": "^1.9.0",
22
- "chalk": "^4.1.2",
23
- "dotenv": "^16.3.1",
24
- "express": "^4.18.2",
25
- "https-proxy-agent": "^7.0.2",
26
- "jsdom": "^22.1.0",
27
- "node-fetch": "^3.3.2",
28
- "playwright": "^1.40.1"
29
- },
30
- "devDependencies": {
31
- "nodemon": "^3.0.2"
32
- }
33
- }
 
 
1
+ {
2
+ "name": "notion2api-nodejs",
3
+ "version": "1.0.0",
4
+ "description": "Notion API client with lightweight browser-free option",
5
+ "main": "src/lightweight-client-express.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "node src/lightweight-client-express.js",
9
+ "dev": "nodemon src/lightweight-client-express.js",
10
+ "original": "node src/index.js"
11
+ },
12
+ "keywords": [
13
+ "notion",
14
+ "openai",
15
+ "api",
16
+ "bridge"
17
+ ],
18
+ "author": "",
19
+ "license": "MIT",
20
+ "dependencies": {
21
+ "axios": "^1.9.0",
22
+ "chalk": "^4.1.2",
23
+ "dotenv": "^16.3.1",
24
+ "express": "^4.18.2",
25
+ "https-proxy-agent": "^7.0.2",
26
+ "jsdom": "^22.1.0",
27
+ "node-fetch": "^3.3.2",
28
+ "playwright": "^1.40.1",
29
+ "socks-proxy-agent": "^8.0.5"
30
+ },
31
+ "devDependencies": {
32
+ "nodemon": "^3.0.2"
33
+ }
34
+ }
proxy_server.log CHANGED
@@ -102,3 +102,33 @@
102
  2025/06/07 23:50:04.640668 chrome_tls_proxy.go:710: 已禁用并发限制:允许同一IP发起多个并发请求
103
  2025/06/07 23:50:04.640668 chrome_tls_proxy.go:711: 已强制使用IPv4连接,并使用8.8.8.8作为DNS服务器
104
  2025/06/07 23:50:04.640668 chrome_tls_proxy.go:712: 使用Chrome浏览器的TLS指纹进行连接
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  2025/06/07 23:50:04.640668 chrome_tls_proxy.go:710: 已禁用并发限制:允许同一IP发起多个并发请求
103
  2025/06/07 23:50:04.640668 chrome_tls_proxy.go:711: 已强制使用IPv4连接,并使用8.8.8.8作为DNS服务器
104
  2025/06/07 23:50:04.640668 chrome_tls_proxy.go:712: 使用Chrome浏览器的TLS指纹进行连接
105
+ 2025/06/08 00:44:51.400537 chrome_tls_proxy.go:706: Chrome TLS指纹代理服务器运行在 http://localhost:10655/proxy
106
+ 2025/06/08 00:44:51.408056 chrome_tls_proxy.go:707: 使用方法:向/proxy发送POST请求,请求体包含目标URL、方法、请求头和请求体
107
+ 2025/06/08 00:44:51.408056 chrome_tls_proxy.go:708: 支持流式响应,需要在请求体中添加 'stream': true
108
+ 2025/06/08 00:44:51.408056 chrome_tls_proxy.go:709: 已禁用速率限制:允许无限制请求
109
+ 2025/06/08 00:44:51.408056 chrome_tls_proxy.go:710: 已禁用并发限制:允许同一IP发起多个并发请求
110
+ 2025/06/08 00:44:51.408056 chrome_tls_proxy.go:711: 已强制使用IPv4连接,并使用8.8.8.8作为DNS服务器
111
+ 2025/06/08 00:44:51.408056 chrome_tls_proxy.go:712: 使用Chrome浏览器的TLS指纹进行连接
112
+ 2025/06/08 00:45:24.831086 chrome_tls_proxy.go:706: Chrome TLS指纹代理服务器运行在 http://localhost:10655/proxy
113
+ 2025/06/08 00:45:24.838018 chrome_tls_proxy.go:707: 使用方法:向/proxy发送POST请求,请求体包含目标URL、方法、请求头和请求体
114
+ 2025/06/08 00:45:24.838018 chrome_tls_proxy.go:708: 支持流式响应,需要在请求体中添加 'stream': true
115
+ 2025/06/08 00:45:24.838018 chrome_tls_proxy.go:709: 已禁用速率限制:允许无限制请求
116
+ 2025/06/08 00:45:24.838018 chrome_tls_proxy.go:710: 已禁用并发限制:允许同一IP发起多个并发请求
117
+ 2025/06/08 00:45:24.838018 chrome_tls_proxy.go:711: 已强制使用IPv4连接,并使用8.8.8.8作为DNS服务器
118
+ 2025/06/08 00:45:24.838018 chrome_tls_proxy.go:712: 使用Chrome浏览器的TLS指纹进行连接
119
+ 2025/06/08 00:47:10.787309 chrome_tls_proxy.go:706: Chrome TLS指纹代理服务器运行在 http://localhost:10655/proxy
120
+ 2025/06/08 00:47:10.791530 chrome_tls_proxy.go:707: 使用方法:向/proxy发送POST请求,请求体包含目标URL、方法、请求头和请求体
121
+ 2025/06/08 00:47:10.791530 chrome_tls_proxy.go:708: 支持流式响应,需要在请求体中添加 'stream': true
122
+ 2025/06/08 00:47:10.791530 chrome_tls_proxy.go:709: 已禁用速率限制:允许无限制请求
123
+ 2025/06/08 00:47:10.791530 chrome_tls_proxy.go:710: 已禁用并发限制:允许同一IP发起多个并发请求
124
+ 2025/06/08 00:47:10.791530 chrome_tls_proxy.go:711: 已强制使用IPv4连接,并使用8.8.8.8作为DNS服务器
125
+ 2025/06/08 00:47:10.791530 chrome_tls_proxy.go:712: 使用Chrome浏览器的TLS指纹进行连接
126
+ 2025/06/08 00:47:10.792061 chrome_tls_proxy.go:716: 服务器启动失败: listen tcp :10655: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
127
+ 2025/06/08 00:54:49.318617 chrome_tls_proxy.go:706: Chrome TLS指纹代理服务器运行在 http://localhost:10655/proxy
128
+ 2025/06/08 00:54:49.325299 chrome_tls_proxy.go:707: 使用方法:向/proxy发送POST请求,请求体包含目标URL、方法、请求头和请求体
129
+ 2025/06/08 00:54:49.325299 chrome_tls_proxy.go:708: 支持流式响应,需要在请求体中添加 'stream': true
130
+ 2025/06/08 00:54:49.325299 chrome_tls_proxy.go:709: 已禁用速率限制:允许无限制请求
131
+ 2025/06/08 00:54:49.325299 chrome_tls_proxy.go:710: 已禁用并发限制:允许同一IP发起多个并发请求
132
+ 2025/06/08 00:54:49.325299 chrome_tls_proxy.go:711: 已强制使用IPv4连接,并使用8.8.8.8作为DNS服务器
133
+ 2025/06/08 00:54:49.325299 chrome_tls_proxy.go:712: 使用Chrome浏览器的TLS指纹进行连接
134
+ 2025/06/08 00:54:49.325813 chrome_tls_proxy.go:716: 服务器启动失败: listen tcp :10655: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
src/lightweight-client-express.js CHANGED
@@ -10,7 +10,6 @@ import {
10
  import {
11
  initialize,
12
  streamNotionResponse,
13
- buildNotionRequest,
14
  FETCHED_IDS_SUCCESSFULLY
15
  } from './lightweight-client.js';
16
  import { proxyPool } from './ProxyPool.js';
@@ -131,9 +130,6 @@ app.post('/v1/chat/completions', authenticate, async (req, res) => {
131
  });
132
  }
133
 
134
- // 构建Notion请求
135
- const notionRequestBody = buildNotionRequest(requestData);
136
-
137
  // 处理流式响应
138
  if (requestData.stream) {
139
  res.setHeader('Content-Type', 'text/event-stream');
@@ -141,7 +137,7 @@ app.post('/v1/chat/completions', authenticate, async (req, res) => {
141
  res.setHeader('Connection', 'keep-alive');
142
 
143
  logger.info(`开始流式响应`);
144
- const stream = await streamNotionResponse(notionRequestBody);
145
  stream.pipe(res);
146
 
147
  // 处理客户端断开连接
@@ -153,7 +149,7 @@ app.post('/v1/chat/completions', authenticate, async (req, res) => {
153
  // 创建一个内部流来收集完整响应
154
  logger.info(`开始非流式响应`);
155
  const chunks = [];
156
- const stream = await streamNotionResponse(notionRequestBody);
157
 
158
  return new Promise((resolve, reject) => {
159
  stream.on('data', (chunk) => {
 
10
  import {
11
  initialize,
12
  streamNotionResponse,
 
13
  FETCHED_IDS_SUCCESSFULLY
14
  } from './lightweight-client.js';
15
  import { proxyPool } from './ProxyPool.js';
 
130
  });
131
  }
132
 
 
 
 
133
  // 处理流式响应
134
  if (requestData.stream) {
135
  res.setHeader('Content-Type', 'text/event-stream');
 
137
  res.setHeader('Connection', 'keep-alive');
138
 
139
  logger.info(`开始流式响应`);
140
+ const stream = await streamNotionResponse(requestData);
141
  stream.pipe(res);
142
 
143
  // 处理客户端断开连接
 
149
  // 创建一个内部流来收集完整响应
150
  logger.info(`开始非流式响应`);
151
  const chunks = [];
152
+ const stream = await streamNotionResponse(requestData);
153
 
154
  return new Promise((resolve, reject) => {
155
  stream.on('data', (chunk) => {
src/lightweight-client.js CHANGED
@@ -18,7 +18,7 @@ const __filename = fileURLToPath(import.meta.url);
18
  const __dirname = dirname(__filename);
19
 
20
  // 加载环境变量
21
- dotenv.config({ path: join(dirname(__dirname), '.env') });
22
 
23
  // 日志配置
24
  const logger = {
@@ -30,15 +30,10 @@ const logger = {
30
 
31
  // 配置
32
  const NOTION_API_URL = "https://www.notion.so/api/v3/runInferenceTranscript";
33
- let NOTION_COOKIE = '';
34
- let NOTION_SPACE_ID = process.env.NOTION_SPACE_ID;
35
- let FETCHED_NOTION_USER_ID = process.env.NOTION_ACTIVE_USER_HEADER;
36
  const USE_NATIVE_PROXY_POOL = process.env.USE_NATIVE_PROXY_POOL === 'true';
37
  const ENABLE_PROXY_SERVER = process.env.ENABLE_PROXY_SERVER === 'true';
38
- let proxy = null;
39
- let isMoreThanOne = false;
40
- let index = 0;
41
-
42
 
43
  // 代理配置
44
  const PROXY_URL = process.env.PROXY_URL || "";
@@ -72,21 +67,14 @@ process.on('exit', () => {
72
  });
73
  });
74
 
75
- function getCookie() {
76
- const cookies = process.env.NOTION_COOKIE;
77
- if (cookies) {
78
- let cookiePairs = cookies.split('|');
79
- if (cookiePairs.length > 1){
80
- isMoreThanOne=true;
81
- }
82
- let currentIndex = index;
83
- index++;
84
- if (index >= cookiePairs.length) {
85
- index = 0;
86
- }
87
- return cookiePairs[currentIndex];
88
  }
89
- return '';
 
 
 
90
  }
91
 
92
  // 添加一个通用的cookie解析函数
@@ -136,184 +124,78 @@ function parseCookiesFromString(cookieString, logPrefix = "") {
136
  }
137
 
138
  // 获取Notion空间ID和用户ID
139
- async function fetchAndSetNotionIds() {
140
- if (!NOTION_COOKIE) {
141
- logger.error(`无法获取Notion ID: 未设置NOTION_COOKIE`);
142
- FETCHED_IDS_SUCCESSFULLY = false;
143
- return;
144
- }
145
-
146
  try {
147
- logger.info(`正在设置JSDOM环境...`);
148
-
149
- // 创建JSDOM实例模拟浏览器环境
150
- const dom = new JSDOM("", {
151
- url: "https://www.notion.so",
152
- referrer: "https://www.notion.so/",
153
- contentType: "text/html",
154
- includeNodeLocations: true,
155
- storageQuota: 10000000,
156
- pretendToBeVisual: true,
157
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
158
- });
159
-
160
- // 设置全局对象
161
- const { window } = dom;
162
-
163
- // 使用更安全的方式设置全局对象
164
- try {
165
- if (!global.window) {
166
- global.window = window;
167
- }
168
-
169
- if (!global.document) {
170
- global.document = window.document;
171
- }
172
-
173
- // 安全地设置navigator
174
- if (!global.navigator) {
175
- try {
176
- Object.defineProperty(global, 'navigator', {
177
- value: window.navigator,
178
- writable: true,
179
- configurable: true
180
- });
181
- } catch (navError) {
182
- logger.warning(`无法设置navigator: ${navError.message},继续执行`);
183
- // 继续执行,不会中断流程
184
- }
185
- }
186
- } catch (globalError) {
187
- logger.warning(`设置全局对象时出错: ${globalError.message}`);
188
- }
189
-
190
- // 设置cookie
191
- document.cookie = NOTION_COOKIE;
192
 
193
- // 创建fetch选项
194
- const fetchOptions = {
195
  method: 'POST',
196
  headers: {
197
  'Content-Type': 'application/json',
198
  'accept': '*/*',
199
- 'accept-language': 'en-US,en;q=0.9',
200
- 'notion-audit-log-platform': 'web',
201
- 'notion-client-version': '23.13.0.3686',
202
- 'origin': 'https://www.notion.so',
203
- 'referer': 'https://www.notion.so/',
204
- 'user-agent': window.navigator.userAgent,
205
- 'Cookie': NOTION_COOKIE
206
  },
207
  body: JSON.stringify({}),
208
  };
 
 
 
 
209
 
210
- // 添加代理配置(如果有)
211
- if (PROXY_URL) {
212
- const { HttpsProxyAgent } = await import('https-proxy-agent');
213
- fetchOptions.agent = new HttpsProxyAgent(PROXY_URL);
214
- logger.info(`使用代理: ${PROXY_URL}`);
215
- }
216
- logger.info(`正在获取Notion用户/空间ID...`);
217
-
218
- // 发送请求
219
- const response = await fetch("https://www.notion.so/api/v3/getSpaces", fetchOptions);
220
-
221
- if (!response.ok) {
222
- throw new Error(`HTTP error! status: ${response.status}`);
223
- }
224
-
225
- const data = await response.json();
226
-
227
- // 提取用户ID
228
  const userIdKey = Object.keys(data)[0];
229
- if (!userIdKey) {
230
- logger.error(`无法从响应中提取用户ID`);
231
- FETCHED_IDS_SUCCESSFULLY = false;
232
- return;
233
- }
234
-
235
- FETCHED_NOTION_USER_ID = userIdKey;
236
- logger.success(`已获取Notion用户ID`);
237
-
238
- // 提取空间ID
239
  const userRoot = data[userIdKey]?.user_root?.[userIdKey];
240
  const spaceViewPointers = userRoot?.value?.value?.space_view_pointers;
241
-
242
- if (spaceViewPointers && Array.isArray(spaceViewPointers) && spaceViewPointers.length > 0) {
243
- NOTION_SPACE_ID = spaceViewPointers[0].spaceId;
244
-
245
- if (NOTION_SPACE_ID) {
246
- logger.success(`已获取Notion空间ID`);
247
- FETCHED_IDS_SUCCESSFULLY = true;
248
- } else {
249
- logger.error(`无法从space_view_pointers中提取spaceId`);
250
- FETCHED_IDS_SUCCESSFULLY = false;
251
- }
252
- } else {
253
- logger.error(`在响应中找不到space_view_pointers或spaceId`);
254
- FETCHED_IDS_SUCCESSFULLY = false;
255
- }
256
-
257
- // 清理全局对象
258
- try {
259
- if (global.window) delete global.window;
260
- if (global.document) delete global.document;
261
-
262
- // 安全地删除navigator
263
- if (global.navigator) {
264
- try {
265
- delete global.navigator;
266
- } catch (navError) {
267
- // 如果无法删除,尝试将其设置为undefined
268
- try {
269
- Object.defineProperty(global, 'navigator', {
270
- value: undefined,
271
- writable: true,
272
- configurable: true
273
- });
274
- } catch (defineError) {
275
- logger.warning(`无法清理navigator: ${defineError.message}`);
276
- }
277
- }
278
- }
279
- } catch (cleanupError) {
280
- logger.warning(`清理全局对象时出错: ${cleanupError.message}`);
281
  }
282
-
 
283
  } catch (error) {
284
- logger.error(`获取Notion ID时出错: ${error}`);
285
- FETCHED_IDS_SUCCESSFULLY = false;
286
-
287
- // 确保清理全局对象
288
- try {
289
- if (global.window) delete global.window;
290
- if (global.document) delete global.document;
291
-
292
- // 安全地删除navigator
293
- if (global.navigator) {
294
- try {
295
- delete global.navigator;
296
- } catch (navError) {
297
- // 如果无法删除,尝试将其设置为undefined
298
- try {
299
- Object.defineProperty(global, 'navigator', {
300
- value: undefined,
301
- writable: true,
302
- configurable: true
303
- });
304
- } catch (defineError) {
305
- logger.warning(`无法清理navigator: ${defineError.message}`);
306
- }
307
- }
308
- }
309
- } catch (cleanupError) {
310
- logger.warning(`清理全局对象时出错: ${cleanupError.message}`);
311
- }
312
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  }
314
 
315
  // 构建Notion请求
316
- function buildNotionRequest(requestData) {
317
  // 当前时间
318
  const now = new Date();
319
  // 格式化为ISO字符串,确保包含毫秒和时区
@@ -348,8 +230,8 @@ function buildNotionRequest(requestData) {
348
  transcript.push(new NotionTranscriptItem({
349
  type: "context",
350
  value: new NotionTranscriptContextValue({
351
- userId: FETCHED_NOTION_USER_ID,
352
- spaceId: NOTION_SPACE_ID,
353
  surface: "home_module",
354
  timezone: "America/Los_Angeles",
355
  userName: userName,
@@ -389,7 +271,7 @@ function buildNotionRequest(requestData) {
389
  transcript.push(new NotionTranscriptItemByuser({
390
  type: "user",
391
  value: [[content]],
392
- userId: FETCHED_NOTION_USER_ID,
393
  createdAt: message.createdAt || isoString
394
  }));
395
  } else if (message.role === "user") {
@@ -397,7 +279,7 @@ function buildNotionRequest(requestData) {
397
  transcript.push(new NotionTranscriptItemByuser({
398
  type: "user",
399
  value: [[content]],
400
- userId: FETCHED_NOTION_USER_ID,
401
  createdAt: message.createdAt || isoString
402
  }));
403
  } else if (message.role === "assistant") {
@@ -413,7 +295,7 @@ function buildNotionRequest(requestData) {
413
 
414
  // 创建请求体
415
  return new NotionRequestBody({
416
- spaceId: NOTION_SPACE_ID,
417
  transcript: transcript,
418
  createThread: true,
419
  traceId: randomUUID(),
@@ -428,13 +310,25 @@ function buildNotionRequest(requestData) {
428
  }
429
 
430
  // 流式处理Notion响应
431
- async function streamNotionResponse(notionRequestBody) {
432
- // 创建流
433
  const stream = new PassThrough();
 
 
 
 
 
 
 
 
 
434
 
435
- // 添加初始数据,确保连接建立
436
- stream.write(':\n\n'); // 发送一个空注释行,保持连接活跃
437
 
 
 
 
 
 
438
  // 设置HTTP头模板
439
  const headers = {
440
  'Content-Type': 'application/json',
@@ -443,10 +337,10 @@ async function streamNotionResponse(notionRequestBody) {
443
  'notion-audit-log-platform': 'web',
444
  'notion-client-version': '23.13.0.3686',
445
  'origin': 'https://www.notion.so',
446
- 'referer': 'https://www.notion.so/chat',
447
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36',
448
- 'x-notion-active-user-header': FETCHED_NOTION_USER_ID,
449
- 'x-notion-space-id': NOTION_SPACE_ID
450
  };
451
 
452
  // 设置超时处理,确保流不会无限等待
@@ -477,7 +371,7 @@ async function streamNotionResponse(notionRequestBody) {
477
  notionRequestBody,
478
  headers,
479
  NOTION_API_URL,
480
- NOTION_COOKIE,
481
  timeoutId
482
  ).catch((error) => {
483
  logger.error(`流处理出错: ${error}`);
@@ -677,11 +571,6 @@ async function fetchNotionResponse(chunkQueue, notionRequestBody, headers, notio
677
  reader.on('end', () => {
678
  try {
679
  logger.info(`响应完成`);
680
- if (isMoreThanOne){
681
- NOTION_COOKIE = getCookie(); // 获取下一个cookie
682
- logger.info('开始切换cookie和ID');
683
- fetchAndSetNotionIds(); // 切换到下一个ID
684
- }
685
 
686
  // 如果没有收到任何响应,发送一个提示消息
687
  if (!responseReceived) {
@@ -884,48 +773,43 @@ async function fetchNotionResponse(chunkQueue, notionRequestBody, headers, notio
884
  async function initialize() {
885
  logger.info(`初始化Notion配置...`);
886
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
887
  // 启动代理服务器
888
  try {
889
- await proxyServer.start();
 
 
890
  } catch (error) {
891
  logger.error(`启动代理服务器失败: ${error.message}`);
892
  }
893
 
894
- // 检查是否已从环境变量中获取ID
895
- if (NOTION_SPACE_ID && FETCHED_NOTION_USER_ID) {
896
- logger.info(`使用环境变量��的Notion ID配置
897
- - NOTION_SPACE_ID: ${NOTION_SPACE_ID}
898
- - NOTION_ACTIVE_USER_HEADER: ${FETCHED_NOTION_USER_ID}`);
899
- // logger.info(`- NOTION_SPACE_ID: ${NOTION_SPACE_ID}`);
900
- // logger.info(`- NOTION_ACTIVE_USER_HEADER: ${FETCHED_NOTION_USER_ID}`);
901
- FETCHED_IDS_SUCCESSFULLY = true;
902
- } else {
903
- // 尝试从Notion API获取ID
904
- NOTION_COOKIE = getCookie(); // 获取第一个cookie
905
- if (!NOTION_COOKIE) {
906
- logger.error(`错误: 未设置NOTION_COOKIE环境变量,应用无法正常工作`);
907
- logger.error(`请在.env文件中设置有效的NOTION_COOKIE值`);
908
- return;
909
- }
910
-
911
- logger.info(`未检测到ID配置,正在通过API自动获取Notion ID...`);
912
- await fetchAndSetNotionIds();
913
-
914
- if (!FETCHED_IDS_SUCCESSFULLY) {
915
- logger.error(`获取Notion ID失败,应用无法正常工作`);
916
- logger.error(`请检查以下可能的问题:`);
917
- logger.error(`1. NOTION_COOKIE是否有效`);
918
- logger.error(`2. 网络连接是否正常`);
919
- logger.error(`3. Notion服务是否可访问`);
920
- logger.error(`或者手动在.env文件中设置NOTION_SPACE_ID和NOTION_ACTIVE_USER_HEADER`);
921
- } else {
922
- logger.info(`成功通过API获取Notion ID
923
- - 用户ID: ${FETCHED_NOTION_USER_ID}
924
- - 空间ID: ${NOTION_SPACE_ID}`);
925
- // logger.info(`- 用户ID: ${FETCHED_NOTION_USER_ID}`);
926
- // logger.info(`- 空间ID: ${NOTION_SPACE_ID}`);
927
- }
928
- }
929
  if (process.env.USE_NATIVE_PROXY_POOL === 'true') {
930
  logger.info(`正在初始化本地代理池...`);
931
  await proxyPool.initialize();
 
18
  const __dirname = dirname(__filename);
19
 
20
  // 加载环境变量
21
+ dotenv.config({ path: join(dirname(dirname(__filename)), '.env') });
22
 
23
  // 日志配置
24
  const logger = {
 
30
 
31
  // 配置
32
  const NOTION_API_URL = "https://www.notion.so/api/v3/runInferenceTranscript";
33
+ let ACCOUNTS = [];
 
 
34
  const USE_NATIVE_PROXY_POOL = process.env.USE_NATIVE_PROXY_POOL === 'true';
35
  const ENABLE_PROXY_SERVER = process.env.ENABLE_PROXY_SERVER === 'true';
36
+ let currentAccountIndex = 0;
 
 
 
37
 
38
  // 代理配置
39
  const PROXY_URL = process.env.PROXY_URL || "";
 
67
  });
68
  });
69
 
70
+ function getNextAccount() {
71
+ if (ACCOUNTS.length === 0) {
72
+ return null;
 
 
 
 
 
 
 
 
 
 
73
  }
74
+ const account = ACCOUNTS[currentAccountIndex];
75
+ const index = currentAccountIndex;
76
+ currentAccountIndex = (currentAccountIndex + 1) % ACCOUNTS.length;
77
+ return { ...account, index };
78
  }
79
 
80
  // 添加一个通用的cookie解析函数
 
124
  }
125
 
126
  // 获取Notion空间ID和用户ID
127
+ async function fetchAccountDetails(notionCookie) {
128
+ let userId, spaceId, email;
129
+
130
+ // Part 1: Get User and Space ID from getSpaces
 
 
 
131
  try {
132
+ const dom = new JSDOM("", { url: "https://www.notion.so" });
133
+ global.window = dom.window;
134
+ global.document = dom.window.document;
135
+ global.navigator = dom.window.navigator;
136
+ document.cookie = notionCookie;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
+ const getSpacesOptions = {
 
139
  method: 'POST',
140
  headers: {
141
  'Content-Type': 'application/json',
142
  'accept': '*/*',
143
+ 'user-agent': global.navigator.userAgent,
144
+ 'Cookie': notionCookie
 
 
 
 
 
145
  },
146
  body: JSON.stringify({}),
147
  };
148
+
149
+ const spacesResponse = await fetch("https://www.notion.so/api/v3/getSpaces", getSpacesOptions);
150
+ if (!spacesResponse.ok) throw new Error(`getSpaces failed with status ${spacesResponse.status}`);
151
+ const data = await spacesResponse.json();
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  const userIdKey = Object.keys(data)[0];
154
+ if (!userIdKey) throw new Error("Could not extract user ID from getSpaces response.");
155
+ userId = userIdKey;
156
+
 
 
 
 
 
 
 
157
  const userRoot = data[userIdKey]?.user_root?.[userIdKey];
158
  const spaceViewPointers = userRoot?.value?.value?.space_view_pointers;
159
+ if (spaceViewPointers && spaceViewPointers.length > 0) {
160
+ spaceId = spaceViewPointers[0].spaceId;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  }
162
+ if (!spaceId) throw new Error("Could not extract space ID from getSpaces response.");
163
+
164
  } catch (error) {
165
+ logger.error(`获取用户/空间ID失败: ${error.message}`);
166
+ return null;
167
+ } finally {
168
+ if (global.window) delete global.window;
169
+ if (global.document) delete global.document;
170
+ if (global.navigator) delete global.navigator;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  }
172
+
173
+ // Part 2: Get User Email from getUserAnalyticsSettings
174
+ try {
175
+ const analyticsOptions = {
176
+ method: 'POST',
177
+ headers: {
178
+ 'Content-Type': 'application/json',
179
+ 'accept': '*/*',
180
+ 'Cookie': notionCookie,
181
+ 'x-notion-active-user-header': userId,
182
+ },
183
+ body: JSON.stringify({}),
184
+ };
185
+ const analyticsResponse = await fetch("https://www.notion.so/api/v3/getUserAnalyticsSettings", analyticsOptions);
186
+ if (!analyticsResponse.ok) throw new Error(`getUserAnalyticsSettings failed with status ${analyticsResponse.status}`);
187
+ const analyticsData = await analyticsResponse.json();
188
+ email = analyticsData?.user_email || '邮箱获取失败';
189
+ } catch (error) {
190
+ logger.warning(`获取用户邮箱失败: ${error.message}. 将继续操作。`);
191
+ email = '邮箱获取失败';
192
+ }
193
+
194
+ return { cookie: notionCookie, userId, spaceId, email };
195
  }
196
 
197
  // 构建Notion请求
198
+ function buildNotionRequest(requestData, account) {
199
  // 当前时间
200
  const now = new Date();
201
  // 格式化为ISO字符串,确保包含毫秒和时区
 
230
  transcript.push(new NotionTranscriptItem({
231
  type: "context",
232
  value: new NotionTranscriptContextValue({
233
+ userId: account.userId,
234
+ spaceId: account.spaceId,
235
  surface: "home_module",
236
  timezone: "America/Los_Angeles",
237
  userName: userName,
 
271
  transcript.push(new NotionTranscriptItemByuser({
272
  type: "user",
273
  value: [[content]],
274
+ userId: account.userId,
275
  createdAt: message.createdAt || isoString
276
  }));
277
  } else if (message.role === "user") {
 
279
  transcript.push(new NotionTranscriptItemByuser({
280
  type: "user",
281
  value: [[content]],
282
+ userId: account.userId,
283
  createdAt: message.createdAt || isoString
284
  }));
285
  } else if (message.role === "assistant") {
 
295
 
296
  // 创建请求体
297
  return new NotionRequestBody({
298
+ spaceId: account.spaceId,
299
  transcript: transcript,
300
  createThread: true,
301
  traceId: randomUUID(),
 
310
  }
311
 
312
  // 流式处理Notion响应
313
+ async function streamNotionResponse(requestData) {
 
314
  const stream = new PassThrough();
315
+ const account = getNextAccount();
316
+
317
+ if (!account) {
318
+ const errorMessage = "无法处理请求: 未配置或加载任何有效的Notion账号。";
319
+ logger.error(errorMessage);
320
+ stream.emit('error', new Error(errorMessage));
321
+ stream.end();
322
+ return stream;
323
+ }
324
 
325
+ const notionRequestBody = buildNotionRequest(requestData, account);
 
326
 
327
+ logger.info(`正在使用账号 #${account.index + 1} (${account.email}) 进行本次请求...`);
328
+
329
+ // 从代理池获取代理
330
+ const proxyToUse = await proxyPool.getProxy();
331
+
332
  // 设置HTTP头模板
333
  const headers = {
334
  'Content-Type': 'application/json',
 
337
  'notion-audit-log-platform': 'web',
338
  'notion-client-version': '23.13.0.3686',
339
  'origin': 'https://www.notion.so',
340
+ 'referer': 'https://www.notion.so/',
341
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36',
342
+ 'x-notion-active-user-header': account.userId,
343
+ 'x-notion-space-id': account.spaceId
344
  };
345
 
346
  // 设置超时处理,确保流不会无限等待
 
371
  notionRequestBody,
372
  headers,
373
  NOTION_API_URL,
374
+ account.cookie,
375
  timeoutId
376
  ).catch((error) => {
377
  logger.error(`流处理出错: ${error}`);
 
571
  reader.on('end', () => {
572
  try {
573
  logger.info(`响应完成`);
 
 
 
 
 
574
 
575
  // 如果没有收到任何响应,发送一个提示消息
576
  if (!responseReceived) {
 
773
  async function initialize() {
774
  logger.info(`初始化Notion配置...`);
775
 
776
+ const cookieString = process.env.NOTION_COOKIE || '';
777
+ if (!cookieString) {
778
+ logger.error("关键错误: 环境变量 'NOTION_COOKIE' 未设置。请在.env文件中提供至少一个有效的Notion Cookie。");
779
+ FETCHED_IDS_SUCCESSFULLY = false;
780
+ return;
781
+ }
782
+
783
+ const cookies = cookieString.split('|').filter(c => c.trim() !== '');
784
+ logger.info(`发现 ${cookies.length} 个Cookie,正在逐一获取账号信息...`);
785
+
786
+ for (const cookie of cookies) {
787
+ const accountDetails = await fetchAccountDetails(cookie.trim());
788
+ if (accountDetails) {
789
+ ACCOUNTS.push(accountDetails);
790
+ logger.success(`成功加载账号: ${accountDetails.email}`);
791
+ } else {
792
+ logger.warning(`加载其中一个Cookie失败,已跳过。`);
793
+ }
794
+ }
795
+
796
+ if (ACCOUNTS.length === 0) {
797
+ logger.error("未能成功加载任何Notion账号。请检查您的COOKIE是否有效或已过期。");
798
+ FETCHED_IDS_SUCCESSFULLY = false;
799
+ } else {
800
+ logger.success(`共成功加载 ${ACCOUNTS.length} 个账号。服务已准备就绪。`);
801
+ FETCHED_IDS_SUCCESSFULLY = true;
802
+ }
803
+
804
  // 启动代理服务器
805
  try {
806
+ if (ENABLE_PROXY_SERVER) {
807
+ await proxyServer.start();
808
+ }
809
  } catch (error) {
810
  logger.error(`启动代理服务器失败: ${error.message}`);
811
  }
812
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
813
  if (process.env.USE_NATIVE_PROXY_POOL === 'true') {
814
  logger.info(`正在初始化本地代理池...`);
815
  await proxyPool.initialize();