From 7b53fa6bc254a44b882f4caf59313721dabb8a3c Mon Sep 17 00:00:00 2001 From: karuo Date: Wed, 4 Mar 2026 17:03:12 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=84=20=E5=8D=A1=E8=8B=A5AI=20=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=202026-03-04=2017:03=20|=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=EF=BC=9A=E5=8D=A1=E6=9C=A8=E3=80=81=E8=BF=90=E8=90=A5=E4=B8=AD?= =?UTF-8?q?=E6=9E=A2=E5=B7=A5=E4=BD=9C=E5=8F=B0=20|=20=E6=8E=92=E9=99=A4?= =?UTF-8?q?=20>20MB:=2011=20=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../抖音视频解析/n8n_一键下载抖音视频文案.json | 102 ++++++++++++++++++ .../抖音视频解析/n8n_一键下载抖音视频文案_使用说明.md | 47 ++++++++ .../木叶_视频内容/抖音视频解析/脚本/douyin_api.py | 100 +++++++++++++++++ .../抖音视频解析/脚本/requirements_api.txt | 2 + 运营中枢/工作台/gitea_push_log.md | 1 + 运营中枢/工作台/website分组清单.md | 5 +- 运营中枢/工作台/代码管理.md | 1 + 运营中枢/工作台/端口登记/SKILL.md | 1 + 8 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案.json create mode 100644 03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案_使用说明.md create mode 100644 03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/douyin_api.py create mode 100644 03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/requirements_api.txt diff --git a/03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案.json b/03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案.json new file mode 100644 index 00000000..a1d43958 --- /dev/null +++ b/03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案.json @@ -0,0 +1,102 @@ +{ + "name": "一键下载抖音视频文案", + "nodes": [ + { + "parameters": {}, + "id": "a1b2c3d4-0000-4000-8000-000000000001", + "name": "手动输入抖音链接", + "type": "n8n-nodes-base.manualTrigger", + "typeVersion": 1, + "position": [240, 300], + "webhookId": "" + }, + { + "parameters": { + "assignments": { + "assignments": [ + { + "id": "url", + "name": "url", + "value": "https://v.douyin.com/请替换为实际链接", + "type": "string" + }, + { + "id": "download", + "name": "download", + "value": true, + "type": "boolean" + } + ] + }, + "options": {} + }, + "id": "a1b2c3d4-0000-4000-8000-000000000002", + "name": "设置链接与是否下载", + "type": "n8n-nodes-base.set", + "typeVersion": 3.4, + "position": [460, 300], + "onError": "continue" + }, + { + "parameters": { + "method": "POST", + "url": "http://douyin-api:3099/parse", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "Content-Type", + "value": "application/json" + } + ] + }, + "sendBody": true, + "bodyContentType": "json", + "specifyBody": "json", + "jsonBody": "={{ JSON.stringify({ url: $json.url, download: $json.download }) }}", + "options": { + "timeout": 60000 + } + }, + "id": "a1b2c3d4-0000-4000-8000-000000000003", + "name": "调用抖音解析API", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [680, 300], + "onError": "continue" + } + ], + "connections": { + "手动输入抖音链接": { + "main": [ + [ + { + "node": "设置链接与是否下载", + "type": "main", + "index": 0 + } + ] + ] + }, + "设置链接与是否下载": { + "main": [ + [ + { + "node": "调用抖音解析API", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "settings": { + "executionOrder": "v1" + }, + "staticData": null, + "meta": { + "templateCredsSetupCompleted": true + }, + "pinData": {}, + "versionId": "1" +} diff --git a/03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案_使用说明.md b/03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案_使用说明.md new file mode 100644 index 00000000..95aed422 --- /dev/null +++ b/03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案_使用说明.md @@ -0,0 +1,47 @@ +# n8n 工作流:一键下载抖音视频文案 + +## 功能 + +- 在 n8n 中执行一次即可:输入抖音链接 → 自动解析文案并保存到本机,可选下载无水印视频。 +- 依赖同编排内的 **抖音解析 API**(`website-douyin-api`,端口 3099),与 n8n 同属 website 分组。 + +## 一键完成(全自动) + +### 1. 确保服务已启动(一条命令) + +```bash +cd /Users/karuo/Documents/开发/2、私域银行/神射手 && docker compose up -d douyin-api n8n +``` + +### 2. 在 n8n 中导入工作流(唯一需手动的一步) + +1. 打开 n8n:http://localhost:5678 +2. 左上角 **菜单** → **Workflows** → **Import from File**(或 **Import from URL**) +3. 选择本目录下的 **`n8n_一键下载抖音视频文案.json`** 导入 + (路径:`卡若AI/03_卡木(木)/木叶_视频内容/抖音视频解析/n8n_一键下载抖音视频文案.json`) +4. 保存工作流(可命名如「一键下载抖音视频文案」) + +### 3. 使用方式 + +- **方式一(推荐)**:执行前点击节点「**设置链接与是否下载**」,将 `url` 改为要解析的抖音链接(如 `https://v.douyin.com/xxx`),`download` 为 `true` 则同时下载视频,为 `false` 则仅解析文案。然后点击 **Test workflow** 或 **Execute Workflow**。 +- **方式二**:用「**Execute Workflow**」时在输入数据中传入一条数据:`{"url": "https://v.douyin.com/xxx", "download": true}`。 + +### 4. 结果 + +- 文案会保存到本机:`/Users/karuo/Documents/卡若Ai的文件夹/视频/{aweme_id}_文案.json` 与 `{aweme_id}_文案.txt` +- 若 `download: true`,视频会保存到同目录下 +- n8n 最后一个节点会输出 API 返回的 JSON(aweme_id、title、desc、hashtags、caption_txt_path、video_path 等) + +## 端口与编排 + +| 服务 | 容器名 | 端口 | 说明 | +|-------------|--------------------|-------|----------------| +| 抖音解析 API | website-douyin-api | 3099 | 供 n8n 调用 | +| n8n | website-n8n | 5678 | 工作流编辑与执行 | + +两者均在 **神射手** 同一 docker-compose 下,网络互通,n8n 内请求地址为 `http://douyin-api:3099/parse`。 + +## 故障排查 + +- **调用抖音解析API 报错**:确认 `docker ps` 中 `website-douyin-api` 在运行,且 n8n 与 douyin-api 在同一 compose 网络(均为 website)。 +- **解析失败**:检查链接是否为抖音短链或完整视频链接;若被风控,可在本机用脚本 `douyin_parse.py` 或 MCP 浏览器兜底。 diff --git a/03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/douyin_api.py b/03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/douyin_api.py new file mode 100644 index 00000000..2ad7d739 --- /dev/null +++ b/03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/douyin_api.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +抖音解析 HTTP API:供 n8n 等调用,一键解析抖音链接并返回文案(可选下载视频)。 +POST /parse Body: {"url": "https://v.douyin.com/xxx", "download": true|false} +""" +from pathlib import Path + +from flask import Flask, request, jsonify + +# 同目录下的 douyin_parse +from douyin_parse import fetch_and_parse, download_video, DEFAULT_OUTPUT + +app = Flask(__name__) +app.config["JSON_AS_ASCII"] = False + +# 输出目录:容器内用 /data/douyin_output(需挂载),本机用 DEFAULT_OUTPUT +import os as _os +OUTPUT = Path(_os.environ.get("DOUYIN_OUTPUT_DIR", str(DEFAULT_OUTPUT))) +OUTPUT.mkdir(parents=True, exist_ok=True) + + +@app.route("/health", methods=["GET"]) +def health(): + return jsonify({"status": "ok"}) + + +@app.route("/parse", methods=["POST", "GET"]) +def parse(): + """ + POST: JSON body {"url": "https://v.douyin.com/xxx", "download": false} + GET: ?url=https://v.douyin.com/xxx&download=false + """ + if request.method == "GET": + url = request.args.get("url", "").strip() + download = request.args.get("download", "false").lower() in ("1", "true", "yes") + else: + data = request.get_json(silent=True) or {} + url = (data.get("url") or "").strip() + download = data.get("download", False) in (True, "true", "1", "yes") + + if not url: + return jsonify({"error": "缺少 url 参数", "usage": "POST /parse body: {\"url\": \"抖音链接\", \"download\": false}"}), 400 + + info, video_url = fetch_and_parse(url) + aweme_id = info.get("aweme_id") + + if info.get("error"): + return jsonify({"error": info["error"], "info": info}), 500 + if not aweme_id or aweme_id == "unknown": + return jsonify({"error": "无法解析视频,请检查链接", "info": info}), 400 + + # 保存文案 JSON 与 TXT + OUTPUT.mkdir(parents=True, exist_ok=True) + import json as _json + import re as _re + caption_json = OUTPUT / f"{aweme_id}_文案.json" + caption_txt = OUTPUT / f"{aweme_id}_文案.txt" + with open(caption_json, "w", encoding="utf-8") as f: + _json.dump(info, f, ensure_ascii=False, indent=2) + txt_lines = [ + (info.get("title") or "").strip(), + "", + (info.get("desc") or "").strip(), + "", + "话题: " + " ".join(f"#{t}" for t in (info.get("hashtags") or [])), + "", + f"aweme_id: {aweme_id}", + f"链接: https://www.douyin.com/video/{aweme_id}", + ] + with open(caption_txt, "w", encoding="utf-8") as f: + f.write("\n".join(txt_lines)) + + result = { + "aweme_id": aweme_id, + "title": info.get("title") or "", + "desc": info.get("desc") or "", + "hashtags": info.get("hashtags") or [], + "author": info.get("author") or "", + "caption_txt_path": str(caption_txt), + "caption_json_path": str(caption_json), + "video_url": video_url, + "video_downloaded": False, + "video_path": None, + } + + if download and video_url: + safe_title = _re.sub(r"[^\w\s\u4e00-\u9fff]+", "_", (info.get("title") or aweme_id))[:50].strip("_") + out_file = OUTPUT / f"{aweme_id}_{safe_title or 'video'}.mp4" + ok, err = download_video(video_url, out_file) + result["video_downloaded"] = ok + result["video_path"] = str(out_file) if ok else None + if not ok: + result["video_error"] = err + + return jsonify(result) + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=3099, debug=False) diff --git a/03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/requirements_api.txt b/03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/requirements_api.txt new file mode 100644 index 00000000..3d13b1ef --- /dev/null +++ b/03_卡木(木)/木叶_视频内容/抖音视频解析/脚本/requirements_api.txt @@ -0,0 +1,2 @@ +flask>=2.0.0 +requests>=2.28.0 diff --git a/运营中枢/工作台/gitea_push_log.md b/运营中枢/工作台/gitea_push_log.md index 2534c046..2eb81a19 100644 --- a/运营中枢/工作台/gitea_push_log.md +++ b/运营中枢/工作台/gitea_push_log.md @@ -219,3 +219,4 @@ | 2026-03-03 14:29:21 | 🔄 卡若AI 同步 2026-03-03 14:29 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 14 个 | | 2026-03-03 17:28:23 | 🔄 卡若AI 同步 2026-03-03 17:28 | 更新:Cursor规则、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | | 2026-03-03 22:01:54 | 🔄 卡若AI 同步 2026-03-03 22:01 | 更新:Cursor规则、金仓、水溪整理归档、卡木、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | +| 2026-03-04 11:48:54 | 🔄 卡若AI 同步 2026-03-04 11:48 | 更新:水桥平台对接、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | diff --git a/运营中枢/工作台/website分组清单.md b/运营中枢/工作台/website分组清单.md index 3bc7a802..2082804b 100644 --- a/运营中枢/工作台/website分组清单.md +++ b/运营中枢/工作台/website分组清单.md @@ -20,6 +20,7 @@ | 神射手 | website-shensheshou | **3117** | `开发/2、私域银行/神射手/docker-compose.yml` | 与玩值电竞、OpenClaw、n8n 同文件启动 | | 玩值电竞 Web | website-wanzhi-web | **3001** | 同上 | 同上 | | n8n | website-n8n | **5678** | 同上 | 工作流自动化,镜像 docker.n8n.io/n8nio/n8n | +| 抖音解析 API | website-douyin-api | **3099** | 同上 | 供 n8n「一键下载抖音视频文案」工作流调用 | | OpenClaw 网关 | website-openclaw-gateway | **18789** / **18790** | 同上 | 镜像 openclaw:local 需在 OpenClaw 项目内先 build;配置用 `openclaw/.env` | | 存客宝 Web | cunkebao-web | **3100** | `开发/2、私域银行/cunkebao_v3/docker-compose.yml` | 独立编排(不设 name: website);同编排含触客宝+后端+MySQL+Redis | | 触客宝 Web | touchkebao-web | **3101** | 同上 | 同上 | @@ -31,9 +32,9 @@ ## 统一启动方式 -- **神射手 + 玩值电竞 + n8n + OpenClaw 网关**(主站):在神射手目录执行 +- **神射手 + 玩值电竞 + n8n + 抖音解析 API + OpenClaw 网关**(主站):在神射手目录执行 `docker compose up -d` 或 `docker compose up -d --build` - 各服务会出现在 Docker Desktop 的 **website** 分组下。n8n 访问 http://localhost:5678。OpenClaw 镜像需先在 `开发/8、小工具/Docker项目/OpenClaw/openclaw` 内执行 `docker compose build` 生成 `openclaw:local`。 + 各服务会出现在 Docker Desktop 的 **website** 分组下。n8n 访问 http://localhost:5678;抖音解析 API 内网 http://douyin-api:3099/parse(供 n8n 工作流调用)。OpenClaw 镜像需先在 `开发/8、小工具/Docker项目/OpenClaw/openclaw` 内执行 `docker compose build` 生成 `openclaw:local`。 - **存客宝 + 触客宝**:在存客宝项目目录执行 `cd 开发/2、私域银行/cunkebao_v3 && docker compose up -d`(或 `--build` 拉取最新) 存客宝 http://localhost:3100 、触客宝 http://localhost:3101 ;同编排内含后端 8082、MySQL 3307、Redis 6380。 diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index c1c76877..9ad177eb 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -222,3 +222,4 @@ | 2026-03-03 14:29:21 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-03 14:29 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-03 17:28:23 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-03 17:28 | 更新:Cursor规则、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-03 22:01:54 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-03 22:01 | 更新:Cursor规则、金仓、水溪整理归档、卡木、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | +| 2026-03-04 11:48:54 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-04 11:48 | 更新:水桥平台对接、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | diff --git a/运营中枢/工作台/端口登记/SKILL.md b/运营中枢/工作台/端口登记/SKILL.md index 136daf40..03f82811 100644 --- a/运营中枢/工作台/端口登记/SKILL.md +++ b/运营中枢/工作台/端口登记/SKILL.md @@ -47,6 +47,7 @@ description: 本机(卡若)Docker 与各类服务端口统一登记表。凡 | 3001 | Web | website-wanzhi-web | 万知 web(玩值电竞) | | 3117 | Web | website-shensheshou | 深深手 | | 5678 | Web | website-n8n | n8n 工作流自动化 | +| 3099 | API | website-douyin-api | 抖音解析 API(供 n8n 调用) | | 8000 | 管理 | portainer | Portainer HTTP | | 9443 | 管理 | portainer | Portainer HTTPS | | 27017 | 数据库 | datacenter_mongodb | MongoDB(唯一,见唯一MongoDB约定) |