xiaoyukkkk commited on
Commit
a3c4d24
·
verified ·
1 Parent(s): 3bc87c7

Upload 10 files

Browse files
Files changed (3) hide show
  1. .gitattributes +0 -1
  2. README.md +74 -6
  3. gemini-business2api helper.js +425 -0
.gitattributes CHANGED
@@ -1,3 +1,2 @@
1
  # Auto detect text files and perform LF normalization
2
  * text=auto
3
- __pycache__/main.cpython-313.pyc filter=lfs diff=lfs merge=lfs -text
 
1
  # Auto detect text files and perform LF normalization
2
  * text=auto
 
README.md CHANGED
@@ -11,13 +11,14 @@ license: mit
11
  # Gemini Business2API
12
 
13
  将 Google Gemini Business API 转换为 OpenAI 兼容接口,支持多账户负载均衡。
 
14
 
15
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
16
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
17
 
18
  **快速部署到 HuggingFace Spaces:**
19
 
20
- [![Deploy to Spaces](https://huggingface.co/datasets/huggingface/badges/resolve/main/deploy-to-spaces-md.svg)](https://huggingface.co/spaces/YOUR_USERNAME/gemini-business2api?duplicate=true)
21
 
22
  ## ✨ 功能特性
23
 
@@ -33,14 +34,36 @@ license: mit
33
 
34
  ## 📸 功能展示
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  ### 管理面板
37
- <!-- 在这里添加管理面板截图 -->
38
 
39
- ### 图片生成效果
40
- <!-- 在这里添加图片生成示例截图 -->
 
 
 
 
41
 
42
- ### 公开日志系统
43
- <!-- 在这里添加日志系统截图 -->
 
 
 
 
 
 
44
 
45
  ## 🚀 快速开始
46
 
@@ -259,6 +282,18 @@ curl -X POST http://localhost:7860/v1/v1/chat/completions \
259
  | `/public/log/html` | GET | 公开日志页面 |
260
  | `/health` | GET | 健康检查 |
261
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  ## ❓ 常见问题
263
 
264
  ### 1. 图片生成后在哪里找到文件?
@@ -315,6 +350,25 @@ Deno.serve(handler);
315
  - **公开日志**: 访问 `/public/log/html` (无需密钥)
316
  - **管理面板**: 访问 `/admin?key=YOUR_ADMIN_KEY`
317
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  ## 📁 项目结构
319
 
320
  ```
@@ -349,4 +403,18 @@ MIT License - 查看 [LICENSE](LICENSE) 文件了解详情
349
 
350
  ---
351
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  **如果这个项目对你有帮助,请给个 ⭐ Star!**
 
11
  # Gemini Business2API
12
 
13
  将 Google Gemini Business API 转换为 OpenAI 兼容接口,支持多账户负载均衡。
14
+ 感谢Claude老师!
15
 
16
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
17
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
18
 
19
  **快速部署到 HuggingFace Spaces:**
20
 
21
+ [![Deploy to Spaces](https://huggingface.co/datasets/huggingface/badges/resolve/main/deploy-to-spaces-md.svg)](https://huggingface.co/spaces/xiaoyukkkk/gemini-business2api?duplicate=true)
22
 
23
  ## ✨ 功能特性
24
 
 
34
 
35
  ## 📸 功能展示
36
 
37
+ ### 图片生成效果
38
+
39
+ <table>
40
+ <tr>
41
+ <td><img src="https://github.com/user-attachments/assets/5378ad0b-2a96-4239-9582-df68e8ffa53f" alt="图片生成示例1" width="800"/></td>
42
+ <td><img src="https://github.com/user-attachments/assets/82aeedf8-ad87-40bc-ae41-defa7271e8b1" alt="图片生成示例2" width="800"/></td>
43
+ </tr>
44
+ <tr>
45
+ <td><img src="https://github.com/user-attachments/assets/772d29c3-a75c-4ab8-98eb-cefea164b62c" alt="图片生成示例3" width="800"/></td>
46
+ <td><img src="https://github.com/user-attachments/assets/15d36604-dedd-4411-bbfb-f4cf95365101" alt="图片生成示例4" width="800"/></td>
47
+ </tr>
48
+ </table>
49
+
50
  ### 管理面板
 
51
 
52
+ <table>
53
+ <tr>
54
+ <td><img src="https://github.com/user-attachments/assets/42c0a906-e926-4199-97e4-73ac06381b07" alt="管理面板1" width="800"/></td>
55
+ <td><img src="https://github.com/user-attachments/assets/d6b9a16b-2ed1-4be9-8465-4c28f974daa7" alt="管理面板2" width="800"/></td>
56
+ </tr>
57
+ </table>
58
 
59
+ ###开日志系统
60
+
61
+ <table>
62
+ <tr>
63
+ <td><img src="https://github.com/user-attachments/assets/8640d7ce-9d22-41de-9907-5c2292883f0c" alt="日志系统1" width="800"/></td>
64
+ <td><img src="https://github.com/user-attachments/assets/048a6253-fa7d-4e00-a748-2bb615e16638" alt="日志系统2" width="800"/></td>
65
+ </tr>
66
+ </table>
67
 
68
  ## 🚀 快速开始
69
 
 
282
  | `/public/log/html` | GET | 公开日志页面 |
283
  | `/health` | GET | 健康检查 |
284
 
285
+ **访问示例**:
286
+
287
+ 假设你的配置为:
288
+ - Space URL: `https://your-space.hf.space`
289
+ - PATH_PREFIX: `my_prefix`
290
+ - ADMIN_KEY: `my_admin_key`
291
+
292
+ 则访问地址为:
293
+ - **管理面板**: `https://your-space.hf.space/my_prefix/admin?key=my_admin_key`
294
+ - **公开日志**: `https://your-space.hf.space/public/log/html`
295
+ - **API 端点**: `https://your-space.hf.space/my_prefix/v1/chat/completions`
296
+
297
  ## ❓ 常见问题
298
 
299
  ### 1. 图片生成后在哪里找到文件?
 
350
  - **公开日志**: 访问 `/public/log/html` (无需密钥)
351
  - **管理面板**: 访问 `/admin?key=YOUR_ADMIN_KEY`
352
 
353
+ ## 🔧 油猴脚本使用说明
354
+
355
+ 本项目提供油猴脚本辅助获取配置参数,使用前需要配置 TamperMonkey:
356
+
357
+ ### TamperMonkey 设置
358
+
359
+ 1. **配置模式**:改为 `高级`
360
+ 2. **安全设置**:允许脚本访问 Cookie 改为 `All`
361
+
362
+ ### Google Chrome 额外设置
363
+
364
+ 1. 打开油猴扩展设置
365
+ 2. 启用 **允许运行用户脚本**
366
+ 3. 设置 **有权访问的网站** 权限
367
+
368
+ 配置完成后即可使用脚本自动获取 `secure_c_ses`、`csesidx`、`config_id` 等参数。
369
+
370
+ ---
371
+
372
  ## 📁 项目结构
373
 
374
  ```
 
403
 
404
  ---
405
 
406
+ ## 🙏 致谢
407
+
408
+ - 源项目:[heixxin/gemini](https://huggingface.co/spaces/heixxin/gemini/tree/main) | [Linux.do 讨论](https://linux.do/t/topic/1226413)
409
+ - 绘图参考:[Gemini-Link-System](https://github.com/qxd-ljy/Gemini-Link-System) | [Linux.do 讨论](https://linux.do/t/topic/1234363)
410
+ - Gemini Business 2API Helper 参考:[Linux.do 讨论](https://linux.do/t/topic/1231008)
411
+
412
+ ---
413
+
414
+ ## ⭐ Star History
415
+
416
+ [![Star History Chart](https://api.star-history.com/svg?repos=Dreamy-rain/gemini-business2api&type=Date)](https://star-history.com/#Dreamy-rain/gemini-business2api&Date)
417
+
418
+ ---
419
+
420
  **如果这个项目对你有帮助,请给个 ⭐ Star!**
gemini-business2api helper.js ADDED
@@ -0,0 +1,425 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // ==UserScript==
2
+ // @name Gemini Business 2API Helper (JSON Format + Expiration)
3
+ // @namespace https://linux.do/u/f-droid
4
+ // @version 1.6
5
+ // @icon https://cdn.inviter.co/community/b5c3dc29-b7e3-49f9-a18d-819398ba4fe6.png
6
+ // @description 提取配置,支持 JSON 格式,过期时间逻辑为:Cookie过期时间戳 - 12小时。
7
+ // @author Gemini Business
8
+ // @match https://business.gemini.google/*
9
+ // @grant GM_setClipboard
10
+ // @grant GM_addStyle
11
+ // @grant GM_cookie
12
+ // @connect business.gemini.google
13
+ // ==/UserScript==
14
+
15
+ (function() {
16
+ 'use strict';
17
+
18
+ const getFavicon = () => {
19
+ const link = document.querySelector("link[rel*='icon']") || document.querySelector("link[rel='shortcut icon']");
20
+ return link ? link.href : 'https://cdn.inviter.co/community/b5c3dc29-b7e3-49f9-a18d-819398ba4fe6.png';
21
+ };
22
+
23
+ GM_addStyle(`
24
+ :root {
25
+ --gb-primary: #1a73e8;
26
+ --gb-primary-hover: #1557b0;
27
+ --gb-success: #1e8e3e;
28
+ --gb-success-hover: #137333;
29
+ --gb-surface: #ffffff;
30
+ --gb-bg: #f8f9fa;
31
+ --gb-text-main: #202124;
32
+ --gb-text-sub: #5f6368;
33
+ --gb-border: #dadce0;
34
+ --gb-shadow-sm: 0 1px 2px 0 rgba(60,64,67,0.3), 0 1px 3px 1px rgba(60,64,67,0.15);
35
+ --gb-shadow-md: 0 4px 8px 3px rgba(60,64,67,0.15), 0 1px 3px rgba(60,64,67,0.3);
36
+ --gb-shadow-lg: 0 8px 24px rgba(60,64,67,0.2);
37
+ --gb-font: 'Google Sans', 'Roboto', Arial, sans-serif;
38
+ --gb-mono: 'Roboto Mono', 'Menlo', monospace;
39
+ --transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
40
+ }
41
+
42
+ #gb-float-ball {
43
+ position: fixed;
44
+ bottom: 32px;
45
+ right: 32px;
46
+ width: 60px;
47
+ height: 60px;
48
+ background: white;
49
+ border-radius: 50%;
50
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
51
+ cursor: pointer;
52
+ z-index: 9998;
53
+ border: 1px solid var(--gb-border);
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ transition: var(--transition);
58
+ transform: scale(1);
59
+ }
60
+
61
+ #gb-float-ball:hover {
62
+ transform: scale(1.1) rotate(10deg);
63
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
64
+ }
65
+
66
+ #gb-float-ball img {
67
+ width: 36px;
68
+ height: 36px;
69
+ border-radius: 8px;
70
+ object-fit: contain;
71
+ pointer-events: none;
72
+ }
73
+
74
+ #gb-float-ball::after {
75
+ content: 'JSON';
76
+ position: absolute;
77
+ bottom: -4px;
78
+ right: -4px;
79
+ font-size: 8px;
80
+ font-weight: bold;
81
+ background: var(--gb-success);
82
+ color: white;
83
+ padding: 2px 6px;
84
+ border-radius: 8px;
85
+ transform: rotate(-15deg);
86
+ }
87
+
88
+ #gb-overlay {
89
+ position: fixed; inset: 0;
90
+ background: rgba(32, 33, 36, 0.6);
91
+ backdrop-filter: blur(3px);
92
+ z-index: 9999;
93
+ display: flex; align-items: center; justify-content: center;
94
+ opacity: 0; pointer-events: none;
95
+ transition: opacity 0.25s ease;
96
+ }
97
+ #gb-overlay.active { opacity: 1; pointer-events: auto; }
98
+
99
+ #gb-panel {
100
+ width: 550px; max-width: 90vw;
101
+ background: var(--gb-surface);
102
+ border-radius: 24px;
103
+ box-shadow: var(--gb-shadow-lg);
104
+ overflow: hidden;
105
+ display: flex; flex-direction: column;
106
+ transform: scale(0.92) translateY(20px);
107
+ transition: transform 0.3s cubic-bezier(0.2, 0.0, 0, 1);
108
+ font-family: var(--gb-font);
109
+ }
110
+ #gb-overlay.active #gb-panel { transform: scale(1) translateY(0); }
111
+
112
+ .gb-header {
113
+ background: linear-gradient(135deg, #4285f4 0%, #34a853 100%);
114
+ padding: 24px 32px;
115
+ color: white;
116
+ }
117
+ .gb-title { font-size: 22px; font-weight: 500; margin: 0; letter-spacing: 0.5px; }
118
+ .gb-subtitle { font-size: 13px; opacity: 0.9; margin-top: 6px; font-weight: 400; }
119
+
120
+ .gb-body { padding: 24px 32px 16px; background: var(--gb-surface); }
121
+ .gb-label {
122
+ font-size: 14px; color: var(--gb-text-sub);
123
+ margin-bottom: 12px; font-weight: 500;
124
+ display: flex; justify-content: space-between; align-items: center;
125
+ }
126
+
127
+ .gb-textarea-wrapper {
128
+ position: relative;
129
+ border: 1px solid var(--gb-border);
130
+ border-radius: 12px;
131
+ background: var(--gb-bg);
132
+ transition: border-color 0.2s, background 0.2s;
133
+ }
134
+ .gb-textarea-wrapper.editing {
135
+ background: white;
136
+ border-color: var(--gb-primary);
137
+ box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.2);
138
+ }
139
+ .gb-textarea {
140
+ width: 100%; height: 220px;
141
+ border: none; background: transparent;
142
+ padding: 16px;
143
+ font-family: var(--gb-mono);
144
+ font-size: 13px; line-height: 1.6;
145
+ color: var(--gb-text-main);
146
+ resize: none; outline: none;
147
+ box-sizing: border-box;
148
+ white-space: pre;
149
+ }
150
+
151
+ .gb-status {
152
+ margin-top: 12px; font-size: 13px;
153
+ display: flex; align-items: center; gap: 8px;
154
+ color: var(--gb-text-sub);
155
+ height: 20px;
156
+ }
157
+ .gb-dot { width: 8px; height: 8px; border-radius: 50%; background: #ccc; transition: background 0.3s; }
158
+ .gb-dot.success { background: var(--gb-success); }
159
+ .gb-dot.error { background: #ea4335; }
160
+
161
+ .gb-footer {
162
+ padding: 16px 32px 24px;
163
+ display: flex; justify-content: flex-end; gap: 12px;
164
+ border-top: 1px solid #f1f3f4;
165
+ background: var(--gb-surface);
166
+ }
167
+
168
+ .gb-btn {
169
+ border: none; outline: none;
170
+ padding: 0 24px; height: 40px;
171
+ border-radius: 20px;
172
+ font-family: var(--gb-font);
173
+ font-size: 14px; font-weight: 500;
174
+ cursor: pointer;
175
+ transition: all 0.2s;
176
+ display: flex; align-items: center; justify-content: center;
177
+ }
178
+ .gb-btn-text {
179
+ background: transparent; color: var(--gb-text-sub);
180
+ }
181
+ .gb-btn-text:hover { background: rgba(0,0,0,0.05); color: var(--gb-text-main); }
182
+
183
+ .gb-btn-primary {
184
+ background: var(--gb-primary); color: white;
185
+ box-shadow: var(--gb-shadow-sm);
186
+ }
187
+ .gb-btn-primary:hover {
188
+ background: var(--gb-primary-hover);
189
+ box-shadow: var(--gb-shadow-md);
190
+ }
191
+ .gb-btn-primary:active { transform: scale(0.98); }
192
+
193
+ .gb-btn-success {
194
+ background: var(--gb-success); color: white;
195
+ }
196
+ .gb-btn-success:hover { background: var(--gb-success-hover); }
197
+
198
+ .gb-hidden { display: none !important; }
199
+ `);
200
+
201
+ // Helper: 格式化 Unix 时间戳 (秒)
202
+ const formatTimestamp = (ts) => {
203
+ if (!ts) return "Session (Browser Close)";
204
+ // ts 是秒,需要转毫秒
205
+ const date = new Date(ts * 1000);
206
+ const y = date.getFullYear();
207
+ const m = String(date.getMonth() + 1).padStart(2, '0');
208
+ const d = String(date.getDate()).padStart(2, '0');
209
+ const h = String(date.getHours()).padStart(2, '0');
210
+ const min = String(date.getMinutes()).padStart(2, '0');
211
+ const s = String(date.getSeconds()).padStart(2, '0');
212
+ return `${y}-${m}-${d} ${h}:${min}:${s}`;
213
+ };
214
+
215
+ const floatBall = document.createElement('div');
216
+ floatBall.id = 'gb-float-ball';
217
+ floatBall.title = "提取配置";
218
+ const ballIcon = document.createElement('img');
219
+ ballIcon.src = getFavicon();
220
+ floatBall.appendChild(ballIcon);
221
+ document.body.appendChild(floatBall);
222
+
223
+ const overlay = document.createElement('div');
224
+ overlay.id = 'gb-overlay';
225
+ const panel = document.createElement('div');
226
+ panel.id = 'gb-panel';
227
+ overlay.appendChild(panel);
228
+ document.body.appendChild(overlay);
229
+
230
+ const header = document.createElement('div');
231
+ header.className = 'gb-header';
232
+ const title = document.createElement('h2');
233
+ title.className = 'gb-title';
234
+ title.textContent = 'Gemini Business 2API Helper';
235
+ const subtitle = document.createElement('div');
236
+ subtitle.className = 'gb-subtitle';
237
+ subtitle.textContent = '配置提取与管理';
238
+ header.appendChild(title);
239
+ header.appendChild(subtitle);
240
+ panel.appendChild(header);
241
+
242
+ const body = document.createElement('div');
243
+ body.className = 'gb-body';
244
+
245
+ const label = document.createElement('div');
246
+ label.className = 'gb-label';
247
+ label.textContent = '提取的配置 (JSON):';
248
+ body.appendChild(label);
249
+
250
+ const textWrapper = document.createElement('div');
251
+ textWrapper.className = 'gb-textarea-wrapper';
252
+ const textarea = document.createElement('textarea');
253
+ textarea.className = 'gb-textarea';
254
+ textarea.readOnly = true;
255
+ textarea.spellcheck = false;
256
+ textWrapper.appendChild(textarea);
257
+ body.appendChild(textWrapper);
258
+
259
+ const statusDiv = document.createElement('div');
260
+ statusDiv.className = 'gb-status';
261
+ const statusDot = document.createElement('div');
262
+ statusDot.className = 'gb-dot';
263
+ const statusText = document.createElement('span');
264
+ statusText.textContent = '等待操作...';
265
+ statusDiv.appendChild(statusDot);
266
+ statusDiv.appendChild(statusText);
267
+ body.appendChild(statusDiv);
268
+ panel.appendChild(body);
269
+
270
+ const footer = document.createElement('div');
271
+ footer.className = 'gb-footer';
272
+
273
+ const btnClose = document.createElement('button');
274
+ btnClose.className = 'gb-btn gb-btn-text';
275
+ btnClose.textContent = '关闭';
276
+
277
+ const btnEdit = document.createElement('button');
278
+ btnEdit.className = 'gb-btn gb-btn-text';
279
+ btnEdit.textContent = '编辑';
280
+
281
+ const btnSave = document.createElement('button');
282
+ btnSave.className = 'gb-btn gb-btn-success gb-hidden';
283
+ btnSave.textContent = '保存修改';
284
+
285
+ const btnCopy = document.createElement('button');
286
+ btnCopy.className = 'gb-btn gb-btn-primary';
287
+ btnCopy.textContent = '复制配置';
288
+
289
+ footer.appendChild(btnClose);
290
+ footer.appendChild(btnEdit);
291
+ footer.appendChild(btnSave);
292
+ footer.appendChild(btnCopy);
293
+ panel.appendChild(footer);
294
+
295
+ let isEditing = false;
296
+ let extractedData = "";
297
+
298
+ const setStatus = (type, msg) => {
299
+ statusDot.className = 'gb-dot ' + (type === 'success' ? 'success' : type === 'error' ? 'error' : '');
300
+ statusText.textContent = msg;
301
+ };
302
+
303
+ const toggleEditMode = () => {
304
+ isEditing = !isEditing;
305
+ textarea.readOnly = !isEditing;
306
+
307
+ if (isEditing) {
308
+ textWrapper.classList.add('editing');
309
+ btnEdit.classList.add('gb-hidden');
310
+ btnCopy.classList.add('gb-hidden');
311
+ btnSave.classList.remove('gb-hidden');
312
+ setStatus('normal', '正在编辑...');
313
+ textarea.focus();
314
+ } else {
315
+ textWrapper.classList.remove('editing');
316
+ btnEdit.classList.remove('gb-hidden');
317
+ btnCopy.classList.remove('gb-hidden');
318
+ btnSave.classList.add('gb-hidden');
319
+ }
320
+ };
321
+
322
+ const saveContent = () => {
323
+ extractedData = textarea.value;
324
+ toggleEditMode();
325
+ setStatus('success', '修改已保存');
326
+ };
327
+
328
+ const openPanel = () => {
329
+ overlay.classList.add('active');
330
+
331
+ textarea.value = "正在读取环境数据...";
332
+ textarea.style.color = "#9aa0a6";
333
+ btnCopy.disabled = true;
334
+ btnEdit.style.display = 'none';
335
+ setStatus('normal', '分析中...');
336
+
337
+ const pathParts = window.location.pathname.split('/');
338
+ const cidIndex = pathParts.indexOf('cid');
339
+ const config_id = (cidIndex !== -1 && pathParts.length > cidIndex + 1) ? pathParts[cidIndex + 1] : null;
340
+ const urlParams = new URLSearchParams(window.location.search);
341
+ const csesidx = urlParams.get('csesidx');
342
+
343
+ GM_cookie('list', {}, (cookies, error) => {
344
+ if (error) {
345
+ textarea.value = "错误:无法读取 Cookie。\n请检查 Tampermonkey 权限。";
346
+ textarea.style.color = "#ea4335";
347
+ setStatus('error', '读取失败');
348
+ return;
349
+ }
350
+
351
+ const host_c_oses_raw = (cookies.find(c => c.name === '__Host-C_OSES' && c.domain === window.location.hostname) || {}).value;
352
+ const host_c_oses_formatted = host_c_oses_raw ? `"${host_c_oses_raw}"` : "null";
353
+
354
+ // 获取 SES Cookie 对象
355
+ const sesCookieObj = cookies.find(c => c.name === '__Secure-C_SES') || {};
356
+ const secure_c_ses = sesCookieObj.value || null;
357
+
358
+ // 修正过期时间逻辑:Cookie 过期时间戳 - 12小时 (12 * 60 * 60 = 43200秒)
359
+ let expireTime = "Session (Unknown)";
360
+ if (sesCookieObj.expirationDate) {
361
+ // expirationDate 是秒
362
+ const adjustedTimestamp = sesCookieObj.expirationDate - 43200;
363
+ expireTime = formatTimestamp(adjustedTimestamp);
364
+ } else {
365
+ // 如果没有过期时间(浏览器会话结束),显示 Session
366
+ expireTime = "Session (Browser Close)";
367
+ }
368
+
369
+ if (!config_id || !csesidx || !secure_c_ses) {
370
+ textarea.value = "⚠️ 数据不完整。\n请确保您在 Gemini Business 聊天界面,且 URL 包含 /cid/ 和 ?csesidx=";
371
+ textarea.style.color = "#f9ab00";
372
+ setStatus('error', '数据缺失');
373
+ return;
374
+ }
375
+
376
+ extractedData = `"csesidx": "${csesidx}",
377
+ "config_id": "${config_id}",
378
+ "secure_c_ses": "${secure_c_ses}",
379
+ "host_c_oses": ${host_c_oses_formatted},
380
+ "expires_at": "${expireTime}"`;
381
+
382
+ textarea.value = extractedData;
383
+ textarea.style.color = "var(--gb-text-main)";
384
+ btnCopy.disabled = false;
385
+ btnEdit.style.display = 'block';
386
+ setStatus('success', '提取成功');
387
+ });
388
+ };
389
+
390
+ const closePanel = () => {
391
+ overlay.classList.remove('active');
392
+ if (isEditing) {
393
+ textarea.value = extractedData;
394
+ toggleEditMode();
395
+ }
396
+ };
397
+
398
+ const copyToClipboard = () => {
399
+ if (!textarea.value) return;
400
+ GM_setClipboard(textarea.value);
401
+
402
+ const originalText = btnCopy.textContent;
403
+ btnCopy.textContent = "已复制";
404
+ btnCopy.classList.remove('gb-btn-primary');
405
+ btnCopy.classList.add('gb-btn-success');
406
+
407
+ setTimeout(() => {
408
+ btnCopy.textContent = originalText;
409
+ btnCopy.classList.remove('gb-btn-success');
410
+ btnCopy.classList.add('gb-btn-primary');
411
+ closePanel();
412
+ }, 1200);
413
+ };
414
+
415
+ floatBall.addEventListener('click', openPanel);
416
+ btnClose.addEventListener('click', closePanel);
417
+ btnCopy.addEventListener('click', copyToClipboard);
418
+ btnEdit.addEventListener('click', toggleEditMode);
419
+ btnSave.addEventListener('click', saveContent);
420
+
421
+ overlay.addEventListener('click', (e) => {
422
+ if (e.target === overlay) closePanel();
423
+ });
424
+
425
+ })();