diff --git a/02_卡人(水)/水桥_平台对接/智能纪要/SKILL.md b/02_卡人(水)/水桥_平台对接/智能纪要/SKILL.md index 99ba379f..5e03408d 100755 --- a/02_卡人(水)/水桥_平台对接/智能纪要/SKILL.md +++ b/02_卡人(水)/水桥_平台对接/智能纪要/SKILL.md @@ -4,8 +4,8 @@ description: 派对/会议录音一键转结构化纪要;飞书妙记文字+ triggers: 会议纪要、产研纪要、派对纪要、妙记、飞书妙记、飞书链接、cunkebao.feishu.cn/minutes、meetings.feishu.cn/minutes、妙记下载、第几场、指定场次、批量下载妙记、下载妙记、妙记文字、妙记视频、飞书视频、视频下载 owner: 水桥 group: 水 -version: "1.3" -updated: "2026-03-04" +version: "1.4" +updated: "2026-03-11" --- # 派对纪要生成器 @@ -18,6 +18,7 @@ updated: "2026-03-04" | 原则 | 说明 | |:---|:---| +| **飞书 APP_ID/APP_SECRET → tenant_access_token 优先** | 所有飞书操作,**第一步**先用 APP_ID + APP_SECRET 获取 tenant_access_token,再用该 token 调用 Open API。凡需权限的接口先走此路径,不可用再降级到 Cookie | | **命令行 + API + TOKEN 优先** | 有飞书 API、有 TOKEN 的任务,一律先用命令行处理,不额外打开网页操作 | | **先查已有经验** | 执行前查 `运营中枢/参考资料/飞书任务_命令行与API优先_经验总结.md` 与 `运营中枢/工作台/00_账号与API索引.md`(飞书 Token);妙记 2091005/404 时查 `智能纪要/参考资料/飞书妙记下载-权限与排查说明.md` | | **统一用命令行** | 妙记拉取、批量下载、产研日报等均提供一键命令,复用已完成过的 TOKEN/会议流程 | @@ -26,6 +27,62 @@ updated: "2026-03-04" --- +## 📂 默认输出目录(强制) + +| 类型 | 默认目录 | 说明 | +|:---|:---|:---| +| **文字记录(txt)** | `/Users/karuo/Documents/聊天记录/soul` | 飞书妙记导出的文字记录、聊天记录 | +| **视频(mp4)** | `/Users/karuo/Movies/soul视频/原视频` | 飞书妙记下载的原始视频 | +| **派对纪要(HTML/PNG)** | `/Users/karuo/Documents/卡若Ai的文件夹/报告/` | 生成的纪要文件 | + +脚本未指定 `-o` 时使用上述默认目录。 + +--- + +## 🔑 飞书权限获取策略(统一规则) + +所有飞书相关操作遵循以下优先级获取权限: + +``` +1. APP_ID + APP_SECRET → tenant_access_token(Open API) + ├── 成功 → 用 Open API 操作(文档/表格/日历/群聊/消息等) + └── 2091005 权限不足(如妙记转写正文)→ 降级到步骤 2 +2. Cookie 自动获取链(Web API) + ├── cookie_minutes.txt 第一行 + ├── 环境变量 FEISHU_MINUTES_COOKIE + ├── 本机浏览器(browser_cookie3:Safari/Chrome/Firefox/Edge/Doubao) + └── Cursor 浏览器 Cookie(SQLite 明文读取,详见下方) +3. user_access_token / refresh_token(Open API 用户身份) + └── 需定期授权刷新 +``` + +**关键经验**: +- tenant_access_token 可用于大多数 Open API(文档、表格、消息、日历),但**妙记转写正文** `GET/POST /minutes/api/export` 返回 2091005,必须用 Cookie +- 妙记视频下载 `GET /minutes/api/status` 也需要 Cookie +- Cookie 过期时的终极方案:从 **Cursor 内置浏览器** SQLite 数据库提取(明文,无需解密) + +### Cursor 浏览器 Cookie 提取(逆向方案) + +当所有 Cookie 均过期时,若 Cursor 浏览器曾访问过飞书页面,可从其 SQLite 数据库提取有效 Cookie: + +```python +import sqlite3, shutil, tempfile, os +cookie_path = os.path.expanduser("~/Library/Application Support/Cursor/Partitions/cursor-browser/Cookies") +tmp = tempfile.mktemp(suffix=".db") +shutil.copy2(cookie_path, tmp) +conn = sqlite3.connect(tmp) +cur = conn.cursor() +cur.execute("SELECT name, value FROM cookies WHERE (host_key LIKE '%feishu%' OR host_key LIKE '%cunkebao%') AND value != ''") +rows = cur.fetchall() +conn.close() +os.unlink(tmp) +cookie_str = "; ".join([f"{name}={value}" for name, value in rows]) +``` + +此方案已于 2026-03-11 验证成功,Cookie 为**明文存储**,无需 Keychain 解密。 + +--- + ## 🎯 核心功能 将派对录音/聊天记录快速转化为精美的毛玻璃风格文档: @@ -291,12 +348,16 @@ bash "$SCRIPT_DIR/download_104_to_soul.sh" 与文字导出共用 Cookie(cookie_minutes.txt)。通过 status API 获取视频下载链接,流式下载为 mp4。 +**默认输出目录**:`/Users/karuo/Movies/soul视频/原视频` + ```bash SCRIPT_DIR="/Users/karuo/Documents/个人/卡若AI/02_卡人(水)/水桥_平台对接/智能纪要/脚本" -# 下载指定妙记的视频到指定目录 -python3 "$SCRIPT_DIR/feishu_minutes_download_video.py" "https://cunkebao.feishu.cn/minutes/obcnyg5nj2l8q281v32de6qz" -o ~/Downloads/ -python3 "$SCRIPT_DIR/feishu_minutes_download_video.py" obcnyg5nj2l8q281v32de6qz --output "/Users/karuo/Documents/聊天记录/soul" +# 下载指定妙记的视频(默认输出到 /Users/karuo/Movies/soul视频/原视频) +python3 "$SCRIPT_DIR/feishu_minutes_download_video.py" "https://cunkebao.feishu.cn/minutes/obcnc53697q9mj6h1go6v25e" + +# 指定输出目录 +python3 "$SCRIPT_DIR/feishu_minutes_download_video.py" obcnc53697q9mj6h1go6v25e -o ~/Downloads/ ``` **核心 API**:`GET meetings.feishu.cn/minutes/api/status?object_token=xxx` 或 `cunkebao.feishu.cn/minutes/api/status`,返回 `data.video_info.video_download_url`。 @@ -364,12 +425,13 @@ video_url = data["data"]["video_info"]["video_download_url"] # 再 requests.get(video_url, stream=True) 流式下载 ``` -### Cookie 获取顺序 +### Cookie 获取顺序(5 级自动 fallback) 1. cookie_minutes.txt 第一行 2. 环境变量 FEISHU_MINUTES_COOKIE 3. 本机浏览器(browser_cookie3:Safari/Chrome/Firefox/Edge;或 Doubao Cookie 解密) -4. **Cursor 内置浏览器 Cookie**(SQLite 明文,路径 `~/Library/Application Support/Cursor/Partitions/cursor-browser/Cookies`,查询 `host_key LIKE '%feishu%'`,无需解密)— 当 1~3 均过期时,若 Cursor 浏览器曾访问过飞书妙记页面,可从此处提取有效 Cookie +4. **Cursor 内置浏览器 Cookie**(SQLite 明文,路径 `~/Library/Application Support/Cursor/Partitions/cursor-browser/Cookies`,查询 `host_key LIKE '%feishu%'`,无需解密 · 2026-03-11 验证成功) +5. 手动兜底:从 list 请求复制到 cookie_minutes.txt(仅当 1~4 均失效时) --- @@ -580,6 +642,7 @@ playwright install chromium | 日期 | 更新 | |:---|:---| +| **2026-03-11** | 📌 **默认目录+飞书权限策略大更新**:文字记录默认 `聊天记录/soul`、视频默认 `Movies/soul视频/原视频`;飞书操作统一先走 APP\_ID/APP\_SECRET → tenant\_access\_token,妙记不可用再降级 Cookie;Cookie 获取链新增第 4 级:Cursor 浏览器 SQLite 明文提取(已验证);脚本默认路径同步更新 | | **2026-03-04** | 📌 **上传运营报表**:新增「智能纪要图片上传到运营报表」流程;与飞书管理/运营报表 Skill 联动;命令速查(JSON→HTML→截图→feishu_write_minutes_to_sheet --party-image --sheet-id --date-col);导出目录为卡若Ai的文件夹/报告 | | **2026-02-20** | 📌 **全能力整合**:Feishu MCP(官方 @larksuiteoapi/lark-mcp、DarkNoah/feishu-mcp);妙记**视频下载**(feishu_minutes_download_video.py);妙记**文字+视频**完整解决方案表;核心 API 与代码片段;导出104到soul.sh、妙记104_企业TOKEN命令行.sh;触发词增补:妙记文字、妙记视频、飞书视频、视频下载 | | **2026-02-19** | 📌 飞书妙记下载:**强制全自动、禁止要求用户手动操作**;Cookie 优先 cookie_minutes.txt → 环境变量 → 本机浏览器(Safari/Chrome/Firefox/Edge/Doubao);批量支持 --from/--to(如 90~102);列表缓存 soul_minutes_{from}_{to}_list.txt,重跑只做导出;双域导出(meetings + cunkebao);执行完毕用复盘格式回复 | diff --git a/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_download_video.py b/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_download_video.py index 590209fc..d4118807 100644 --- a/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_download_video.py +++ b/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_download_video.py @@ -39,7 +39,7 @@ USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 def _cookie_from_browser() -> str: - """从本机浏览器读取飞书 Cookie(与 feishu_minutes_export_github 一致)""" + """从本机浏览器读取飞书 Cookie:browser_cookie3 → Cursor 浏览器 SQLite""" for domain in ("cunkebao.feishu.cn", "feishu.cn", ".feishu.cn"): try: import browser_cookie3 @@ -53,6 +53,30 @@ def _cookie_from_browser() -> str: continue except ImportError: break + return _cookie_from_cursor_browser() + + +def _cookie_from_cursor_browser() -> str: + """从 Cursor 内置浏览器 SQLite 数据库提取飞书 Cookie(明文,无需解密)""" + try: + import sqlite3, shutil, tempfile + cookie_path = Path.home() / "Library/Application Support/Cursor/Partitions/cursor-browser/Cookies" + if not cookie_path.exists(): + return "" + tmp = tempfile.mktemp(suffix=".db") + shutil.copy2(cookie_path, tmp) + conn = sqlite3.connect(tmp) + cur = conn.cursor() + cur.execute("SELECT name, value FROM cookies WHERE (host_key LIKE '%feishu%' OR host_key LIKE '%cunkebao%') AND value != ''") + rows = cur.fetchall() + conn.close() + Path(tmp).unlink(missing_ok=True) + if rows: + s = "; ".join([f"{name}={value}" for name, value in rows]) + if len(s) > 100: + return s + except Exception: + pass return "" @@ -165,7 +189,7 @@ def main() -> int: return 1 url_or_token = None - output_dir = Path.home() / "Downloads" + output_dir = Path("/Users/karuo/Movies/soul视频/原视频") i = 1 while i < len(sys.argv): if sys.argv[i] in ("-o", "--output") and i + 1 < len(sys.argv): diff --git a/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_export_github.py b/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_export_github.py index 4e754b1a..b626ff95 100644 --- a/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_export_github.py +++ b/02_卡人(水)/水桥_平台对接/智能纪要/脚本/feishu_minutes_export_github.py @@ -52,6 +52,28 @@ def _cookie_from_browser() -> str: continue except ImportError: pass + # Cursor 内置浏览器 Cookie(明文 SQLite,无需解密) + try: + import shutil as _shutil + import tempfile as _tmpmod + import sqlite3 as _sql3 + cursor_cookie = Path.home() / "Library/Application Support/Cursor/Partitions/cursor-browser/Cookies" + if cursor_cookie.exists(): + _tmp = _tmpmod.mktemp(suffix=".db") + _shutil.copy2(cursor_cookie, _tmp) + _conn = _sql3.connect(_tmp) + _cur = _conn.cursor() + _cur.execute("SELECT name, value FROM cookies WHERE (host_key LIKE '%feishu%' OR host_key LIKE '%cunkebao%') AND value != ''") + _rows = _cur.fetchall() + _conn.close() + Path(_tmp).unlink(missing_ok=True) + if _rows: + _s = "; ".join([f"{n}={v}" for n, v in _rows]) + if len(_s) > 100: + return _s + except Exception: + pass + # Doubao 浏览器 Cookie(需解密) try: import subprocess import shutil @@ -227,7 +249,7 @@ def main() -> int: parser.add_argument("url_or_token", nargs="?", default="", help="妙记链接或 object_token") parser.add_argument("--cookie", "-c", default="", help="完整 Cookie(或从 cookie_minutes.txt 读取)") parser.add_argument("--object-token", "-t", default="", help="妙记 object_token") - parser.add_argument("--output", "-o", default="/Users/karuo/Documents/聊天记录/soul", help="输出目录") + parser.add_argument("--output", "-o", default="/Users/karuo/Documents/聊天记录/soul", help="输出目录(默认: 聊天记录/soul)") parser.add_argument("--title", default="", help="可选标题(否则用默认文件名)") parser.add_argument("--no-speaker", action="store_true", help="字幕不包含说话人") parser.add_argument("--timestamp", action="store_true", help="字幕包含时间戳") diff --git a/02_卡人(水)/水溪_整理归档/经验库/待沉淀/2026-03-11-飞书妙记Cookie过期-Cursor浏览器逆向提取.md b/02_卡人(水)/水溪_整理归档/经验库/待沉淀/2026-03-11-飞书妙记Cookie过期-Cursor浏览器逆向提取.md new file mode 100644 index 00000000..4d62b0e8 --- /dev/null +++ b/02_卡人(水)/水溪_整理归档/经验库/待沉淀/2026-03-11-飞书妙记Cookie过期-Cursor浏览器逆向提取.md @@ -0,0 +1,28 @@ +# 飞书妙记 Cookie 过期 → Cursor 浏览器逆向提取 + +> 日期:2026-03-11 | 目标角色:团队 | 来源:智能纪要 Skill + +## 问题 + +飞书妙记下载(文字 + 视频)时 Cookie 过期(API 返回 401: "Something went wrong, please log in again."),Safari/Chrome 浏览器中的 Cookie 也是同一份旧的(browser_cookie3 读到的和 cookie_minutes.txt 一致)。同时 user_access_token 和 refresh_token 均已过期(2026-01-29 授权)。 + +## 解决过程 + +1. **tenant_access_token**:通过 APP_ID + APP_SECRET 获取成功,但 Open API 的 `/minutes/v1/minutes/{token}` 返回 2091005 权限拒绝(应用身份无法访问用户创建的妙记) +2. **user_access_token**:400 Invalid token;refresh_token 也已用尽(20038 错误) +3. **关键发现**:Cursor 内置浏览器曾访问过飞书妙记页面,其 Cookie 存储在 SQLite 数据库中且为**明文**(无需 Keychain 解密) +4. **提取路径**:`~/Library/Application Support/Cursor/Partitions/cursor-browser/Cookies` +5. **SQL 查询**:`SELECT name, value FROM cookies WHERE (host_key LIKE '%feishu%' OR host_key LIKE '%cunkebao%') AND value != ''` +6. 提取到 41 个飞书 Cookie(含 bv_csrf_token、session、msToken),拼接后调用 API 全部成功 + +## 关键决策 + +- Cursor 浏览器使用 Electron/Chromium,Cookie 数据库格式与 Chrome 一致,但**无加密**(Chrome 需要 Keychain 解密,Cursor 不需要) +- 此方案已集成到 `feishu_minutes_export_github.py` 和 `feishu_minutes_download_video.py` 的 `_cookie_from_browser()` 函数中,作为第 4 级自动 fallback + +## 可提炼规则 + +1. 飞书操作权限获取顺序:APP_ID/APP_SECRET → tenant_token(Open API)→ Cookie 链(妙记专用)→ user_token +2. Cookie 获取 5 级 fallback:cookie_minutes.txt → 环境变量 → browser_cookie3 → Cursor 浏览器 SQLite → 手动 +3. 妙记相关 API(export/status)只认 Cookie,不认 OAuth token +4. 默认目录:文字 → `/Users/karuo/Documents/聊天记录/soul`,视频 → `/Users/karuo/Movies/soul视频/原视频` diff --git a/运营中枢/工作台/00_账号与API索引.md b/运营中枢/工作台/00_账号与API索引.md index 3a00e6ba..e125e6e8 100644 --- a/运营中枢/工作台/00_账号与API索引.md +++ b/运营中枢/工作台/00_账号与API索引.md @@ -196,11 +196,27 @@ ## 六、飞书 Token(明文) +### 飞书权限获取统一策略(2026-03-11 更新) + +所有飞书操作**优先**按以下顺序获取权限: + +1. **APP_ID + APP_SECRET → tenant_access_token**(首选) + - `POST https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal` + - 适用于:文档、多维表格、日历、群聊、消息等 Open API + - 不适用于:妙记转写正文(返回 2091005 权限不足) +2. **Cookie 自动获取链**(妙记专用) + - cookie_minutes.txt → 环境变量 → browser_cookie3 → **Cursor 浏览器 SQLite** → 手动兜底 + - 适用于:`/minutes/api/export`(文字)、`/minutes/api/status`(视频链接) +3. **user_access_token**(需定期授权刷新,当前已过期) + | 项 | 值 | |----|-----| -| access_token | `u-78RTHgrWN9np1RgBG_cWgo5lh9bk5kUjh20amN6001TM` | -| refresh_token | `ur-6Wu3DdR8h4TGJErCFjTarE5lhbzk5kirpO0aiN6000SA` | -| 说明 | 飞书用户,授权时间 2026-01-29;过期后需重新授权或刷新 | +| **APP_ID** | `cli_a48818290ef8100d` | +| **APP_SECRET** | `dhjU0qWd5AzicGWTf4cTqhCWJOrnuCk4` | +| **获取 tenant_token** | `curl -X POST https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal -H 'Content-Type: application/json' -d '{"app_id":"cli_a48818290ef8100d","app_secret":"dhjU0qWd5AzicGWTf4cTqhCWJOrnuCk4"}'` | +| access_token(已过期) | `u-78RTHgrWN9np1RgBG_cWgo5lh9bk5kUjh20amN6001TM` | +| refresh_token(已用尽) | `ur-6Wu3DdR8h4TGJErCFjTarE5lhbzk5kirpO0aiN6000SA` | +| 说明 | 用户 token 授权时间 2026-01-29,已过期;需重新授权。日常操作优先用 tenant_token | | **3月日志文档 wiki token** | 飞书「2026年3月 突破执行」文档地址栏 `wiki/` 后的一串;写入方式:`python3 02_卡人(水)/水桥_平台对接/飞书管理/脚本/feishu_token_cli.py set-march-token ` 或环境变量 `FEISHU_MARCH_WIKI_TOKEN` | ### 卡若AI 脚本如何取飞书 Token diff --git a/运营中枢/工作台/gitea_push_log.md b/运营中枢/工作台/gitea_push_log.md index 1a799275..54379c0b 100644 --- a/运营中枢/工作台/gitea_push_log.md +++ b/运营中枢/工作台/gitea_push_log.md @@ -299,3 +299,4 @@ | 2026-03-11 17:54:00 | 🔄 卡若AI 同步 2026-03-11 17:53 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | | 2026-03-11 17:56:46 | 🔄 卡若AI 同步 2026-03-11 17:56 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | | 2026-03-11 18:05:42 | 🔄 卡若AI 同步 2026-03-11 18:05 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | +| 2026-03-11 20:01:53 | 🔄 卡若AI 同步 2026-03-11 20:01 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 11 个 | diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index f21e6ddc..d66ea43f 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -302,3 +302,4 @@ | 2026-03-11 17:54:00 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 17:53 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-11 17:56:46 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 17:56 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-11 18:05:42 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 18:05 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | +| 2026-03-11 20:01:53 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 20:01 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |