158 lines
4.9 KiB
Python
158 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
标数脚本 — 飞书剧本表格互动行自动编号
|
|
|
|
用法:
|
|
python3 biaoshu_number.py <wiki_url> [--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 <wiki_url> [--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()
|