🔄 卡若AI 同步 2026-03-11 20:12 | 更新:水桥平台对接、水溪整理归档、运营中枢工作台 | 排除 >20MB: 11 个
This commit is contained in:
@@ -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);执行完毕用复盘格式回复 |
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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="字幕包含时间戳")
|
||||
|
||||
@@ -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视频/原视频`
|
||||
@@ -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 <token>` 或环境变量 `FEISHU_MARCH_WIKI_TOKEN` |
|
||||
|
||||
### 卡若AI 脚本如何取飞书 Token
|
||||
|
||||
@@ -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 个 |
|
||||
|
||||
@@ -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) |
|
||||
|
||||
Reference in New Issue
Block a user