#!/usr/bin/env python3 """ 标数脚本 — 飞书剧本表格互动行自动编号 用法: python3 biaoshu_number.py [--prefix PREFIX] 示例: python3 biaoshu_number.py "https://makee-interactive.feishu.cn/wiki/P9bvw6nXziqzWZkxDmMcOZN4ndc" python3 biaoshu_number.py "https://makee-interactive.feishu.cn/wiki/xxx" --prefix 12186 """ import json import sys import requests # ========== 配置 ========== APP_ID = "cli_a931175d41799cc7" APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14" SHEET_MAX_ROWS = 250 def get_tenant_token() -> str: r = requests.post( "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", json={"app_id": APP_ID, "app_secret": APP_SECRET}, ) return r.json()["tenant_access_token"] def get_doc_blocks(token: str, obj_token: str) -> list: r = requests.get( f"https://open.feishu.cn/open-apis/docx/v1/documents/{obj_token}/blocks", headers={"Authorization": f"Bearer {token}"}, ) return r.json().get("data", {}).get("items", []) def find_embedded_sheet(blocks: list) -> tuple: """Find block_type=30 (embedded sheet), return (spreadsheet_token, sheet_id)""" for block in blocks: if block.get("block_type") == 30: st = block.get("sheet", {}).get("token", "") parts = st.split("_") if len(parts) == 2: return parts[0], parts[1] return None, None def read_sheet(token: str, spreadsheet_token: str, sheet_id: str) -> list: r = requests.get( f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}" f"/values/{sheet_id}!A1:B{SHEET_MAX_ROWS}?valueRenderOption=ToString", headers={"Authorization": f"Bearer {token}"}, ) return r.json()["data"]["valueRange"]["values"] def write_cell(token: str, spreadsheet_token: str, sheet_id: str, row: int, value: str) -> bool: body = { "valueRange": { "range": f"{sheet_id}!B{row}:B{row}", "values": [[value]], } } r = requests.put( f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values", headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"}, json=body, ) return r.json().get("code") == 0 def verify_sheet(token: str, spreadsheet_token: str, sheet_id: str) -> list: r = requests.get( f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}" f"/values/{sheet_id}!A1:B{SHEET_MAX_ROWS}?valueRenderOption=ToString", headers={"Authorization": f"Bearer {token}"}, ) return r.json()["data"]["valueRange"]["values"] def parse_wiki_url(url: str) -> str: """Extract obj_token from wiki URL""" # https://xxx.feishu.cn/wiki/P9bvw6nXziqzWZkxDmMcOZN4ndc?... from urllib.parse import urlparse path = urlparse(url).path parts = path.strip("/").split("/") return parts[-1] if parts else url def main(): if len(sys.argv) < 2: print("Usage: python3 biaoshu_number.py [--prefix PREFIX]") sys.exit(1) wiki_url = sys.argv[1] prefix = "12185" if len(sys.argv) >= 4 and sys.argv[2] == "--prefix": prefix = sys.argv[3] obj_token = parse_wiki_url(wiki_url) print(f"📄 文档 token: {obj_token}") print(f"🔢 ID 前缀: {prefix}") token = get_tenant_token() print("✅ Token 获取成功") blocks = get_doc_blocks(token, obj_token) spreadsheet_token, sheet_id = find_embedded_sheet(blocks) if not spreadsheet_token: print("❌ 未找到内嵌 Sheet!") sys.exit(1) print(f"📊 Sheet: {spreadsheet_token} / {sheet_id}") rows = read_sheet(token, spreadsheet_token, sheet_id) print(f"📖 读取 {len(rows)} 行") # Identify interaction rows (A列 not empty, not 'TL') interactions = [] for i, r in enumerate(rows[1:], start=2): a = (r[0] or "").strip() if len(r) > 0 else "" if a and a != "TL": interactions.append((i, a)) print(f"🎯 识别到 {len(interactions)} 个互动行") # Write IDs ok = 0 fail = 0 for idx, (row_num, a_type) in enumerate(interactions, start=1): new_id = f"{prefix}{idx:02d}" if write_cell(token, spreadsheet_token, sheet_id, row_num, new_id): ok += 1 print(f" ✅ Row {row_num:3d} ({a_type}) → {new_id}") else: fail += 1 print(f" ❌ Row {row_num:3d} ({a_type}) → 写入失败") print(f"\n📊 结果: {ok} 成功 / {fail} 失败") # Verify print("\n🔍 验证...") updated = verify_sheet(token, spreadsheet_token, sheet_id) for i, r in enumerate(updated[1:], start=2): a = (r[0] or "").strip() if len(r) > 0 else "" b = (r[1] or "").strip() if len(r) > 1 else "" if b: status = "✅" if b.startswith(prefix) else "⚠️" print(f" {status} Row {i}: {a} → {b}") if __name__ == "__main__": main()